10.2. Chuỗi sang Chuỗi áp dụng Cơ chế Tập trung

Trong phần này, chúng ta thêm cơ chế tập trung vào mô hình chuỗi sang chuỗi (seq2seq) giới thiệu trong Section 9.7 để gộp các trạng thái theo trọng số tương ứng một cách tường minh. Fig. 10.2.1 mô tả kiến trúc mô hình thực hiện mã hóa và giải mã tại bước thời gian \(t\). Bộ nhớ của tầng tập trung ở đây bao gồm tất cả thông tin mà bộ mã hóa đã được học—đầu ra của bộ mã hóa tại từng bước thời gian. Trong quá trình giải mã, đầu ra của bộ giải mã tại bước thời gian trước đó \(t-1\) được sử dụng làm câu truy vấn. Đầu ra của mô hình tập trung có thể được hiểu là thông tin ngữ cảnh của chuỗi, phần ngữ cảnh này được ghép nối với đầu vào của bộ giải mã \(D_t\) và kết quả được đưa vào bộ giải mã.

../_images/seq2seq_attention.svg

Fig. 10.2.1 Quá trình giải mã tại bước thời gian thứ 2 trong mô hình chuỗi sang chuỗi áp dụng cơ chế tập trung.

Để minh họa kiến trúc tổng thể của mô hình seq2seq áp dụng cơ chế tập trung, cấu trúc tầng của bộ mã hóa và bộ giải mã được mô tả trong Fig. 10.2.2.

../_images/seq2seq-attention-details.svg

Fig. 10.2.2 Các tầng trong mô hình chuỗi sang chuỗi áp dụng cơ chế tập trung.

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

10.2.1. Bộ Giải mã

Do bộ mã hóa của mô hình seq2seq áp dụng cơ chế tập trung giống với bộ mã hóa của Seq2SeqEncoder trong Section 9.7 nên ở phần này, chúng ta sẽ chỉ tập trung vào bộ giải mã. Ta thêm tầng tập trung MLP (MLPAttention) có cùng kích thước ẩn với tầng LSTM trong bộ giải mã. Sau đó ta khởi tạo trạng thái của bộ giải mã bằng cách truyền vào ba đầu ra thu được từ bộ mã hóa:

  • Đầu ra của bộ mã hóa tại tất cả các bước thời gian: được sử dụng như bộ nhớ của tầng tập trung có cùng các khóa và giá trị;
  • Trạng thái ẩn của bộ mã hóa tại bước thời gian cuối cùng: được sử dụng làm trạng thái ẩn ban đầu của bộ giải mã;
  • Độ dài hợp lệ của bộ mã hóa: để tầng tập trung có thể bỏ qua những token đệm có trong đầu ra của bộ mã hóa.

Ở mỗi bước thời gian trong quá trình giải mã, ta sử dụng trạng thái ẩn của tầng RNN cuối cùng làm câu truy vấn cho tầng tập trung. Đầu ra của mô hình tập trung sau đó được ghép nối với vector embedding đầu vào để đưa vào tầng RNN. Mặc dù trạng thái ẩn của tầng RNN cũng chứa thông tin từ bộ giải mã ở các bước thời gian trước đó nhưng đầu ra của tầng tập trung sẽ lựa chọn các đầu ra của bộ mã hóa một cách tường minh dựa vào enc_valid_lennhằm loại bỏ những thông tin không liên quan.

Hãy cùng lập trình bộ giải mã Seq2SeqAttentionDecoder và xem xét sự khác biệt của nó so với bộ giải mã trong mô hình seq2seq ở Section 9.7.2.

class Seq2SeqAttentionDecoder(d2l.Decoder):
    def __init__(self, vocab_size, embed_size, num_hiddens, num_layers,
                 dropout=0, **kwargs):
        super(Seq2SeqAttentionDecoder, self).__init__(**kwargs)
        self.attention_cell = d2l.MLPAttention(num_hiddens, dropout)
        self.embedding = nn.Embedding(vocab_size, embed_size)
        self.rnn = rnn.LSTM(num_hiddens, num_layers, dropout=dropout)
        self.dense = nn.Dense(vocab_size, flatten=False)

    def init_state(self, enc_outputs, enc_valid_len, *args):
        outputs, hidden_state = enc_outputs
        # Transpose outputs to (batch_size, seq_len, num_hiddens)
        return (outputs.swapaxes(0, 1), hidden_state, enc_valid_len)

    def forward(self, X, state):
        enc_outputs, hidden_state, enc_valid_len = state
        X = self.embedding(X).swapaxes(0, 1)
        outputs = []
        for x in X:
            # query shape: (batch_size, 1, num_hiddens)
            query = np.expand_dims(hidden_state[0][-1], axis=1)
            # context has same shape as query
            context = self.attention_cell(
                query, enc_outputs, enc_outputs, enc_valid_len)
            # Concatenate on the feature dimension
            x = np.concatenate((context, np.expand_dims(x, axis=1)), axis=-1)
            # Reshape x to (1, batch_size, embed_size + num_hiddens)
            out, hidden_state = self.rnn(x.swapaxes(0, 1), hidden_state)
            outputs.append(out)
        outputs = self.dense(np.concatenate(outputs, axis=0))
        return outputs.swapaxes(0, 1), [enc_outputs, hidden_state,
                                        enc_valid_len]

