Sự khác biệt giữa phần đệm 'SAME' và 'VALID' trong tf.nn.max_pool của tenorflow là gì?


309

Sự khác biệt giữa phần đệm 'CÙNG' và 'GIÁ TRỊ' tf.nn.max_pooltensorflowgì?

Theo tôi, 'GIÁ TRỊ' có nghĩa là sẽ không có phần đệm nào bên ngoài các cạnh khi chúng ta thực hiện nhóm tối đa.

Theo Hướng dẫn về số học tích chập để học sâu , nó nói rằng sẽ không có phần đệm trong toán tử pool, tức là chỉ sử dụng 'GIÁ TRỊ' của tensorflow. Nhưng phần đệm 'CÙNG' của nhóm tối đa là tensorflowgì?


3
Kiểm tra tenorflow.org/api_guides/python/ để biết chi tiết, đây là cách tf thực hiện nó.
GabrielChu


4
Kiểm tra những gifs tuyệt vời này để hiểu làm thế nào đệm và sải chân hoạt động. Liên kết
Deepak

1
@GabrielChu liên kết của bạn dường như đã chết và hiện đang chuyển hướng đến một tổng quan chung.
matt

Khi Tensorflow nâng cấp lên 2.0, mọi thứ sẽ được thay thế bởi Keras và tôi tin rằng bạn có thể tìm thấy thông tin tổng hợp trong tài liệu của Keras. @matt
GabrielChu

Câu trả lời:


163

Tôi sẽ đưa ra một ví dụ để làm cho nó rõ ràng hơn:

  • x: hình ảnh đầu vào của hình dạng [2, 3], 1 kênh
  • valid_pad: nhóm tối đa với kernel 2x2, sải 2 và đệm VALID.
  • same_pad: nhóm tối đa với kernel 2x2, sải chân 2 và đệm SAME (đây là cách cổ điển để đi)

