Предварительные требования для этой публикации: базовые знания Python и Jupyter Notebook; базовые знания о машинном обучении.

В этом посте я расскажу, как создать причудливую и интерактивную визуализацию данных, подобную этой.

Но прежде чем мы перейдем к этому, давайте начнем с понимания, почему нам нужно визуализировать данные.

Зачем нужна визуализация данных?

Визуализация данных - это группа методов, которые могут преобразовывать гигантские данные с сотнями или тысячами измерений в 2D / 3D представление, чтобы мы, крошечные люди, могли хорошо понимать.

Обычно есть две причины для его использования:

  1. Визуализируйте необработанные данные, когда данные представлены в 2D / 3D пространстве, их легко идентифицировать. Если для каждой точки данных есть категориальные метки, мы можем легко сказать, какие категории похожи, а какие дальше друг от друга. И это может дать нам представление о том, насколько сложна модель, которую нам нужно построить для такого набора данных. Например, если на нашем 2D / 3D графике разные категории уже находятся в соответствующих блоках, мы, вероятно, не захотим использовать Excalibur, чтобы убить такую ​​курицу.
  2. Визуализируйте закодированные функции из необработанных данных / внедрений, мы хотели бы знать, имеют ли эти функции смысл или модель кодировщика усвоила правильные вещи. Обычно это более применимо к наборам данных изображений, где по графику мы можем сказать, соответствуют ли закодированные функции тем семантическим характеристикам, которые распознаются людьми.

В этом посте я расскажу о методах визуализации данных, дам несколько практических примеров и, конечно же, сделаю это увлекательным, сделав его интерактивным.

Методы визуализации данных

Существует множество способов визуализации данных, два самых популярных из них - PCA и t-SNE:

  • PCA: анализ основных компонентов, как следует из названия, он находит наиболее важные и релевантные компоненты для представления данных. По сути, этот алгоритм снижает размерность до минимума. Для любопытных есть более подробное объяснение.
  • T-SNE: t-распределенное стохастическое соседнее встраивание, более сложное название. По сути, этот алгоритм смотрит на распределение данных и пытается представить то же распределение с меньшим количеством измерений. Опять более подробная информация.

Алгоритм T-SNE требует больших вычислительных ресурсов и времени по сравнению с PCA. Однако у PCA есть ограничение: это метод уменьшения линейных размеров. В общем, t-SNE может моделировать истинное распределение данных лучше, чем PCA.

Визуализация статических данных

Сначала я хотел бы начать с неинтерактивной визуализации данных, поскольку ее проще реализовать. Другая причина заключается в том, что преимущества интерактивной визуализации данных можно будет лучше оценить, если у вас будет некоторый опыт работы с неинтерактивной версией.

Но если вы любите приключения и готовы принять вызов, смело переходите к следующему разделу :)

Вот ссылка на полный код на github, но позвольте мне помочь вам шаг за шагом.

Пакеты python, которые нам нужны для визуализации статических данных, - это numpy, matplotlib и sklearn, пожалуйста, установите их, если вы этого не сделали, и импортируйте их в наш проект.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import offsetbox
from sklearn import manifold, datasets, decomposition

и мы будем использовать классические наборы данных рукописных цифр MNIST, чтобы продемонстрировать визуализацию необработанных данных, так что давайте подготовим данные

digits = datasets.load_digits(n_class=10)
X = digits.data
y = digits.target

Давайте определим функцию построения графика, которая будет использоваться позже. Эта простая функция в основном выполняет три задачи. Сначала он масштабирует значения, чтобы они соответствовали графику. Затем он форматирует представление точки данных так, чтобы каждая точка данных отображалась в виде цветного текста. Наконец, он добавляет AnnotationBox для некоторых образцов, который показывает соответствующее изображение точки данных.

def plot_MNIST(X, title=None):
    x_min, x_max = np.min(X, 0), np.max(X, 0)
    X = (X - x_min) / (x_max - x_min) # scale the values to fit    
    plt.figure(figsize= (10,10))
    ax = plt.subplot(111)
    for i in range(X.shape[0]):
        plt.text(X[i, 0], X[i, 1], str(digits.target[i]),
                 color=plt.cm.Set1(y[i] / 10.),
                 fontdict={'weight': 'bold', 'size': 9}) 
    if hasattr(offsetbox, 'AnnotationBbox'):
        ## only print thumbnails with matplotlib > 1.0
        shown_images = np.array([[1., 1.]])  # just something big
        for i in range(digits.data.shape[0]):
            dist = np.sum((X[i] - shown_images) ** 2, 1)
            if np.min(dist) < 5e-3:
                ## don't show points that are too close
                continue
            shown_images = np.r_[shown_images, [X[i]]]
            imagebox = offsetbox.AnnotationBbox(
                offsetbox.OffsetImage(digits.images[i], cmap=plt.cm.gray_r),
                X[i])
            ax.add_artist(imagebox)
    plt.xticks([]), plt.yticks([])
    if title is not None:
        plt.title(title)