Giờ ta có thể chạy thử mô hình seq2seq áp dụng cơ chế tập trung. Để nhất quán khi so sánh với mô hình không áp dụng cơ chế tập trung trong Section 9.7, những siêu tham số vocab_size, embed_size, num_hiddens, và num_layers sẽ được giữ nguyên. Kết quả, ta thu được đầu ra của bộ giải mã có cùng kích thước nhưng khác về cấu trúc trạng thái.

encoder = d2l.Seq2SeqEncoder(vocab_size=10, embed_size=8,
                             num_hiddens=16, num_layers=2)
encoder.initialize()
decoder = Seq2SeqAttentionDecoder(vocab_size=10, embed_size=8,
                                  num_hiddens=16, num_layers=2)
decoder.initialize()
X = np.zeros((4, 7))
state = decoder.init_state(encoder(X), None)
out, state = decoder(X, state)
out.shape, len(state), state[0].shape, len(state[1]), state[1][0].shape
((4, 7, 10), 3, (4, 7, 16), 2, (2, 4, 16))

10.2.2. Huấn luyện

Chúng ta hãy xây dựng một mô hình đơn giản sử dụng cùng một bộ siêu tham số và hàm mất mát để huấn luyện như Section 9.7.4. Từ kết quả, ta thấy tầng tập trung được thêm vào mô hình không tạo ra cải thiện đáng kể nào do các chuỗi trong tập huấn luyện khá ngắn. Bởi chi phí tính toán tốn thêm từ các tầng tập trung trong bộ mã hóa và bộ giải mã, mô hình này họat động chậm hơn nhiều so với mô hình seq2seq không áp dụng tập trung.

embed_size, num_hiddens, num_layers, dropout = 32, 32, 2, 0.0
batch_size, num_steps = 64, 10
lr, num_epochs, ctx = 0.005, 200, d2l.try_gpu()

src_vocab, tgt_vocab, train_iter = d2l.load_data_nmt(batch_size, num_steps)
encoder = d2l.Seq2SeqEncoder(
    len(src_vocab), embed_size, num_hiddens, num_layers, dropout)
decoder = Seq2SeqAttentionDecoder(
    len(tgt_vocab), embed_size, num_hiddens, num_layers, dropout)
model = d2l.EncoderDecoder(encoder, decoder)
d2l.train_s2s_ch9(model, train_iter, lr, num_epochs, ctx)
loss 0.033, 3874.4 tokens/sec on gpu(0)
../_images/output_seq2seq-attention_vn_6a9836_7_1.svg

Cuối cùng, ta hãy thử dự đoán một vài mẫu dưới đây.

for sentence in ['Go .', 'Wow !', "I'm OK .", 'I won !']:
    print(sentence + ' => ' + d2l.predict_s2s_ch9(
        model, sentence, src_vocab, tgt_vocab, num_steps, ctx))
Go . => va !
Wow ! => <unk> !
I'm OK . => je vous ai <unk> .
I won ! => j'ai gagné !

10.2.3. Tóm tắt

  • Mô hình seq2seq áp dụng cơ chế tập trung thêm một tầng tập trung vào mô hình seq2seq ban đầu.
  • Bộ giải mã của mô hình seq2seq áp dụng cơ chế tập trung được truyền vào ba đầu ra từ bộ mã hóa: đầu ra của bộ mã hóa tại tất cả các bước thời gian, trạng thái ẩn của bộ mã hóa tại bước thời gian cuối cùng, độ dài hợp lệ của bộ mã hóa.

10.2.4. Bài tập

  1. So sánh Seq2SeqAttentionDecoderSeq2seqDecoder bằng cách sử dụng cùng bộ tham số và kiểm tra giá trị hàm mất mát.
  2. Bạn hãy thử suy nghĩ liệu có trường hợp nào mà Seq2SeqAttentionDecoder vượt trội hơn Seq2seqDecoder?

10.2.5. Thảo luận

10.2.6. 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
  • Đỗ Trường Giang
  • Nguyễn Văn Quang
  • Nguyễn Văn Cường
  • Lê Khắc Hồng Phúc
  • Phạm Hồng Vinh