.. raw:: html
.. raw:: html
.. raw:: html
.. _sec_dropout:
Dropout
=======
.. raw:: html
Vừa xong ở :numref:`sec_weight_decay`, chúng tôi đã giới thiệu cách
tiếp cận điển hình để điều chuẩn các mô hình thống kê bằng cách phạt giá
trị chuẩn :math:`\ell_2` của các trọng số. Theo ngôn ngữ xác suất, ta có
thể giải thích kĩ thuật này bằng cách nói ta đã có một niềm tin từ trước
rằng các trọng số được lấy ngẫu nhiên từ một phân phối Gauss với trung
bình bằng :math:`0`. Hiểu một cách trực quan, ta có thể nói rằng mô hình
được khuyến khích trải rộng giá trị các trọng số ra trên nhiều đặc trưng
thay vì quá phụ thuộc vào một vài những liên kết có khả năng không chính
xác.
.. raw:: html
Bàn lại về Quá khớp
-------------------
.. raw:: html
Khi có nhiều đặc trưng hơn số mẫu, các mô hình tuyến tính sẽ có xu hướng
quá khớp. Tuy nhiên nếu có nhiều mẫu hơn số đặc trưng, nhìn chung ta có
thể tin cậy mô hình tuyến tính sẽ không quá khớp. Thật không may, mô
hình tuyến tính dựa trên tính ổn định này để khái quát hoá lại kèm theo
một cái giá phải trả: Mô hình tuyến tính không màng tới sự tương tác
giữa các đặc trưng, nếu chỉ được áp dụng một cách đơn giản. Mỗi đặc
trưng sẽ được gán một giá trị trọng số hoặc là âm, hoặc là dương mà
không màng tới ngữ cảnh.
.. raw:: html
Trong các tài liệu truyền thống, vấn đề cốt lõi giữa khả năng khái quát
và tính linh hoạt này được gọi là *đánh đổi độ chệch - phương sai*
(*bias-variance tradeoff*). Mô hình tuyến tính có độ chệch cao (vì nó
chỉ có thể biểu diễn một nhóm nhỏ các hàm số) nhưng lại có phương sai
thấp (vì nó cho kết quả khá tương đồng trên nhiều tập dữ liệu được lấy
mẫu ngẫu nhiên).
.. raw:: html
Mạng nơ-ron sâu lại nằm ở thái cực trái ngược trên phổ độ chệch - phương
sai. Khác với mô hình tuyến tính, các mạng nơ-ron không bị giới hạn ở
việc chỉ được xét từng đặc trưng một cách riêng biệt. Chúng có thể học
được sự tương tác giữa các nhóm đặc trưng. Chẳng hạn, chúng có thể suy
ra được rằng nếu từ “Nigeria” và “Western Union” xuất hiện cùng nhau
trong một email thì đó là thư rác, nhưng nếu hai từ đó xuất hiện riêng
biệt thì lại không phải.
.. raw:: html
Ngay cả khi số mẫu nhiều hơn hẳn so với số đặc trưng, mạng nơ-ron sâu
vẫn có thể quá khớp. Năm 2017, một nhóm các nhà nghiên cứu đã minh họa
khả năng linh hoạt tột cùng của mạng nơ-ron bằng cách huấn luyện mạng
nơ-ron sâu trên tập ảnh được gán nhãn ngẫu nhiên. Dù không hề có bất cứ
một khuôn mẫu nào liên kết đầu vào và đầu ra, họ phát hiện rằng mạng
nơ-ron được tối ưu bằng SGD vẫn có thể khớp tất cả nhãn trên tập huấn
luyện một cách hoàn hảo.
.. raw:: html
Hãy cùng xem xét ý nghĩa của điều này. Nếu nhãn được gán ngẫu nhiên từ
một phân phối đều với 10 lớp, sẽ không có bộ phân loại nào có thể có độ
chính xác cao hơn 10% trên tập dữ liệu kiểm tra. Khoảng cách khái quát
là tận 90%. Nếu mô hình của chúng ta có đủ năng lực để quá khớp tới như
vậy, phải như thế nào chúng ta mới có thể trông đợi rằng mô hình sẽ
không quá khớp? Nền tảng toán học đằng sau tính chất khái quát hoá hóc
búa của mạng nơ-ron sâu vẫn còn là một câu hỏi mở và chúng tôi khuyến
khích bạn đọc chú trọng lý thuyết đào sâu hơn vào chủ đề này. Còn bây
giờ, hãy quay về bề mặt của vấn đề và chuyển sang tìm hiểu các công cụ
dựa trên thực nghiệm để cải thiện khả năng khái quát của các mạng nơ-ron
sâu.
.. raw:: html
.. raw:: html
.. raw:: html
.. raw:: html
.. raw:: html
Khả năng Kháng Nhiễu
--------------------
.. raw:: html
Hãy cùng nghĩ một chút về thứ mà ta mong đợi từ một mô hình dự đoán tốt.
Ta muốn mô hình hoạt động tốt khi gặp dữ liệu mà nó chưa từng thấy. Lý
thuyết khái quát cổ điển cho rằng: để thu hẹp khoảng cách giữa chất
lượng khi huấn luyện và chất lượng khi kiểm tra, ta nên hướng tới một mô
hình *đơn giản*. Sự đơn giản này có thể nằm ở việc đặc trưng có số chiều
thấp, điều mà chúng ta đã nghiên cứu khi thảo luận về hàm cơ sở đơn thức
trong mô hình tuyến tính ở :numref:`sec_model_selection`. Như ta đã
thấy khi bàn về suy giảm trọng số (điều chuẩn :math:`\ell_2`) ở
:numref:`sec_weight_decay`, chuẩn (nghịch đảo) của các tham số là một
phép đo khác cho sự đơn giản. Một khái niệm hữu ích khác để biểu diễn sự
đơn giản là độ mượt, tức hàm số không nên quá nhạy với những thay đổi
nhỏ ở đầu vào. Ví dụ, khi phân loại ảnh, ta mong muốn rằng việc thêm một
chút nhiễu ngẫu nhiên vào các điểm ảnh sẽ không ảnh hưởng nhiều tới kết
quả dự đoán.
.. raw:: html
Vào năm 1995, Christopher Bishop đã chính quy hóa ý tưởng này khi ông
chứng minh rằng việc huấn luyện với đầu vào chứa nhiễu tương đương với
điều chuẩn Tikhonov :cite:`Bishop.1995`. Công trình này đã chỉ rõ mối
liên kết toán học giữa điều kiện hàm là mượt (nên nó cũng đơn giản) với
khả năng kháng nhiễu đầu vào của hàm số.
.. raw:: html
Và rồi vào năm 2014, Srivastava et al.
:cite:`Srivastava.Hinton.Krizhevsky.ea.2014` đã phát triển một ý tưởng
thông minh để áp dụng ý tưởng trên của Bishop cho các tầng *nội bộ* của
mạng nơ-ron. Cụ thể, họ đề xuất việc thêm nhiễu vào mỗi tầng của mạng
trước khi tính toán các tầng kế tiếp trong quá trình huấn luyện. Họ nhận
ra rằng khi huấn luyện mạng đa tầng, thêm nhiễu vào dữ liệu chỉ ép buộc
điều kiện mượt lên phép ánh xạ giữa đầu vào và đầu ra.
.. raw:: html
Ý tưởng này, có tên gọi là *dropout*, hoạt động bằng cách thêm nhiễu khi
tính toán các tầng nội bộ trong lượt truyền xuôi và nó đã trở thành một
kỹ thuật tiêu chuẩn để huấn luyện các mạng nơ-ron. Phương pháp này có
tên gọi như vậy là bởi ta *loại bỏ* (*drop out*) một số nơ-ron trong quá
trình huấn luyện. Tại mỗi vòng lặp huấn luyện, phương pháp dropout tiêu
chuẩn sẽ đặt giá trị của một lượng nhất định (thường là 50%) các nút
trong mỗi tầng về không, trước khi tính toán các tầng kế tiếp.
.. raw:: html
Để nói cho rõ, mối liên kết đến Bishop là của chúng tôi tự đặt ra. Đáng
ngạc nhiên, bài báo gốc về dropout xây dựng cách hiểu trực giác bằng
việc so sánh nó với quá trình sinh sản hữu tính. Các tác giả cho rằng
hiện tượng quá khớp mạng nơ-ron là biểu hiện của việc mỗi tầng đều dựa
vào một khuôn mẫu nhất định của các giá trị kích hoạt ở tầng trước đó,
họ gọi trạng thái này là *đồng thích nghi*. Họ khẳng định rằng dropout
phá bỏ sự đồng thích nghi này, tương tự như luận điểm sinh sản hữu tính
phá bỏ các gen đã đồng thích nghi.
.. raw:: html
Thách thức chính bây giờ là *làm thế nào* để thêm nhiễu. Một cách để làm
điều này là thêm nhiễu một cách *không thiên lệch* sao cho giá trị kỳ
vọng của mỗi tầng bằng giá trị kỳ vọng của chính tầng đó trước khi được
thêm nhiễu, giả sử rằng các tầng khác được giữ nguyên.
.. raw:: html
.. raw:: html
.. raw:: html
Trong nghiên cứu của Bishop, ông thêm nhiễu Gauss cho đầu vào của một mô
hình tuyến tính như sau: Tại mỗi bước huấn luyện, ông đã thêm nhiễu lấy
từ một phân phối có trung bình bằng không
:math:`\epsilon \sim \mathcal{N}(0,\sigma^2)` cho đầu vào
:math:`\mathbf{x}`, thu được một điểm bị nhiễu
:math:`\mathbf{x}' = \mathbf{x} + \epsilon` với kỳ vọng
:math:`E[\mathbf{x}'] = \mathbf{x}`.
.. raw:: html
Với điều chuẩn dropout tiêu chuẩn, ta khử độ chệch tại mỗi tầng bằng
cách chuẩn hóa theo tỉ lệ các nút được giữ lại (chứ không phải các nút
bị loại bỏ). Nói cách khác, dropout với *xác suất dropout* :math:`p`
được áp dụng như sau:
.. math::
\begin{aligned}
h' =
\begin{cases}
0 & \text{ với~xác~suất } p \\
\frac{h}{1-p} & \text{ khác }
\end{cases}
\end{aligned}
.. raw:: html
Như ta mong muốn, kỳ vọng không bị thay đổi, hay nói cách khác
:math:`E[h'] = h`. Đầu ra của các hàm kích hoạt trung gian :math:`h`
được thay thế bởi một biến ngẫu nhiên :math:`h'` với kỳ vọng tương ứng.
.. raw:: html
.. raw:: html
.. raw:: html
Dropout trong Thực tiễn
-----------------------
.. raw:: html
Nhắc lại về mạng perceptron đa tầng (:numref:`sec_mlp`) với duy nhất
một tầng ẩn có 5 nút ẩn. Kiến trúc mạng được biểu diễn như sau
.. math::
\begin{aligned}
\mathbf{h} & = \sigma(\mathbf{W}_1 \mathbf{x} + \mathbf{b}_1), \\
\mathbf{o} & = \mathbf{W}_2 \mathbf{h} + \mathbf{b}_2, \\
\hat{\mathbf{y}} & = \mathrm{softmax}(\mathbf{o}).
\end{aligned}
.. raw:: html
Khi chúng ta áp dụng dropout cho một tầng ẩn, tức gán mỗi nút ẩn bằng
không với xác suất là :math:`p`, kết quả có thể được xem như là một mạng
chỉ chứa một tập con của các nơ-ron ban đầu. Trong
:numref:`fig_dropout2`, :math:`h_2` và :math:`h_5` bị loại bỏ. Hệ quả
là, việc tính toán :math:`y` không còn phụ thuộc vào :math:`h_2` và
:math:`h_5` nữa và gradient tương ứng của chúng cũng biến mất khi thực
hiện lan truyền ngược. Theo cách này, việc tính toán tầng đầu ra không
thể quá phụ thuộc vào bất kỳ một thành phần nào trong
:math:`h_1, \ldots, h_5`.
.. raw:: html
.. _fig_dropout2:
.. figure:: ../img/dropout2.svg
MLP trước và sau khi dropout
.. raw:: html
Thông thường, **chúng ta sẽ vô hiệu hóa dropout tại thời điểm kiểm
tra**. Với một mô hình đã huấn luyện và một mẫu kiểm tra, ta sẽ không
thực hiện loại bỏ bất kỳ nút nào (do đó cũng không cần chuẩn hóa). Tuy
nhiên cũng có một vài ngoại lệ. Một vài nhà nghiên cứu sử dụng dropout
tại thời điểm kiểm tra như một thủ thuật đề ước lượng *độ bất định*
trong dự đoán của mạng nơ-ron: nếu các dự đoán giống nhau với nhiều mặt
nạ dropout khác nhau, ta có thể nói rằng mạng đó đáng tin cậy hơn. Hiện
tại, ta sẽ để dành phần ước lượng độ bất định này cho các chương sau.
.. raw:: html
.. raw:: html
.. raw:: html
Lập trình từ đầu
----------------
.. raw:: html
Để lập trình hàm dropout cho một tầng đơn, ta sẽ lấy mẫu từ một biến
ngẫu nhiên Bernoulli (nhị phân) với số lượng bằng với số chiều của tầng,
trong đó biến ngẫu nhiên đạt giá trị :math:`1` (giữ) với xác suất bằng
:math:`1-p` và giá trị :math:`0` (bỏ) với xác suất bằng :math:`p`. Một
cách đơn giản để thực hiện việc này là lấy mẫu từ một phân phối đều
:math:`U[0, 1]`, sau đó ta có thể giữ các nút có mẫu tương ứng lớn hơn
:math:`p` và bỏ đi những nút còn lại.
.. raw:: html
Trong đoạn mã nguồn bên dưới, ta lập trình hàm ``dropout_layer`` có chức
năng bỏ đi các phần tử trong mảng ``ndarray`` đầu vào ``X`` với xác suất
``dropout``, rồi chia các phần tử còn lại cho ``1.0-dropout`` như đã mô
tả bên trên.
.. code:: python
from d2l import mxnet as d2l
from mxnet import autograd, gluon, init, np, npx
from mxnet.gluon import nn
npx.set_np()
def dropout_layer(X, dropout):
assert 0 <= dropout <= 1
# In this case, all elements are dropped out
if dropout == 1:
return np.zeros_like(X)
# In this case, all elements are kept
if dropout == 0:
return X
mask = np.random.uniform(0, 1, X.shape) > dropout
return mask.astype(np.float32) * X / (1.0-dropout)
.. raw:: html
Ta có thể thử nghiệm hàm ``dropout_layer`` với một vài mẫu. Trong đoạn
mã nguồn dưới đây, đầu vào ``X`` được truyền qua bước dropout với xác
suất lần lượt là 0, 0.5 và 1.
.. code:: python
X = np.arange(16).reshape(2, 8)
print(dropout_layer(X, 0))
print(dropout_layer(X, 0.5))
print(dropout_layer(X, 1))
.. parsed-literal::
:class: output
[[ 0. 1. 2. 3. 4. 5. 6. 7.]
[ 8. 9. 10. 11. 12. 13. 14. 15.]]
[[ 0. 2. 4. 6. 8. 10. 12. 14.]
[ 0. 18. 20. 0. 0. 0. 28. 0.]]
[[0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0.]]
.. raw:: html
.. raw:: html
.. raw:: html
Định nghĩa các Tham số Mô hình
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. raw:: html
Một lần nữa, ta sẽ làm việc với bộ dữ liệu Fashion-MNIST được giới thiệu
ở :numref:`sec_softmax_scratch`. Ta sẽ tạo một perception đa tầng với
hai tầng ẩn, mỗi tầng gồm 256 đầu ra.
.. code:: python
num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 784, 10, 256, 256
W1 = np.random.normal(scale=0.01, size=(num_inputs, num_hiddens1))
b1 = np.zeros(num_hiddens1)
W2 = np.random.normal(scale=0.01, size=(num_hiddens1, num_hiddens2))
b2 = np.zeros(num_hiddens2)
W3 = np.random.normal(scale=0.01, size=(num_hiddens2, num_outputs))
b3 = np.zeros(num_outputs)
params = [W1, b1, W2, b2, W3, b3]
for param in params:
param.attach_grad()
.. raw:: html
.. raw:: html
.. raw:: html
Định nghĩa Mô hình
~~~~~~~~~~~~~~~~~~
.. raw:: html
Mô hình dưới đây áp dụng dropout cho đầu ra của mỗi tầng ẩn (theo sau
hàm kích hoạt). Ta có thể đặt các giá trị xác suất dropout riêng biệt
cho mỗi tầng. Một xu hướng chung là đặt xác suất dropout thấp hơn cho
tầng ở gần với tầng đầu vào hơn. Bên dưới ta đặt xác suất dropout bằng
0.2 và 0.5 tương ứng cho tầng ẩn thứ nhất và thứ hai. Bằng cách sử dụng
hàm ``is_training`` mô tả ở :numref:`sec_autograd`, ta có thể chắc
chắn rằng dropout chỉ được kích hoạt trong quá trình huấn luyện.
.. code:: python
dropout1, dropout2 = 0.2, 0.5
def net(X):
X = X.reshape(-1, num_inputs)
H1 = npx.relu(np.dot(X, W1) + b1)
# Use dropout only when training the model
if autograd.is_training():
# Add a dropout layer after the first fully connected layer
H1 = dropout_layer(H1, dropout1)
H2 = npx.relu(np.dot(H1, W2) + b2)
if autograd.is_training():
# Add a dropout layer after the second fully connected layer
H2 = dropout_layer(H2, dropout2)
return np.dot(H2, W3) + b3
.. raw:: html
Huấn luyện và Kiểm tra
~~~~~~~~~~~~~~~~~~~~~~
.. raw:: html
Việc này tương tự với quá trình huấn luyện và kiểm tra của các
perceptron đa tầng trước đây.
.. code:: python
num_epochs, lr, batch_size = 10, 0.5, 256
loss = gluon.loss.SoftmaxCrossEntropyLoss()
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs,
lambda batch_size: d2l.sgd(params, lr, batch_size))
.. figure:: output_dropout_vn_54f65a_9_0.svg
.. raw:: html
.. raw:: html
.. raw:: html
Cách lập trình súc tích
-----------------------
.. raw:: html
Bằng việc sử dụng Gluon, tất cả những gì ta cần làm là thêm một tầng
``Dropout`` (cũng nằm trong gói ``nn``) vào sau mỗi tầng kết nối đầy đủ
và truyền vào xác suất dropout, đối số duy nhất của hàm khởi tạo. Trong
quá trình huấn luyện, hàm ``Dropout`` sẽ bỏ ngẫu nhiên một số đầu ra của
tầng trước (hay tương đương với đầu vào của tầng tiếp theo) dựa trên xác
suất dropout được định nghĩa trước đó.
.. code:: python
net = nn.Sequential()
net.add(nn.Dense(256, activation="relu"),
# Add a dropout layer after the first fully connected layer
nn.Dropout(dropout1),
nn.Dense(256, activation="relu"),
# Add a dropout layer after the second fully connected layer
nn.Dropout(dropout2),
nn.Dense(10))
net.initialize(init.Normal(sigma=0.01))
.. raw:: html
Tiếp theo, ta huấn luyện và kiểm tra mô hình.
.. code:: python
trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': lr})
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
.. figure:: output_dropout_vn_54f65a_13_0.svg
.. raw:: html
.. raw:: html
.. raw:: html
Tóm tắt
-------
.. raw:: html
- Ngoài phương pháp kiểm soát số chiều và độ lớn của vector trọng số,
dropout cũng là một công cụ khác để tránh tình trạng quá khớp. Thông
thường thì cả ba cách được sử dụng cùng nhau.
- Dropout thay thế giá trị kích hoạt :math:`h` bằng một biến ngẫu nhiên
:math:`h'` với giá trị kỳ vọng :math:`h` và phương sai bằng xác suất
dropout :math:`p`.
- Dropout chỉ được sử dụng trong quá trình huấn luyện.
.. raw:: html
Bài tập
-------
.. raw:: html
1. Điều gì xảy ra nếu bạn thay đổi xác suất dropout của tầng 1 và 2? Cụ
thể, điều gì xảy ra nếu bạn tráo đổi xác suất của hai tầng này? Thiết
kế một thí nghiệm để trả lời những câu hỏi này, mô tả các kết quả một
cách định lượng và tóm tắt các bài học rút ra một cách định tính.
2. Tăng số lượng epoch và so sánh các kết quả thu được khi sử dụng và
khi không sử dụng dropout.
3. Tính toán phương sai của các giá trị kích hoạt ở mỗi tầng ẩn khi sử
dụng và khi không sử dụng dropout. Vẽ biểu đồ thể hiện sự thay đổi
của giá trị phương sai này theo thời gian cho cả hai mô hình.
4. Tại sao dropout thường không được sử dụng tại bước kiểm tra?
5. Sử dụng mô hình trong phần này làm ví dụ, so sánh hiệu quả của việc
sử dụng dropout và suy giảm trọng số. Điều gì xảy ra khi dropout và
suy giảm trọng số được sử dụng cùng một lúc? Hai phương pháp này bổ
trợ cho nhau, làm giảm hiệu quả của nhau hay (tệ hơn) loại trừ lẫn
nhau?
6. Điều gì xảy ra nếu chúng ta áp dụng dropout cho các trọng số riêng lẻ
của ma trận trọng số thay vì các giá trị kích hoạt?
7. Hãy phát minh một kỹ thuật khác với kỹ thuật dropout tiêu chuẩn để
thêm nhiễu ngẫu nhiên ở mỗi tầng. Bạn có thể phát triển một phương
pháp cho kết quả tốt hơn dropout trên bộ dữ liệu FashionMNIST không
(với cùng một kiến trúc)?
.. raw:: html
.. 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
- Lê Khắc Hồng Phúc
- Phạm Minh Đức
- Nguyễn Văn Tâm
- Phạm Hồng Vinh
- Nguyễn Duy Du
- Vũ Hữu Tiệp