Яка різниця між накладками 'SAME' та 'VALID' у tf.nn.max_pool tensorflow?


309

У чому різниця між «SAME» і «ДІЙСНО» оббивкою в tf.nn.max_poolз tensorflow?

На мою думку, "VALID" означає, що за межами країв не буде нульової прокладки, коли ми робимо максимальний пул.

Відповідно до Посібника з арифметики згортання для глибокого навчання , в ньому йдеться про те, що в операторі пулу не буде прокладки, тобто просто використовувати 'VALID' з tensorflow. Але що таке "SAME" прокладки з максимального басейну tensorflow?


3
Перевірте tensorflow.org/api_guides/python/… для деталей, ось як це зробили.
ГабріельЧу


4
Ознайомтеся з цими дивовижними подарунками, щоб зрозуміти, як працює підкладка та крок. Посилання
Діпак

1
@GabrielChu ваше посилання, здається, померло, і тепер перенаправлення на загальний огляд.
мат

По мірі оновлення Tensorflow до 2.0, речі будуть замінені Keras, і я вважаю, що ви можете знайти інформацію про об'єднання в документаціях Keras. @matt
GabrielChu

Відповіді:


163

Я наведу приклад, щоб зробити його зрозумілішим:

  • x: вхідне зображення форми [2, 3], 1 канал
  • valid_pad: макс. пул з ядром 2х2, крок 2 та валіда.
  • 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.]


603

Якщо вам подобається мистецтво ascii:

  • "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"прокладки немає "готових" входів для підкладки. У шарі використовуються лише дійсні вхідні дані.

Чи справедливо сказати "SAME" означає "використовувати нульову підкладку, щоб переконатися, що розмір фільтра не повинен змінюватися, якщо ширина зображення не кратна ширині фільтра або висота зображення не кратна висоті фільтра "? Як і в "pad з нулями до кратного ширини фільтра", якщо проблема з шириною?
StatsSorceress

2
Відповідаючи на власне побічне запитання: НІ, це не сенс нульової прокладки. Ви вибираєте розмір фільтра для роботи з входом (включаючи нульове набивання), але ви не обираєте нульову прокладку після розміру фільтра.
СтатистикаSorceress

Я не розумію вашої власної відповіді @StatsSorceress. Мені здається, ви додаєте достатньо нулів (максимально симетричним способом), щоб усі входи були охоплені якимсь фільтром, я прав?
guillefix

2
Відмінна відповідь, просто додати: Якщо тензорні значення можуть бути негативними, накладка для max_pooling має значення -inf.
Тони29

Що робити, якщо вхідна ширина є парним числом, коли ksize = 2, stride = 2 та з SAME padding? ... тоді вона не повинна бути з нульовим розміром правильно? .... Я це говорю, коли дивлюсь код темного потоку , вони використовують SAME pad, stride = 2, ksize = 2 для maxpool .... після максимальної збірки ширина зображення зменшується до 208 пікселів із 416 пікселів. Хтось може це уточнити?
К.вінді

161

Коли stride1 (більш типовий для згортання, ніж об'єднання), ми можемо думати про наступне розрізнення:

  • "SAME": розмір виходу однаковий як і розмір вводу. Для цього потрібне вікно фільтра ковзати поза вхідною картою, отже, необхідність прокладати.
  • "VALID": Вікно фільтра залишається на правильному положенні всередині вхідної карти, тому розмір виводу зменшується на filter_size - 1. Ніяких прокладок не відбувається.

65
Це, нарешті, корисно. До цього моменту, виявилося , що SAMEі , VALIDможливо, також був названий fooіbar
omatai

7
Я думаю, що "розмір вихідного сигналу такий же, як розмір введення" є істинним лише тоді, коли довжина кроку дорівнює 1.
omsrisagar

92

Приклад згортки TensorFlow дає огляд різниці між 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]))

46

Прокладка - це операція зі збільшення розміру вхідних даних. У разі одновимірних даних ви просто додаєте / додаєте масив з постійною величиною, у 2-димній об'ємній матриці з цими константами. У n-dim ви оточуєте n-dim гіперкуб постійною. У більшості випадків ця константа дорівнює нулю, і її називають нульовою накладкою.

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


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

  • ВАЛІДНІ підкладки . Найпростіший випадок - це взагалі відсутність прокладки. Просто залиште свої дані такими, як це було.
  • SAME прокладки іноді називають HALF padding . Він називається SAME, оскільки для згортання з кроком = 1, (або для об'єднання) він повинен отримати вихід такого ж розміру, що і вхідний. Він називається HALF, тому що для розміру ядраk введіть тут опис зображення
  • ПОВНА накладка - це максимальна обшивка, яка не призводить до згортання тільки що прокладених елементів. Для розміру ядра розміром kця підкладка дорівнює k - 1.

Для використання довільної прокладки в TF ви можете використовувати tf.pad()


32

Швидке пояснення

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

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

Примітки

  • Це стосується шарів conv, а також максимальних шарів пулу таким же чином
  • Термін "дійсний" трохи помилковий, оскільки речі не стають "недійсними", якщо ви скинете частину зображення. Колись вам навіть цього захочеться. Це, мабуть, слід було б назватиNO_PADDING замість цього.
  • Термін "той самий" є помилковим, оскільки він має сенс для кроку 1 лише тоді, коли вихідний вимір такий же, як вхідний вимір. Для кроку 2, наприклад, розміри виходу будуть наполовину, наприклад. Це, мабуть, слід було б назвати AUTO_PADDINGзамість цього.
  • В SAME (тобто режимі автоматичної прокладки) Tensorflow намагатиметься рівномірно розподілити набивання як зліва, так і справа.
  • У VALID(тобто не в режимі прокладки) Tensorflow видалить праву та / або нижню клітинку, якщо ваш фільтр та крок не мають повного вхідного зображення покриття.

19

Я цитую цю відповідь з офіційних документів tensorflow 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]))

