В чем разница между "одинаковым" и "действительным" заполнением в tf.НН.максимальный пул тензорного потока?



В чем разница между "одинаковым" и "действительным" заполнением в tf.nn.max_pool на tensorflow?



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



по данным руководство по арифметике свертки для глубокого обучения, он говорит, что в операторе пула не будет заполнения, т. е. просто используйте 'VALID' of tensorflow.
Но что такое "то же самое" заполнение максимального пула в tensorflow?

670   11  

11 ответов:

я приведу пример, чтобы было понятнее:

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

выходные формы:

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

Если вам нравится 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
  • Stride = 5

Примечания:

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

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

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

The Свертка Тензорного Потока пример дает обзор о разнице между 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]))

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

вот пример нулевого заполнения с p=1 применяется к 2-d тензору: enter image description here


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

  • допустимое заполнение. Самый простой случай, означает отсутствие обивки вообще. Просто оставьте ваши данные такими же, какими они были.
  • та же обивка иногда называют половина обивка. Она называется то же самое потому что для свертки с шагом=1, (или для объединения) он должен производить выход того же размера, что и вход. Она называется пол потому что для ядра размере kenter image description here
  • полная обивка - это максимальное заполнение, которое не приводит к свертке над просто дополненными элементами. Для ядра размером k, это дополнение равно k - 1.

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

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

  • допустимо или нет заполнение:

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

  • такая же или половинная прокладка:

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

  • полная обивка:

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

таким образом, количество отступов: (действительный)

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

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

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

Примечания

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

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

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

для "допустимого" заполнения выходные высота и ширина вычисляются как:

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

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

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

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

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

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)

то же самое дополнение: это довольно сложно понять в первую очередь, потому что мы должны рассмотреть 2 условия отдельно, как указано в официальные документы.

давайте возьмем ввод как , выход а , обивка как , Stride, как и размер ядра как . (singal dimentina is считается)

01 случае: :

корпус 02: :

рассчитывается su, что минимальное значение, которое может быть принято для заполнения. Так как значение известно, стоимостью можно найти с помощью этого формульного .

давайте рассмотрим этот пример:

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)

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

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

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

прокладка вкл/выкл. Определяет эффективный размер входных данных.

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

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

Comments

    Ничего не найдено.