Các hình dạng đầu ra là:

  • valid_pad: ở đây, không có phần đệm nên hình dạng đầu ra là [1, 1]
  • same_pad: ở đây, chúng tôi đệm hình ảnh vào hình dạng [2, 4] (với -infvà sau đó áp dụng nhóm tối đa), vì vậy hình dạng đầu ra là [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

Nếu bạn thích nghệ thuật ascii:

  • "VALID" = không có phần đệm:

       inputs:         1  2  3  4  5  6  7  8  9  10 11 (12 13)
                      |________________|                dropped
                                     |_________________|
  • "SAME" = với phần đệm bằng không:

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

Trong ví dụ này:

  • Chiều rộng đầu vào = 13
  • Độ rộng bộ lọc = 6
  • Sải bước = 5

Ghi chú:

  • "VALID" chỉ bao giờ giảm các cột ngoài cùng bên phải (hoặc hàng dưới cùng).
  • "SAME" cố gắng đệm đều sang trái và phải, nhưng nếu số lượng cột được thêm là số lẻ, nó sẽ thêm cột phụ vào bên phải, như trường hợp trong ví dụ này (logic tương tự được áp dụng theo chiều dọc: có thể có thêm một hàng số không ở phía dưới).

Chỉnh sửa :

Về tên:

  • Với phần "SAME"đệm, nếu bạn sử dụng sải chân 1, các đầu ra của lớp sẽ có cùng kích thước không gian với các đầu vào của nó.
  • Với phần "VALID"đệm, không có đầu vào đệm "tạo thành". Lớp chỉ sử dụng dữ liệu đầu vào hợp lệ .

Có công bằng không khi nói "CÙNG" có nghĩa là "sử dụng phần đệm bằng 0 để đảm bảo kích thước bộ lọc không phải thay đổi nếu chiều rộng hình ảnh không phải là bội số của chiều rộng bộ lọc hoặc chiều cao hình ảnh không phải là bội số của chiều cao bộ lọc "? Như trong, "pad có số không lên đến bội số của chiều rộng bộ lọc" nếu chiều rộng là vấn đề?
Số liệu thống kê

2
Trả lời câu hỏi phụ của tôi: KHÔNG, đó không phải là điểm không đệm. Bạn chọn kích thước bộ lọc để làm việc với đầu vào (bao gồm cả phần đệm bằng 0), nhưng bạn không chọn phần đệm bằng 0 sau kích thước bộ lọc.
Chỉ số thống kê

Tôi không hiểu câu trả lời của riêng bạn @StatsSorceress. Dường như với tôi rằng bạn thêm đủ số không (theo cách đối xứng nhất có thể) để tất cả các đầu vào được bao phủ bởi một số bộ lọc, phải không?
guillefix

2
Câu trả lời tuyệt vời, chỉ cần thêm: Trong trường hợp các giá trị tenxơ có thể âm, đệm cho max_pooling là với -inf.
Tones29

Điều gì sẽ xảy ra nếu độ rộng đầu vào là một số chẵn khi ksize = 2, stride = 2 và với phần đệm SAME? ... thì nó không phải là phần đệm phải không? .... Tôi đang nói điều này khi tôi nhìn vào repo mã dòng tối , họ đang sử dụng SAME pad, stride = 2, ksize = 2 cho maxpool .... sau khi chiều rộng hình ảnh maxpool giảm xuống còn 208 pixel từ chiều rộng 416 pixel. Bất cứ ai có thể làm rõ điều này?
K.vindi

161

Khi stridelà 1 (điển hình hơn với tích chập so với gộp), chúng ta có thể nghĩ đến sự khác biệt sau:

  • "SAME": kích thước đầu ra giống như kích thước đầu vào. Điều này đòi hỏi cửa sổ bộ lọc trượt ra ngoài bản đồ đầu vào, do đó cần phải đệm.
  • "VALID": Cửa sổ bộ lọc giữ ở vị trí hợp lệ bên trong bản đồ đầu vào, do đó kích thước đầu ra co lại theo filter_size - 1. Không có đệm xảy ra.

65
Điều này cuối cùng là hữu ích. Tính đến thời điểm này, dường như SAMEVALIDcó thể cũng đã được gọi foobar
omatai

7
Tôi nghĩ rằng "kích thước đầu ra giống như kích thước đầu vào" chỉ đúng khi chiều dài sải chân là 1.
omsrisagar

92

Các TensorFlow Convolution dụ đưa ra một cái nhìn tổng quan về sự khác biệt giữa SAMEVALID:

  • Đối với phần SAMEđệm, chiều cao và chiều rộng đầu ra được tính là:

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

  • Đối với phần VALIDđệm, chiều cao và chiều rộng đầu ra được tính là:

    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

Đệm là một hoạt động để tăng kích thước của dữ liệu đầu vào. Trong trường hợp dữ liệu 1 chiều, bạn chỉ cần thêm / thêm vào mảng với hằng số, trong ma trận 2 chiều bạn bao quanh với các hằng số này. Trong n-dim bạn bao quanh hypercube n-dim của bạn với hằng số. Trong hầu hết các trường hợp, hằng số này là 0 và nó được gọi là zero-padding.

Dưới đây là một ví dụ về phần đệm bằng 0 p=1được áp dụng cho tenxơ 2 chiều: nhập mô tả hình ảnh ở đây


Bạn có thể sử dụng phần đệm tùy ý cho kernel của mình nhưng một số giá trị của phần đệm được sử dụng thường xuyên hơn các phần khác:

  • Đệm có giá trị . Trường hợp dễ nhất, có nghĩa là không có phần đệm nào cả. Chỉ cần để lại dữ liệu của bạn giống như vậy.
  • CÙNG đệm đôi khi được gọi là đệm HALF . Nó được gọi là CÙNG vì đối với tích chập có sải = 1, (hoặc để gộp), nó sẽ tạo ra đầu ra có cùng kích thước với đầu vào. Nó được gọi là HALF vì hạt nhân có kích thướck nhập mô tả hình ảnh ở đây
  • Đệm đầy là phần đệm tối đa không dẫn đến tích chập so với chỉ các phần tử được đệm. Đối với một hạt nhân có kích thước k, phần đệm này bằng k - 1.

Để sử dụng phần đệm tùy ý trong TF, bạn có thể sử dụng tf.pad()


32

Giải thích nhanh

VALID: Không áp dụng bất kỳ phần đệm nào, tức là giả sử rằng tất cả các kích thước đều hợp lệ để hình ảnh đầu vào được che phủ hoàn toàn bởi bộ lọc và sải bước bạn đã chỉ định.

SAME: Áp dụng phần đệm cho đầu vào (nếu cần) để hình ảnh đầu vào được bao phủ hoàn toàn bởi bộ lọc và sải bước bạn đã chỉ định. Đối với sải chân 1, điều này sẽ đảm bảo rằng kích thước hình ảnh đầu ra giống như đầu vào.

Ghi chú

  • Điều này áp dụng cho các lớp đối lưu cũng như các lớp nhóm tối đa theo cùng một cách
  • Thuật ngữ "hợp lệ" là một chút sai lầm vì mọi thứ không trở thành "không hợp lệ" nếu bạn bỏ một phần hình ảnh. Đôi khi bạn thậm chí có thể muốn điều đó. Điều này có lẽ nên được gọi NO_PADDINGthay thế.
  • Thuật ngữ "giống nhau" cũng là một cách gọi sai vì nó chỉ có ý nghĩa cho bước tiến 1 khi kích thước đầu ra giống với kích thước đầu vào. Ví dụ, đối với sải chân là 2, kích thước đầu ra sẽ là một nửa. Điều này có lẽ nên được gọi AUTO_PADDINGthay thế.
  • Trong SAME(tức là chế độ tự động đệm), Tensorflow sẽ cố gắng trải đều phần đệm ở cả bên trái và bên phải.
  • Trong VALID(nghĩa là không có chế độ đệm), Tensorflow sẽ thả các ô bên phải và / hoặc dưới cùng nếu bộ lọc và sải chân của bạn không che hết hình ảnh đầu vào.

19

Tôi đang trích dẫn câu trả lời này từ các tài liệu tenorflow chính thức https://www.tensorflow.org/api_guides/python/nn#Convolution Đối với phần đệm 'SAME', chiều cao và chiều rộng đầu ra được tính như sau:

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

và phần đệm ở trên cùng và bên trái được tính là:

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

Đối với phần đệm 'VALID', chiều cao và chiều rộng đầu ra được tính là:

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

và các giá trị đệm luôn bằng không.


1
Thành thật mà nói đây là câu trả lời hợp lệ và đầy đủ duy nhất xung quanh, không giới hạn ở những bước tiến của 1. Và tất cả những gì nó cần là một trích dẫn từ các tài liệu. +1
P-Gn

1
Rất hữu ích để có câu trả lời này, đặc biệt vì liên kết bạn trỏ đến không hoạt động nữa và có vẻ như Google đã xóa thông tin đó khỏi trang web tf!
Daniel

12

Có ba lựa chọn về phần đệm: hợp lệ (không có phần đệm), giống nhau (hoặc một nửa), đầy đủ. Bạn có thể tìm thấy lời giải thích (trong Theano) tại đây: http://deeplearning.net/software/theano/tutorial/conv_arithatures.html

  • Hợp lệ hoặc không có phần đệm:

Phần đệm hợp lệ không có phần đệm bằng 0, do đó, phần này chỉ bao gồm phần đầu vào hợp lệ, không bao gồm các số 0 được tạo giả tạo. Độ dài của đầu ra là ((độ dài của đầu vào) - (k-1)) cho kích thước hạt nhân k nếu sải chân s = 1.

  • Đệm hoặc cùng một nửa:

Việc đệm giống nhau làm cho kích thước của đầu ra giống với kích thước của đầu vào khi s = 1. Nếu s = 1, số lượng số không được đệm là (k - 1).

  • Đệm đầy đủ:

Phần đệm đầy đủ có nghĩa là kernel chạy trên toàn bộ đầu vào, vì vậy ở phần cuối, kernel có thể chỉ đáp ứng một đầu vào và các số không khác. Số lượng số không được đệm là 2 (k - 1) nếu s = 1. Độ dài của đầu ra là ((độ dài của đầu vào) + (k-1)) nếu s = 1.

Do đó, số lượng paddings: (hợp lệ) <= (giống nhau) <= (đầy đủ)


8

Đệm bật / tắt. Xác định kích thước hiệu quả của đầu vào của bạn.

VALID:Không đệm. Chuyển đổi, vv ops chỉ được thực hiện tại các vị trí "hợp lệ", tức là không quá gần với đường viền của tenor của bạn.
Với hạt nhân 3x3 và hình ảnh của 10x10, bạn sẽ thực hiện tích chập trên khu vực 8x8 bên trong đường viền.

SAME:Đệm được cung cấp. Bất cứ khi nào hoạt động của bạn tham chiếu đến một vùng lân cận (dù lớn đến đâu), các giá trị 0 được cung cấp khi vùng lân cận đó nằm ngoài phạm vi ban đầu để cho phép thao tác đó hoạt động trên các giá trị biên.
Với hạt nhân 3x3 và hình ảnh của 10x10, bạn sẽ thực hiện tích chập trên toàn bộ khu vực 10x10.


8

HỢP LỆ padding: đây là với zero padding. Hy vọng không có sự nhầm lẫ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)

