Técnica de normalização de peso usada no Image Style Transfer

6

Estou tentando implementar o documento Image Style Transfer usando redes neurais convolucionais . Na seção 2 - Representações de imagens profundas, os autores mencionam a seguinte técnica de normalização de peso:

Normalizamos a rede dimensionando os pesos de forma que a ativação média de cada filtro convolucional sobre imagens e posições seja igual a um. Esse redimensionamento pode ser feito para a rede VGG sem alterar sua saída, pois contém apenas funções de ativação linear de retificação e nenhuma normalização ou agrupamento nos mapas de recursos.

De uma pergunta relacionada feita anteriormente, descobri que os autores estão usando os valores de ativação de imagens de validação do ILSVRC definidas para normalizar os pesos.

Eu queria conhecer a formulação matemática de realizar tal normalização, já que eu mesmo não conseguia criar uma.

De acordo com minha compreensão do problema, tenho um mapa de ativação (X) e, correspondente a ele, tenho mapas de ativação K da camada anterior (L) e uma matriz de peso (W) de dimensões 3x3xK, de modo que quando a camada L é convoluída com W produz X. Agora, depois de capturar os valores de ativação de todos os neurônios na camada L para todas as imagens no conjunto de validação, o objetivo é fazer com que a média de todos os neurônios em X em todas as imagens no conjunto de validação seja igual a 1 ajustando de alguma forma W.

Não consegui descobrir o que devo fazer com o W para que isso aconteça.

Além disso, eu queria saber se isso deve ser executado em cascata (sequencial) normalizando primeiro os pesos da camada inicial e depois usando os novos mapas de recursos para normalizar os pesos das camadas à frente ou independentemente para cada mapa de ativação, os valores da camada anterior como os pesos pré-treinados originais para cada mapa de ativação?

codetrotter
fonte

Respostas:

1

Você está certo que, uma vez que temos as ativações médias de recursos em um conjunto de imagens, normalizamos a rede sequencialmente, camada por camada. Há uma sutileza envolvida, no entanto. Você não pode redimensionar os pesos da camada independentemente das camadas anteriores.

Seja e os pesos e a inclinação do ésimo filtro convolucional na camada . O kernel tem uma forma 3D com dimensões (altura, largura, canais_em), mas para uma notação mais fácil no caminho, vamos remodelá-lo para , onde .WilbililWilh×w×cp×cp=h×w

Fijlmax(0, WilPjl1+bil) é a ativação do ésimo filtro na camada na ésima posição na mapa de ativação. Aqui designa a operação de convolução (ou produto interno Frobenius, ou multiplique; adotei o símbolo da resposta de Baba) e é a janela de ativações na saída da camada as quais o filtro convence na posição em consideração.iljPjl1h×w×c=p×cl1

Seja é a ativação média do ésimo filtro na camada sobre todas as imagens no conjunto de dados e todas as posições no mapa de ativação do filtro. Obviamente, esse é um número não negativo e, na verdade, é positivo para todos os filtros nas redes VGG (quando ativações médias são coletadas em um conjunto de dados de tamanho decente).

μilEX,jFijl=1NMlXj=1MlFijl=1NMlXj=1Mlmax(0, WilPjl1+bil)
ilNXMl

Agora, suponha que "normalizemos" as ativações dividindo pesos e desvios por . Isso tornaria a média da ativação igual a 1, se as ativações recebidas fossem as mesmas que as ativações não normalizadas originais . Ou seja, , mas somente se as ativações da camada anterior forem as mesmas da rede não normalizada original - a rede que calculamosμilEX,jmax(0, WilμilPjl1+bilμil)=1Pjl1μilin. Isso é válido apenas para a primeira camada de conv na rede normalizada, a camada que convolve com a imagem de entrada. Para outras camadas, isso não apenas resultará em escala incorreta, mas também poderá reverter o sinal da convolução e, conseqüentemente, zerar as ativações após a passagem pela ReLU. Em outras palavras, ele altera a saída da rede .

Para corrigir isso, precisamos restaurar as ativações recebidas: mas não podemos alterar os valores recebidos, temos que desfazer a normalização da camada anterior usando os pesos da camada atual. Observe que um peso em um filtro interage apenas com um único canal na camada anterior. Então, redimensionamos todos os pesos em que interagem com o ésimo canal na camada multiplicando-os por . Isso cancela a normalização da camada anterior.Wilkl1μkl1

Para formalizar, deixe

Dl1[μ1l1000μ2l1000μcl1] ser as diagonais matriz construída utilizando todas as activações médias de camada .c×ccl1

Então, . (E é por isso que remodelamos os pesos para 2D, para que possamos multiplicar matrizes em vez de tensores, por uma questão de clareza.)EX,jmax(0, WilDl1μilPjl1+bilμil)=1

Observe também que as camadas de pool máxima e média não interferem nesse esquema, porque não alteram a escala.

O exemplo acima provavelmente parece mais complexo do que no código real. Enviei um repositório do GitHub com uma implementação curta do Keras: https://github.com/corleypc/vgg-normalize . Observar o código de amostra provavelmente elucidará ainda mais as coisas.

cpc
fonte
1

Resposta curta: pegue o mapa de ativação correspondente a uma matriz de peso específica, calcule a média de todas as ativações e faça a média dessa média em todas as imagens. Em seguida, divida a matriz de pesos e o viés por essa média. E sim, faz sentido fazê-lo sequencialmente.

Resposta longa: (Usando a notação usada no artigo que você citou)

O operador de convolução para o mapa de recursos executa um produto interno com patches de imagem :ithxj

max{0, wilxj+bjl}=Fijl

Eles assumem a média de ativações em todas as imagens e em todos os locais espaciais (vamos chamar de )χjsi

silEχ,j[max{0, wilxj+bjl}]=1KMlχj=1MlFijl

Aqui é o número de imagens no conjunto de dados.K

Agora você apenas escala e por , fornecendo a você:wilbjl1sil

Eχ,j[max{0, wilsilxj+bjlsil}]=1

Isso também garante que as ativações que eram zero antes, após passar pela não linearidade da RELU, permaneçam assim, ou seja,

wilxj+bjl<0wilsilxj+bjlsil<0

Baba
fonte