Compartilhar via


Codificador automático de imagem usando desconvolução e unpooling

Sumário

Resumo

image

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.

image

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.pool1z.pool_B07_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.