Codificador automático de imagem usando desconvolução e unpooling
Sumário
Resumo
O exemplo Image\GettingStarted\07_Deconvolution_PY.py mostra como usar Deconvolution e Unpooling para gerar um codificador automático de imagem simples (07_Deconvolution_BS.cntk é a versão do BrainScript correspondente). Ele usa o conjunto de dados MNIST, que tem uma resolução de 28x28x1, codifica-o em uma representação 7x7x1 usando convolução, pooling e decodificações para a resolução original. O critério de treinamento é RMSE (erro raiz-média-quadrado). A figura acima mostra as visualizações da imagem original, a imagem codificada e a imagem decodificada para as cinco primeiras imagens do conjunto de testes MNIST.
Instalação
Para executar o exemplo, você precisa do conjunto de dados MNIST. Você pode obter os dados executando o seguinte comando da Examples\Image\DataSets\MNIST
pasta:
python install_mnist.py
Executar o exemplo
O exemplo está localizado na Examples\Image\GettingStarted
pasta. Para executar este exemplo, use o comando a seguir para executar a versão do Python (de um ambiente do Python CNTK):
python 07_Deconvolution_PY.py
ou este comando para a versão do BrainScript:
cntk configFile=07_Deconvolution_BS.cntk
Os valores RMSE para treinamento e teste são 0,225 e 0,223, respectivamente. Para visualizar as imagens codificadas e decodificadas, execute o seguinte comando:
python 07_Deconvolution_Visualizer.py
Definido use_brain_script_model=True
para o modelo BrainScript e False
para o modelo python.
As visualizações serão armazenadas na Output
pasta em Examples\Image\GettingStarted
conjunto com uma representação de texto do codificador e a saída do decodificador.
Detalhes técnicos
Abaixo está a definição de modelo para o codificador automático de imagem simples no BrainScript (para o arquivo de configuração completo, consulte 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
A definição de modelo correspondente em 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)
Descrevemos a versão do BrainScript aqui, a versão do Python é análoga. O modelo aplica primeiro um ConvolutionalLayer com uma profundidade dos recursos de cMap=1
entrada seguidos de uma ativação reLU e usa um MaxPoolingLayer com uma forma de filtro e um passo de (4:4)
. Isso resulta em um tensor codificado de tamanho 7x7x1
. Em seguida, ele usa um MaxUnpoolingLayer e um DeconvLayer com as formas de filtro correspondentes para decodificá-lo de volta para a resolução original.
A parte do decodificador compacta os números originais 784
(28x28) para 49
(7x7), um fator de 16
. Usar apenas uma profundidade do 1
ConvolutionalLayer tem a vantagem de que os resultados do codificador podem ser visualizados de maneira significativa (consulte a figura na parte superior desta página). Pode-se aumentar o número de filtros convolucionais, por exemplo, para cMap=3
ter menos compactação e, espero, melhores resultados de decodificação. Neste exemplo, o RMSE para treinamento e teste é reduzido a 0.196
. Outra maneira de ter menos compactação é usar uma forma de filtro menor e passo a passo para a camada de pooling. Usar (2:2)
para pooling e unpooling gera um tensor codificado de tamanho 14x14x1
e reduz o RMSE neste exemplo para 0.136
treinamento e 0.131
teste. A figura abaixo mostra a visualização da imagem original e a imagem decodificada para as cinco primeiras imagens do conjunto de testes MNIST para as três configurações discutidas.
Desconvolution and Unpooling
Vamos examinar um pouco mais de perto o MaxUnpoolingLayer e o DeconvLayer.
MaxUnpoolingLayer {(4:4), stride=(4:4)}(pool1, conv1)
O MaxPoolingLayer requer duas entradas, que são a saída da camada de pool correspondente (pool1
nesse caso) e a entrada da camada de pool correspondente (conv1
nesse caso). conv1
é necessário em CNTK para determinar o destino da operação Unpooling, uma vez que CNTK não armazena as chamadas variáveis de comutador (consulte aqui para obter detalhes).
DeconvLayer {1, (5:5), cMap, lowerPad=(2:2:0), upperPad=(2:2:0)}
O primeiro parâmetro do DeconvLayer é a profundidade do volume de saída, o segundo é a forma do kernel (largura:altura) e o terceiro é a profundidade do volume de entrada. Os parâmetros de preenchimento devem ser definidos de acordo com a forma do kernel para alcançar a largura e a altura desejadas do tensor de saída (28x28 nesse caso). Para obter mais detalhes sobre o DeconvLayer, consulte a página Referência de Camada.
Codificador automático de várias camadas
Você pode empilhar mais camadas de Conv/Deconv e Pool/Unpool para um codificador automático mais complexo. Veja a seguir um exemplo com duas camadas de cada tipo em 07_Deconvolution_BS.cntk
que você pode usar (basta substituir o modelo no arquivo):
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
Para visualizar os resultados que você precisa substituir z.pool1
z.pool_B
07_Deconvolution_Visualizer.py
antes de executá-lo para endereçar o nome do nó correto para a saída do codificador. Para investigar todos os nomes de nó no modelo, basta descompactar print_all_node_names(model_file)
no script Python.