.. _sec_deep_rnn:
Mạng thần kinh tái phát sâu
===========================
Cho đến nay, chúng ta chỉ thảo luận về RNNs với một layer ẩn một chiều
duy nhất. Trong đó hình thức chức năng cụ thể của cách các biến và quan
sát tiềm ẩn tương tác là khá tùy ý. Đây không phải là một vấn đề lớn
miễn là chúng ta có đủ linh hoạt để mô hình hóa các loại tương tác khác
nhau. Tuy nhiên, với một lớp duy nhất, điều này có thể khá khó khăn.
Trong trường hợp của các mô hình tuyến tính, chúng tôi đã khắc phục vấn
đề này bằng cách thêm nhiều lớp hơn. Trong RNNs, điều này phức tạp hơn
một chút, vì trước tiên chúng ta cần quyết định cách thức và ở đâu để
thêm tính phi tuyến thêm.
Trên thực tế, chúng ta có thể xếp chồng nhiều lớp RNNlên nhau. Điều này
dẫn đến một cơ chế linh hoạt, do sự kết hợp của một số lớp đơn giản. Đặc
biệt, dữ liệu có thể có liên quan ở các cấp độ khác nhau của ngăn xếp.
Ví dụ: chúng tôi có thể muốn giữ dữ liệu cấp cao về các điều kiện thị
trường tài chính (thị trường gấu hoặc thị trường tăng giá) có sẵn, trong
khi ở mức thấp hơn, chúng tôi chỉ ghi lại động thái thời gian ngắn hạn.
Ngoài tất cả các cuộc thảo luận trừu tượng ở trên, có lẽ dễ dàng nhất để
hiểu được gia đình của các mô hình mà chúng tôi quan tâm bằng cách xem
xét :numref:`fig_deep_rnn`. Nó mô tả một RNN sâu với :math:`L` lớp ẩn.
Mỗi trạng thái ẩn liên tục được truyền cho cả bước thời gian tiếp theo
của lớp hiện tại và bước thời gian hiện tại của lớp tiếp theo.
.. _fig_deep_rnn:
.. figure:: ../img/deep-rnn.svg
Architecture of a deep RNN.
Phụ thuộc chức năng
-------------------
Chúng ta có thể chính thức hóa các phụ thuộc chức năng trong kiến trúc
sâu của :math:`L` các lớp ẩn được mô tả trong :numref:`fig_deep_rnn`.
Cuộc thảo luận sau đây của chúng tôi tập trung chủ yếu vào mô hình
vanilla RNN, nhưng nó cũng áp dụng cho các mô hình trình tự khác.
Giả sử rằng chúng ta có một đầu vào minibatch
:math:`\mathbf{X}_t \in \mathbb{R}^{n \times d}` (số ví dụ: :math:`n`,
số lượng đầu vào trong mỗi ví dụ: :math:`d`) tại bước thời gian
:math:`t`. Đồng thời bước, hãy để trạng thái ẩn của lớp ẩn
:math:`l^\mathrm{th}` (:math:`l=1,\ldots,L`) là
:math:`\mathbf{H}_t^{(l)} \in \mathbb{R}^{n \times h}` (số đơn vị ẩn:
:math:`h`) và biến lớp đầu ra là
:math:`\mathbf{O}_t \in \mathbb{R}^{n \times q}` (số lượng đầu ra:
:math:`q`). Đặt :math:`\mathbf{H}_t^{(0)} = \mathbf{X}_t`, trạng thái ẩn
của lớp ẩn :math:`l^\mathrm{th}` sử dụng hàm kích hoạt :math:`\phi_l`
được thể hiện như sau:
.. math:: \mathbf{H}_t^{(l)} = \phi_l(\mathbf{H}_t^{(l-1)} \mathbf{W}_{xh}^{(l)} + \mathbf{H}_{t-1}^{(l)} \mathbf{W}_{hh}^{(l)} + \mathbf{b}_h^{(l)}),
:label: eq_deep_rnn_H
trong đó trọng lượng
:math:`\mathbf{W}_{xh}^{(l)} \in \mathbb{R}^{h \times h}` và
:math:`\mathbf{W}_{hh}^{(l)} \in \mathbb{R}^{h \times h}`, cùng với sự
thiên vị :math:`\mathbf{b}_h^{(l)} \in \mathbb{R}^{1 \times h}`, là các
thông số mô hình của lớp ẩn :math:`l^\mathrm{th}`.
Cuối cùng, việc tính toán lớp đầu ra chỉ dựa trên trạng thái ẩn của lớp
ẩn cuối cùng :math:`L^\mathrm{th}`:
.. math:: \mathbf{O}_t = \mathbf{H}_t^{(L)} \mathbf{W}_{hq} + \mathbf{b}_q,
trong đó trọng lượng :math:`\mathbf{W}_{hq} \in \mathbb{R}^{h \times q}`
và thiên vị :math:`\mathbf{b}_q \in \mathbb{R}^{1 \times q}` là các
thông số mô hình của lớp đầu ra.
Cũng giống như với MLP, số lượng lớp ẩn :math:`L` và số đơn vị ẩn
:math:`h` là các siêu tham số. Nói cách khác, chúng có thể được điều
chỉnh hoặc chỉ định bởi chúng tôi. Ngoài ra, chúng ta có thể dễ dàng có
được một RNN có cổng sâu bằng cách thay thế tính toán trạng thái ẩn
trong :eq:`eq_deep_rnn_H` với nó từ GRU hoặc LSTM.
Thực hiện ngắn gọn
------------------
May mắn thay, nhiều chi tiết hậu cần cần thiết để triển khai nhiều lớp
của một RNN có sẵn trong các API cấp cao. Để giữ cho mọi thứ đơn giản,
chúng tôi chỉ minh họa việc thực hiện bằng cách sử dụng các chức năng
tích hợp như vậy. Hãy để chúng tôi lấy một mô hình LSTM làm ví dụ. Mã
này rất giống với mã chúng tôi đã sử dụng trước đây trong
:numref:`sec_lstm`. Trên thực tế, sự khác biệt duy nhất là chúng ta
chỉ định số lớp một cách rõ ràng hơn là chọn mặc định của một lớp duy
nhất. Như thường lệ, chúng ta bắt đầu bằng cách tải tập dữ liệu.
.. raw:: html
.. raw:: html
.. code:: python
from mxnet import npx
from mxnet.gluon import rnn
from d2l import mxnet as d2l
npx.set_np()
batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)
.. raw:: html
.. raw:: html
.. code:: python
import torch
from torch import nn
from d2l import torch as d2l
batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)
.. raw:: html
.. raw:: html
.. code:: python
import tensorflow as tf
from d2l import tensorflow as d2l
batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)
.. raw:: html
.. raw:: html
Các quyết định kiến trúc như chọn siêu tham số rất giống với các quyết
định của :numref:`sec_lstm`. Chúng tôi chọn cùng một số đầu vào và đầu
ra như chúng tôi có mã thông báo riêng biệt, tức là ``vocab_size``. Số
lượng đơn vị ẩn vẫn là 256. Sự khác biệt duy nhất là chúng ta bây giờ
chọn một số không tầm thường của các lớp ẩn bằng cách xác định giá trị
của ``num_layers``.
.. raw:: html
.. raw:: html
.. code:: python
vocab_size, num_hiddens, num_layers = len(vocab), 256, 2
device = d2l.try_gpu()
lstm_layer = rnn.LSTM(num_hiddens, num_layers)
model = d2l.RNNModel(lstm_layer, len(vocab))
.. raw:: html
.. raw:: html
.. code:: python
vocab_size, num_hiddens, num_layers = len(vocab), 256, 2
num_inputs = vocab_size
device = d2l.try_gpu()
lstm_layer = nn.LSTM(num_inputs, num_hiddens, num_layers)
model = d2l.RNNModel(lstm_layer, len(vocab))
model = model.to(device)
.. raw:: html
.. raw:: html
.. code:: python
vocab_size, num_hiddens, num_layers = len(vocab), 256, 2
num_inputs = vocab_size
device_name = d2l.try_gpu()._device_name
strategy = tf.distribute.OneDeviceStrategy(device_name)
rnn_cells = [tf.keras.layers.LSTMCell(num_hiddens) for _ in range(num_layers)]
stacked_lstm = tf.keras.layers.StackedRNNCells(rnn_cells)
lstm_layer = tf.keras.layers.RNN(stacked_lstm, time_major=True,
return_sequences=True, return_state=True)
with strategy.scope():
model = d2l.RNNModel(lstm_layer, len(vocab))
.. raw:: html
.. raw:: html
Đào tạo và Dự đoán
------------------
Kể từ bây giờ chúng tôi khởi tạo hai lớp với mô hình LSTM, kiến trúc khá
phức tạp hơn này làm chậm quá trình đào tạo đáng kể.
.. raw:: html
.. raw:: html
.. code:: python
num_epochs, lr = 500, 2
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)
.. parsed-literal::
:class: output
perplexity 1.0, 121050.9 tokens/sec on gpu(0)
time travelleryou can show black is white by argument said filby
travelleryou can show black is white by argument said filby
.. figure:: output_deep-rnn_d70a11_27_1.svg
.. raw:: html
.. raw:: html
.. code:: python
num_epochs, lr = 500, 2
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)
.. parsed-literal::
:class: output
perplexity 1.0, 191605.7 tokens/sec on cuda:0
time travelleryou can show black is white by argument said filby
travelleryou can show black is white by argument said filby
.. figure:: output_deep-rnn_d70a11_30_1.svg
.. raw:: html
.. raw:: html
.. code:: python
num_epochs, lr = 500, 2
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, strategy)
.. parsed-literal::
:class: output
perplexity 1.0, 4589.2 tokens/sec on /GPU:0
time travelleryou can show black is white by argument said filby
travelleryou can show black is white by argument said filby
.. figure:: output_deep-rnn_d70a11_33_1.svg
.. raw:: html
.. raw:: html
Tóm tắt
-------
- Trong RNNsâu, thông tin trạng thái ẩn được chuyển sang bước thời gian
tiếp theo của lớp hiện tại và bước thời gian hiện tại của lớp tiếp
theo.
- Có tồn tại nhiều hương vị khác nhau của RNNsâu, chẳng hạn như LSTMs,
Grus, hoặc RNN vani. Thuận tiện, các mô hình này đều có sẵn như là
một phần của API cấp cao của các khuôn khổ deep learning.
- Khởi tạo các mô hình đòi hỏi sự chăm sóc. Nhìn chung, RNN sâu đòi hỏi
lượng công việc đáng kể (chẳng hạn như tốc độ học tập và cắt) để đảm
bảo sự hội tụ thích hợp.
Bài tập
-------
1. Cố gắng thực hiện RNN hai lớp từ đầu bằng cách sử dụng triển khai lớp
duy nhất mà chúng tôi đã thảo luận trong :numref:`sec_rnn_scratch`.
2. Thay thế LSTM bằng GRU và so sánh độ chính xác và tốc độ đào tạo.
3. Tăng dữ liệu đào tạo để bao gồm nhiều cuốn sách. Làm thế nào thấp bạn
có thể đi trên quy mô bối rối?
4. Bạn có muốn kết hợp các nguồn của các tác giả khác nhau khi mô hình
hóa văn bản? Tại sao đây là một ý tưởng tốt? Điều gì có thể đi sai?
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html