Затем мы используем функцию sklearn для вычисления PCA, как вы можете догадаться, «n_components = 2» указывает, что результат должен состоять из двух измерений.

print("Computing PCA projection")
t0 = time()
X_pca = decomposition.TruncatedSVD(n_components=2).fit_transform(X)
plot_MNIST(X_pca,
               "Principal Components projection of the digits (time %.2fs)" %
               (time() - t0))
plt.show()

Ниже представлен результат визуализации данных PCA. Время, необходимое для его обработки, невероятно быстрое, всего 0,01 секунды. Мы можем сказать, что цифры в одной категории собраны вместе, но кластеры перекрывают друг друга, и в центральной части графика есть большой беспорядок.

Тогда давай попробуем t-SNE. Снова мы используем предварительно созданную функцию sklearn для вычисления t-SNE, кроме нашего старого друга «n_components», есть еще один параметр «init = 'pca'», он предназначен для инициализации распределения с помощью pca, чтобы лучше сохранить глобальную структуру распространение.

print("Computing t-SNE embedding")
t0 = time()
X_tsne = manifold.TSNE(n_components=2, init='pca').fit_transform(X)
plot_MNIST(X_tsne,
               "t-SNE embedding of the digits (time %.2fs)" %
               (time() - t0))
plt.show()

В результате t-SNE разные рукописные цифры хорошо разделены, это более четкое представление по сравнению с PCA, а также четкое указание на то, что этому набору данных не требуется слишком сложная модель для выполнения классификации.

Интерактивная визуализация данных

Мы успешно реализовали визуализацию данных PCA и t-SNE в предыдущем разделе. Но такая визуализация статична, мы не можем увеличивать интересующую нас область, мы не можем делать такие крутые вещи, как вращение точек данных в трехмерном пространстве, и у нее определенно отсутствует красивый интерфейс.

Tensorboard - это волшебный инструмент, который предоставляет все, что нам нужно. Это инструмент визуализации из семейства Tensorflow. Он изначально поддерживает Tensorflow и недавно также открыл границу с Pytorch. В этом посте мы будем использовать Tensorflow, вот ссылка на полный код, а ниже - пошаговое руководство.

Помимо пакетов, которые мы уже установили ранее, нам также необходимо установить Tensorflow, поэтому, пожалуйста, установите его, если вы еще не сделали этого.

%matplotlib inline
import matplotlib.pyplot as plt
import tensorflow as tf
import numpy as np
import os
from tensorflow.contrib.tensorboard.plugins import projector
from tensorflow.examples.tutorials.mnist import input_data

Чтобы использовать тензорную плату для визуализации данных, нам нужно подготовить для нее три вещи:

  1. данные в форме ckpt. Это точки данных, которые мы собираемся визуализировать.
  2. метаданные в формате TSV (необязательно). Метаданные могут быть категориальной меткой, чтобы мы могли позже раскрасить точки по метке. Он также может быть в текстовом формате, поэтому, если мы визуализируем вложение слова, мы можем проверить, какое слово представляет точка данных.
  3. спрайт в формате png (необязательно). Это для набора данных изображения. Когда мы хотим видеть образцы изображений, а не просто точки, нам это нужно.

Все они должны быть помещены в один каталог журнала, поэтому давайте определим каталог и имена файлов, а также настроим проектор (который будет использоваться Tensorboard) так, чтобы он указывал на правильные пути.

LOG_DIR = os.getcwd()+'/mnist_log'
path_for_mnist_checkpoint = os.path.join(LOG_DIR, "model.ckpt")
path_for_mnist_metadata =  os.path.join(LOG_DIR,'metadata.tsv')
path_for_mnist_sprites =  os.path.join(LOG_DIR,'mnistdigits.png')
tensor_name = 'mnist_embeddings'
summary_writer = tf.summary.FileWriter(LOG_DIR)
config = projector.ProjectorConfig()
embedding = config.embeddings.add()
embedding.tensor_name = tensor_name
embedding.metadata_path = path_for_mnist_metadata 
embedding.sprite.image_path = path_for_mnist_sprites
embedding.sprite.single_image_dim.extend([28,28])
projector.visualize_embeddings(summary_writer, config)

