В чем разница между "SAME" и "VALID" дополнением в tf.nn.max_pool тензорного потока?

В чем разница между "SAME" и "VALID" дополнением в tf.nn.max_pool от tensorflow?

На мой взгляд, "VALID" означает, что при максимальном пуле не будет нулевого заполнения за пределами краев.

В соответствии с Руководством по арифметике свертки для глубокого обучения в нем говорится, что в пуле оператора не будет заполнения, т.е. просто используйте 'VALID' tensorflow, Но что такое "ТОЛЬКО" заполнение максимального пула в tensorflow?

Ответ 1

Я приведу пример, чтобы сделать его более ясным:

  • x: входное изображение формы [2, 3], 1 канал
  • valid_pad: максимальный пул с ядром 2x2, шаг 2 и добавление VALID.
  • same_pad: максимальный пул с ядром 2x2, шаг 2 и SAME padding (это классический способ)

Формы вывода:

  • valid_pad: здесь нет прокладки, поэтому форма вывода [1, 1]
  • same_pad: здесь мы помещаем изображение в форму [2, 4] (с -inf, а затем применяем максимальный пул), поэтому форма вывода [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.]

Ответ 2

Если тебе нравится ascii art:

  • "VALID"= без дополнения:

       inputs:         1  2  3  4  5  6  7  8  9  10 11 (12 13)
                      |________________|                dropped
                                     |_________________|
    
  • "SAME"= с дополнением нулями:

                   pad|                                      |pad
       inputs:      0 |1  2  3  4  5  6  7  8  9  10 11 12 13|0  0
                   |________________|
                                  |_________________|
                                                 |________________|
    

В этом примере:

  • Ширина ввода = 13
  • Ширина фильтра = 6
  • Страйд = 5

Заметки:

  • "VALID" удаляет только самые правые столбцы (или самые нижние строки).
  • "SAME" пытается равномерно заполнить левую и правую части, но если количество столбцов, которые будут добавлены, будет нечетным, это добавит дополнительный столбец справа, как в случае с этим примером (та же логика применяется вертикально: может быть дополнительный ряд нулей внизу).

Редактировать:

О названии:

  • При использовании "SAME" заполнения, если вы используете шаг 1, выходы слоя будут иметь те же пространственные размеры, что и его входы.
  • С заполнением "VALID" нет "готовых" вводов заполнения. Слой использует только правильные входные данные.

Ответ 3

Когда stride 1 (более типичный с сверткой, чем объединение), мы можем думать о следующем различии:

  • "SAME": размер вывода совпадает с размером ввода. Для этого требуется, чтобы окно фильтра проскальзывало внешнюю карту ввода, следовательно, необходимо проложить.
  • "VALID": окно фильтра остается в допустимой позиции внутри карты ввода, поэтому размер вывода уменьшается с помощью filter_size - 1. Прописи не происходит.

Ответ 4

Пример TensorFlow Convolution дает обзор о разнице между SAME и VALID:

  • Для того SAME САМОГО, высота и ширина вывода вычисляются как:

    out_height = ceil(float(in_height) / float(strides[1]))
    out_width  = ceil(float(in_width) / float(strides[2]))
    

А также

  • Для заполнения VALID высота и ширина вывода вычисляются как:

    out_height = ceil(float(in_height - filter_height + 1) / float(strides[1]))
    out_width  = ceil(float(in_width - filter_width + 1) / float(strides[2]))
    

Ответ 5

Заполнение - это операция по увеличению размера входных данных. В случае одномерных данных вы просто добавляете/добавляете массив с константой, в 2-мерную матрицу окружающего пространства с этими константами. В n-dim вы окружаете свой n-мерный гиперкуб с константой. В большинстве случаев эта константа равна нулю и называется нулевым дополнением.

Вот пример нулевого заполнения с p=1, примененного к 2-му тензору: введите описание изображения здесь


Вы можете использовать произвольное дополнение для вашего ядра, но некоторые из значений дополнения используются чаще, чем другие:

  • добавление VALID. Самый простой случай, вообще говоря, не требует отступов. Просто оставьте свои данные тем же, что и было.
  • САМЫЙ отступы, иногда называемый дополнением HALF. Он называется SAME, потому что для свертки с шагом = 1 (или для объединения) он должен выводить выходные данные того же размера, что и вход. Он называется HALF, потому что для ядра размером k введите описание изображения здесь
  • FULL padding - это максимальное заполнение, которое не приводит к свертке поверх только дополненных элементов. Для ядра размером k это дополнение равно k - 1.

Чтобы использовать произвольное дополнение в TF, вы можете использовать tf.pad()

Ответ 6

Краткое пояснение

VALID: не применяйте дополнения, т.е. Допускайте, чтобы все размеры были действительными, чтобы входное изображение полностью покрывалось фильтром и шагом, указанным вами.

SAME: Применить заполнение для ввода (если необходимо), чтобы входное изображение полностью покрывалось фильтром и шагом, указанным вами. Для шага 1 это гарантирует, что размер выходного изображения будет таким же, как и вход.

Заметки

  • Это относится как к слоям conv, так и к уровням максимального пула таким же образом
  • Термин "действительный" является немного неправильным, потому что вещи не становятся "недействительными", если вы отбрасываете часть изображения. Иногда может понадобиться это. Вероятно, это должно было бы называться NO_PADDING.
  • Термин "тот же" также является неправильным, поскольку он имеет смысл только для шага 1, когда размерность выхода такая же, как и входная. Например, для шага 2 выходные размеры будут наполовину. Вероятно, это, вероятно, следует называть AUTO_PADDING.
  • В SAME (т.е. В автоматическом режиме) Tensorflow будет пытаться равномерно распределять посылку как слева, так и справа.
  • В VALID (т.е. Без дополнительного режима) Tensorflow будет падать вправо и/или нижние ячейки, если ваш фильтр и шаг не будут полностью заполнены.