Đệm SAME : Đây là loại khó hiểu ngay từ đầu vì chúng ta phải xem xét hai điều kiện riêng biệt như được đề cập trong các tài liệu chính thức .

Chúng ta hãy lấy đầu vào là , đầu ra là , đệm như , sải bước và kích thước hạt nhân như (chỉ một chiều duy nhất được xem xét)

Trường hợp 01 ::

Trường hợp 02 ::

được tính toán sao cho giá trị tối thiểu có thể được lấy để đệm. Vì giá trị được biết đến, giá trị của có thể được tìm thấy bằng cách sử dụng công thức này .

Hãy làm ví dụ này:

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)

Ở đây kích thước của x là (3,4). Sau đó, nếu hướng ngang được thực hiện (3):

Nếu hướng dọc được lấy (4):

Hy vọng điều này sẽ giúp hiểu cách thực sự SAME padding hoạt động trong TF.


7

Dựa trên lời giải thích ở đây và theo dõi câu trả lời của Tristan, tôi thường sử dụng các chức năng nhanh này để kiểm tra độ tỉnh táo.

# 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

Tóm lại, phần đệm 'hợp lệ' có nghĩa là không có phần đệm. Kích thước đầu ra của lớp chập co lại tùy thuộc vào kích thước đầu vào & kích thước hạt nhân.

