python - raspberry - tensorflow seq2seq
¿Cuál es la diferencia entre el relleno ''SAME'' y ''VALID'' en tf.nn.max_pool de tensorflow? (13)
Acolchado activado / desactivado. Determina el tamaño efectivo de su entrada.
VALID:
sin relleno.
Las operaciones de convolución, etc., solo se realizan en ubicaciones "válidas", es decir, no demasiado cerca de los bordes de su tensor.
Con un núcleo de 3x3 y una imagen de 10x10, estaría realizando una convolución en el área de 8x8 dentro de los bordes.
SAME:
Se proporciona relleno.
Siempre que su operación haga referencia a un vecindario (no importa cuán grande), se proporcionan valores cero cuando ese vecindario se extiende fuera del tensor original para permitir que esa operación funcione también en valores de borde.
Con un núcleo de 3x3 y una imagen de 10x10, estaría realizando una convolución en el área completa de 10x10.
¿Cuál es la diferencia entre el relleno ''SAME'' y ''VALID'' en
tf.nn.max_pool
de
tensorflow
?
En mi opinión, ''VÁLIDO'' significa que no habrá relleno cero fuera de los bordes cuando hagamos el grupo máximo.
De acuerdo con
una guía de aritmética de convolución para el aprendizaje profundo
, dice que no habrá relleno en el operador de la piscina, es decir, solo use ''VÁLIDO'' de
tensorflow
.
Pero, ¿qué es el relleno ''MISMO'' de la agrupación máxima en
tensorflow
?
Basado en la explicación here y siguiendo la respuesta de Tristan, usualmente uso estas funciones rápidas para controles de cordura.
# a function to help us stay clean
def getPaddings(pad_along_height,pad_along_width):
# if even.. easy..
if pad_along_height%2 == 0:
pad_top = pad_along_height / 2
pad_bottom = pad_top
# if odd
else:
pad_top = np.floor( pad_along_height / 2 )
pad_bottom = np.floor( pad_along_height / 2 ) +1
# check if width padding is odd or even
# if even.. easy..
if pad_along_width%2 == 0:
pad_left = pad_along_width / 2
pad_right= pad_left
# if odd
else:
pad_left = np.floor( pad_along_width / 2 )
pad_right = np.floor( pad_along_width / 2 ) +1
#
return pad_top,pad_bottom,pad_left,pad_right
# strides [image index, y, x, depth]
# padding ''SAME'' or ''VALID''
# bottom and right sides always get the one additional padded pixel (if padding is odd)
def getOutputDim (inputWidth,inputHeight,filterWidth,filterHeight,strides,padding):
if padding == ''SAME'':
out_height = np.ceil(float(inputHeight) / float(strides[1]))
out_width = np.ceil(float(inputWidth) / float(strides[2]))
#
pad_along_height = ((out_height - 1) * strides[1] + filterHeight - inputHeight)
pad_along_width = ((out_width - 1) * strides[2] + filterWidth - inputWidth)
#
# now get padding
pad_top,pad_bottom,pad_left,pad_right = getPaddings(pad_along_height,pad_along_width)
#
print ''output height'', out_height
print ''output width'' , out_width
print ''total pad along height'' , pad_along_height
print ''total pad along width'' , pad_along_width
print ''pad at top'' , pad_top
print ''pad at bottom'' ,pad_bottom
print ''pad at left'' , pad_left
print ''pad at right'' ,pad_right
elif padding == ''VALID'':
out_height = np.ceil(float(inputHeight - filterHeight + 1) / float(strides[1]))
out_width = np.ceil(float(inputWidth - filterWidth + 1) / float(strides[2]))
#
print ''output height'', out_height
print ''output width'' , out_width
print ''no padding''
# use like so
getOutputDim (80,80,4,4,[1,1,1,1],''SAME'')
Cito esta respuesta de los documentos oficiales de Tensorflow https://www.tensorflow.org/api_guides/python/nn#Convolution Para el relleno ''SAME'', la altura y el ancho de salida se calculan como:
out_height = ceil(float(in_height) / float(strides[1]))
out_width = ceil(float(in_width) / float(strides[2]))
y el relleno en la parte superior e izquierda se calculan como:
pad_along_height = max((out_height - 1) * strides[1] +
filter_height - in_height, 0)
pad_along_width = max((out_width - 1) * strides[2] +
filter_width - in_width, 0)
pad_top = pad_along_height // 2
pad_bottom = pad_along_height - pad_top
pad_left = pad_along_width // 2
pad_right = pad_along_width - pad_left
Para el relleno ''VÁLIDO'', la altura y el ancho de salida se calculan como:
out_height = ceil(float(in_height - filter_height + 1) / float(strides[1]))
out_width = ceil(float(in_width - filter_width + 1) / float(strides[2]))
y los valores de relleno son siempre cero.
Cuando el
stride
es 1 (más típico con convolución que agrupación), podemos pensar en la siguiente distinción:
-
"SAME"
: el tamaño de salida es el mismo que el tamaño de entrada. Esto requiere que la ventana del filtro se deslice fuera del mapa de entrada, de ahí la necesidad de rellenar. -
"VALID"
: la ventana de filtro permanece en una posición válida dentro del mapa de entrada, por lo que el tamaño de salida se reduce porfilter_size - 1
. No se produce relleno.
Daré un ejemplo para aclararlo:
-
x
: imagen de entrada de forma [2, 3], 1 canal -
valid_pad
: grupo máximo con 2x2 kernel, stride 2 y relleno VÁLIDO. -
same_pad
: grupo máximo con kernel 2x2, stride 2 y el mismo relleno (esta es la forma clásica de hacerlo)
Las formas de salida son:
-
valid_pad
: aquí, sin relleno, por lo que la forma de salida es [1, 1] -
same_pad
: aquí, rellenamos la imagen a la forma [2, 4] (con-inf
y luego aplicamos el grupo máximo), por lo que la forma de salida es [1, 2]
x = tf.constant([[1., 2., 3.],
[4., 5., 6.]])
x = tf.reshape(x, [1, 2, 3, 1]) # give a shape accepted by tf.nn.max_pool
valid_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding=''VALID'')
same_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding=''SAME'')
valid_pad.get_shape() == [1, 1, 1, 1] # valid_pad is [5.]
same_pad.get_shape() == [1, 1, 2, 1] # same_pad is [5., 6.]
El ejemplo de
convolución TensorFlow
ofrece una visión general sobre la diferencia entre
SAME
y
VALID
:
-
Para el
SAME
relleno, la altura y el ancho de salida se calculan como:out_height = ceil(float(in_height) / float(strides[1])) out_width = ceil(float(in_width) / float(strides[2]))
Y
-
Para el relleno
VALID
, la altura y el ancho de salida se calculan como:out_height = ceil(float(in_height - filter_height + 1) / float(strides[1])) out_width = ceil(float(in_width - filter_width + 1) / float(strides[2]))
El relleno es una operación para aumentar el tamaño de los datos de entrada. En el caso de datos unidimensionales, simplemente agrega / antepone la matriz con una constante, en 2-dim rodea la matriz envolvente con estas constantes. En n-dim rodeas tu hipercubo n-dim con la constante. En la mayoría de los casos, esta constante es cero y se llama relleno de cero.
Aquí hay un ejemplo de relleno cero con
p=1
aplicado al tensor 2-d:
Puede usar relleno arbitrario para su núcleo, pero algunos de los valores de relleno se usan con más frecuencia que otros:
- Relleno VÁLIDO . El caso más fácil, significa que no hay relleno en absoluto. Simplemente deje sus datos como estaban.
-
El mismo relleno a
veces llamado
MEDIO relleno
.
Se llama
MISMO
porque para una convolución con una zancada = 1, (o para agrupar) debería producir una salida del mismo tamaño que la entrada.
Se llama
MEDIO
porque para un núcleo de tamaño
k
-
El relleno COMPLETO
es el relleno máximo que no da como resultado una convolución sobre solo elementos rellenados.
Para un núcleo de tamaño
k
, este relleno es igual ak - 1
.
Para usar relleno arbitrario en TF, puede usar
tf.pad()
En resumen, el relleno "válido" significa que no hay relleno. El tamaño de salida de la capa convolucional se reduce según el tamaño de entrada y el tamaño del núcleo.
Por el contrario, el "relleno" significa usar relleno. El tamaño de salida de la capa convolucional se mantiene como el tamaño de entrada al agregar un cierto número de ''borde 0'' alrededor de los datos de entrada al calcular la convolución.
Espero que esta descripción intuitiva ayude.
Hay tres opciones de relleno: válido (sin relleno), igual (o medio), completo. Puede encontrar explicaciones (en Theano) aquí: http://deeplearning.net/software/theano/tutorial/conv_arithmetic.html
- Válido o sin relleno:
El relleno válido no implica relleno cero, por lo que cubre solo la entrada válida, sin incluir ceros generados artificialmente. La longitud de salida es ((la longitud de entrada) - (k-1)) para el tamaño de kernel k si la zancada s = 1.
- Mismo o medio relleno:
El mismo relleno hace que el tamaño de las salidas sea el mismo que el de las entradas cuando s = 1. Si s = 1, el número de ceros rellenos es (k-1).
- Relleno completo:
El relleno completo significa que el núcleo se ejecuta sobre todas las entradas, por lo que en los extremos, el núcleo puede cumplir con la única entrada y ceros más. El número de ceros rellenos es 2 (k-1) si s = 1. La longitud de salida es ((la longitud de entrada) + (k-1)) si s = 1.
Por lo tanto, el número de rellenos: (válido) <= (igual) <= (completo)
Si te gusta el arte ascii:
-
"VALID"
= sin relleno:inputs: 1 2 3 4 5 6 7 8 9 10 11 (12 13) |________________| dropped |_________________|
-
"SAME"
= con cero relleno:pad| |pad inputs: 0 |1 2 3 4 5 6 7 8 9 10 11 12 13|0 0 |________________| |_________________| |________________|
En este ejemplo:
- Ancho de entrada = 13
- Ancho del filtro = 6
- Zancada = 5
Notas:
-
"VALID"
solo elimina las columnas del extremo derecho (o las filas del extremo inferior). -
"SAME"
intenta rellenar uniformemente hacia la izquierda y hacia la derecha, pero si la cantidad de columnas que se agregarán es impar, agregará la columna adicional a la derecha, como es el caso en este ejemplo (la misma lógica se aplica verticalmente: puede haber una fila adicional de ceros en la parte inferior).
Editar :
Sobre el nombre
-
Con el relleno
"SAME"
, si usa un paso de 1, las salidas de la capa tendrán las mismas dimensiones espaciales que sus entradas. -
Con el relleno
"VALID"
, no hay entradas de relleno "inventadas". La capa solo usa datos de entrada válidos .
Explicacion rapida
VALID
: no aplique ningún relleno, es decir, suponga que todas las dimensiones son
válidas
para que la imagen de entrada quede completamente cubierta por el filtro y la zancada que especificó.
SAME
: aplique relleno a la entrada (si es necesario) para que la imagen de entrada quede completamente cubierta por el filtro y la zancada que especificó.
Para el paso 1, esto asegurará que el tamaño de la imagen de salida sea el
mismo
que el de la entrada.
Notas
- Esto se aplica a las capas conv, así como a las capas de grupo máximo de la misma manera
-
El término "válido" es un nombre poco apropiado porque las cosas no se vuelven "inválidas" si suelta parte de la imagen.
En algún momento incluso podrías querer eso.
Probablemente debería haberse llamado
NO_PADDING
enNO_PADDING
lugar. -
El término "igual" también es incorrecto porque solo tiene sentido para el paso 1 cuando la dimensión de salida es igual a la dimensión de entrada.
Para zancadas de 2, las dimensiones de salida serán la mitad, por ejemplo.
Probablemente debería haberse llamado
AUTO_PADDING
enAUTO_PADDING
lugar. -
En
SAME
(es decir, el modo de relleno automático), Tensorflow intentará distribuir el relleno de manera uniforme tanto a la izquierda como a la derecha. -
En
VALID
(es decir, sin modo de relleno), Tensorflow soltará las celdas derecha y / o inferior si su filtro y zancada no cubren por completo la imagen de entrada.
Relleno VÁLIDO : esto es con relleno cero. Espero que no haya confusión.
x = tf.constant([[1., 2., 3.], [4., 5., 6.],[ 7., 8., 9.], [ 7., 8., 9.]])
x = tf.reshape(x, [1, 4, 3, 1])
valid_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding=''VALID'')
print (valid_pad.get_shape()) # output-->(1, 2, 1, 1)
El mismo relleno: es un poco difícil de entender en primer lugar porque tenemos que considerar dos condiciones por separado como se menciona en los documentos oficiales .
Tomemos entrada como , salida como , relleno como andar como y el tamaño del grano como (solo se considera una sola dimensión)
Caso 01: :
Caso 02: :
se calcula de tal manera que el valor mínimo que se puede tomar para el relleno. Como valor de es conocido, valor de se puede encontrar usando esta fórmula .
Analicemos este ejemplo:
x = tf.constant([[1., 2., 3.], [4., 5., 6.],[ 7., 8., 9.], [ 7., 8., 9.]])
x = tf.reshape(x, [1, 4, 3, 1])
same_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding=''SAME'')
print (same_pad.get_shape()) # --> output (1, 2, 2, 1)
Aquí la dimensión de x es (3,4). Entonces, si se toma la dirección horizontal (3):
Si se toma la dirección vertical (4):
Espero que esto ayude a comprender cómo funciona realmente el mismo relleno en TF.