14.4. Tiền huấn luyện word2vec¶
Trong phần này, ta sẽ huấn luyện một mô hình skip-gram đã được định nghĩa ở Section 14.1.
Đầu tiên, ta nhập các gói thư viện và mô-đun cần thiết cho thí nghiệm, và nạp tập dữ liệu PTB.
14.4.1. Mô hình Skip-Gram¶
Ta sẽ lập trình mô hình skip-gram bằng cách sử dụng các tầng embedding và phép nhân minibatch. Các phương pháp này cũng thường được sử dụng để lập trình các ứng dụng xử lý ngôn ngữ tự nhiên khác.
14.4.1.1. Tầng Embedding¶
Để thu được các embedding từ, ta sử dụng tầng embedding, có thể được tạo
bằng một thực thể nn.Embedding
trong Gluon. Trọng số của tầng
embedding là một ma trận có số hàng là kích thước từ điển
(input_dim
) và số cột là chiều của mỗi vector từ (output_dim
).
Ta đặt kích thước từ điển bằng 20 và chiều vector từ là
4.
Parameter embedding0_weight (shape=(20, 4), dtype=float32)
Đầu vào của tầng embedding là chỉ số của từ. Khi ta nhập vào chỉ số i của một từ, tầng embedding sẽ trả về vector từ tương ứng là hàng thứ i của ma trận trọng số. Dưới đây ta nhập vào tầng embedding một chỉ số có kích thước (2, 3). Vì số chiều vector từ là 4, ta thu được vector từ kích thước (2, 3, 4).
array([[[ 0.01438687, 0.05011239, 0.00628365, 0.04861524],
[-0.01068833, 0.01729892, 0.02042518, -0.01618656],
[-0.00873779, -0.02834515, 0.05484822, -0.06206018]],
[[ 0.06491279, -0.03182812, -0.01631819, -0.00312688],
[ 0.0408415 , 0.04370362, 0.00404529, -0.0028032 ],
[ 0.00952624, -0.01501013, 0.05958354, 0.04705103]]])
14.4.1.2. Phép nhân Minibatch¶
batch_dot
. Giả sử batch đầu tiên chứa n ma trận
X1,…,Xn có kích thước là
a×b, và batch thứ hai chứa n ma trận
Y1,…,Yn có kích thước là
b×c. Đầu ra của toán tử nhân ma trận trên hai batch đầu
vào là n ma trận
X1Y1,…,XnYn có
kích thước là a×c.(2, 1, 6)
14.4.1.3. Tính toán Truyền xuôi của Mô hình Skip-Gram¶
Ở lượt truyền xuôi, đầu vào của mô hình skip-gram chứa chỉ số center
của từ đích trung tâm và chỉ số contexts_and_negatives
được nối lại
từ chỉ số của từ ngữ cảnh và từ nhiễu. Trong đó, biến center
có kích
thước là (kích thước batch, 1), và biến contexts_and_negatives
có
kích thước là (kích thước batch, max_len
). Đầu tiên hai biến này
được biến đổi từ chỉ số từ thành vector từ bởi tầng embedding từ, sau đó
đầu ra có kích thước là (kích thước batch, 1, max_len
) thu được bằng
phép nhân minibatch. Mỗi phần tử của đầu ra là tích vô hướng của vector
từ đích trung tâm và vector từ ngữ cảnh hoặc vector từ nhiễu.
Hãy xác nhận kích thước đầu ra là (kích thước batch, 1, max_len
).
(2, 1, 4)
14.4.2. Huấn luyện¶
Trước khi huấn luyện mô hình embedding từ, ta cần định nghĩa hàm mất mát của mô hình.
14.4.2.1. Hàm Mất mát Entropy chéo Nhị phân¶
Theo định nghĩa hàm mất mát trong phương pháp lấy mẫu âm, ta có thể sử
dụng trực tiếp hàm mất mát entropy chéo nhị phân của Gluon
SigmoidBinaryCrossEntropyLoss
.
Lưu ý là ta có thể sử dụng biến mặt nạ để chỉ định một phần giá trị dự đoán và nhãn được dùng khi tính hàm mất mát trong minibatch: khi mặt nạ bằng 1, giá trị dự đoán và nhãn của vị trí tương ứng sẽ được dùng trong phép tính hàm mất mát; khi mặt nạ bằng 0, giá trị dự đoán và nhãn của vị trí tương ứng sẽ không được dùng trong phép tính hàm mất mát. Như đã đề cập, các biến mặt nạ có thể được sử dụng nhằm tránh ảnh hưởng của vùng đệm lên phép tính hàm mất mát.
Với hai mẫu giống nhau, mặt nạ khác nhau sẽ dẫn đến giá trị mất mát cũng khác nhau.
array([0.724077 , 0.3620385])
Ta có thể chuẩn hóa mất mát trong từng mẫu do các mẫu có độ dài khác nhau.
array([0.724077, 0.724077])
14.4.2.2. Khởi tạo Tham số Mô hình¶
Ta khai báo tầng embedding lần lượt của từ trung tâm và từ ngữ cảnh, và
đặt siêu tham số số chiều của vector từ embed_size
bằng 100.
14.4.2.3. Huấn luyện¶
Hàm huấn luyện được định nghĩa như dưới đây. Do có phần đệm nên phép tính mất mát có một chút khác biệt so với các hàm huấn luyện trước.
def train(net, data_iter, lr, num_epochs, device=d2l.try_gpu()):
net.initialize(ctx=device, force_reinit=True)
trainer = gluon.Trainer(net.collect_params(), 'adam',
{'learning_rate': lr})
animator = d2l.Animator(xlabel='epoch', ylabel='loss',
xlim=[0, num_epochs])
for epoch in range(num_epochs):
timer = d2l.Timer()
metric = d2l.Accumulator(2) # Sum of losses, no. of tokens
for i, batch in enumerate(data_iter):
center, context_negative, mask, label = [
data.as_in_ctx(device) for data in batch]
with autograd.record():
pred = skip_gram(center, context_negative, net[0], net[1])
l = (loss(pred.reshape(label.shape), label, mask)
/ mask.sum(axis=1) * mask.shape[1])
l.backward()
trainer.step(batch_size)
metric.add(l.sum(), l.size)
if (i+1) % 50 == 0:
animator.add(epoch+(i+1)/len(data_iter),
(metric[0]/metric[1],))
print(f'loss {metric[0] / metric[1]:.3f}, '
f'{metric[1] / timer.stop():.1f} tokens/sec on {str(device)}')
Giờ ta có thể huấn luyện một mô hình skip-gram sử dụng phương pháp lấy mẫu âm.
loss 0.331, 24813.8 tokens/sec on gpu(0)
14.4.3. Áp dụng Mô hình Embedding Từ¶
Sau khi huấn luyện mô hình embedding từ, ta có thể biểu diễn sự tương tự về nghĩa giữa các từ dựa trên độ tương tự cô-sin giữa hai vector từ. Có thể thấy, khi sử dụng mô hình embedding từ đã được huấn luyện, các từ có nghĩa gần nhất với từ “chip” hầu hết là những từ có liên quan đến chip xử lý.
def get_similar_tokens(query_token, k, embed):
W = embed.weight.data()
x = W[vocab[query_token]]
# Compute the cosine similarity. Add 1e-9 for numerical stability
cos = np.dot(W, x) / np.sqrt(np.sum(W * W, axis=1) * np.sum(x * x) + 1e-9)
topk = npx.topk(cos, k=k+1, ret_typ='indices').asnumpy().astype('int32')
for i in topk[1:]: # Remove the input words
print(f'cosine sim={float(cos[i]):.3f}: {vocab.idx_to_token[i]}')
get_similar_tokens('chip', 3, net[0])
cosine sim=0.596: intel
cosine sim=0.466: computer
cosine sim=0.447: hewlett-packard
14.4.4. Tóm tắt¶
Ta có thể tiền huấn luyện một mô hình skip-gram thông qua phương pháp lấy mẫu âm.
14.4.5. Bài tập¶
- Đặt
sparse_grad=True
khi tạo một đối tượngnn.Embedding
. Việc này có tăng tốc quá trình huấn luyện không? Hãy tra tài liệu của MXNet để tìm hiểu ý nghĩa của tham số này. - Hãy tìm từ đồng nghĩa cho các từ khác.
- Điều chỉnh các siêu tham số, quan sát và phân tích kết quả thí nghiệm.
- Khi tập dữ liệu lớn, ta thường lấy mẫu các từ ngữ cảnh và các từ nhiễu cho từ đích trung tâm trong minibatch hiện tại chỉ khi cập nhật tham số mô hình. Nói cách khác, cùng một từ đích trung tâm có thể có các từ ngữ cảnh và từ nhiễu khác nhau với mỗi epoch khác nhau. Cách huấn luyện này có lợi ích gì? Hãy thử lập trình phương pháp huấn luyện này.
14.4.6. Thảo luận¶
- Tiếng Anh: MXNet
- Tiếng Việt: Diễn đàn Machine Learning Cơ Bản
14.4.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
- Đỗ Trường Giang
- Phạm Minh Đức
- Lê Khắc Hồng Phúc
- Phạm Hồng Vinh
- Nguyễn Văn Cường
Lần cập nhật gần nhất: 12/09/2020. (Cập nhật lần cuối từ nội dung gốc: 21/07/2020)