Ngược lại, phần đệm 'cùng' có nghĩa là sử dụng phần đệm. Khi sải chân được đặt là 1, kích thước đầu ra của lớp chập duy trì là kích thước đầu vào bằng cách nối thêm một số '0-viền' nhất định xung quanh dữ liệu đầu vào khi tính tích chập.

Hy vọng mô tả trực quan này sẽ giúp.


5

Công thức chung

Ở đây, W và H là chiều rộng và chiều cao của đầu vào, F là kích thước bộ lọc, P là kích thước đệm (nghĩa là số lượng hàng hoặc cột được đệm)

Đối với phần đệm CÙNG:

CÙNG đệm

Đối với phần đệm GIÁ TRỊ:

Đệm giá trị


2

Bổ sung cho câu trả lời tuyệt vời của YvesgereY, tôi thấy hình dung này cực kỳ hữu ích:

Hình dung đệm

Đệm ' hợp lệ ' là con số đầu tiên. Cửa sổ bộ lọc vẫn ở bên trong hình ảnh.

Đệm ' giống nhau ' là con số thứ ba. Đầu ra có cùng kích thước.


Tìm thấy nó trên bài viết này .


0

Câu trả lời tương thích Tensorflow 2.0 : Giải thích chi tiết đã được cung cấp ở trên, về phần đệm "Hợp lệ" và "Tương tự".

Tuy nhiên, tôi sẽ chỉ định các Hàm gộp khác nhau và các Lệnh tương ứng của chúng Tensorflow 2.x (>= 2.0), vì lợi ích của cộng đồng.

Hàm trong 1.x :

tf.nn.max_pool

tf.keras.layers.MaxPool2D

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

Hàm trong 2.x :

tf.nn.max_poolnếu được sử dụng trong 2.x và tf.compat.v1.nn.max_pool_v2hoặc tf.compat.v2.nn.max_pool, nếu di chuyển từ 1.x sang 2.x.

tf.keras.layers.MaxPool2D nếu được sử dụng trong 2.x và

tf.compat.v1.keras.layers.MaxPool2Dhay tf.compat.v1.keras.layers.MaxPooling2Dhay tf.compat.v2.keras.layers.MaxPool2Dhay tf.compat.v2.keras.layers.MaxPooling2D, nếu di cư từ 1.x để 2.x.

Average Pooling => tf.nn.avg_pool2dhoặc tf.keras.layers.AveragePooling2Dnếu được sử dụng trong TF 2.x và

tf.compat.v1.nn.avg_pool_v2hay tf.compat.v2.nn.avg_poolhay tf.compat.v1.keras.layers.AveragePooling2Dhay tf.compat.v1.keras.layers.AvgPool2Dhay tf.compat.v2.keras.layers.AveragePooling2Dhay tf.compat.v2.keras.layers.AvgPool2D, nếu di cư từ 1.x để 2.x.

Để biết thêm thông tin về Di chuyển từ Tensorflow 1.x sang 2.x, vui lòng tham khảo Hướng dẫn di chuyển này .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.