Partilhar via


Codificador de imagem auto usando desconvolução e desconserção

Tabela de Conteúdos

Resumo

image

O exemplo Image\GettingStarted\07_Deconvolution_PY.py mostra como usar Deconvolution e Unpooling para gerar um simples codificador de imagem automática (07_Deconvolution_BS.cntk é a versão BrainScript correspondente). Utiliza o conjunto de dados MNIST, que tem uma resolução de 28x28x1, codifica-o numa representação 7x7x1 utilizando convolução e agrupamento e descodifica a resolução original. O critério de formação é um erro de raiz-médio-quadrado (RMSE). A figura acima mostra visualizações da imagem original, a imagem codificada e a imagem descodificada para as primeiras cinco imagens do conjunto de testes do MNIST.

Configuração

Para executar o exemplo, precisa do conjunto de dados do MNIST. Pode obter os dados executando o seguinte comando a Examples\Image\DataSets\MNIST partir da pasta:

python install_mnist.py

Executar o exemplo

O exemplo encontra-se na Examples\Image\GettingStarted pasta. Para executar este exemplo, utilize o seguinte comando para executar a versão Python (a partir de um ambiente Python CNTK):

python 07_Deconvolution_PY.py

ou este comando para a versão BrainScript:

cntk configFile=07_Deconvolution_BS.cntk

Os valores de RMSE para treino e teste são 0.225 e 0.223, respectivamente. Para visualizar as imagens codificadas e descodificada executam o seguinte comando:

python 07_Deconvolution_Visualizer.py

Definido use_brain_script_model=True para o BrainScript modelo e False para o Python modelo. As visualizações serão armazenadas na Output pasta em conjunto Examples\Image\GettingStarted com uma representação de texto do codificador e da saída do descodificador.

Detalhes técnicos

Abaixo está a definição modelo para o codificador de imagem simples em BrainScript (para o ficheiro completo config ver 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 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 BrainScript aqui, a versão Python é análoga. O modelo aplica primeiro um ConvolutionalLayer com uma profundidade das características de entrada seguida de cMap=1 uma ativação ReLU e utiliza um MaxPoolingLayer com uma forma de filtro e passo de (4:4). Isto resulta num tensor codificado de tamanho 7x7x1. Em seguida, utiliza um MaxUnpoolingLayer e um DeconvLayer com as formas de filtro correspondentes para descodificá-lo de volta à resolução original.

A parte descodificadora comprime os números originais 784 (28x28) para 49 (7x7), um fator de 16. A utilização de apenas uma profundidade para o ConvolutionalLayer tem a vantagem de 1 que os resultados do codificador podem ser visualizados de forma significativa (ver figura no topo desta página). Pode-se aumentar o número de filtros convolucionais, por exemplo, para cMap=3 ter menos compressão e, esperemos, melhores resultados de descodição. Neste exemplo, o RMSE para treinos e testes é reduzido a 0.196. Outra forma de ter menos compressão é usar uma forma de filtro menor e passo para a camada de piscina. A utilização (2:2) tanto para a piscina como para desajustar produz um tensor codificado de tamanho 14x14x1 e reduz o RMSE neste exemplo para 0.136 treino e 0.131 teste. A figura abaixo mostra a visualização da imagem original e a imagem descodificada para as cinco primeiras imagens do conjunto de testes MNIST para as três definições discutidas.

image

Desconvolução e Unpooling

Vamos olhar um pouco mais de perto para 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 agrupamento correspondente (pool1 neste caso) e a entrada da camada de agrupamento correspondente (conv1 neste caso). conv1é necessário em CNTK determinar o alvo da operação Unpooling, uma vez CNTK não armazena as chamadas variáveis switch (consulte aqui para mais 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 núcleo (largura:altura) e o terceiro é a profundidade do volume de entrada. Os parâmetros de enchimento devem ser definidos de acordo com a forma do núcleo para alcançar a largura e altura desejadas do tensor de saída (28x28 neste caso). Para mais detalhes no DeconvLayer consulte a página de Referência da Camada.

Codificação de vários camadas de automóveis

Você pode empilhar mais camadas de Conv/Deconv e Pool/Unpool para um codificador de automóveis mais complexo. Segue-se um exemplo com duas camadas de cada tipo em 07_Deconvolution_BS.cntk que pode utilizar (basta substituir a modelo no ficheiro):

    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, tem de ser substituído z.pool1z.pool_B07_Deconvolution_Visualizer.py antes de o executar para endereçar o nome correto do nó para a saída do codificante. Para investigar todos os nomes de nó no modelo simplesmente descomprometê-lo print_all_node_names(model_file) no Python script.