.. _sec_synonyms:
Từ tương tự và tương tự
=======================
Trong :numref:`sec_word2vec_pretraining`, chúng tôi đã đào tạo một mô
hình word2vec trên một tập dữ liệu nhỏ và áp dụng nó để tìm các từ tương
tự về mặt ngữ nghĩa cho một từ đầu vào. Trong thực tế, các vectơ từ được
đào tạo trước trên thể lớn có thể được áp dụng cho các nhiệm vụ xử lý
ngôn ngữ tự nhiên hạ nguồn, sẽ được đề cập sau này vào năm
:numref:`chap_nlp_app`. Để chứng minh ngữ nghĩa của vectơ từ được đào
tạo trước từ thể lớn một cách đơn giản, chúng ta hãy áp dụng chúng trong
các nhiệm vụ tương tự và tương tự từ.
.. raw:: html
.. raw:: html
.. code:: python
import os
from mxnet import np, npx
from d2l import mxnet as d2l
npx.set_np()
.. raw:: html
.. raw:: html
.. code:: python
import os
import torch
from torch import nn
from d2l import torch as d2l
.. raw:: html
.. raw:: html
Đang tải Pretrained Word Vectơ
------------------------------
Dưới đây liệt kê các bản nhúng Glove được đào tạo trước có kích thước
50, 100 và 300, có thể tải xuống từ `GloVe
website `__. Các bản nhúng
fastText được đào tạo trước có sẵn bằng nhiều ngôn ngữ. Ở đây chúng tôi
xem xét một phiên bản tiếng Anh (300-dimensional “wiki.en”) có thể được
tải xuống từ `fastText website `__.
.. raw:: html
.. raw:: html
.. code:: python
#@save
d2l.DATA_HUB['glove.6b.50d'] = (d2l.DATA_URL + 'glove.6B.50d.zip',
'0b8703943ccdb6eb788e6f091b8946e82231bc4d')
#@save
d2l.DATA_HUB['glove.6b.100d'] = (d2l.DATA_URL + 'glove.6B.100d.zip',
'cd43bfb07e44e6f27cbcc7bc9ae3d80284fdaf5a')
#@save
d2l.DATA_HUB['glove.42b.300d'] = (d2l.DATA_URL + 'glove.42B.300d.zip',
'b5116e234e9eb9076672cfeabf5469f3eec904fa')
#@save
d2l.DATA_HUB['wiki.en'] = (d2l.DATA_URL + 'wiki.en.zip',
'c1816da3821ae9f43899be655002f6c723e91b88')
.. raw:: html
.. raw:: html
.. code:: python
#@save
d2l.DATA_HUB['glove.6b.50d'] = (d2l.DATA_URL + 'glove.6B.50d.zip',
'0b8703943ccdb6eb788e6f091b8946e82231bc4d')
#@save
d2l.DATA_HUB['glove.6b.100d'] = (d2l.DATA_URL + 'glove.6B.100d.zip',
'cd43bfb07e44e6f27cbcc7bc9ae3d80284fdaf5a')
#@save
d2l.DATA_HUB['glove.42b.300d'] = (d2l.DATA_URL + 'glove.42B.300d.zip',
'b5116e234e9eb9076672cfeabf5469f3eec904fa')
#@save
d2l.DATA_HUB['wiki.en'] = (d2l.DATA_URL + 'wiki.en.zip',
'c1816da3821ae9f43899be655002f6c723e91b88')
.. raw:: html
.. raw:: html
Để tải các Glove được đào tạo trước này và các embeddings fastText,
chúng tôi xác định lớp ``TokenEmbedding`` sau.
.. raw:: html
.. raw:: html
.. code:: python
#@save
class TokenEmbedding:
"""Token Embedding."""
def __init__(self, embedding_name):
self.idx_to_token, self.idx_to_vec = self._load_embedding(
embedding_name)
self.unknown_idx = 0
self.token_to_idx = {token: idx for idx, token in
enumerate(self.idx_to_token)}
def _load_embedding(self, embedding_name):
idx_to_token, idx_to_vec = [''], []
data_dir = d2l.download_extract(embedding_name)
# GloVe website: https://nlp.stanford.edu/projects/glove/
# fastText website: https://fasttext.cc/
with open(os.path.join(data_dir, 'vec.txt'), 'r') as f:
for line in f:
elems = line.rstrip().split(' ')
token, elems = elems[0], [float(elem) for elem in elems[1:]]
# Skip header information, such as the top row in fastText
if len(elems) > 1:
idx_to_token.append(token)
idx_to_vec.append(elems)
idx_to_vec = [[0] * len(idx_to_vec[0])] + idx_to_vec
return idx_to_token, np.array(idx_to_vec)
def __getitem__(self, tokens):
indices = [self.token_to_idx.get(token, self.unknown_idx)
for token in tokens]
vecs = self.idx_to_vec[np.array(indices)]
return vecs
def __len__(self):
return len(self.idx_to_token)
.. raw:: html
.. raw:: html
.. code:: python
#@save
class TokenEmbedding:
"""Token Embedding."""
def __init__(self, embedding_name):
self.idx_to_token, self.idx_to_vec = self._load_embedding(
embedding_name)
self.unknown_idx = 0
self.token_to_idx = {token: idx for idx, token in
enumerate(self.idx_to_token)}
def _load_embedding(self, embedding_name):
idx_to_token, idx_to_vec = [''], []
data_dir = d2l.download_extract(embedding_name)
# GloVe website: https://nlp.stanford.edu/projects/glove/
# fastText website: https://fasttext.cc/
with open(os.path.join(data_dir, 'vec.txt'), 'r') as f:
for line in f:
elems = line.rstrip().split(' ')
token, elems = elems[0], [float(elem) for elem in elems[1:]]
# Skip header information, such as the top row in fastText
if len(elems) > 1:
idx_to_token.append(token)
idx_to_vec.append(elems)
idx_to_vec = [[0] * len(idx_to_vec[0])] + idx_to_vec
return idx_to_token, torch.tensor(idx_to_vec)
def __getitem__(self, tokens):
indices = [self.token_to_idx.get(token, self.unknown_idx)
for token in tokens]
vecs = self.idx_to_vec[torch.tensor(indices)]
return vecs
def __len__(self):
return len(self.idx_to_token)
.. raw:: html
.. raw:: html
Dưới đây chúng tôi tải các nhúng Glove 50 chiều (được đào tạo trước trên
một tập con Wikipedia). Khi tạo phiên bản ``TokenEmbedding``, tệp nhúng
được chỉ định phải được tải xuống nếu chưa.
.. raw:: html
.. raw:: html
.. code:: python
glove_6b50d = TokenEmbedding('glove.6b.50d')
.. parsed-literal::
:class: output
Downloading ../data/glove.6B.50d.zip from http://d2l-data.s3-accelerate.amazonaws.com/glove.6B.50d.zip...
.. raw:: html
.. raw:: html
.. code:: python
glove_6b50d = TokenEmbedding('glove.6b.50d')
.. parsed-literal::
:class: output
Downloading ../data/glove.6B.50d.zip from http://d2l-data.s3-accelerate.amazonaws.com/glove.6B.50d.zip...
.. raw:: html
.. raw:: html
Xuất kích thước từ vựng. Từ vựng chứa 400000 từ (mã thông báo) và một mã
thông báo không xác định đặc biệt.
.. raw:: html
.. raw:: html
.. code:: python
len(glove_6b50d)
.. parsed-literal::
:class: output
400001
.. raw:: html
.. raw:: html
.. code:: python
len(glove_6b50d)
.. parsed-literal::
:class: output
400001
.. raw:: html
.. raw:: html
Chúng ta có thể lấy chỉ mục của một từ trong từ vựng, và ngược lại.
.. raw:: html
.. raw:: html
.. code:: python
glove_6b50d.token_to_idx['beautiful'], glove_6b50d.idx_to_token[3367]
.. parsed-literal::
:class: output
(3367, 'beautiful')
.. raw:: html
.. raw:: html
.. code:: python
glove_6b50d.token_to_idx['beautiful'], glove_6b50d.idx_to_token[3367]
.. parsed-literal::
:class: output
(3367, 'beautiful')
.. raw:: html
.. raw:: html
Áp dụng vectơ Word Pretrained
-----------------------------
Sử dụng các vectơ Glove được tải, chúng tôi sẽ chứng minh ngữ nghĩa của
chúng bằng cách áp dụng chúng trong các tác vụ tương tự và tương tự từ
sau đây.
Từ tương tự
~~~~~~~~~~~
Tương tự như :numref:`subsec_apply-word-embed`, để tìm các từ tương tự
về mặt ngữ nghĩa cho một từ đầu vào dựa trên sự tương đồng cosin giữa
các vectơ từ, chúng tôi thực hiện hàm ``knn`` (:math:`k`-láng giềng gần
nhất) sau đây.
.. raw:: html
.. raw:: html
.. code:: python
def knn(W, x, k):
# Add 1e-9 for numerical stability
cos = np.dot(W, x.reshape(-1,)) / (
np.sqrt(np.sum(W * W, axis=1) + 1e-9) * np.sqrt((x * x).sum()))
topk = npx.topk(cos, k=k, ret_typ='indices')
return topk, [cos[int(i)] for i in topk]
.. raw:: html
.. raw:: html
.. code:: python
def knn(W, x, k):
# Add 1e-9 for numerical stability
cos = torch.mv(W, x.reshape(-1,)) / (
torch.sqrt(torch.sum(W * W, axis=1) + 1e-9) *
torch.sqrt((x * x).sum()))
_, topk = torch.topk(cos, k=k)
return topk, [cos[int(i)] for i in topk]
.. raw:: html
.. raw:: html
Sau đó, chúng ta tìm kiếm các từ tương tự bằng cách sử dụng vectơ từ
được đào tạo trước từ trường hợp ``TokenEmbedding`` ``embed``.
.. raw:: html
.. raw:: html
.. code:: python
def get_similar_tokens(query_token, k, embed):
topk, cos = knn(embed.idx_to_vec, embed[[query_token]], k + 1)
for i, c in zip(topk[1:], cos[1:]): # Exclude the input word
print(f'cosine sim={float(c):.3f}: {embed.idx_to_token[int(i)]}')
.. raw:: html
.. raw:: html
.. code:: python
def get_similar_tokens(query_token, k, embed):
topk, cos = knn(embed.idx_to_vec, embed[[query_token]], k + 1)
for i, c in zip(topk[1:], cos[1:]): # Exclude the input word
print(f'cosine sim={float(c):.3f}: {embed.idx_to_token[int(i)]}')
.. raw:: html
.. raw:: html
Từ vựng của các vectơ từ được đào tạo trước trong ``glove_6b50d`` chứa
400000 từ và một mã thông báo không xác định đặc biệt. Không bao gồm từ
đầu vào và mã thông báo không xác định, trong số từ vựng này cho phép
chúng ta tìm thấy ba từ tương tự về mặt ngữ nghĩa nhất với từ “chip”.
.. raw:: html
.. raw:: html
.. code:: python
get_similar_tokens('chip', 3, glove_6b50d)
.. parsed-literal::
:class: output
cosine sim=0.856: chips
cosine sim=0.749: intel
cosine sim=0.749: electronics
.. raw:: html
.. raw:: html
.. code:: python
get_similar_tokens('chip', 3, glove_6b50d)
.. parsed-literal::
:class: output
cosine sim=0.856: chips
cosine sim=0.749: intel
cosine sim=0.749: electronics
.. raw:: html
.. raw:: html
Dưới đây xuất ra các từ tương tự như “em bé” và “đẹp”.
.. raw:: html
.. raw:: html
.. code:: python
get_similar_tokens('baby', 3, glove_6b50d)
.. parsed-literal::
:class: output
cosine sim=0.839: babies
cosine sim=0.800: boy
cosine sim=0.792: girl
.. code:: python
get_similar_tokens('beautiful', 3, glove_6b50d)
.. parsed-literal::
:class: output
cosine sim=0.921: lovely
cosine sim=0.893: gorgeous
cosine sim=0.830: wonderful
.. raw:: html
.. raw:: html
.. code:: python
get_similar_tokens('baby', 3, glove_6b50d)
.. parsed-literal::
:class: output
cosine sim=0.839: babies
cosine sim=0.800: boy
cosine sim=0.792: girl
.. code:: python
get_similar_tokens('beautiful', 3, glove_6b50d)
.. parsed-literal::
:class: output
cosine sim=0.921: lovely
cosine sim=0.893: gorgeous
cosine sim=0.830: wonderful
.. raw:: html
.. raw:: html
Từ tương tự
~~~~~~~~~~~
Bên cạnh việc tìm các từ tương tự, chúng ta cũng có thể áp dụng vectơ từ
cho các tác vụ tương tự từ. Ví dụ, “man”: “woman”:: “con trai”: “con
gái” là hình thức của một từ tương tự: “người đàn ông” là “người phụ nữ”
là “con trai” là “con gái”. Cụ thể, nhiệm vụ hoàn thành từ tương tự có
thể được định nghĩa là: đối với một từ tương tự :math:`a : b :: c : d`,
cho ba từ đầu tiên :math:`a`, :math:`b` và :math:`c`, tìm :math:`d`.
Biểu thị vector của từ :math:`w` bởi :math:`\text{vec}(w)`. Để hoàn
thành sự tương tự, chúng ta sẽ tìm thấy từ có vector tương tự nhất với
kết quả của :math:`\text{vec}(c)+\text{vec}(b)-\text{vec}(a)`.
.. raw:: html
.. raw:: html
.. code:: python
def get_analogy(token_a, token_b, token_c, embed):
vecs = embed[[token_a, token_b, token_c]]
x = vecs[1] - vecs[0] + vecs[2]
topk, cos = knn(embed.idx_to_vec, x, 1)
return embed.idx_to_token[int(topk[0])] # Remove unknown words
.. raw:: html
.. raw:: html
.. code:: python
def get_analogy(token_a, token_b, token_c, embed):
vecs = embed[[token_a, token_b, token_c]]
x = vecs[1] - vecs[0] + vecs[2]
topk, cos = knn(embed.idx_to_vec, x, 1)
return embed.idx_to_token[int(topk[0])] # Remove unknown words
.. raw:: html
.. raw:: html
Hãy để chúng tôi xác minh sự tương tự “nam-nữ” bằng cách sử dụng các
vectơ từ được tải.
.. raw:: html
.. raw:: html
.. code:: python
get_analogy('man', 'woman', 'son', glove_6b50d)
.. parsed-literal::
:class: output
'daughter'
.. raw:: html
.. raw:: html
.. code:: python
get_analogy('man', 'woman', 'son', glove_6b50d)
.. parsed-literal::
:class: output
'daughter'
.. raw:: html
.. raw:: html
Dưới đây hoàn thành một cách tương tự “thủ đô-quốc gia”: “beijing”:
“china”:: “tokyo”: “japan”. Điều này thể hiện ngữ nghĩa trong vectơ từ
được đào tạo trước.
.. raw:: html
.. raw:: html
.. code:: python
get_analogy('beijing', 'china', 'tokyo', glove_6b50d)
.. parsed-literal::
:class: output
'japan'
.. raw:: html
.. raw:: html
.. code:: python
get_analogy('beijing', 'china', 'tokyo', glove_6b50d)
.. parsed-literal::
:class: output
'japan'
.. raw:: html
.. raw:: html
Đối với tính từ tương tự “tính từ siêu” như “bad”: “worst”:: “big”:
“big”: “biggest”, chúng ta có thể thấy rằng các vectơ từ được đào tạo
trước có thể nắm bắt thông tin cú pháp.
.. raw:: html
.. raw:: html
.. code:: python
get_analogy('bad', 'worst', 'big', glove_6b50d)
.. parsed-literal::
:class: output
'biggest'
.. raw:: html
.. raw:: html
.. code:: python
get_analogy('bad', 'worst', 'big', glove_6b50d)
.. parsed-literal::
:class: output
'biggest'
.. raw:: html
.. raw:: html
Để thể hiện khái niệm bị bắt về thì quá khứ trong vectơ từ được đào tạo
trước, chúng ta có thể kiểm tra cú pháp bằng cách sử dụng tương tự “thì
quá khứ hiện tại”: “do”: “did”:: “go”: “went”.
.. raw:: html
.. raw:: html
.. code:: python
get_analogy('do', 'did', 'go', glove_6b50d)
.. parsed-literal::
:class: output
'went'
.. raw:: html
.. raw:: html
.. code:: python
get_analogy('do', 'did', 'go', glove_6b50d)
.. parsed-literal::
:class: output
'went'
.. raw:: html
.. raw:: html
Tóm tắt
-------
- Trong thực tế, các vectơ từ được đào tạo trước trên thể lớn có thể
được áp dụng cho các nhiệm vụ xử lý ngôn ngữ tự nhiên hạ nguồn.
- Vectơ từ được đào tạo trước có thể được áp dụng cho các tác vụ tương
tự và tương tự từ.
Bài tập
-------
1. Kiểm tra kết quả fastText bằng cách sử dụng
``TokenEmbedding('wiki.en')``.
2. Khi từ vựng cực kỳ lớn, làm thế nào chúng ta có thể tìm thấy các từ
tương tự hoặc hoàn thành một từ tương tự nhanh hơn?
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html