.. raw:: html
.. raw:: html
.. raw:: html
.. _sec_softmax_gluon:
Cách lập trình súc tích Hồi quy Softmax
=======================================
.. raw:: html
Giống như cách Gluon giúp việc lập trình hồi quy tuyến tính ở
:numref:`sec_linear_gluon` trở nên dễ dàng hơn, ta sẽ thấy nó cũng
mang đến sự tiện lợi tương tự (hoặc có thể hơn) khi lập trình các mô
hình phân loại. Một lần nữa, chúng ta bắt đầu bằng việc nhập các gói thư
viện.
.. code:: python
from d2l import mxnet as d2l
from mxnet import gluon, init, npx
from mxnet.gluon import nn
npx.set_np()
.. raw:: html
Chúng ta sẽ tiếp tục làm việc với bộ dữ liệu Fashion-MNIST và giữ kích
thước batch bằng :math:`256` như ở mục trước.
.. code:: python
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
.. raw:: html
Khởi tạo Tham số Mô hình
------------------------
.. raw:: html
Như đã đề cập trong :numref:`sec_softmax`, tầng đầu ra của hồi quy
softmax là một tầng kết nối đầy đủ (``Dense``). Do đó, để xây dựng mô
hình, ta chỉ cần thêm một tầng ``Dense`` với 10 đầu ra vào đối tượng
``Sequential``. Việc sử dụng ``Sequential`` ở đây không thực sự cần
thiết, nhưng ta nên hình thành thói quen này vì nó sẽ luôn hiện diện khi
ta xây dựng các mô hình sâu. Một lần nữa, chúng ta khởi tạo các trọng số
một cách ngẫu nhiên với trung bình bằng không và độ lệch chuẩn bằng
:math:`0.01`.
.. code:: python
net = nn.Sequential()
net.add(nn.Dense(10))
net.initialize(init.Normal(sigma=0.01))
.. raw:: html
.. raw:: html
.. raw:: html
Hàm Softmax
-----------
.. raw:: html
Ở ví dụ trước, ta đã tính toán kết quả đầu ra của mô hình và sau đó đưa
các kết quả này vào hàm mất mát entropy chéo. Về mặt toán học, cách làm
này hoàn toàn có lý. Tuy nhiên, từ góc độ điện toán, sử dụng hàm mũ có
thể là nguồn gốc của các vấn đề về ổn định số học (được bàn trong
:numref:`sec_naive_bayes`). Hãy nhớ rằng, hàm softmax tính
:math:`\hat y_j = \frac{e^{z_j}}{\sum_{i=1}^{n} e^{z_i}}`, trong đó
:math:`\hat y_j` là phần tử thứ :math:`j^\mathrm{th}` của ``yhat`` và
:math:`z_j` là phần tử thứ :math:`j^\mathrm{th}` của biến đầu vào
``y_linear``.
.. raw:: html
Nếu một phần tử :math:`z_i` quá lớn, :math:`e^{z_i}` có thể sẽ lớn hơn
giá trị cực đại mà kiểu ``float`` có thể biểu diễn được (đây là hiện
tượng tràn số trên). Lúc này mẫu số hoặc tử số (hoặc cả hai) sẽ tiến tới
``inf`` và ta gặp phải trường hợp :math:`\hat y_i` bằng :math:`0`,
``inf`` hoặc ``nan``. Trong những tình huống này, giá trị trả về của
``cross_entropy`` có thể không được xác định một cách rõ ràng. Một mẹo
để khắc phục việc này là: đầu tiên ta trừ tất cả các :math:`z_i` đi
:math:`\text{max}(z_i)`, sau đó mới đưa chúng vào hàm ``softmax``. Bạn
có thể nhận thấy rằng việc tịnh tiến mỗi :math:`z_i` theo một hệ số
không đổi sẽ không làm ảnh hưởng đến giá trị trả về của hàm ``softmax``.
.. raw:: html
Sau khi thực hiện bước trừ và chuẩn hóa, một vài :math:`z_j` có thể có
giá trị âm lớn và do đó :math:`e^{z_j}` sẽ xấp xỉ 0. Điều này có thể dẫn
đến việc chúng bị làm tròn thành 0 do khả năng biễu diễn chính xác là
hữu hạn (tức tràn số dưới), khiến :math:`\hat y_j` tiến về không và giá
trị :math:`\text{log}(\hat y_j)` tiến về ``-inf``. Thực hiện vài bước
lan truyền ngược với lỗi trên, ta có thể sẽ đối mặt với một loạt giá trị
``nan`` (*not-a-number*: *không phải số*) đáng sợ.
.. raw:: html
May mắn thay, mặc dù ta đang thực hiện tính toán với các hàm mũ, kết quả
cuối cùng ta muốn là giá trị log của nó (khi tính hàm mất mát entropy
chéo). Bằng cách kết hợp cả hai hàm (``softmax`` và ``cross-entropy``)
lại với nhau, ta có thể khắc phục vấn đề về ổn định số học và tránh gặp
khó khăn trong quá trình lan truyền ngược. Trong phương trình bên dưới,
ta đã không tính :math:`e^{z_j}` mà thay vào đó, ta tính trực tiếp
:math:`z_j` do việc rút gọn :math:`\log(\exp(\cdot))`.
.. math::
\begin{aligned}
\log{(\hat y_j)} & = \log\left( \frac{e^{z_j}}{\sum_{i=1}^{n} e^{z_i}}\right) \\
& = \log{(e^{z_j})}-\text{log}{\left( \sum_{i=1}^{n} e^{z_i} \right)} \\
& = z_j -\log{\left( \sum_{i=1}^{n} e^{z_i} \right)}.
\end{aligned}
.. raw:: html
Ta vẫn muốn giữ lại hàm softmax gốc để sử dụng khi muốn tính đầu ra của
mô hình dưới dạng xác suất. Nhưng thay vì truyền xác suất softmax vào
hàm mất mát mới, ta sẽ chỉ truyền các giá trị logit (các giá trị khi
chưa qua softmax) và tính softmax cùng log của nó trong hàm mất mát
``softmax_cross_entropy``. Hàm này cũng sẽ tự động thực hiện các mẹo
thông minh như log-sum-exp (`xem thêm
Wikipedia `__).
.. code:: python
loss = gluon.loss.SoftmaxCrossEntropyLoss()
.. raw:: html
.. raw:: html
.. raw:: html
.. raw:: html
.. raw:: html
Thuật toán Tối ưu
-----------------
.. raw:: html
Ở đây, chúng ta sử dụng thuật toán tối ưu hạ gradient ngẫu nhiên theo
minibatch với tốc độ học bằng :math:`0.1`. Lưu ý rằng cách làm này giống
hệt cách làm ở ví dụ về hồi quy tuyến tính, minh chứng cho tính khái
quát của bộ tối ưu hạ gradient ngẫu nhiên.
.. code:: python
trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': 0.1})
.. raw:: html
Huấn luyện
----------
.. raw:: html
Tiếp theo, chúng ta sẽ gọi hàm huấn luyện đã được khai báo ở mục trước
để huấn luyện mô hình.
.. code:: python
num_epochs = 10
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
.. figure:: output_softmax-regression-gluon_vn_91b0d4_11_0.svg
.. raw:: html
Giống lần trước, thuật toán hội tụ tới một mô hình có độ chính xác 83.7%
nhưng chỉ khác là cần ít dòng lệnh hơn. Lưu ý rằng trong nhiều trường
hợp, Gluon không chỉ dùng các mánh phổ biến mà còn sử dụng các kỹ thuật
khác để tránh các lỗi kĩ thuật tính toán mà ta dễ gặp phải nếu tự lập
trình mô hình từ đầu.
.. raw:: html
Bài tập
-------
.. raw:: html
1. Thử thay đổi các siêu tham số như kích thước batch, số epoch và tốc
độ học. Theo dõi kết quả sau khi thay đổi.
2. Tại sao độ chính xác trên tập kiểm tra lại giảm sau một khoảng thời
gian? Chúng ta giải quyết việc này thế nào?
.. raw:: html
.. raw:: html
.. raw:: html
Thảo luận
---------
- `Tiếng Anh `__
- `Tiếng Việt `__
.. raw:: html
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 Duy Du
- Vũ Hữu Tiệp
- Lê Khắc Hồng Phúc
- Lý Phi Long
- Phạm Minh Đức
- Dương Nhật Tân
- Nguyễn Văn Tâm
- Phạm Hồng Vinh