.. raw:: html
.. raw:: html
.. raw:: html
.. _sec_pooling:
Gộp (*Pooling*)
===============
.. raw:: html
Khi xử lý ảnh, ta thường muốn giảm dần độ phân giải không gian của các
biểu diễn ẩn, tổng hợp thông tin lại để khi càng đi sâu vào mạng, vùng
tiếp nhận (ở đầu vào) ảnh hưởng đến mỗi nút ẩn càng lớn.
.. raw:: html
Nhiệm vụ cuối cùng thường là trả lời một câu hỏi nào đó về toàn bộ tấm
ảnh, ví dụ như: *trong ảnh có mèo không?* Vậy nên các nút của tầng cuối
cùng thường cần phải chịu ảnh hưởng của toàn bộ đầu vào. Bằng cách dần
gộp thông tin lại để tạo ra các ánh xạ đặc trưng thưa dần, ta sẽ học
được một biểu diễn toàn cục, trong khi vẫn có thể giữ nguyên toàn bộ lợi
thế đến từ các tầng tích chập xử lý trung gian.
.. raw:: html
Hơn nữa, khi phát hiện các đặc trưng cấp thấp như cạnh (được thảo luận
tại :numref:`sec_conv_layer`), ta thường muốn cách biểu diễn này bất
biến với phép tịnh tiến trong một chừng mực nào đó. Ví dụ, nếu ta lấy
ảnh ``X`` với một ranh giới rõ rệt giữa màu đen và màu trắng và dịch
chuyển toàn bộ tấm ảnh sang phải một điểm ảnh, tức
``Z[i, j] = X[i, j+1]`` thì đầu ra cho ảnh mới ``Z`` có thể sẽ khác đi
rất nhiều. Đường biên đó và các giá trị kích hoạt sẽ đều dịch chuyển
sang một điểm ảnh. Trong thực tế, các vật thể hiếm khi xuất hiện chính
xác ở cùng một vị trí. Thậm chí với một chân máy ảnh và một vật thể
tĩnh, chuyển động của màn trập vẫn có thể làm rung máy ảnh và dịch
chuyển tất cả đi một vài điểm ảnh (các máy ảnh cao cấp được trang bị
những tính năng đặc biệt nhằm khắc phục vấn đề này).
.. raw:: html
Trong mục này, chúng tôi sẽ giới thiệu về các tầng gộp, với hai chức
năng là giảm độ nhạy cảm của các tầng tích chập đối với vị trí và giảm
kích thước của các biểu diễn.
.. raw:: html
.. raw:: html
.. raw:: html
Gộp cực đại và Gộp trung bình
-----------------------------
.. raw:: html
Giống như các tầng tích chập, các toán tử gộp bao gồm một cửa sổ có kích
thước cố định được trượt trên tất cả các vùng đầu vào với giá trị sải
bước nhất định, tính toán một giá trị đầu ra duy nhất tại mỗi vị trí mà
cửa sổ (đôi lúc được gọi là *cửa sổ gộp*) trượt qua. Tuy nhiên, không
giống như phép toán tương quan chéo giữa đầu vào và hạt nhân ở tầng tích
chập, tầng gộp không chứa bất kỳ tham số nào (ở đây không có “bộ lọc”).
Thay vào đó, các toán tử gộp được định sẵn. Chúng thường tính giá trị
cực đại hoặc trung bình của các phần tử trong cửa sổ gộp. Các phép tính
này lần lượt được gọi là là *gộp cực đại* (*max pooling*) và *gộp trung
bình* (*average pooling*).
.. raw:: html
Trong cả hai trường hợp, giống như với toán tử tương quan chéo, ta có
thể xem như cửa sổ gộp bắt đầu từ phía trên bên trái của mảng đầu vào và
trượt qua mảng này từ trái sang phải và từ trên xuống dưới. Ở mỗi vị trí
mà cửa sổ gộp dừng, nó sẽ tính giá trị cực đại hoặc giá trị trung bình
của mảng con nằm trong cửa sổ (tùy thuộc vào phép gộp được sử dụng).
.. raw:: html
.. _fig_pooling:
.. figure:: ../img/pooling.svg
Gộp cực đại với cửa sổ có kích thước :math:`2\times 2`. Các phần tô
đậm thể hiện phần tử đầu ra đầu tiên và phần tử đầu vào được dùng để
tính toán: :math:`\max(0, 1, 3, 4)=4`
.. raw:: html
Mảng đầu ra ở :numref:`fig_pooling` phía trên có chiều cao là 2 và
chiều rộng là 2. Bốn phần tử của nó được là các giá trị cực đại của hàm
:math:`\text{max}`:
.. math::
\max(0, 1, 3, 4)=4,\\
\max(1, 2, 4, 5)=5,\\
\max(3, 4, 6, 7)=7,\\
\max(4, 5, 7, 8)=8.\\
.. raw:: html
.. raw:: html
.. raw:: html
Một tầng gộp với cửa sổ gộp có kích thước :math:`p \times q` được gọi là
một tầng gộp :math:`p \times q`. Phép gộp sẽ được gọi là phép gộp
:math:`p \times q`.
.. raw:: html
Hãy cùng quay trở lại với ví dụ nhận diện biên của vật thể được đề cập ở
đầu mục. Bây giờ, chúng ta sẽ sử dụng kết quả của tầng tích chập làm giá
trị đầu vào cho tầng gộp cực đại :math:`2\times 2`. Đặt giá trị đầu vào
của tầng tích chập là ``X`` và kết quả của tầng gộp là ``Y``. Dù giá trị
của ``X[i, j]`` và ``X[i, j+1]`` hay giá trị của ``X[i, j+1]`` và
``X[i, j+2]`` có khác nhau hay không, tất cả giá trị trả về của tầng gộp
sẽ là ``Y[i, j]=1``. Nói cách khác, khi sử dụng tầng gộp cực đại
:math:`2\times 2`, ta vẫn có thể phát hiện ra khuôn mẫu được nhận diện
bởi tầng tích chập nếu nó bị chuyển dịch không nhiều hơn một phần tử
theo chiều cao và chiều rộng.
.. raw:: html
Trong đoạn mã bên dưới, ta lập trình lượt truyền xuôi của tầng gộp trong
hàm ``pool2d``. Hàm này khá giống với hàm ``corr2d`` trong
:numref:`sec_conv_layer`. Tuy nhiên, hàm này không có bộ lọc nên kết
quả đầu ra hoặc là giá trị lớn nhất, hoặc là giá trị trung bình tương
ứng của mỗi vùng đầu vào.
.. code:: python
from mxnet import np, npx
from mxnet.gluon import nn
npx.set_np()
def pool2d(X, pool_size, mode='max'):
p_h, p_w = pool_size
Y = np.zeros((X.shape[0] - p_h + 1, X.shape[1] - p_w + 1))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
if mode == 'max':
Y[i, j] = np.max(X[i: i + p_h, j: j + p_w])
elif mode == 'avg':
Y[i, j] = X[i: i + p_h, j: j + p_w].mean()
return Y
.. raw:: html
Chúng ta có thể xây dựng mảng đầu vào ``X`` ở biểu đồ ở trên để kiểm tra
giá trị kết quả của tầng gộp cực đại hai chiều.
.. code:: python
X = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
pool2d(X, (2, 2))
.. parsed-literal::
:class: output
array([[4., 5.],
[7., 8.]])
.. raw:: html
Đồng thời, chúng ta cũng thực hiện thí nghiệm với tầng gộp trung bình.
.. code:: python
pool2d(X, (2, 2), 'avg')
.. parsed-literal::
:class: output
array([[2., 3.],
[5., 6.]])
.. raw:: html
.. raw:: html
.. raw:: html
.. raw:: html
.. raw:: html
Đệm và Sải bước
---------------
.. raw:: html
Cũng giống như các tầng tính chập, các tầng gộp cũng có thể thay đổi
kích thước đầu ra. Và cũng như trước, chúng ta có thể thay đổi cách thức
hoạt động của tầng gộp để đạt được kích thước đầu ra như mong muốn bằng
cách thêm đệm vào đầu vào và điều chỉnh sải bước. Chúng ta có thể minh
hoạ cách sử dụng đệm và sải bước trong các tầng gộp thông qua tầng gộp
cực đại hai chiều MaxPool2D được cung cấp trong mô-đun ``nn`` của thư
viện MXNet Gluon. Đầu tiên, chúng ta tạo ra dữ liệu đầu vào kích thước
``(1, 1, 4, 4)``, trong đó hai chiều đầu tiên lần lượt là kích thước
batch và số kênh.
.. code:: python
X = np.arange(16).reshape(1, 1, 4, 4)
X
.. parsed-literal::
:class: output
array([[[[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.]]]])
.. raw:: html
Theo mặc định, sải bước trong lớp ``MaxPool2D`` có cùng kích thước với
cửa sổ gộp. Dưới đây, chúng ta sử dụng cửa sổ gộp kích thước ``(3,3)``,
vì vậy theo mặc định kích thước của sải bước trong tầng gộp này là
``(3,3)``.
.. code:: python
pool2d = nn.MaxPool2D(3)
# Because there are no model parameters in the pooling layer, we do not need
# to call the parameter initialization function
pool2d(X)
.. parsed-literal::
:class: output
array([[[[10.]]]])
.. raw:: html
Giá trị của sải bước và đệm có thể được gán thủ công.
.. code:: python
pool2d = nn.MaxPool2D(3, padding=1, strides=2)
pool2d(X)
.. parsed-literal::
:class: output
array([[[[ 5., 7.],
[13., 15.]]]])
.. raw:: html
Dĩ nhiên, chúng ta có thể định nghĩa một cửa sổ gộp hình chữ nhật tuỳ ý
và chỉ rõ giá trị phần đệm và sải bước tương ứng với chiều cao và chiều
rộng của cửa sổ.
.. code:: python
pool2d = nn.MaxPool2D((2, 3), padding=(1, 2), strides=(2, 3))
pool2d(X)
.. parsed-literal::
:class: output
array([[[[ 0., 3.],
[ 8., 11.],
[12., 15.]]]])
.. raw:: html
.. raw:: html
.. raw:: html
Với đầu vào Đa Kênh
-------------------
.. raw:: html
Khi xử lý dữ liệu đầu vào đa kênh, tầng gộp sẽ áp dụng lên từng kênh một
cách riêng biệt thay vì cộng từng phần tử tương ứng của các kênh lại với
nhau như tầng tích chập. Điều này có nghĩa là số lượng kênh đầu ra của
tầng gộp sẽ giống số lượng kênh đầu vào. Dưới đây, chúng ta sẽ ghép 2
mảng ``X`` và ``X+1`` theo chiều kênh để tạo ra đầu vào 2 kênh.
.. code:: python
X = np.concatenate((X, X + 1), axis=1)
X
.. parsed-literal::
:class: output
array([[[[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.]],
[[ 1., 2., 3., 4.],
[ 5., 6., 7., 8.],
[ 9., 10., 11., 12.],
[13., 14., 15., 16.]]]])
.. raw:: html
Có thể thấy, số kênh của đầu ra vẫn là 2 sau khi gộp.
.. code:: python
pool2d = nn.MaxPool2D(3, padding=1, strides=2)
pool2d(X)
.. parsed-literal::
:class: output
array([[[[ 5., 7.],
[13., 15.]],
[[ 6., 8.],
[14., 16.]]]])
.. raw:: html
Tóm tắt
-------
.. raw:: html
- Với các phần tử đầu vào nằm trong cửa sổ gộp, tầng gộp cực đại sẽ cho
đầu ra là giá trị lớn nhất trong số các phần tử đó và tầng gộp trung
bình sẽ cho đầu ra là giá trị trung bình của các phần tử.
- Một trong những chức năng chủ yếu của tầng gộp là giảm thiểu sự ảnh
hưởng quá mức của vị trí tới tầng tích chập.
- Chúng ta có thể chỉ rõ giá trị của đệm và sải bước cho tầng gộp.
- Tầng gộp cực đại kết hợp với sải bước lớn hơn 1 có thể dùng để giảm
độ phân giải.
- Số lượng kênh đầu ra của tầng gộp sẽ bằng số lượng kênh đầu vào tầng
gộp đó.
.. raw:: html
Bài tập
-------
.. raw:: html
1. Có thể lập trình tầng gộp trung bình như một trường hợp đặc biệt của
tầng tích chập không? Nếu được, hãy thực hiện nó.
2. Có thể lập trình tầng gộp cực đại như một trường hợp đặc biệt của
tầng tích chập không? Nếu được, hãy thực hiện nó.
3. Hãy tính chi phí tính toán của tầng gộp trong trường hợp, giả sử đầu
vào của tầng gộp có kích thước :math:`c\times h\times w`, kích thước
của cửa sổ gộp :math:`p_h\times p_w` với đệm :math:`(p_h, p_w)` và
sải bước :math:`(s_h, s_w)`.
4. Tại sao ta mong đợi tầng gộp cực đại và tầng gộp trung bình có những
ảnh hưởng khác nhau?
5. Theo ý kiến của bạn, có cần riêng một tầng gộp cực tiểu không? Có thể
thay thế bằng một cơ chế khác không?
6. Hãy thử suy nghĩ một cơ chế khác nằm giữa gộp trung bình và gộp cực
đại (gợi ý: hãy nhớ lại hàm softmax). Tại sao nó không phổ biến?
.. raw:: html
.. raw:: html
Thảo luận
---------
- `Tiếng Anh `__
- `Tiếng Việt `__
Những người thực hiện
---------------------
Bản dịch trong trang này được thực hiện bởi:
- Đoàn Võ Duy Thanh
- Nguyễn Văn Cường
- Phạm Minh Đức
- Nguyễn Đình Nam
- Lê Khắc Hồng Phúc
- Đinh Đắc
- Phạm Hồng Vinh