Eu estava olhando os documentos do tensorflow tf.nn.conv2d
aqui . Mas não consigo entender o que faz ou o que está tentando alcançar. Diz nos documentos,
# 1: Nivela o filtro para uma matriz 2-D com forma
[filter_height * filter_width * in_channels, output_channels]
.
Agora o que isso faz? Isso é multiplicação por elementos ou simplesmente multiplicação por matriz? Também não consegui entender os outros dois pontos mencionados nos documentos. Eu os escrevi abaixo:
# 2: Extrai amostras de imagens do tensor de entrada para formar um tensor virtual de forma
[batch, out_height, out_width, filter_height * filter_width * in_channels]
.Nº 3: para cada patch, multiplica à direita a matriz do filtro e o vetor de patch da imagem.
Seria realmente útil se alguém pudesse dar um exemplo, um pedaço de código (extremamente útil) talvez e explicar o que está acontecendo lá e por que a operação é assim.
Tentei codificar uma pequena parte e imprimir a forma da operação. Ainda assim, eu não consigo entender.
Eu tentei algo assim:
op = tf.shape(tf.nn.conv2d(tf.random_normal([1,10,10,10]),
tf.random_normal([2,10,10,10]),
strides=[1, 2, 2, 1], padding='SAME'))
with tf.Session() as sess:
result = sess.run(op)
print(result)
Entendo pedaços de redes neurais convolucionais. Eu os estudei aqui . Mas a implementação no tensorflow não é o que eu esperava. Por isso, levantou a questão.
EDIT : Então, eu implementei um código muito mais simples. Mas não consigo descobrir o que está acontecendo. Quero dizer como os resultados são assim. Seria extremamente útil se alguém pudesse me dizer qual processo produz essa saída.
input = tf.Variable(tf.random_normal([1,2,2,1]))
filter = tf.Variable(tf.random_normal([1,1,1,1]))
op = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='SAME')
init = tf.initialize_all_variables()
with tf.Session() as sess:
sess.run(init)
print("input")
print(input.eval())
print("filter")
print(filter.eval())
print("result")
result = sess.run(op)
print(result)
resultado
input
[[[[ 1.60314465]
[-0.55022103]]
[[ 0.00595062]
[-0.69889867]]]]
filter
[[[[-0.59594476]]]]
result
[[[[-0.95538563]
[ 0.32790133]]
[[-0.00354624]
[ 0.41650501]]]]
fonte
tf.nn.conv2d()
, portanto o método em questão não é usado quando usamos o TF com suporte à GPU, a menos queuse_cudnn_on_gpu=False
seja especificado explicitamente.Respostas:
A convolução 2D é calculada de maneira semelhante ao cálculo da convolução 1D : você desliza seu kernel sobre a entrada, calcula as multiplicações em elementos e as soma. Mas ao invés de seu kernel / input ser uma matriz, aqui estão elas.
No exemplo mais básico, não há preenchimento e passada = 1. Vamos assumir o seu
input
ekernel
são:Ao usar seu kernel, você receberá a seguinte saída:, que é calculada da seguinte maneira:
A função conv2d do TF calcula as convoluções em lotes e usa um formato ligeiramente diferente. Para uma entrada, é
[batch, in_height, in_width, in_channels]
para o kernel que é[filter_height, filter_width, in_channels, out_channels]
. Portanto, precisamos fornecer os dados no formato correto:Posteriormente, a convolução é calculada com:
E será equivalente ao que calculamos à mão.
Para exemplos com preenchimento / passada, dê uma olhada aqui .
fonte
Ok, acho que essa é a maneira mais simples de explicar tudo.
Seu exemplo é 1 imagem, tamanho 2x2, com 1 canal. Você tem 1 filtro, com tamanho 1x1 e 1 canal (tamanho é altura x largura x canais x número de filtros).
Nesse caso simples, a imagem 2x2, 1 canal resultante (tamanho 1x2x2x1, número de imagens x altura x largura xx canais) é o resultado da multiplicação do valor do filtro por cada pixel da imagem.
Agora vamos tentar mais canais:
Aqui, a imagem 3x3 e o filtro 1x1 possuem 5 canais. A imagem resultante será 3x3 com 1 canal (tamanho 1x3x3x1), em que o valor de cada pixel é o produto escalar através dos canais do filtro com o pixel correspondente na imagem de entrada.
Agora com um filtro 3x3
Aqui temos uma imagem 1x1, com 1 canal (tamanho 1x1x1x1). O valor é a soma dos produtos com 9 pontos e 5 elementos. Mas você pode chamar isso de um produto com 45 elementos.
Agora com uma imagem maior
A saída é uma imagem 3x3 de 1 canal (tamanho 1x3x3x1). Cada um desses valores é uma soma de 9 pontos com 5 elementos.
Cada saída é feita centralizando o filtro em um dos 9 pixels centrais da imagem de entrada, para que nenhum filtro se destaque. Os
x
s abaixo representam os centros de filtro para cada pixel de saída.Agora com o preenchimento "MESMO":
Isso fornece uma imagem de saída 5x5 (tamanho 1x5x5x1). Isso é feito centralizando o filtro em cada posição da imagem.
Qualquer um dos produtos com 5 elementos onde o filtro ultrapassa a borda da imagem obtém um valor zero.
Portanto, os cantos são apenas somas de produtos com 4 pontos e 5 elementos.
Agora com vários filtros.
Isso ainda fornece uma imagem de saída 5x5, mas com 7 canais (tamanho 1x5x5x7). Onde cada canal é produzido por um dos filtros no conjunto.
Agora com passos 2,2:
Agora, o resultado ainda tem 7 canais, mas é apenas 3x3 (tamanho 1x3x3x7).
Isso ocorre porque, em vez de centralizar os filtros em todos os pontos da imagem, os filtros são centralizados em todos os outros pontos da imagem, seguindo etapas (passos) da largura 2. Os
x
itens abaixo representam o centro do filtro para cada pixel de saída, em a imagem de entrada.E, claro, a primeira dimensão da entrada é o número de imagens, para que você possa aplicá-lo em um lote de 10 imagens, por exemplo:
Isso realiza a mesma operação, para cada imagem independentemente, fornecendo uma pilha de 10 imagens como resultado (tamanho 10x3x3x7)
fonte
Must have strides[0] = strides[3] = 1. For the most common case of the same horizontal and vertices strides, strides = [1, stride, stride, 1].
the 3x3 image and the 1x1 filter each have 5 channels
, acho que o resultado é diferente do produto escalável calculado manualmente.Apenas para adicionar às outras respostas, você deve pensar nos parâmetros em
como '5' correspondente ao número de canais em cada filtro. Cada filtro é um cubo 3d, com uma profundidade de 5. A profundidade do filtro deve corresponder à profundidade da imagem de entrada. O último parâmetro, 7, deve ser considerado como o número de filtros no lote. Apenas esqueça que isso é 4D e imagine que você tem um conjunto ou um lote de 7 filtros. O que você faz é criar 7 cubos de filtro com dimensões (3,3,5).
É muito mais fácil visualizar no domínio de Fourier, uma vez que a convolução se torna multiplicação por pontos. Para uma imagem de entrada de dimensões (100.100,3), você pode reescrever as dimensões do filtro como
Para obter um dos 7 mapas de recursos de saída, simplesmente executamos a multiplicação por pontos do cubo de filtro com o cubo de imagem e, em seguida, somamos os resultados através da dimensão de canais / profundidade (aqui é 3), colapsando em um 2d (100.100) apresentam mapa. Faça isso com cada cubo de filtro e você obterá 7 mapas de recursos 2D.
fonte
Eu tentei implementar o conv2d (para os meus estudos). Bem, eu escrevi isso:
Espero ter feito isso corretamente. Verificado no MNIST, teve resultados muito próximos (mas essa implementação é mais lenta). Espero que isso ajude você.
fonte
Além de outras respostas, a operação conv2d está operando em c ++ (cpu) ou cuda para máquinas gpu que exigem nivelar e remodelar dados de certa maneira e usar a multiplicação da matriz gemmBLAS ou cuBLAS (cuda).
fonte