9.3. Mạng Nơ-ron Hồi tiếp Sâu

Cho đến nay, chúng ta mới chỉ thảo luận về các mạng nơ-ron hồi tiếp với duy nhất một tầng ẩn đơn hướng. Trong đó, cách các biến tiềm ẩn và các quan sát tương tác với nhau còn khá khá tuỳ ý. Đây không phải là một vấn đề lớn miễn là ta vẫn có đủ độ linh hoạt để mô hình hóa các loại tương tác khác nhau. Tuy nhiên, đây lại là một thách thức với các mạng đơn tầng. Trong trường hợp của perceptron, chúng ta giải quyết vấn đề này bằng cách đưa thêm nhiều tầng vào mạng. Cách này hơi phức tạp một chút với trường hợp của mạng RNN, vì đầu tiên chúng ta cần phải quyết định thêm tính phi tuyến vào mạng ở đâu và như thế nào. Thảo luận dưới đây tập trung chủ yếu vào LSTM, nhưng cũng có thể áp dụng cho các mô hình chuỗi khác.

  • Chúng ta có thể bổ sung thêm tính phi tuyến vào các cơ chế cổng. Nghĩa là, thay vì sử dụng một tầng perceptron duy nhất, chúng ta có thể sử dụng nhiều tầng perceptron. Cách này không làm thay đổi cơ chế của mạng LSTM, ngược lại, còn làm cho nó tinh xảo hơn. Điều này chỉ có lợi nếu chúng ta tin rằng cơ chế LSTM biểu diễn một hình thái phổ quát nào đó về cách hoạt động của các mô hình tự hồi quy biến tiềm ẩn.
  • Chúng ta có thể chồng nhiều tầng LSTM lên nhau. Cách này tạo ra một cơ chế linh hoạt hơn nhờ vào sự kết hợp giữa các tầng đơn giản. Đặc biệt là, các đặc tính liên quan của dữ liệu có thể được biểu diễn ở các tầng khác nhau. Ví dụ, chúng ta có thể muốn lưu dữ liệu về tình hình thị trường tài chính (thị trường giá lên hay giá xuống) ở tầng cao hơn, trong khi đó chỉ ghi lại động lực thời hạn ngắn hơn ở một tầng thấp hơn.

Ngoài những thứ khá trừu tượng trên, để hiểu được các nhóm mô hình chúng ta đang thảo luận một cách dễ dàng nhất, chúng ta nên xem lại Fig. 9.3.1. Hình trên mô tả một mạng nơ-ron hồi tiếp sâu với \(L\) tầng ẩn. Mỗi trạng thái ẩn liên tục được truyền tới bước thời gian kế tiếp ở tầng hiện tại và tới bước thời gian hiện tại ở tầng kế tiếp.

../_images/deep-rnn.svg

Fig. 9.3.1 Kiến trúc của một mạng nơ-ron hồi tiếp sâu.

9.3.1. Các Phụ thuộc Hàm

Tại bước thời gian \(t\), giả sử rằng chúng ta có một minibatch \(\mathbf{X}_t \in \mathbb{R}^{n \times d}\) (số lượng mẫu: \(n\), số lượng đầu vào: \(d\)). Trạng thái ẩn của tầng ẩn \(\ell\) (\(\ell=1,\ldots, T\)) là \(\mathbf{H}_t^{(\ell)} \in \mathbb{R}^{n \times h}\) (số đơn vị ẩn: \(h\)), biến tầng đầu ra là \(\mathbf{O}_t \in \mathbb{R}^{n \times q}\) (số lượng đầu ra: \(q\)) và một hàm kích hoạt tầng ẩn \(f_l\) cho tầng \(l\) . Chúng ta tính toán trạng thái ẩn của tầng đầu tiên như trước đây, sử dụng đầu vào là \(\mathbf{X}_t\). Đối với tất cả các tầng tiếp theo, trạng thái ẩn của tầng trước được sử dụng thay cho \(\mathbf{X}_t\).

(9.3.1)\[\begin{split}\begin{aligned} \mathbf{H}_t^{(1)} & = f_1\left(\mathbf{X}_t, \mathbf{H}_{t-1}^{(1)}\right), \\ \mathbf{H}_t^{(l)} & = f_l\left(\mathbf{H}_t^{(l-1)}, \mathbf{H}_{t-1}^{(l)}\right). \end{aligned}\end{split}\]

Cuối cùng, tầng đầu ra chỉ dựa trên trạng thái ẩn của tầng ẩn \(L\). Chúng ta sử dụng một hàm đầu ra \(g\) để xử lý trạng thái này:

(9.3.2)\[\mathbf{O}_t = g \left(\mathbf{H}_t^{(L)}\right).\]

Giống như perceptron đa tầng, số tầng ẩn \(L\) và số đơn vị ẩn \(h\) được coi là các siêu tham số. Đặc biệt, chúng ta có thể chọn một trong các kiến trúc RNN, GRU, hoặc LSTM thông thường để xây dựng mô hình.

9.3.2. Lập trình Súc tích

May mắn thay nhiều chi tiết hỗ trợ cần thiết để lập trình một kiến trúc RNN đa tầng đã có sẵn trong Gluon. Để đơn giản, chúng ta chỉ minh họa việc lập trình bằng cách sử dụng những chức năng được tích hợp sẵn. Mã nguồn dưới đây rất giống đoạn mã mà ta sử dụng cho mạng LSTM trước đây. Trong thực tế, sự khác biệt duy nhất là chúng ta chỉ định số lượng các tầng một cách tường minh thay vì chọn mặc định là một tầng duy nhất. Hãy bắt đầu bằng cách nhập các mô-đun thích hợp và nạp dữ liệu.

from d2l import mxnet as d2l
from mxnet import npx
from mxnet.gluon import rnn
npx.set_np()

batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)

Các quyết định liên quan tới kiến ​​trúc mạng (ví dụ như lựa chọn các tham số) rất giống với những phần trước. Chúng ta sử dụng cùng số lượng đầu vào và đầu ra bởi ta có các token không trùng lặp nhau, ở đây là vocab_size. Số lượng nút ẩn vẫn là 256. Sự khác biệt duy nhất là bây giờ chúng ta sẽ chọn một giá trị lớn hơn 1 cho số tầng num_layers = 2.

vocab_size, num_hiddens, num_layers, ctx = len(vocab), 256, 2, d2l.try_gpu()
lstm_layer = rnn.LSTM(num_hiddens, num_layers)
model = d2l.RNNModel(lstm_layer, len(vocab))

9.3.3. Huấn luyện

Quá trình huấn luyện tương tự như trước đây. Sự khác biệt duy nhất là bây giờ chúng ta khởi tạo mô hình với hai tầng LSTM. Quá trình huấn luyện sẽ chậm hơn đáng kể do kiến trúc mô hình phức tạp hơn và số lượng epoch lớn.

num_epochs, lr = 500, 2
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, ctx)
perplexity 1.1, 103346.9 tokens/sec on gpu(0)
time traveller  it s against reason said filby  what reason said
traveller  it s against reason said filby  what reason said
../_images/output_deep-rnn_vn_a01e99_5_1.svg

9.3.4. Tóm tắt

  • Trong các mạng nơ-ron hồi tiếp sâu, thông tin trạng thái ẩn được truyền tới bước thời gian kế tiếp ở tầng hiện tại và truyền tới bước thời gian hiện tại ở tầng kế tiếp.
  • Có nhiều phiên bản khác nhau của mạng RNN sâu, ví dụ như LSTM, GRU hoặc RNN thông thường. Những mô hình này được lập trình sẵn trong mô-đun rnn của Gluon.
  • Chúng ta cần phải cẩn thận trong việc khởi tạo mô hình. Nhìn chung, các mạng RNN sâu thường đòi hỏi khá nhiều công sức (ví dụ như việc chọn tốc độ học hay việc gọt gradient) để đảm bảo quá trình học hội tụ một cách hợp lý.

9.3.5. Bài tập

  1. Hãy lập trình một mạng RNN hai tầng từ đầu sử dụng mã nguồn cho mạng một tầng mà ta đã thảo luận ở Section 8.5.
  2. Hãy thay thế khối LSTM bằng khối GRU và so sánh độ chính xác của mô hình.
  3. Tăng dữ liệu huấn luyện bằng việc thêm nhiều cuốn sách. Bạn có thể giảm perplexity tới mức nào?
  4. Có nên kết hợp nhiều nguồn sách từ các tác giả khác nhau khi mô hình hoá dữ liệu văn bản hay không?. Tại sao việc này lại là một ý tưởng hay? Vấn đề gì có thể xảy ra ở đây?

9.3.6. Thảo luận

9.3.7. 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 Quang
  • Lê Khắc Hồng Phúc
  • Nguyễn Lê Quang Nhật
  • Nguyễn Văn Cường
  • Phạm Hồng Vinh
  • Phạm Minh Đức