Как хранить несколько изображений в Tensorboard, чтобы увидеть эволюцию вашей нейронной сети. Применение кейса к модели GAN

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

После долгих поисков и нескольких файлов документации я, наконец, пришел к результату, который вы можете видеть на изображении:

В приведенном выше примере модель пытается перевести данное изображение в художественную картину Моне, используя модель Pix2Pix [ссылка на бумагу]. Вы можете найти набор данных, который вы просматриваете, в репозитории Kaggle [ссылка]

Примечание 1. Количество эпох, с которыми была обучена модель, очень мало, так как я просто хотел показать приборную панель, поэтому результаты выглядят очень плохо.

Зачем использовать Tensorboard

Tensorboard – это инструмент визуализации, предоставляющий основу для анализа производительности нейронной сети. Его можно интегрировать с помощью библиотек Tensorflow и Pytorch, создавая интерфейс на локальном порту вашего компьютера, куда можно проецировать метрики, такие как эволюция функции потерь, или отслеживать настроенные, такие как сгенерированные изображения, как в этом случае.

Эти визуализации необходимы на этапе разработки модели нейронной сети, позволяя нам обнаруживать ключевые проблемы, такие как переобучение/недообучение, измерять и сравнивать несколько моделей. strong> или предоставить информацию о том, какие изменения могут улучшить общую производительность(настройка гиперпараметров)
Например, анализ сгенерированных изображений в каждую эпоху может помочь нам обнаружить слабые места в генераторе, такие как генерация зернистых узоров или стагнация из-за коллапса режима, но это темы для другой статьи.

Для получения дополнительной информации о Tensorboard вы можете ознакомиться с документацией здесь.

Код

Я не хочу тратить ваше время, поэтому вот код для сохранения изображений:

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

Объяснение кода

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

1-й Нам нужно создать подкласс keras-callbacks, в котором мы можем определить наш пользовательский обратный вызов.
Обратные вызовы — это функции, которые выполняются с определенной частотой во время обучения [см. документ]. Чтобы указать Tensorflow использовать обратные вызовы при обучении, нам просто нужно передать их в качестве аргументов в виде объекта списка (см. шаг 5).

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

Мы также определяем переменную экземпляра self.writer, которая создает средство записи сводного файла для данного каталога журнала (где мы собираемся хранить информацию для последующего отображения на Tensorboard).

2nd Мы определяем метод класса on_epoch_end, который, как следует из его названия, будет выполняться после каждой эпохи.

Примечание 2. Аргументы, которые получают этот метод, имеют префикс Tensorflow, поэтому не пытайтесь их изменить.

В методе on_epoch_end мы также должны определить функцию для генерации изображений (так код будет выглядеть чище и лучше организованным).

Функция generate_imgs берет набор изображений (элемент TakeDataset из Tensorflow.data) и генератор (g) и возвращает список изображений с тремя дисплеями, объединяющих по вертикали входное изображение x , переведенное изображение по модели out и наземной правде y. Если мы не объединим изображения, они будут отображаться на разных картах в Tensorboard.

Примечание 3. Перед объединением мы должны удалить измерения пакета, используя функцию tf.squeeze(), чтобы предотвратить исключения.

3-й Затем мы сохраняем изображения, используя tf.summary.image()

Первая строка self.writer.as_default() указывает Tensorflow сохранять следующие операции в том же графе (граф self.writer), поэтому все изображения, сгенерированные после каждой эпохи обратным вызовом, будут записаны в один и тот же файл [проверьте doc, link]
Далее функция tf.name_scope() добавляет к имени каждого изображения префикс train/ или val/, поэтому изображения, сгенерированные поездом и проверкой, сохраняются в разных папках в вашем рабочем каталоге (в Tensorboard это отображается как разные разделы, но на самом деле оба файла имеют одинаковые имена и принадлежат к одному и тому же итоговому файлу)

Примечание 4. В этом случае я снова определил имена изображений как область действия, поэтому они будут называться «train/train/» или «val/val». ”, но для дальнейших проектов рекомендую поменять.

4-й Инициализировать класс.
Вернемся к нашему файлу train.py, в котором мы создали нашу модель, мы инициализируем класс, вызвав его (строка 9). Для проекта я решил взять 4 изображения из обучающего набора и еще 4 изображения из проверки, каждое изображение из другой партии. Затем я указываю генератор (pix2pix — это keras.model, поэтому я могу вызывать генератор как метод) и logdir, в котором следует сохранять сводку.

Примечание 5. Кто-то может подумать, что если мы передаем генератор в качестве аргумента, то при обучении их веса не будут обновляться и результаты будут неверными. Однако Tensorflow удается сделать именно это, так как мы передаем экземпляр класса pix2pix.g, который указывает на созданный класс pix2pix, т.е. когда pix2pix обновляет свои веса, он применяется ко всем его экземплярам.
Я лично проверял это ( и вы тоже можете это сделать, если не верите мне), добавив строку в пользовательский обратный вызов:

print(self.g.get_weights()[0][0][0][0])

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

Обучите модель с помощью пользовательского обратного вызова.

Выводы

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

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

Хорошим решением этой проблемы является создание переменной частоты, которая будет сравниваться с номером эпохи в пользовательском классе обратного вызова, чтобы, если epoch % frequency == 0, мы тестировали генератор и сохраняли результаты.

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