Uma Explicação Ilustrada da Execução de Convoluções 2D Usando Multiplicações de Matrizes

, Author

Neste artigo, vou explicar como as Convoluções 2D são implementadas como multiplicações de matrizes. Esta explicação é baseada nas notas do CS231n Convolutional Neural Networks for Visual Recognition (Módulo 2). Assumo que o leitor está familiarizado com o conceito de uma operação de convolução no contexto de uma rede neural profunda. Caso contrário, este repo tem um relatório e excelentes animações que explicam o que são convoluções. O código para reproduzir os cálculos deste artigo pode ser baixado aqui.

Pequeno Exemplo

Suponha que temos um único canal 4 x 4 imagem, X, e seus valores de pixel são os seguintes:

Um único canal 4 x 4 imagem

Outra suponha que definimos uma convolução 2D com as seguintes propriedades:

Propriedades da operação de convolução 2D que queremos realizar na nossa imagem

Isto significa que haverá 9 patches de imagem 2 x 2 que serão multiplicados por elementos com a matriz W, assim

Todos os 2 x 2 patches de imagem possíveis em X, dados os parâmetros da convolução 2D. Cada cor representa um único patch

Estes patches de imagem podem ser representados como vetores de coluna 4-dimensional e concatenados para formar uma única matriz 4 x 9, P, assim:

A matriz de correções de imagem, P

Note que a i-ésima coluna da matriz P é na verdade a i-ésima correção de imagem em forma de coluna vetorial.

A matriz de pesos para a camada de convolução, W, pode ser achatada para um vetor de linha 4-dimensional, K, como tal:

>

W como um vector de linha achatado K

Para realizar a convolução, primeiro multiplicamos a matriz K por P para obter um vector de linha 9-dimensional (matriz 1 x 9) que nos dá:

O resultado de K P

Então reformulamos o resultado de K P para a forma correta, que é uma matriz 3 x 3 x 1 (última dimensão de canal). A dimensão do canal é 1 porque ajustamos os filtros de saída para 1. A altura e largura é 3 porque de acordo com as notas CS231n:

Fórmula para calcular a altura depois de aplicar uma operação de convolução a uma imagem. A fórmula para calcular a largura é a mesma (basta substituir a altura da imagem e a altura do kernel pela largura da imagem e largura do kernel respectivamente

Isso significa que o resultado da convolução é o mesmo:

Resultado final de fazer a convolução usando multiplicações de matriz

Que verifica se executamos a convolução usando funções PyTorch embutidas (veja este artigo acompanhando o código para detalhes).

Exemplo maior

O exemplo na secção anterior assume uma única imagem e os canais de saída da convolução é 1. O que mudaria se nós relaxássemos estas suposições?

Vamos assumir que a nossa entrada para a convolução é uma imagem 4 x 4 com 3 canais com os seguintes valores de pixel:

Valores de pixel na nossa imagem de entrada 4 x 4 x 3

Como para a nossa convolução, vamos defini-la para ter as mesmas propriedades da secção anterior, excepto que os seus filtros de saída são 2. Isto significa que a matriz de pesos iniciais, W, deve ter forma (2, 2, 2, 3) i.e. (filtros de saída, altura do kernel, largura do kernel, canais da imagem de entrada). Vamos definir W para ter os seguintes valores:

Valores para W dado um kernel de 2 x 2, 2 filtros de saída e imagem de entrada de 3 canais

Notem que cada filtro de saída terá o seu próprio kernel (razão pela qual temos 2 kernels neste exemplo) e cada canal do kernel é 3 (uma vez que a imagem de entrada tem 3 canais).

Desde que ainda estamos a girar um kernel 2 x 2 numa imagem 4 x 4 com 0 zero-padding e stride 1, o número de patches de imagem é ainda 9. No entanto, a matriz de patches de imagem, P, será diferente. Mais especificamente, a i-ésima coluna de P será a concatenação dos valores do 1º, 2º e 3º canais (como um vetor de coluna) correspondente ao patch de imagem i. P será agora uma matriz de 12 x 9. As linhas são 12 porque cada patch de imagem tem 3 canais e cada canal tem 4 elementos desde que definimos o tamanho do kernel para 2 x 2. Aqui está o aspecto de P:

A matriz de 12 x 9 patches de imagem, P

As para W, cada kernel será achatado em um vetor de linha e concatenado em linha para formar uma matriz de 2 x 12, K. A i-ésima linha de K é a concatenação dos valores do 1º, 2º e 3º canal (em forma de linha vetorial) correspondente ao i-ésimo kernel. Aqui está como K será:

A matriz 2 x 12 de valores de kernel achatados em W, K
Agora tudo o que resta é realizar a multiplicação da matriz K P e remodelá-la para a forma correta. A forma correta é uma matriz 3 x 3 x 2 (última dimensão do canal). Aqui está o resultado da multiplicação:

O resultado de K P, uma matriz 2 x 9

E aqui está o resultado depois de reformulá-lo para uma matriz 3 x 3 x 2:

Resultado final de fazer a convolução usando multiplicações de matriz

Que novamente verifica se devemos fazer a convolução usando as funções PyTorch embutidas (veja o código que acompanha este artigo para detalhes).

Então o quê?

Por que devemos nos preocupar em expressar convoluções 2D em termos de multiplicações de matrizes? Além de ter uma implementação eficiente adequada para rodar em uma GPU, o conhecimento desta abordagem nos permitirá raciocinar sobre o comportamento de uma rede neural convolucional profunda. Por exemplo, He et. al. (2015) expressou convoluções 2D em termos de multiplicações de matrizes que lhes permitiram aplicar as propriedades de matrizes/vetores aleatórios para argumentar por uma melhor rotina de inicialização de pesos.

Conclusão

Neste artigo, expliquei como realizar convoluções 2D usando multiplicações de matrizes, passando por dois pequenos exemplos. Espero que isto seja suficiente para que você generalize para dimensões de imagem de entrada arbitrárias e propriedades de convolução. Deixe-me saber nos comentários se algo não estiver claro.

1D Convolution

O método descrito neste artigo também generaliza para convoluções 1D.

Por exemplo, suponha que sua entrada seja um vetor 12-dimensional de 3 canais assim:

Uma entrada que seja um vetor 12-D com 3 canais

Se definirmos nossa convolução 1D para ter os seguintes parâmetros:

  • tamanho do núcleo: 1 x 4
  • canais de saída: 2
  • tride: 2
  • padding: 0
  • bias: 0

Então os parâmetros na operação de convolução, W, serão um tensor com forma (2 , 3, 1, 4). Vamos definir W para ter os seguintes valores:

Valores para W. Note que cada kernel é um (3, 1, 4) tensor

Baseado nos parâmetros da operação de convolução, a matriz de “image” patches P, terá uma forma (12, 5) (5 patches de imagem onde cada patch de imagem é um vetor 12-D já que um patch tem 4 elementos em 3 canais) e terá este aspecto:

Valores para P, uma matriz de 12 x 5

Próximo, achatamos W para obter K, que tem forma (2, 12) já que há 2 kernels e cada kernel tem 12 elementos. Este é o aspecto de K:

Valores de K, uma matriz de 2 x 12

Agora podemos multiplicar K com P que dá:

O resultado de K P, uma matriz 2 x 5

Finalmente, remodelamos o K P para a forma correta, que de acordo com a fórmula é uma “imagem” com forma (1, 5). Isto significa que o resultado desta convolução é um tensor com forma (2, 1, 5), uma vez que definimos os canais de saída para 2. Este é o resultado final:

O resultado de K P após a remodelação para a forma correcta

Que, como esperado, verifica se vamos executar a convolução usando as funções internas do PyTorch.

Deixe uma resposta

O seu endereço de email não será publicado.