.. raw:: html
.. raw:: html
.. raw:: html
.. _sec_plain_rnn:
Mạng nơ-ron Hồi tiếp
====================
.. raw:: html
:numref:`sec_language_model` đã giới thiệu mô hình :math:`n`-gram,
trong đó xác suất có điều kiện của từ :math:`x_t` tại vị trí :math:`t`
chỉ phụ thuộc vào :math:`n-1` từ trước đó. Nếu muốn kiểm tra ảnh hưởng
có thể có của các từ ở trước vị trí :math:`t-(n-1)` đến từ :math:`x_t`,
ta cần phải tăng :math:`n`. Tuy nhiên, cùng với đó số lượng tham số của
mô hình cũng sẽ tăng lên theo hàm mũ, vì ta cần lưu :math:`|V|^n` giá
trị với một từ điển :math:`V` nào đó. Do đó, thay vì mô hình hóa
:math:`p(x_t \mid x_{t-1}, \ldots, x_{t-n+1})`, sẽ tốt hơn nếu ta sử
dụng *mô hình biến tiềm ẩn* (*latent variable model*), trong đó
.. math:: p(x_t \mid x_{t-1}, \ldots, x_1) \approx p(x_t \mid x_{t-1}, h_{t}).
.. raw:: html
:math:`h_t` được gọi là *biến tiềm ẩn* và nó lưu trữ thông tin của
chuỗi. Biến tiềm ẩn còn được gọi là *biến ẩn* (*hidden variable*),
*trạng thái ẩn* (*hidden state*) hay *biến trạng thái ẩn* (*hidden state
variable*). Trạng thái ẩn tại thời điểm :math:`t` có thể được tính dựa
trên cả đầu vào :math:`x_{t}` và trạng thái ẩn :math:`h_{t-1}` như sau
.. math:: h_t = f(x_{t}, h_{t-1}).
.. raw:: html
Với một hàm :math:`f` đủ mạnh, mô hình biến tiềm ẩn không phải là một
phép xấp xỉ. Sau cùng, :math:`h_t` có thể chỉ đơn thuần lưu lại tất cả
dữ liệu đã quan sát được cho đến thời điểm hiện tại. Điều này đã được
thảo luận tại :numref:`sec_sequence`. Tuy nhiên nó có thể khiến cho
việc tính toán và lưu trữ trở nên nặng nề.
.. raw:: html
Chú ý rằng ta cũng sử dụng :math:`h` để kí hiệu số lượng nút ẩn trong
một tầng ẩn. Tầng ẩn và trạng thái ẩn là hai khái niệm rất khác nhau.
Tầng ẩn, như đã được giải thích, là các tầng không thể nhìn thấy trong
quá trình đi từ đầu vào đến đầu ra. Trạng thái ẩn, về mặt kỹ thuật là
*đầu vào* của một bước tính toán tại một thời điểm xác định. Chúng chỉ
có thể được tính dựa vào dữ liệu tại các vòng lặp trước đó. Về điểm này,
trạng thái ẩn giống với các mô hình biến tiềm ẩn trong thống kê như mô
hình phân cụm hoặc mô hình chủ đề (*topic model*), trong đó các cụm tác
động đến đầu ra nhưng không thể quan sát trực tiếp.
.. raw:: html
Mạng nơ-ron hồi tiếp là mạng nơ-ron với các trạng thái ẩn. Trước khi tìm
hiểu mô hình này, hãy cùng xem lại perceptron đa tầng tại
:numref:`sec_mlp`.
.. raw:: html
.. raw:: html
.. raw:: html
Mạng Hồi tiếp không có Trạng thái ẩn
------------------------------------
.. raw:: html
Xét một perception đa tầng với một tầng ẩn duy nhất. Giả sử ta có một
minibatch :math:`\mathbf{X} \in \mathbb{R}^{n \times d}` với :math:`n`
mẫu và :math:`d` đầu vào. Gọi hàm kích hoạt của tầng ẩn là :math:`\phi`.
Khi đó, đầu ra của tầng ẩn
:math:`\mathbf{H} \in \mathbb{R}^{n \times h}` được tính như sau
.. math:: \mathbf{H} = \phi(\mathbf{X} \mathbf{W}_{xh} + \mathbf{b}_h).
:label: rnn_h_without_state
.. raw:: html
Trong đó, :math:`\mathbf{W}_{xh} \in \mathbb{R}^{d \times h}` là tham số
trọng số, :math:`\mathbf{b}_h \in \mathbb{R}^{1 \times h}` là hệ số điều
chỉnh và :math:`h` là số nút ẩn của tầng ẩn.
.. raw:: html
Biến ẩn :math:`\mathbf{H}` được sử dụng làm đầu vào của tầng đầu ra.
Tầng đầu ra được tính toán bởi
.. math:: \mathbf{O} = \mathbf{H} \mathbf{W}_{hq} + \mathbf{b}_q.
.. raw:: html
Trong đó :math:`\mathbf{O} \in \mathbb{R}^{n \times q}` là biến đầu ra,
:math:`\mathbf{W}_{hq} \in \mathbb{R}^{h \times q}` là tham số trọng số
và :math:`\mathbf{b}_q \in \mathbb{R}^{1 \times q}` là hệ số điều chỉnh
của tầng đầu ra. Nếu đang giải quyết bài toán phân loại, ta có thể sử
dụng :math:`\text{softmax}(\mathbf{O})` để tính phân phối xác suất của
các lớp đầu ra.
.. raw:: html
Do bài toán này hoàn toàn tương tự với bài toán hồi quy được giải quyết
trong :numref:`sec_sequence`, ta sẽ bỏ qua các chi tiết ở đây. Và chỉ
cần biết thêm rằng ta có thể chọn các cặp :math:`(x_t, x_{t-1})` một
cách ngẫu nhiên và ước lượng các tham số :math:`\mathbf{W}` và
:math:`\mathbf{b}` của mạng thông qua phép vi phân tự động và hạ
gradient ngẫu nhiên.
.. raw:: html
.. raw:: html
.. raw:: html
.. raw:: html
.. raw:: html
Mạng Hồi tiếp có Trạng thái ẩn
------------------------------
.. raw:: html
Vấn đề sẽ khác đi hoàn toàn nếu ta sử dụng các trạng thái ẩn. Hãy xem
xét cấu trúc này một cách chi tiết hơn. Chúng ta thường gọi vòng lặp thứ
:math:`t` là thời điểm :math:`t` trong thuật toán tối ưu, nhưng trong
mạng nơ-ron hồi tiếp, thời điểm :math:`t` lại tương ứng với các bước
trong một vòng lặp. Giả sử trong một vòng lặp ta có
:math:`\mathbf{X}_t \in \mathbb{R}^{n \times d}`, :math:`t=1,\ldots, T`.
Và :math:`\mathbf{H}_t \in \mathbb{R}^{n \times h}` là biến ẩn tại bước
thời gian :math:`t` của chuỗi. Khác với perceptron đa tầng, ở đây ta lưu
biến ẩn :math:`\mathbf{H}_{t-1}` từ bước thời gian trước đó và dùng thêm
một tham số trọng số mới
:math:`\mathbf{W}_{hh} \in \mathbb{R}^{h \times h}` để mô tả việc sử
dụng biến ẩn của bước thời gian trước đó trong bước thời gian hiện tại.
Cụ thể, biến ẩn của bước thời gian hiện tại được xác định bởi đầu vào
của bước thời gian hiện tại cùng với biến ẩn của bước thời gian trước
đó:
.. math:: \mathbf{H}_t = \phi(\mathbf{X}_t \mathbf{W}_{xh} + \mathbf{H}_{t-1} \mathbf{W}_{hh} + \mathbf{b}_h).
.. raw:: html
So với :eq:`rnn_h_without_state`, phương trình này có thêm
:math:`\mathbf{H}_{t-1} \mathbf{W}_{hh}`. Từ mối quan hệ giữa các biến
ẩn :math:`\mathbf{H}_t` và :math:`\mathbf{H}_{t-1}` của các bước thời
gian liền kề, ta biết rằng chúng đã lưu lại thông tin lịch sử của chuỗi
cho tới bước thời gian hiện tại, giống như trạng thái hay bộ nhớ hiện
thời của mạng nơ-ron. Vì vậy, một biến ẩn còn được gọi là một *trạng
thái ẩn* (*hidden state*). Vì trạng thái ẩn ở bước thời gian hiện tại và
trước đó đều có cùng định nghĩa, phương trình trên được tính toán theo
phương pháp hồi tiếp. Và đây cũng là lý do dẫn đến cái tên mạng nơ-ron
hồi tiếp (*Recurrent Neural Network* - RNN).
.. raw:: html
Có rất nhiều phương pháp xây dựng RNN. Trong số đó, phổ biến nhất là RNN
có trạng thái ẩn như định nghĩa ở phương trình trên. Tại bước thời gian
:math:`t`, tầng đầu ra trả về kết quả tính toán tương tự như trong
perceptron đa tầng:
.. math:: \mathbf{O}_t = \mathbf{H}_t \mathbf{W}_{hq} + \mathbf{b}_q.
.. raw:: html
Các tham số trong mô hình RNN bao gồm trọng số
:math:`\mathbf{W}_{xh} \in \mathbb{R}^{d \times h}, \mathbf{W}_{hh} \in \mathbb{R}^{h \times h}`
của tầng ẩn với hệ số điều chỉnh
:math:`\mathbf{b}_h \in \mathbb{R}^{1 \times h}`, và trọng số
:math:`\mathbf{W}_{hq} \in \mathbb{R}^{h \times q}` của tầng đầu ra với
hệ số điều chỉnh :math:`\mathbf{b}_q \in \mathbb{R}^{1 \times q}`. Lưu ý
rằng RNN luôn sử dùng cùng một bộ tham số mô hình cho dù tính toán ở các
bước thời gian khác nhau. Vì thế, việc tăng số bước thời gian không làm
tăng lượng tham số mô hình của RNN.
.. raw:: html
| :numref:`fig_rnn` minh họa logic tính toán của một RNN tại ba bước
thời gian liền kề. Tại bước thời gian :math:`t`, sau khi nối đầu vào
:math:`\mathbf{X}_t` với trạng thái ẩn :math:`\mathbf{H}_{t-1}` tại
bước thời gian trước đó, ta có thể coi nó như đầu vào của một tầng kết
nối đầy đủ với hàm kích hoạt :math:`\phi`.
| Đầu ra của tầng kết nối đầy đủ chính là trạng thái ẩn ở bước thời gian
hiện tại :math:`\mathbf{H}_t`. Tham số mô hình ở bước thời gian hiện
tại là :math:`\mathbf{W}_{xh}` nối với :math:`\mathbf{W}_{hh}`, cùng
với hệ số điều chỉnh :math:`\mathbf{b}_h`. Trạng thái ẩn ở bước thời
gian hiện tại :math:`t`, :math:`\mathbf{H}_t` được sử dụng để tính
trạng thái ẩn :math:`\mathbf{H}_{t+1}` tại bước thời gian kế tiếp
:math:`t+1`. Hơn nữa, :math:`\mathbf{H}_t` sẽ trở thành đầu vào cho
tầng đầu ra :math:`\mathbf{O}_t`, một tầng kết nối đầy đủ, ở bước thời
gian hiện tại.
.. raw:: html
.. _fig_rnn:
.. figure:: ../img/rnn.svg
Một RNN với một trạng thái ẩn.
.. raw:: html
.. raw:: html
.. raw:: html
Các bước trong một Mô hình Ngôn ngữ
-----------------------------------
.. raw:: html
| Bây giờ hãy cùng xem cách xây dựng mô hình ngôn ngữ bằng RNN. Vì dùng
từ thường dễ hiểu hơn dùng chữ, nên các từ sẽ được dùng làm đầu vào
trong ví dụ đơn giản này.
| Đặt kích thước minibatch là 1, với chuỗi văn bản là phần đầu của tập
dữ liệu: “the time machine by H. G. Wells”. :numref:`fig_rnn_train`
minh họa cách ước lượng từ tiếp theo dựa trên từ hiện tại và các từ
trước đó. Trong quá trình huấn luyện, chúng ta áp dụng softmax cho đầu
ra tại mỗi bước thời gian, sau đó sử dụng hàm mất mát entropy chéo để
tính toán sai số giữa kết quả và nhãn. Do trạng thái ẩn trong tầng ẩn
được tính toán hồi tiếp, đầu ra của bước thời gian thứ 3,
:math:`\mathbf{O}_3`, được xác định bởi chuỗi các từ “the”, “time” và
“machine”. Vì từ tiếp theo của chuỗi trong dữ liệu huấn luyện là “by”,
giá trị mất mát tại bước thời gian thứ 3 sẽ phụ thuộc vào phân phối
xác suất của từ tiếp theo được tạo dựa trên chuỗi đặc trưng “the”,
“time”, “machine” và nhãn “by” tại bước thời gian này.
.. raw:: html
.. _fig_rnn_train:
.. figure:: ../img/rnn-train.svg
Mô hình ngôn ngữ ở mức từ ngữ RNN. Đầu vào và chuỗi nhãn lần lượt là
``the time machine by H.`` và ``time machine by H. G.``
.. raw:: html
Trong thực tế, mỗi từ được biểu diễn bởi một vector :math:`d` chiều và
kích thước batch thường là :math:`n>1`. Do đó, đầu vào
:math:`\mathbf X_t` tại bước thời gian :math:`t` sẽ là ma trận
:math:`n\times d`, giống hệt với những gì chúng ta đã thảo luận trước
đây.
.. raw:: html
.. raw:: html
.. raw:: html
Perplexity
----------
.. raw:: html
Cuối cùng, hãy thảo luận về cách đo lường chất lượng của mô hình chuỗi.
Một cách để làm việc này là kiểm tra mức độ gây ngạc nhiên của văn bản.
Một mô hình ngôn ngữ tốt có thể dự đoán chính xác các token tiếp theo.
Hãy xem xét các cách điền tiếp vào câu “Trời đang mưa” sau, được đề xuất
bởi các mô hình ngôn ngữ khác nhau:
.. raw:: html
1. “Trời đang mưa bên ngoài”
2. “Trời đang mưa cây chuối”
3. “Trời đang mưa piouw;kcj pwepoiut”
.. raw:: html
Về chất lượng, ví dụ 1 rõ ràng là tốt nhất. Các từ được sắp xếp hợp lý
và mạch lạc về mặt logic. Mặc dù nó có thể không phản ánh chính xác hoàn
toàn mặt ngữ nghĩa của các từ theo sau (“ở San Francisco” và “vào mùa
đông” cũng là các phần mở rộng hoàn toàn hợp lý), mô hình vẫn có thể nắm
bắt những từ nghe khá phù hợp. Ví dụ 2 thì tệ hơn đáng kể, mô hình này
đã nối dài câu ra theo cách vô nghĩa. Tuy nhiên, ít nhất mô hình đã viết
đúng chính tả và học được phần nào sự tương quan giữa các từ. Cuối cùng,
ví dụ 3 là một mô hình được huấn luyện kém, không khớp được dữ liệu.
.. raw:: html
.. raw:: html
.. raw:: html
Chúng ta có thể đo lường chất lượng của mô hình bằng cách tính xác suất
:math:`p(w)`, tức độ hợp lý của một chuỗi :math:`w`. Thật không may, đây
là một con số khó để hiểu và so sánh. Xét cho cùng, các chuỗi ngắn có
khả năng xuất hiện cao hơn các chuỗi dài, do đó việc đánh giá mô hình
trên kiệt tác `“Chiến tranh và Hòa
bình” `__ của
Tolstoy chắc chắn sẽ cho kết quả thấp hơn nhiều so với tiểu thuyết
`“Hoàng tử bé” `__ của
Saint-Exupery. Thứ còn thiếu ở đây là một cách tính trung bình qua độ
dài chuỗi.
.. raw:: html
Lý thuyết thông tin rất có ích trong trường hợp này và chúng tôi sẽ giới
thiệu thêm về nó trong :numref:`sec_information_theory`. Nếu chúng ta
muốn nén văn bản, ta có thể yêu cầu ước lượng ký hiệu tiếp theo với bộ
ký hiệu hiện tại. Số lượng bit tối thiểu cần thiết là
:math:`-\log_2 p(x_t \mid x_{t-1}, \ldots, x_1)`. Một mô hình ngôn ngữ
tốt sẽ cho phép chúng ta dự đoán từ tiếp theo một cách khá chính xác và
do đó số bit cần thiết để nén chuỗi là rất thấp. Vì vậy, ta có thể đo
lường mô hình ngôn ngữ bằng số bit trung bình cần sử dụng.
.. math:: \frac{1}{n} \sum_{t=1}^n -\log p(x_t \mid x_{t-1}, \ldots, x_1).
.. raw:: html
Điều này giúp ta so sánh được chất lượng mô hình trên các tài liệu có độ
dài khác nhau. Vì lý do lịch sử, các nhà khoa học xử lý ngôn ngữ tự
nhiên thích sử dụng một đại lượng gọi là *perplexity* (*độ rối rắm, hỗn
độn*) thay vì *bitrate* (*tốc độ bit*). Nói ngắn gọn, nó là luỹ thừa của
biểu thức trên:
.. math:: \mathrm{PPL} := \exp\left(-\frac{1}{n} \sum_{t=1}^n \log p(x_t \mid x_{t-1}, \ldots, x_1)\right).
.. raw:: html
Giá trị này có thể được hiểu rõ nhất như là trung bình điều hòa của số
lựa chọn thực tế mà ta có khi quyết định chọn từ nào là từ tiếp theo.
Lưu ý rằng perplexity khái quát hóa một cách tự nhiên ý tưởng của hàm
mất mát entropy chéo định nghĩa ở phần hồi quy softmax
(:numref:`sec_softmax`). Điều này có nghĩa là khi xét một ký hiệu duy
nhất, perplexity chính là lũy thừa của entropy chéo. Hãy cùng xem xét
một số trường hợp:
.. raw:: html
- Trong trường hợp tốt nhất, mô hình luôn ước tính xác suất của ký hiệu
tiếp theo là :math:`1`. Khi đó perplexity của mô hình là :math:`1`.
- Trong trường hợp xấu nhất, mô hình luôn dự đoán xác suất của nhãn là
0. Khi đó perplexity là vô hạn.
- Tại mức nền, mô hình dự đoán một phân phối đều trên tất cả các token.
Trong trường hợp này, perplexity bằng với kích thước của từ điển
``len(vocab)``.
- Thực chất, nếu chúng ta lưu trữ chuỗi không nén, đây là cách tốt nhất
có thể để mã hóa chúng. Vì vậy, nó cho ta một cận trên mà bất kỳ mô
hình nào cũng phải thỏa mãn.
.. raw:: html
.. raw:: html
.. raw:: html
Tóm tắt
-------
.. raw:: html
- Một mạng sử dụng tính toán hồi tiếp được gọi là mạng nơ-ron hồi tiếp
(RNN).
- Trạng thái ẩn của RNN có thể tổng hợp được thông tin lịch sử của
chuỗi cho tới bước thời gian hiện tại.
- Số lượng tham số của mô hình RNN không tăng khi số lượng bước thời
gian tăng.
- Ta có thể tạo các mô hình ngôn ngữ sử dụng một RNN ở cấp độ ký tự.
.. raw:: html
Bài tập
-------
.. raw:: html
1. Nếu sử dụng RNN để dự đoán ký tự tiếp theo trong chuỗi văn bản thì ta
sẽ cần đầu ra có bao nhiêu chiều?
2. Thử thiết kế một ánh xạ trong đó các trạng thái ẩn của RNN là chính
xác (không chỉ là xấp xỉ). Gợi ý: nếu có một số lượng từ hữu hạn thì
sao?
3. Điều gì xảy ra với gradient nếu ta thực hiện phép lan truyền ngược
qua một chuỗi dài?
4. Một số vấn đề liên quan đến mô hình chuỗi đơn giản được mô tả bên
trên là gì?
.. 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
- Nguyễn Lê Quang Nhật
- Nguyễn Duy Du
- Lê Khắc Hồng Phúc
- Phạm Minh Đức
- Trần Yến Thy
- Phạm Hồng Vinh
- Nguyễn Cảnh Thướng