Как хранить несколько изображений в 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])
Результатом является печать весов первых нейронов каждой эпохи, поэтому вы можете заметить изменения.
5 Обучите модель с помощью пользовательского обратного вызова.
Выводы
Возможность визуализировать эволюцию вашей модели на этапе обучения имеет решающее значение для хорошей разработки и дает ключевую информацию о том, в каком направлении следует двигаться, чтобы повысить точность и производительность модели.
Однако также важно учитывать затраты на оценку наших пользовательских показателей, поскольку время является важным фактом, когда речь идет об обучающих моделях. В этом примере проекта распаковка образов и тестирование генератора может занять несколько дополнительных минут в зависимости от вашего оборудования и размера образа, что значительно замедляет обучение.
Хорошим решением этой проблемы является создание переменной частоты, которая будет сравниваться с номером эпохи в пользовательском классе обратного вызова, чтобы, если epoch % frequency == 0
, мы тестировали генератор и сохраняли результаты.
Я надеюсь, что этот пост был полезным и полезным, чтобы узнать больше статей об искусственном интеллекте и науке о данных, вы можете проверить другие мои посты.