Автокодировщик изображений с помощью деконволюции и отмены вставки
Оглавление
Сводка
В примере Image\GettingStarted\07_Deconvolution_PY.py показано, как использовать deconvolution и unpooling для создания простого автокодировщика изображений (07_Deconvolution_BS.cntk — соответствующая версия BrainScript). Он использует набор данных MNIST, имеющий разрешение 28x28x1, кодирует его в представление 7x7x1 с использованием свертки и объединения в пул и декодирования исходного разрешения. Критерий обучения — это ошибка корневого среднего квадрата (RMSE). На рисунке выше показаны визуализации исходного изображения, закодированного изображения и декодированного изображения для первых пяти изображений тестового набора MNIST.
Настройка
Чтобы запустить пример, вам потребуется набор данных MNIST. Чтобы получить данные, выполните следующую команду из Examples\Image\DataSets\MNIST
папки:
python install_mnist.py
Выполнение примера
Пример находится в папке Examples\Image\GettingStarted
. Чтобы запустить этот пример, используйте следующую команду, чтобы запустить версию Python (из среды Python CNTK):
python 07_Deconvolution_PY.py
или эта команда для версии BrainScript:
cntk configFile=07_Deconvolution_BS.cntk
Значения RMSE для обучения и тестирования : 0,225 и 0,223 соответственно. Чтобы визуализировать закодированные и декодированные изображения, выполните следующую команду:
python 07_Deconvolution_Visualizer.py
Задайте use_brain_script_model=True
для модели BrainScript и False
для модели Python.
Визуализации будут храниться в папке Output
Examples\Image\GettingStarted
вместе с текстовым представлением кодировщика и выходными данными декодера.
Технические сведения
Ниже приведено определение модели для простого автокодировщика изображений в BrainScript (полный файл конфигурации см. в разделе Image\GettingStarted\07_Deconvolution_BS.cntk).
cMap = 1
model = inputFeatures => {
conv1 = ConvolutionalLayer {cMap, (5:5), pad = true, activation=ReLU}(inputFeatures)
pool1 = MaxPoolingLayer {(4:4), stride=(4:4)}(conv1)
unpool1 = MaxUnpoolingLayer {(4:4), stride=(4:4)}(pool1, conv1)
deconv1 = DeconvLayer {1, (5:5), cMap, lowerPad=(2:2:0), upperPad=(2:2:0), bias=false}(unpool1)
}.deconv1
Соответствующее определение модели в файле 07_Deconvolution_PY.py
cMap = 1
conv1 = cntk.layers.Convolution ((5,5), cMap, pad=True, activation=cntk.ops.relu)(scaled_input)
pool1 = cntk.layers.MaxPooling ((4,4), (4,4))(conv1)
unpool1 = cntk.layers.MaxUnpooling ((4,4), (4,4))(pool1, conv1)
z = cntk.layers.Deconvolution((5,5), num_channels, cMap, lower_pad=(0,2,2), upper_pad=(0,2,2), bias=False, init=cntk.glorot_uniform(0.001))(unpool1)
Здесь мы описываем версию BrainScript, Python версия аналогична. Модель сначала применяет convolutionalLayer с глубиной cMap=1
входных функций, за которым следует активация ReLU, и использует MaxPoolingLayer с фигурой фильтра и шагом (4:4)
. Это приводит к тензору закодированного размера 7x7x1
. Затем он использует MaxUnpoolingLayer и DeconvLayer с соответствующими фигурами фильтра, чтобы декодировать его обратно в исходное разрешение.
Часть декодера сжимает исходные 784
числа (28x28) до 49
(7x7), коэффициент 16
. Использование только глубины 1
для ConvolutionalLayer имеет преимущество, что результаты кодировщика можно визуализировать в понятном виде (см. рисунок в верхней части этой страницы). Можно увеличить количество сверточных фильтров, например, чтобы cMap=3
иметь меньше сжатия и, надеюсь, лучше декодировать результаты. В этом примере RMSE для обучения и тестирования сокращается до 0.196
. Другим способом уменьшения сжатия является использование меньшей фигуры фильтра и шага для слоя пула. Использование (2:2)
как для пула, так и для отмены пула дает закодированный тензор размера 14x14x1
и уменьшает RMSE в этом примере 0.136
для обучения и 0.131
тестирования. На рисунке ниже показана визуализация исходного изображения и декодированного изображения для первых пяти изображений тестового набора MNIST для трех рассмотренных параметров.
Деконволюция и отмена перепулирования
Давайте немного ближе рассмотрим MaxUnpoolingLayer и DeconvLayer.
MaxUnpoolingLayer {(4:4), stride=(4:4)}(pool1, conv1)
MaxPoolingLayer требует двух входных данных, которые являются выходными данными соответствующего слоя пула (pool1
в данном случае) и входными данными соответствующего слоя пула (conv1
в данном случае). conv1
требуется в CNTK для определения целевого объекта операции отмены переключения, так как CNTK не хранит так называемые переменные коммутатора (дополнительные сведения см. здесь).
DeconvLayer {1, (5:5), cMap, lowerPad=(2:2:0), upperPad=(2:2:0)}
Первый параметр DeconvLayer — глубина выходного тома, второй — фигура ядра (ширина:высота), а третья — глубина входного тома. Параметры заполнения должны быть заданы в соответствии с формой ядра для достижения требуемой ширины и высоты выходного тензора (в данном случае 28x28). Дополнительные сведения о DeconvLayer см. на странице "Справочник по слоям".
Многоуровневый автоматический кодировщик
Вы можете сложить больше слоев Conv/Deconv и Pool/Unpool для более сложного автоматического кодировщика. Ниже приведен пример с двумя слоями каждого типа, в которых можно использовать 07_Deconvolution_BS.cntk
(просто замените модель в файле):
inputDim = 1
cMap1 = 5
cMap2 = 1
model = inputFeatures => {
conv_A = ConvolutionalLayer {cMap1, (5:5), pad = true, activation=ReLU}(inputFeatures)
pool_A = MaxPoolingLayer {(2:2), stride=(2:2)}(conv_A)
conv_B = ConvolutionalLayer {cMap2, (5:5), pad = true, activation=ReLU}(pool_A)
pool_B = MaxPoolingLayer {(2:2), stride=(2:2)}(conv_B)
unpool_B = MaxUnpoolingLayer {(2:2), stride=(2:2)}(pool_B, conv_B)
deconv_B = DeconvLayer {cMap1, (5:5), cMap2, lowerPad=(2:2:0), upperPad=(2:2:0)}(unpool_B)
unpool_A = MaxUnpoolingLayer {(2:2), stride=(2:2)}(deconv_B, conv_A)
deconv_A = DeconvLayer {inputDim, (5:5), cMap1, lowerPad=(2:2:0), upperPad=(2:2:0)}(unpool_A)
}.deconv_A
Чтобы визуализировать результаты, которые необходимо заменить z.pool1
z.pool_B
07_Deconvolution_Visualizer.py
, прежде чем запускать его, чтобы указать правильное имя узла для выходных данных кодировщика. Чтобы изучить все имена узлов в модели, просто раскомментируйте print_all_node_names(model_file)
его в скрипте Python.