Tensorboard для Pytorch
Введение
Когда мы не хотим применять слишком сложные инструменты для логирования метрик и артефактов, мы можем обращаться к одному из очевидных вариантов — Tensorboard.
TensorBoard — инструмент для визуализации и мониторинга машинного обучения, разработанный Google в рамках проекта TensorFlow.
Среди его преимуществ в сравнении с аналогами (W&B, ClearML) выделяются:
- Простота настройки. Добавить логирование метрик можно за пару строчек кода, а для запуска сервера не нужно ничего настраивать.
- Поддержка многих форматов данных. К ним относятся скаляры, распределения, графы, картинки, аудио, видео, графики и многое другое.
- Бесплатное self-hosted решение. С ним вы будете уверены, что у вас всегда есть доступ к результатам ваших экспериментов.
В то же время у Tensorboard есть недостатки, которые, в первую очередь, влияют на возможность масштабирования:
- Медленная работа. Если количество запусков перевалит за сотню — Tensorboard начнёт подтормаживать.
- Отсутствие сложной группировки данных. Если у вас несколько разных экспериментов — будет крайне неудобно использовать Tensorboard.
В этой статье мы узнаем, как применять Tensorboard для логирования данных в Pytorch. Давайте разбираться со всем по порядку 🙂
Первичная настройка
Единой точкой входа является объект SummaryWriter
, который и даёт нам возможность логировать. Его желательно закрывать в самом конце.
from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter()
#Some code
writer.close()
У SummaryWriter
также есть несколько важных аргументов:
Название параметра | Описание | Значение по умолчанию |
---|---|---|
log_dir | Папка с логами | Папка в директории runs, название которой содержит дату. Например, runs/Aug02_19-01-07 |
max_queue | Максимальный размер очереди логируемых событий, при превышении которого принудительно произойдет запись на диск | 10 |
flush_secs | Частота записи логов на диск | 120 |
Для просмотра того, что было залогировано, нам нужно запустить сам Tensorboard: tensorboard --logdir directory_name
.
Дополнительные параметры представлены в таблице:
Название параметра | Описание |
---|---|
host | Задаёт сетевой интерфейс, где запускается сервер Tensorboard. По умолчанию это localhost . Для доступа с помощью других устройств в сети можно указать 0.0.0.0 , чтобы подключиться с любого IP-адреса. |
port | Указывает номер порта, где запускается сервер Tensorboard. По умолчанию это порт 6006. |
window_title | Позволяет задавать заголовок окна браузера, где открыт Tensorboard. Очень удобно при просмотре разных его экземпляров. |
samples_per_plugin | Помогает ограничивать количество образцов (samples), которые отображаются каждым плагином в Tensorboard. По умолчанию это 10 для изображений, 500 для гистограмм и 1000 для скаляров. Если образцов больше — они даунсэмлятся до нужных лимитов. Например, при добавлении следующего аргумента мы повышаем количество отображаемых изображений до 1000:--samples_per_plugin=images=1000 . |
Логирование скаляров
Чаще всего нам нужно логировать скалярные значения: метрики, лосс, размер learning rate и другое. Для этого у SummaryWriter
есть метод add_scalar
.
writer.add_scalar(scalar_value=loss,
tag="train_loss",
global_step=step,
double_precision=False)
Первый аргумент здесь — значение скаляра. Второй — название. Третий — номер шага (отображается на графике на оси x). Последний — сохранение значения double вместо float.
Теперь если мы залогируем, например, тренировочный лосс и откроем Tensorboard, то увидим примерно следующее:
А если наведём на любую точку графика — увидим в ней значения X и Y.
Для лучшего отображения значений есть несколько полезных фичей. Во-первых, график можно привести к логарифмической шкале с помощью специальной кнопки:
Во-вторых, данные можно сгладить через Smoothing. Он применит на них Exponential Moving Average (подробнее об этом мы рассказывали в нашей статье).
В левом углу есть возможность изменить ось X с помощью трёх вариантов:
- STEP — шаг, то есть
global_step
; - RELATIVE — время от начала эксперимента;
- WALL — абсолютное время.
Конечно, мы можем посмотреть несколько запусков, если выберем их одновременно.
Скаляры можно объединить в группы. Например, если мы передадим в tag
значение losses/train_loss
— у нас появится группа losses
со скаляром train_loss
. Такая группировка очень удобна для отображения, поскольку скаляры находятся рядом.
Иногда мы хотим отображать на одном графике несколько скаляров из одного запуска. Для этого нам нужно использовать add_custom_scalars
. Его можно вызвать разово, и он имеет всего один аргумент layout
. Это словарь, который позволяет объединять скаляры в один график. Давайте рассмотрим его на примере.
Предположим, мы хотим создать два графика: один для отображения значения функции потерь и «потолка» лосса (например, если мы знаем, что он не может быть больше какого-то числа). Второй — для отображения не просто значения лосса, но и его стандартного отклонения.
В таком случае передаём как аргумент:
layout = {'metrics': {'loss_epoch': ['Multiline', ['train_loss', 'train_loss_max']],
'loss_epoch_margin': ['Margin', ['train_loss', 'margin_up', 'margin_down']],
}
}
Здесь мы объединяем скаляры train_loss
и train_loss_max
в график loss_epoch
группы metrics
с помощью метода Multiline
, с одной стороны, и скаляры train_loss
, margin_up
и margin_down
в график loss_epoch_margin
той же группы через метод Margin
.
Multiline
— простое отображение нескольких скаляров на графике.
Margin
— отображение трёх скаляров на графике.
Наибольшее и наименьшее значения обозначаются как границы, а оставшееся значение — как обычный график. При его использовании изменение параметра Smoothing ни на что не повлияет.
Для просмотра этих графиков нужно перейти во вкладку Custom Scalars.
Логирование распределений
В некоторых случаях мы хотим логировать не одиночные значения, а распределения какой-то величины. Например, распределение весов или предсказаний модели. Добавить распределение можно с помощью метода add_histogram
.
writer.add_histogram(tag="probs_distribution_class_0",
values=output[:, 0],
global_step=idx)
Дополнительно возможно настроить способ деления данных на корзинки. За это отвечают аргументы bins
(метод, аналогичный numpy.histogram) и max_bins
(максимальное число корзинок).
При переходе в Tensorboard можно посмотреть графики в разделах distributions и histograms.
Для распределений, близких к нормальному, удобнее пользоваться distributions. Тогда на оси x изобразится global_step
, а яркостью цвета обозначится плотность вероятности (чем светлее цвет, тем меньше вероятность увидеть значение).
Для распределений, отличных от нормального, лучше применять histograms (хотя для близких к нормальному распределений эта вкладка тоже подходит). Здесь они представлены трёхмерно. На одной из осей отображается global_step
, на другой — корзинки. Высота — количество значений.
Логирование артефактов
В Tensorboard также можно логировать различные артефакты.
Граф вычислений
Если добавить в свой код следующие строчки кода — на вкладке graphs появится граф вычислений:
writer.add_graph(model=model, input_to_model=input_data)
Второй аргумент не является обязательным, но при его передаче мы увидим shape тензоров на каждом шаге (Netron, например, такое не умеет).
Предположим, мы решили визуализировать resnet18. Тогда мы имеем:
Если мы кликнем два раза на один из блоков — он развернётся:
К сожалению, иногда части графа накладываются друг на друга. Например, на рисунке выше мы не можем рассмотреть shape. Для решения проблемы нажимаем на блок: в правом верхнем углу появляется информация о нём, в частности входные и выходные shape.
В левой части экрана мы видим инструменты для поиска блоков по имени, выделение цветом (полезно для просмотра блоков, работающих на gpu или cpu) и легенду.
Изображения и видео
Для логирования изображений достаточно вызвать метод add_image:
writer.add_image(tag='image', img_tensor=tensor, global_step=0)
Также можно указать параметр dataformats
для изменения формата данных. Возможные значения: CHW, HWC, HW, WH
.
Чтобы залогировать целый батч изображений, используем torchvision.utils.make_grid
.
Есть возможность логировать видеоролики без звука (гифки):
writer.add_video("video", video_tensor, fps=1)
Предварительно нужно установить библиотеку moviepy
.
Shape video_tensor
должен выглядеть как (батч, Ось времени, Цветовые каналы, Высота, Ширина)
. Количество каналов обязательно равно трём, следовательно, grayscale (1 канал) не поддерживается. Видеоролики находятся в Tensorboard там же, где и картинки.
Embeddings
Одна из самых полезных фичей Tensorboard — projector.
Projector — инструмент для визуализации эмбеддингов объектов.
Он позволяет спроецировать эмбеддинги на трёхмерную систему координат и кластеризовать их.
Для этого необходимо применить метод add_embedding
. Первый аргумент здесь — сами эмбеддинги (например, выходы модели). Дополнительно можно передать изображения (они будут отображаться!), global_step
и tag
, который будем использовать для фильтра.
writer.add_embedding(model.forward(images), label_img=images, global_step=step, tag="emb")
Давайте посмотрим на результат во вкладке projector:
По умолчанию мы видим данные, отраженные на трёхмерную ось с помощью PCA. Выглядит не очень впечатляюще 😟. Чтобы улучшить результат, кластеризуем их через TSNE. Этот процесс происходит на лету, поэтому мы можем видеть промежуточные результаты.
Заключение
Итак, мы рассмотрели Tensorboard — простой и полезный, на наш взгляд, инструмент для логирования метрик и артефактов. Его интуитивно понятный интерфейс и широкие возможности позволяют быстро и эффективно отслеживать динамику обучения, что делает его незаменимым помощником как для начинающих, так и для опытных разработчиков.
А ещё у него есть мощные и продуманные фичи (личные фавориты — это эмбеддинги и графы 🙂). Поэтому Tensorboard хорошо подойдёт для pet-проектов и небольших команд.
Кроме того, в этой статье мы не рассмотрели другие его полезные фичи — логирование аудио, PR-кривых и текстов.
Таким образом, Tensorboard может стать отличным помощником при анализе и оптимизации обучения, который позволит вам глубже понимать весь процесс и принимать более обоснованные решения на всех этапах разработки.