Ответ 7

Существует три варианта заполнения: действительный (без заполнения), тот же (или половинный), полный. Здесь вы можете найти объяснения (в Theano): http://deeplearning.net/software/theano/tutorial/conv_arithmetic.html

  • Допустимые или отсутствующие дополнения:

Действительное заполнение не содержит нулевого заполнения, поэтому оно охватывает только действительный ввод, не считая искусственно созданных нулей. Длина вывода равна ((длина ввода) - (k-1)) для размера ядра k, если шаг s = 1.

  • То же или наполовину заполнение:

Такое же дополнение делает размер выходов одинаковым с входом при s = 1. Если s = 1, количество заполненных нулей равно (k-1).

  • Полное заполнение:

Полное заполнение означает, что ядро ​​работает по всем входам, поэтому на концах ядро ​​может отвечать только одному вводу и нулям else. Количество заполненных нулей равно 2 (k-1), если s = 1. Длина вывода равна ((длина ввода) + (k-1)), если s = 1.

Следовательно, количество проходов: (valid) <= (same) <= (full)

Ответ 8

Я цитирую этот ответ из официальных документов тензорного потока https://www.tensorflow.org/api_guides/python/nn#Convolution. Для заполнения "SAME" высота и ширина вывода вычисляются как:

out_height = ceil(float(in_height) / float(strides[1]))
out_width  = ceil(float(in_width) / float(strides[2]))

и отступы сверху и слева вычисляются как:

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

Для заполнения "VALID" высота и ширина вывода вычисляются как:

out_height = ceil(float(in_height - filter_height + 1) / float(strides[1]))
out_width  = ceil(float(in_width - filter_width + 1) / float(strides[2]))

и значения заполнения всегда равны нулю.

Ответ 9

Основываясь на объяснениях здесь и следуя ответу Тристана, я обычно использую эти быстрые функции для проверки работоспособности.

# 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')

Ответ 10

VALID padding: это с нулевым заполнением. Надеюсь, что нет путаницы.

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)

ТО ЖЕ ВРЕМЯ: Это довольно сложно понять, во-первых, потому что мы должны рассматривать два условия отдельно, как указано в официальных документах.

Возьмем входные данные как gif.latex?n_i, выходные данные как gif.latex?n_o, заполнение как gif.latex?p_i, шаг за шагом как gif.latex?s и размер ядра как gif.latex?k (рассматривается только одно измерение)

Дело 01: gif.latex?n_i&space;%5Cmod&space;s&space;=&space;0: gif.latex?p_i&space;=&space;max(k-s&space;,0)

Дело 02: gif.latex?n_i&space;%5Cmod&space;s&space;%5Cneq&space;0: gif.latex?p_i&space;=&space;max(k&space;-&space;(n_i%5Cmod&space;s)),&space;0)

gif.latex?p_i рассчитывается так, чтобы минимальное значение, которое можно принять для заполнения. Поскольку значение gif.latex?p_i известно, значение gif.latex?n_0 можно найти с помощью этой формулы 2&space;&plus;&space;1&space;=&space;n_0.

Позвольте отработать этот пример:

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)

Здесь размерность х равна (3,4). Тогда, если взять горизонтальное направление (3):

gif.latex?n_i&space;=&space;3,&space;k&space;=2,&space;s&space;=2,&space;p_i&space;=&space;2&space;-&space;(3%5Cmod&space;2)&space;=&space;1,&space;n_0&space;=&space;int&space;(%5Cfrac%7B3-2&plus;2*1%7D%7B2%7D&space;&plus;&space;1)&space;=&space;2

Если вертикальное направление принято (4):

gif.latex?n_i&space;=&space;4,&space;k&space;=2,&space;s&space;=2,&space;p_i&space;=&space;2&space;-&space;2&space;=&space;0,&space;n_0&space;=&space;int&space;(%5Cfrac%7B3-2&plus;2*0%7D%7B2%7D&space;&plus;&space;1)&space;=&space;2

Надеюсь, что это поможет понять, как на самом деле работает то же самое в TF.

Ответ 11

Включение/выключение. Определяет эффективный размер вашего ввода.

VALID: нет отступов. Операции свертки и т.д. Выполняются только в местах, которые являются "действительными", то есть не слишком близки к границам вашего тензора.
С ядром 3x3 и изображением 10x10 вы выполняете свертку в области 8x8 внутри границ.

SAME: Предусмотрено заполнение. Всякий раз, когда ваша операция ссылается на окрестности (независимо от того, насколько она велика), нулевые значения предоставляются, когда эта окрестность простирается за пределы исходного тензора, чтобы эта операция могла работать и на граничных значениях.
С ядром 3x3 и изображением 10x10 вы выполняете свертку на всей области 10x10.

Ответ 12

General Formula

Здесь W и H - ширина и высота ввода, F - размеры фильтра, P - размер заполнения (т.е. Количество строк или столбцов, которые должны быть дополнены).

Для ТО ЖЕ САМОГО дополнения:

SAME Padding

Для VALID дополнения:

VALID padding

Ответ 13

Подводя итог, "действительный" отступ означает отсутствие заполнения. Выходной размер сверточного слоя уменьшается в зависимости от входного размера & размер ядра.

Напротив, "одно и то же" заполнение означает использование заполнения. Выходной размер сверточного слоя сохраняется в качестве входного размера, добавляя определенное число "0-граница" вокруг входных данных при расчете свертки.

Надеюсь, это интуитивное описание поможет.