Argumento do Tensorflow Strides


115

Estou tentando entender o argumento de passos em tf.nn.avg_pool, tf.nn.max_pool, tf.nn.conv2d.

A documentação diz repetidamente

strides: Uma lista de ints que tem comprimento> = 4. A passada da janela deslizante para cada dimensão do tensor de entrada.

Minhas perguntas são:

  1. O que cada um dos 4+ inteiros representam?
  2. Por que eles devem ter passadas [0] = passadas [3] = 1 para convnets?
  3. Em este exemplo , vemos tf.reshape(_X,shape=[-1, 28, 28, 1]). Por que -1?

Infelizmente, os exemplos nos documentos para remodelar usando -1 não se traduzem muito bem neste cenário.

Respostas:


224

As operações de pooling e convolucional deslizam uma "janela" pelo tensor de entrada. Usando tf.nn.conv2dcomo exemplo: Se o tensor de entrada tem 4 dimensões [batch, height, width, channels]:, então a convolução opera em uma janela 2D nas height, widthdimensões.

stridesdetermina quanto a janela muda em cada uma das dimensões. O uso típico define a primeira (o lote) e a última (a profundidade) passada em 1.

Vamos usar um exemplo muito concreto: rodar uma convolução 2-d sobre uma imagem de entrada em escala de cinza de 32x32. Eu digo tons de cinza porque a imagem de entrada tem profundidade = 1, o que ajuda a mantê-la simples. Deixe essa imagem ficar assim:

00 01 02 03 04 ...
10 11 12 13 14 ...
20 21 22 23 24 ...
30 31 32 33 34 ...
...

Vamos executar uma janela de convolução 2x2 em um único exemplo (tamanho do lote = 1). Daremos à convolução uma profundidade de canal de saída de 8.

A entrada para a convolução tem shape=[1, 32, 32, 1].

Se você especificar strides=[1,1,1,1]com padding=SAME, a saída do filtro será [1, 32, 32, 8].

O filtro criará primeiro uma saída para:

F(00 01
  10 11)

E então para:

F(01 02
  11 12)

e assim por diante. Em seguida, ele se moverá para a segunda linha, calculando:

F(10, 11
  20, 21)

então

F(11, 12
  21, 22)

Se você especificar uma distância de [1, 2, 2, 1], não haverá janelas sobrepostas. Ele irá calcular:

F(00, 01
  10, 11)

e depois

F(02, 03
  12, 13)

A passada opera de forma semelhante para os operadores de pool.

Pergunta 2: Por que avanços [1, x, y, 1] para convnets

O primeiro 1 é o lote: normalmente você não deseja pular os exemplos em seu lote, ou não deveria tê-los incluído em primeiro lugar. :)

O último 1 é a profundidade da convolução: geralmente você não deseja pular entradas, pelo mesmo motivo.

O operador conv2d é mais geral, então você pode criar convoluções que deslizam a janela ao longo de outras dimensões, mas esse não é um uso típico em convnets. O uso típico é usá-los espacialmente.

Por que remodelar para -1 -1 é um espaço reservado que diz "ajuste conforme necessário para corresponder ao tamanho necessário para o tensor completo". É uma maneira de fazer com que o código seja independente do tamanho do lote de entrada, de modo que você possa alterar o pipeline e não tenha que ajustar o tamanho do lote em todo o código.


5
@derek porque (do texto) "Daremos à convolução uma profundidade de canal de saída de 8.". É algo que você pode escolher ao configurar a convolução, e o respondente escolheu 8.
etarion

17

As entradas são 4 dimensionais e têm a forma: [batch_size, image_rows, image_cols, number_of_colors]

Strides, em geral, define uma sobreposição entre as operações de aplicação. No caso de conv2d, especifica qual é a distância entre aplicações consecutivas de filtros convolucionais. O valor de 1 em uma dimensão específica significa que aplicamos o operador a cada linha / coluna, o valor de 2 significa a cada segundo e assim por diante.

Re 1) Os valores que importam para convoluções são 2º e 3º e eles representam a sobreposição na aplicação dos filtros convolucionais ao longo de linhas e colunas. O valor de [1, 2, 2, 1] indica que queremos aplicar os filtros a cada segunda linha e coluna.

Re 2) Eu não sei as limitações técnicas (pode ser requisito CuDNN), mas normalmente as pessoas usam passadas ao longo das dimensões de linhas ou colunas. Não faz necessariamente sentido fazer isso sobre o tamanho do lote. Não tenho certeza da última dimensão.

Re 3) Definir -1 para uma das dimensões significa "definir o valor para a primeira dimensão de forma que o número total de elementos no tensor permaneça inalterado". No nosso caso, -1 será igual a batch_size.


11