Загрузим набор данных MNIST.

Samples_to_visualize = 500
mnist = input_data.read_data_sets("MNIST_data/", one_hot=False)
batch_xs, batch_ys = mnist.train.next_batch(Samples_to_visualize)

Давайте сначала создадим данные в форме ckpt (checkpoint)。

embedding_var = tf.Variable(batch_xs, name=tensor_name)
sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
saver = tf.train.Saver()
saver.save(sess, path_for_mnist_checkpoint, 1)

Для метаданных мы будем использовать целевые метки и записывать их в формате tsv.

with open(path_for_mnist_metadata,'w') as f:
    f.write("Index\tLabel\n")
    for index,label in enumerate(batch_ys):
        f.write("%d\t%d\n" % (index,label))

Затем мы создаем изображение спрайта. Этот спрайт похож на большой контейнер для всех образцов изображений в нем. Поскольку мы уже установили размер образца изображения в проекте, tenorboard будет сканировать большое изображение спрайта, используя указанное нами измерение в качестве размера окна. Это изображение спрайта должно быть квадратным, но не обязательно полностью заполненным. Вот почему вы видите пробелы в правом нижнем углу изображения.

to_visualise = batch_xs
# Reshapes mnist digit embedding shape (batch,28*28) to image shape (batch,28,28)
to_visualise = np.reshape(to_visualise,(-1,28,28))
# invert black white
to_visualise = 1-to_visualise
to_visualise = np.array(to_visualise)
img_h = to_visualise.shape[1]
img_w = to_visualise.shape[2]
n_plots = int(np.ceil(np.sqrt(to_visualise.shape[0])))
# create big sprite template
sprite_image = np.ones((img_h * n_plots ,img_w * n_plots ))
# fill the sprite templates with the handwritten digits
for i in range(n_plots):
    for j in range(n_plots):
        this_filter = i * n_plots + j
        if this_filter < to_visualise.shape[0]:
            this_img = to_visualise[this_filter]
            sprite_image[i * img_h:(i + 1) * img_h,
              j * img_w:(j + 1) * img_w] = this_img
# save the sprite image
plt.imsave(path_for_mnist_sprites,sprite_image,cmap='gray')
plt.imshow(sprite_image,cmap='gray')

Когда все файлы будут подготовлены, каталог журнала должен выглядеть примерно так.

Наконец, мы cd в каталог, содержащий каталог журнала, и вводим команду:

tensorboard --logdir=mnist_log

Результат должен быть:

TensorBoard 1.12.0 at http://YOUR_PC_NAME:6006 (Press CTRL+C to quit)

Поздравляю! Tensorboard работает успешно, и все, что вам нужно сделать, это перейти на ваш localhost: 6006 (этот порт может быть другим, просто следуйте тому, который показан в выводе), чтобы проверить свою работу.

Еще одна вещь, которую нужно изменить, - это опция «Coloyby», мы можем выбрать метаданные в качестве цветового индикатора.

И после этого вы увидите это:

Если вы переключите вкладку PCA на вкладку t-SNE в левом нижнем углу, появится что-то вроде этого

Он продолжает меняться, потому что обучение t-SNE все еще продолжается, когда вы его визуализируете. Когда он станет относительно стабильным, вы можете нажать кнопку «Пауза» в нижнем левом углу, чтобы заморозить танцевальные данные.

Tensorboard - довольно мощный инструмент, и есть немало вещей, которые вы можете настроить. Я не буду вдаваться в подробности в этой части, просто приятно поиграться!

Заключение

В этом посте я кратко представил визуализацию данных, продемонстрировал как статическую, так и интерактивную визуализацию данных.

Пока что мы визуализировали необработанные данные. Поскольку я не хочу, чтобы этот пост был слишком длинным, я упустил часть визуализации встраиваемых / закодированных функций. Основное изменение для визуализации внедрений состоит в том, что вместо использования необработанных данных нам нужно использовать кодировщик для преобразования необработанных данных в пространство функций и использовать преобразованные данные для визуализации. Те, кто хочет попробовать, могут проверить word2vec, который преобразует слова в вложения, или предварительно обученную модель vgg / resnet, которая преобразует изображения в вложения. Удачного знакомства :)