Google Deep Dream art: как выбрать слой в нейронной сети и улучшить его

Я заинтересован в недавнем сообщении в блоге Google, в котором описывается использование nn сделать искусство.

Меня особенно интересует одна техника:

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

Это сообщение http://googleresearch.blogspot.co.uk/2015/06/inceptionism-going-deeper-into-neural.html?m=1.

Мой вопрос: пост описывает это как "простой" случай - есть ли реализация nn с открытым исходным кодом, которая могла бы использоваться для этой цели в относительно подключаемом процессе? Нужно ли обучать сеть только для описанной методики?

Без сомнения, для других методов, упомянутых в статье, нужна сеть, уже обученная на большом количестве изображений, но для описанной мной уже есть какой-то пакет визуализации сетевого уровня с открытым исходным кодом?

2 ответа

Решение

UPD: Google опубликовал более подробные инструкции, как они это реализовали: https://github.com/google/deepdream/blob/master/dream.ipynb

Есть еще один проект: https://317070.github.io/Dream/

Если вы прочитаете 1, [2], [3], [4] по вашей ссылке, вы увидите, что они использовали Caffe. Эта структура уже содержит обученные сети для игры. Вам не нужно ничего тренировать вручную, просто загрузите модели с помощью скриптов.sh в models/ папка.

Вы хотите "процесс plug-and-play", это не так просто, потому что помимо фреймворка нам нужен код используемых скриптов и, возможно, патч Caffe. Я пытался сделать что-то, используя их описание. У Caffe есть интерфейс Python и Matlab, но есть и другие.

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

Так

Насколько я понимаю, они запускают оптимизацию

[sum((net.forwardTo(X, n) - enchanced_layer).^2) + lambda * R(X)] -> min

Т.е. искать такой ввод X так что конкретный слой сетевого слова будет производить "расширенные" данные вместо "исходных" данных.

Есть ограничение регуляризации R(X): X должен выглядеть как "естественное изображение" (без высокочастотного шума).

X это наше целевое изображение. Начальная точка X0 это оригинальное изображение.forwardTo(X, n) это то, что наша сеть производит в слое n когда мы вводим ввод с помощью X. Если говорить о Caffe, вы можете сделать полный проход вперед (net.forward) и посмотрите на интересующий вас блоб (net.blob_vec(n).get_data()).

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

таким образом sum((forwardTo(X, n) - enchanced_net).^2) станет нулевым, когда ваше входное изображение производит именно то, что вы хотите в слое n,

lambda является параметром регуляризации и R(X) я показываю X выглядит естественно. Я не реализовал это, и мои результаты выглядят очень шумно. Что касается его формулы, вы можете посмотреть его в [2].

Я использовал Matlab и fminlbfgs оптимизировать.

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

Как я уже сказал, мне не удалось найти градиент R(X), Что касается основной части формулы, мне удалось найти ее следующим образом:

  • Установите diff blob на слой n в forwardTo(X, n) - enchanced_net, (см. документацию по кафе для set_diff а также set_data, set_data используется для пересылки и ждет данных и set_diff используется для обратного распространения и ожидает ошибок данных).
  • Выполнить частичное обратное распространение от слоя n-1 на вход.
  • Входной блок diff будет содержать нужный нам градиент.

Интерфейсы Python и Matlab НЕ содержат частичное обратное распространение, но внутреннее содержимое Caffe C++ содержит его. Я добавил патч ниже, чтобы сделать его доступным в Matlab.

Результат усиления 4-го слоя:

Результат усиления 4-го слоя

Я не доволен результатами, но думаю, что в статье есть что-то общее.

  • Вот код, который выдает картинку выше "как есть". Точка входа - "run2.m", "fit2.m" содержит фитнес-функцию: https://github.com/galchinsky/caf
  • Вот исправление caffe для интерфейса Matlab, чтобы сделать частичное обратное распространение доступным: https://gist.github.com/anonymous/53d7cb44c072ae6320ff

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

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

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

Я не очень разбираюсь в деталях реализации в caffe, так как в основном использую theano. Надеюсь, поможет!

Обновить

Итак, я прочитал о подробных статьях [1],[2],[3],[4] сегодня и выяснил, что [3] на самом деле подробно рассказывает об алгоритме

Локально-оптимальное I можно найти методом обратного распространения. Процедура связана с процедурой обучения ConvNet, где обратное распространение используется для оптимизации весов слоя. Разница в том, что в нашем случае оптимизация выполняется по отношению к входному изображению, в то время как веса привязаны к найденным на этапе обучения. Мы инициализировали оптимизацию с нулевым изображением (в нашем случае ConvNet был обучен на данных с нулевым центрированным изображением), а затем добавили среднее изображение обучающего набора к результату.

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

Другие вопросы по тегам