а значення прокладки завжди дорівнюють нулю.


1
Відверто кажучи, це єдиний вірний і повний відповідь, не обмежуючись кроками 1. І все, що потрібно, - це цитата з документів. +1
P-Gn

1
Дуже корисно мати цю відповідь, особливо тому, що посилання, на яке ви вказуєте, більше не працює і, здається, Google видалив цю інформацію з веб-сайту tf!
Даниїл

12

Є три варіанти оббивки: дійсний (без прокладки), такий же (або наполовину), повний. Пояснення (у 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. Довжина виводу становить ((довжина вводу) + (k-1)), якщо s = 1.

Тому кількість прокладок: (дійсне) <= (однаково) <= (повне)


8

Прокладка включення / вимкнення. Визначає ефективний розмір вашого вкладу.

VALID:Відсутня підкладка. Операції згортання тощо виконуються лише в місцях, які є "дійсними", тобто не надто близько до меж вашого тензора.
З ядром 3х3 та зображенням 10х10 ви б виконували згортку на зоні 8х8 всередині кордонів.

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


8

ВАЛІДНЕ прокладка: це з нульовим накладкою. Сподіваюсь, немає ніякої плутанини.

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)

САМЕ прокладки: Це важко зрозуміти, в першу чергу, оскільки ми повинні розглянути дві умови окремо, як зазначено в офіційних документах .

Давайте візьмемо введення як , виводимо як , padding as , stride as та розмір ядра як (вважається лише один вимір)

Випадок 01: :

Випадок 02 :

обчислюється таким чином, що мінімальне значення, яке можна взяти за прокладку. Оскільки значення відоме, значення можна знайти за допомогою цієї формули .

Давайте опрацюємо цей приклад:

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):

Сподіваємось, це допоможе зрозуміти, як насправді прокладка SAME працює в TF.


7

Виходячи з пояснення тут і надаючи відповіді на Тристана, я зазвичай використовую ці швидкі функції для перевірки здорового стану.

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

6

Підводячи підсумок, "правильне" прокладка означає відсутність прокладки. Розмір вихідного шару згорнутого шару скорочується залежно від розміру вводу та розміру ядра.

Навпаки, "те ж" прокладка означає використання прокладки. Коли для кроку встановлено 1, розмір виводу згорткового шару зберігається як вхідний розмір, додаючи певну кількість '0-меж' навколо вхідних даних при обчисленні згортки.

Сподіваюся, цей інтуїтивний опис допомагає.


5

Загальна формула

Тут W і H - ширина і висота вводу, F - розміри фільтра, P - розмір підкладки (тобто кількість рядків або стовпців, які слід прокласти)

Для прокладки SAME:

САМЕ прокладки

Для валідів VALID:

ВАЛІДНІ підкладки


2

Доповнюючи чудову відповідь YvesgereY, я вважав цю візуалізацію надзвичайно корисною:

Прокладка візуалізації

" Дійсний " прокладки - це перша цифра. Вікно фільтра залишається всередині зображення.

Набивання "те ж " - третя цифра. Вихід однакового розміру.


Знайшов це в цій статті .


0

Відповідь Tensorflow 2.0 : Детальні пояснення надані вище про "Дійсні" та "Те саме" Прокладки.

Однак я вкажу різні функції об'єднання та їх Команди в Tensorflow 2.x (>= 2.0)інтересах громади.

Функції в 1.x :

tf.nn.max_pool

tf.keras.layers.MaxPool2D

Average Pooling => None in tf.nn, tf.keras.layers.AveragePooling2D

Функції в 2.x :

tf.nn.max_poolякщо використовується в 2.x та, tf.compat.v1.nn.max_pool_v2або tf.compat.v2.nn.max_pool, якщо перейшов з 1.x на 2.x.

tf.keras.layers.MaxPool2D якщо використовується в 2.х та

tf.compat.v1.keras.layers.MaxPool2Dабо tf.compat.v1.keras.layers.MaxPooling2Dабо tf.compat.v2.keras.layers.MaxPool2Dабо tf.compat.v2.keras.layers.MaxPooling2D, якщо вони перейшли з 1.x на 2.x.

Average Pooling => tf.nn.avg_pool2dабо tf.keras.layers.AveragePooling2Dякщо використовується в TF 2.x та

tf.compat.v1.nn.avg_pool_v2або tf.compat.v2.nn.avg_poolабо tf.compat.v1.keras.layers.AveragePooling2Dабо tf.compat.v1.keras.layers.AvgPool2Dабо tf.compat.v2.keras.layers.AveragePooling2Dабо tf.compat.v2.keras.layers.AvgPool2D, якщо вони переміщені з 1.x до 2.x.

Для отримання додаткової інформації про міграцію з Tensorflow 1.x до 2.x, зверніться до цього посібника з міграції .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.