Vamos começar com o que o passo faz no caso de 1 dim.

Vamos supor que seu input = [1, 0, 2, 3, 0, 1, 1]e kernel = [2, 1, 3]o resultado da convolução sejam [8, 11, 7, 9, 4], que são calculados deslizando seu kernel sobre a entrada, realizando a multiplicação por elemento e somando tudo. Assim :

  • 8 = 1 * 2 + 0 * 1 + 2 * 3
  • 11 = 0 * 2 + 2 * 1 + 3 * 3
  • 7 = 2 * 2 + 3 * 1 + 0 * 3
  • 9 = 3 * 2 + 0 * 1 + 1 * 3
  • 4 = 0 * 2 + 1 * 1 + 1 * 3

Aqui, deslizamos por um elemento, mas nada o impede de usar qualquer outro número. Este número é o seu passo. Você pode pensar nisso como uma redução da resolução do resultado da convolução de 1 passo apenas tomando cada s-ésimo resultado.

Sabendo o tamanho de entrada i , tamanho do kernel k , passo s e preenchimento p, você pode calcular facilmente o tamanho de saída da convolução como:

insira a descrição da imagem aqui

Aqui || operador significa operação de teto. Para uma camada de pool s = 1.


Caso N-dim.

Saber a matemática para um caso 1-dim, caso n-dim é fácil, uma vez que você vê que cada dim é independente. Então, você apenas desliza cada dimensão separadamente. Aqui está um exemplo para 2-d . Observe que você não precisa ter a mesma passada em todas as dimensões. Portanto, para uma entrada / kernel N-dim, você deve fornecer N passos.


Agora é fácil responder a todas as suas perguntas:

  1. O que cada um dos 4+ inteiros representam? . conv2d , pool informa que esta lista representa os avanços entre cada dimensão. Observe que o comprimento da lista de passadas é igual à classificação do tensor do kernel.
  2. Por que eles devem ter passadas [0] = passadas 3 = 1 para convnets? . A primeira dimensão é o tamanho do lote, a última é os canais. Não há motivo para pular lote nem canal. Então você os torna 1. Para largura / altura, você pode pular algo e é por isso que eles podem não ser 1.
  3. tf.reshape (_X, forma = [- 1, 28, 28, 1]). Por que -1? tf.reshape tem tudo para você:

    Se um componente da forma é o valor especial -1, o tamanho dessa dimensão é calculado para que o tamanho total permaneça constante. Em particular, uma forma de [-1] achata em 1-D. No máximo um componente da forma pode ser -1.


2

@dga fez um trabalho maravilhoso de explicação e não posso ser grato o suficiente por ter sido útil. Da mesma forma, gostaria de compartilhar minhas descobertas sobre como stridefunciona a convolução 3D.

De acordo com a documentação do TensorFlow no conv3d, a forma da entrada deve estar nesta ordem:

[batch, in_depth, in_height, in_width, in_channels]

Vamos explicar as variáveis ​​da extrema direita para a esquerda usando um exemplo. Supondo que a forma de entrada seja input_shape = [1000,16,112,112,3]

input_shape[4] is the number of colour channels (RGB or whichever format it is extracted in)
input_shape[3] is the width of the image
input_shape[2] is the height of the image
input_shape[1] is the number of frames that have been lumped into 1 complete data
input_shape[0] is the number of lumped frames of images we have.

Abaixo está um resumo da documentação de como o passo é usado.

strides: Uma lista de ints que tem comprimento> = 5. Tensor 1-D de comprimento 5. O stride da janela deslizante para cada dimensão de entrada. Deve terstrides[0] = strides[4] = 1

Conforme indicado em muitos trabalhos, passos significam simplesmente quantos passos de distância uma janela ou kernel salta para longe do elemento mais próximo, seja ele um quadro de dados ou pixel (isso é parafraseado a propósito).

Com base na documentação acima, um passo em 3D será semelhante a este strides = (1, X , Y , Z , 1).

A documentação enfatiza isso strides[0] = strides[4] = 1.

strides[0]=1 means that we do not want to skip any data in the batch 
strides[4]=1 means that we do not want to skip in the channel 

strides [X] significa quantos saltos devemos fazer nos quadros concentrados. Portanto, por exemplo, se temos 16 quadros, X = 1 significa usar todos os quadros. X = 2 significa usar cada segundo quadro e assim por diante

strides [y] e strides [z] seguem a explicação de @dga, portanto, não vou refazer essa parte.

No keras, no entanto, você só precisa especificar uma tupla / lista de 3 inteiros, especificando os passos da convolução ao longo de cada dimensão espacial, onde a dimensão espacial é passo [x], passos [y] e passos [z]. strides [0] e strides [4] já está padronizado para 1.

Espero que alguém considere isso útil!

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.