.. _sec_synonyms:
Sözcük Benzerliği ve Benzeşim
=============================
:numref:`sec_word2vec_pretraining` içinde, küçük bir veri kümesi
üzerinde bir word2vec modelini eğittik ve bunu bir girdi sözcüğü için
anlamsal olarak benzer kelimeleri bulmak için uyguladık. Uygulamada,
büyük külliyatlar üzerinde önceden eğitilmiş kelime vektörleri, daha
sonra :numref:`chap_nlp_app` içinde ele alınacak olan doğal dil işleme
görevlerine uygulanabilir. Büyük külliyatlardan önceden eğitilmiş kelime
vektörlerinin anlamını basit bir şekilde göstermek için, bunları sözcük
benzerliğü ve benzeşimi görevlerine uygulayalım.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
import os
from d2l import mxnet as d2l
from mxnet import np, npx
npx.set_np()
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
import os
import torch
from torch import nn
from d2l import torch as d2l
.. raw:: html
.. raw:: html
Önceden Eğitilmiş Sözcük Vektörlerini Yükleme
---------------------------------------------
Aşağıda, `GloVe web
sitesinden `__ indirilebilen
50, 100 ve 300 boyutlarında önceden eğitilmiş GloVe gömme listeleri
verilmektedir. Önceden eğitilmiş fastText gömmeleri birden çok dilde
mevcuttur. Burada indirilebilen bir İngilizce sürümünü düşünelim
(300-boyutlu "wiki.en") `fastText websitesi `__.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. 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
.. raw:: latex
\diilbookstyleinputcell
.. 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
Bu önceden eğitilmiş GloVe ve fastText gömmelerini yüklemek için
aşağıdaki ``TokenEmbedding`` sınıfını tanımlıyoruz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
class TokenEmbedding:
"""Andıç Gömme."""
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 websitesi: https://nlp.stanford.edu/projects/glove/
# fastText websitesi: 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:]]
# fastText'teki en üst satır gibi başlık bilgilerini atla
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
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
class TokenEmbedding:
"""Andıç Gömme."""
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 websitesi: https://nlp.stanford.edu/projects/glove/
# fastText websitesi: 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:]]
# fastText'teki en üst satır gibi başlık bilgilerini atla
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
Aşağıda 50 boyutlu GloVe gömmelerini yüklüyoruz (Wikipedia alt kümesi
üzerinde önceden eğitilmiş). ``TokenEmbedding`` örneğini oluştururken,
belirtilen gömme dosyasının henüz yoksa indirilmesi gerekir.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
glove_6b50d = TokenEmbedding('glove.6b.50d')
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
glove_6b50d = TokenEmbedding('glove.6b.50d')
.. raw:: html
.. raw:: html
Sözcük dağarcığı boyutunu çıktılayın. Sözcük bilgisi 400000 kelime
(belirteç) ve özel bir bilinmeyen belirteci içerir.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
len(glove_6b50d)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
400001
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
len(glove_6b50d)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
400001
.. raw:: html
.. raw:: html
Sözcük hazinesinde bir kelimenin indeksini alabiliriz ve tersi de
geçerlidir.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
glove_6b50d.token_to_idx['beautiful'], glove_6b50d.idx_to_token[3367]
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
(3367, 'beautiful')
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
glove_6b50d.token_to_idx['beautiful'], glove_6b50d.idx_to_token[3367]
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
(3367, 'beautiful')
.. raw:: html
.. raw:: html
Önceden Eğitilmiş Sözcük Vektörlerini Uygulama
----------------------------------------------
Yüklenen GloVe vektörlerini kullanarak, anlamlarını aşağıdak sözcük
benzerliği ve benzeşim görevlerine uygulayarak göstereceğiz.
Sözcük Benzerliği
~~~~~~~~~~~~~~~~~
:numref:`subsec_apply-word-embed` içindekine benzer şekilde, sözcük
vektörleri arasındaki kosinüs benzerliklerine dayanan bir girdi sözcüğü
için anlamsal olarak benzer kelimeleri bulmak için aşağıdaki ``knn``
(:math:`k` en yakın komşu) işlevini uygularız.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def knn(W, x, k):
# Sayısal kararlılık için 1e-9 ekleyin
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
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def knn(W, x, k):
# Sayısal kararlılık için 1e-9 ekleyin
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
Daha sonra, ``TokenEmbedding`` örneğinden önceden eğitilmiş sözcük
vektörlerini kullanarak benzer kelimeleri ararız.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. 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:]): # Girdi sözcüğünü hariç tut
print(f'cosine sim={float(c):.3f}: {embed.idx_to_token[int(i)]}')
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. 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:]): # Girdi sözcüğünü hariç tut
print(f'cosine sim={float(c):.3f}: {embed.idx_to_token[int(i)]}')
.. raw:: html
.. raw:: html
``glove_6b50d``'teki önceden eğitilmiş kelime vektörlerinin kelime
dağarcığı 400000 kelime ve özel bir bilinmeyen belirteç içerir. Girdi
kelimesi ve bilinmeyen belirteci hariç, bu kelime arasında "chip (çip))"
kelimesine en anlamsal olarak benzer üç kelimeyi bulalım.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
get_similar_tokens('chip', 3, glove_6b50d)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
cosine sim=0.856: chips
cosine sim=0.749: intel
cosine sim=0.749: electronics
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
get_similar_tokens('chip', 3, glove_6b50d)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
cosine sim=0.856: chips
cosine sim=0.749: intel
cosine sim=0.749: electronics
.. raw:: html
.. raw:: html
Aşağıda "baby (bebek)" ve " beautiful (güzel)" kelimelerinin benzerleri
çıktılanır.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
get_similar_tokens('baby', 3, glove_6b50d)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
cosine sim=0.839: babies
cosine sim=0.800: boy
cosine sim=0.792: girl
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
get_similar_tokens('beautiful', 3, glove_6b50d)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
cosine sim=0.921: lovely
cosine sim=0.893: gorgeous
cosine sim=0.830: wonderful
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
get_similar_tokens('baby', 3, glove_6b50d)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
cosine sim=0.839: babies
cosine sim=0.800: boy
cosine sim=0.792: girl
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
get_similar_tokens('beautiful', 3, glove_6b50d)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
cosine sim=0.921: lovely
cosine sim=0.893: gorgeous
cosine sim=0.830: wonderful
.. raw:: html
.. raw:: html
Kelime Benzeşimi
~~~~~~~~~~~~~~~~
Benzer kelimeleri bulmanın yanı sıra, kelime vektörlerini kelime
benzetme görevlerine de uygulayabiliriz. Örneğin,
"erkek":"kadın"::"oğul":"kız" bir kelime benzetme şeklidir: "erkek" ile
"kadın", "kız" ile "oğul" benzerdir. Daha özel olarak, kelime benzeşim
tamamlama görevi şu şekilde tanımlanabilir: Bir kelime benzeşimi
:math:`a : b :: c : d` için, ilk üç kelime olan :math:`a`, :math:`b` ve
:math:`c` verildiğinde, :math:`d` bulunsun. :math:`w` kelimesinin
vektörünü :math:`\text{vec}(w)` ile belirtilsin. Benzetmeyi tamamlamak
için, vektörü :math:`\text{vec}(c)+\text{vec}(b)-\text{vec}(a)` sonucuna
en çok benzeyen kelimeyi bulacağız.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. 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])] # Bilinmeyen kelimeleri çıkar
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. 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])] # Bilinmeyen kelimeleri çıkar
.. raw:: html
.. raw:: html
Yüklü kelime vektörlerini kullanarak "erkek-kadın" benzeşimini
doğrulayalım.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
get_analogy('man', 'woman', 'son', glove_6b50d)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
'daughter'
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
get_analogy('man', 'woman', 'son', glove_6b50d)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
'daughter'
.. raw:: html
.. raw:: html
Aşağıdaki bir "başkent-ülke" benzeşimini tamamlar:
"Pekin":"Çin"::"Tokyo":"Japonya". Bu, önceden eğitilmiş kelime
vektörlerindeki anlamı gösterir.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
get_analogy('beijing', 'china', 'tokyo', glove_6b50d)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
'japan'
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
get_analogy('beijing', 'china', 'tokyo', glove_6b50d)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
'japan'
.. raw:: html
.. raw:: html
"Kötü":"en kötü"::"büyük":"en büyük" gibi "sıfat-üstün sıfat" benzetme
için, önceden eğitilmiş kelime vektörlerinin sözdizimsel bilgileri
yakalayabileceğini görebiliriz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
get_analogy('bad', 'worst', 'big', glove_6b50d)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
'biggest'
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
get_analogy('bad', 'worst', 'big', glove_6b50d)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
'biggest'
.. raw:: html
.. raw:: html
Önceden eğitilmiş kelime vektörlerinde geçmiş zaman kavramını göstermek
için, sözdizimini “şimdiki zaman - geçmiş zaman” benzetmesini kullanarak
test edebiliriz: "yap (do)":“yaptım (did)"::"go (git)":"went (gittim)".
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
get_analogy('do', 'did', 'go', glove_6b50d)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
'went'
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
get_analogy('do', 'did', 'go', glove_6b50d)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
'went'
.. raw:: html
.. raw:: html
Özet
----
- Uygulamada, büyük külliyatlar üzerinde önceden eğitilmiş kelime
vektörleri doğal dil işleme görevlerine uygulanabilir.
- Önceden eğitilmiş kelime vektörleri kelime benzerliği ve benzeşimi
görevlerine uygulanabilir.
Alıştırmalar
------------
1. ``TokenEmbedding('wiki.en')`` kullanarak fastText sonuçlarını test
edin.
2. Kelime dağarcığı son derece büyük olduğunda, benzer kelimeleri nasıl
bulabiliriz veya bir kelime benzeşimini daha hızlı tamamlayabiliriz?
.. raw:: html
.. raw:: html
`Tartışmalar `__
.. raw:: html
.. raw:: html
`Tartışmalar `__
.. raw:: html
.. raw:: html