# 10.6 求近義詞和類比詞
在10.3節(word2vec的實現)中,我們在小規模數據集上訓練了一個word2vec詞嵌入模型,并通過詞向量的余弦相似度搜索近義詞。實際中,在大規模語料上預訓練的詞向量常常可以應用到下游自然語言處理任務中。本節將演示如何用這些預訓練的詞向量來求近義詞和類比詞。我們還將在后面兩節中繼續應用預訓練的詞向量。
## 10.6.1 使用預訓練的詞向量
基于PyTorch的關于自然語言處理的常用包有官方的[torchtext](https://github.com/pytorch/text)以及第三方的[pytorch-nlp](https://github.com/PetrochukM/PyTorch-NLP)等等。你可以使用`pip`很方便地按照它們,例如命令行執行
```
pip install torchtext
```
詳情請參見其README。
本節我們使用torchtext進行練習。下面查看它目前提供的預訓練詞嵌入的名稱。
``` python
import torch
import torchtext.vocab as vocab
vocab.pretrained_aliases.keys()
```
輸出:
```
dict_keys(['charngram.100d', 'fasttext.en.300d', 'fasttext.simple.300d', 'glove.42B.300d', 'glove.840B.300d', 'glove.twitter.27B.25d', 'glove.twitter.27B.50d', 'glove.twitter.27B.100d', 'glove.twitter.27B.200d', 'glove.6B.50d', 'glove.6B.100d', 'glove.6B.200d', 'glove.6B.300d'])
```
下面查看查看該`glove`詞嵌入提供了哪些預訓練的模型。每個模型的詞向量維度可能不同,或是在不同數據集上預訓練得到的。
``` python
[key for key in vocab.pretrained_aliases.keys()
if "glove" in key]
```
輸出:
```
['glove.42B.300d',
'glove.840B.300d',
'glove.twitter.27B.25d',
'glove.twitter.27B.50d',
'glove.twitter.27B.100d',
'glove.twitter.27B.200d',
'glove.6B.50d',
'glove.6B.100d',
'glove.6B.200d',
'glove.6B.300d']
```
預訓練的GloVe模型的命名規范大致是“模型.(數據集.)數據集詞數.詞向量維度”。更多信息可以參考GloVe和fastText的項目網站[1,2]。下面我們使用基于維基百科子集預訓練的50維GloVe詞向量。第一次創建預訓練詞向量實例時會自動下載相應的詞向量到`cache`指定文件夾(默認為`.vector_cache`),因此需要聯網。
``` python
cache_dir = "/Users/tangshusen/Datasets/glove"
# glove = vocab.pretrained_aliases["glove.6B.50d"](cache=cache_dir)
glove = vocab.GloVe(name='6B', dim=50, cache=cache_dir) # 與上面等價
```
返回的實例主要有以下三個屬性:
* `stoi`: 詞到索引的字典:
* `itos`: 一個列表,索引到詞的映射;
* `vectors`: 詞向量。
打印詞典大小。其中含有40萬個詞。
``` python
print("一共包含%d個詞。" % len(glove.stoi))
```
輸出:
```
一共包含400000個詞。
```
我們可以通過詞來獲取它在詞典中的索引,也可以通過索引獲取詞。
``` python
glove.stoi['beautiful'], glove.itos[3366] # (3366, 'beautiful')
```
## 10.6.2 應用預訓練詞向量
下面我們以GloVe模型為例,展示預訓練詞向量的應用。
### 10.6.2.1 求近義詞
這里重新實現10.3節(word2vec的實現)中介紹過的使用余弦相似度來搜索近義詞的算法。為了在求類比詞時重用其中的求` $ k $`近鄰(`$ k $`-nearest neighbors)的邏輯,我們將這部分邏輯單獨封裝在`knn`函數中。
``` python
def knn(W, x, k):
# 添加的1e-9是為了數值穩定性
cos = torch.matmul(W, x.view((-1,))) / (
(torch.sum(W * W, dim=1) + 1e-9).sqrt() * torch.sum(x * x).sqrt())
_, topk = torch.topk(cos, k=k)
topk = topk.cpu().numpy()
return topk, [cos[i].item() for i in topk]
```
然后,我們通過預訓練詞向量實例`embed`來搜索近義詞。
``` python
def get_similar_tokens(query_token, k, embed):
topk, cos = knn(embed.vectors,
embed.vectors[embed.stoi[query_token]], k+1)
for i, c in zip(topk[1:], cos[1:]): # 除去輸入詞
print('cosine sim=%.3f: %s' % (c, (embed.itos[i])))
```
已創建的預訓練詞向量實例`glove_6b50d`的詞典中含40萬個詞和1個特殊的未知詞。除去輸入詞和未知詞,我們從中搜索與“chip”語義最相近的3個詞。
``` python
get_similar_tokens('chip', 3, glove)
```
輸出:
```
cosine sim=0.856: chips
cosine sim=0.749: intel
cosine sim=0.749: electronics
```
接下來查找“baby”和“beautiful”的近義詞。
``` python
get_similar_tokens('baby', 3, glove)
```
輸出:
```
cosine sim=0.839: babies
cosine sim=0.800: boy
cosine sim=0.792: girl
```
``` python
get_similar_tokens('beautiful', 3, glove)
```
輸出:
```
cosine sim=0.921: lovely
cosine sim=0.893: gorgeous
cosine sim=0.830: wonderful
```
### 10.6.2.2 求類比詞
除了求近義詞以外,我們還可以使用預訓練詞向量求詞與詞之間的類比關系。例如,“man”(男人): “woman”(女人):: “son”(兒子) : “daughter”(女兒)是一個類比例子:“man”之于“woman”相當于“son”之于“daughter”。求類比詞問題可以定義為:對于類比關系中的4個詞 `$ a : b :: c : d $`,給定前3個詞`$ a $` 、`$ b $`和`$ c $`,求`$ d $`。設詞`$ w $`的詞向量為`$ \text{vec}(w) $`。求類比詞的思路是,搜索與`$ \text{vec}(c)+\text{vec}(b)-\text{vec}(a) $`的結果向量最相似的詞向量。
``` python
def get_analogy(token_a, token_b, token_c, embed):
vecs = [embed.vectors[embed.stoi[t]]
for t in [token_a, token_b, token_c]]
x = vecs[1] - vecs[0] + vecs[2]
topk, cos = knn(embed.vectors, x, 1)
return embed.itos[topk[0]]
```
驗證一下“男-女”類比。
``` python
get_analogy('man', 'woman', 'son', glove) # 'daughter'
```
“首都-國家”類比:“beijing”(北京)之于“china”(中國)相當于“tokyo”(東京)之于什么?答案應該是“japan”(日本)。
``` python
get_analogy('beijing', 'china', 'tokyo', glove) # 'japan'
```
“形容詞-形容詞最高級”類比:“bad”(壞的)之于“worst”(最壞的)相當于“big”(大的)之于什么?答案應該是“biggest”(最大的)。
``` python
get_analogy('bad', 'worst', 'big', glove) # 'biggest'
```
“動詞一般時-動詞過去時”類比:“do”(做)之于“did”(做過)相當于“go”(去)之于什么?答案應該是“went”(去過)。
``` python
get_analogy('do', 'did', 'go', glove) # 'went'
```
## 小結
* 在大規模語料上預訓練的詞向量常常可以應用于下游自然語言處理任務中。
* 可以應用預訓練的詞向量求近義詞和類比詞。
## 參考文獻
[1] GloVe項目網站。 https://nlp.stanford.edu/projects/glove/
[2] fastText項目網站。 https://fasttext.cc/
-----------
> 注:本節除代碼外與原書基本相同,[原書傳送門](https://zh.d2l.ai/chapter_natural-language-processing/similarity-analogy.html)
- Home
- Introduce
- 1.深度學習簡介
- 深度學習簡介
- 2.預備知識
- 2.1環境配置
- 2.2數據操作
- 2.3自動求梯度
- 3.深度學習基礎
- 3.1 線性回歸
- 3.2 線性回歸的從零開始實現
- 3.3 線性回歸的簡潔實現
- 3.4 softmax回歸
- 3.5 圖像分類數據集(Fashion-MINST)
- 3.6 softmax回歸的從零開始實現
- 3.7 softmax回歸的簡潔實現
- 3.8 多層感知機
- 3.9 多層感知機的從零開始實現
- 3.10 多層感知機的簡潔實現
- 3.11 模型選擇、反向傳播和計算圖
- 3.12 權重衰減
- 3.13 丟棄法
- 3.14 正向傳播、反向傳播和計算圖
- 3.15 數值穩定性和模型初始化
- 3.16 實戰kaggle比賽:房價預測
- 4 深度學習計算
- 4.1 模型構造
- 4.2 模型參數的訪問、初始化和共享
- 4.3 模型參數的延后初始化
- 4.4 自定義層
- 4.5 讀取和存儲
- 4.6 GPU計算
- 5 卷積神經網絡
- 5.1 二維卷積層
- 5.2 填充和步幅
- 5.3 多輸入通道和多輸出通道
- 5.4 池化層
- 5.5 卷積神經網絡(LeNet)
- 5.6 深度卷積神經網絡(AlexNet)
- 5.7 使用重復元素的網絡(VGG)
- 5.8 網絡中的網絡(NiN)
- 5.9 含并行連結的網絡(GoogLeNet)
- 5.10 批量歸一化
- 5.11 殘差網絡(ResNet)
- 5.12 稠密連接網絡(DenseNet)
- 6 循環神經網絡
- 6.1 語言模型
- 6.2 循環神經網絡
- 6.3 語言模型數據集(周杰倫專輯歌詞)
- 6.4 循環神經網絡的從零開始實現
- 6.5 循環神經網絡的簡單實現
- 6.6 通過時間反向傳播
- 6.7 門控循環單元(GRU)
- 6.8 長短期記憶(LSTM)
- 6.9 深度循環神經網絡
- 6.10 雙向循環神經網絡
- 7 優化算法
- 7.1 優化與深度學習
- 7.2 梯度下降和隨機梯度下降
- 7.3 小批量隨機梯度下降
- 7.4 動量法
- 7.5 AdaGrad算法
- 7.6 RMSProp算法
- 7.7 AdaDelta
- 7.8 Adam算法
- 8 計算性能
- 8.1 命令式和符號式混合編程
- 8.2 異步計算
- 8.3 自動并行計算
- 8.4 多GPU計算
- 9 計算機視覺
- 9.1 圖像增廣
- 9.2 微調
- 9.3 目標檢測和邊界框
- 9.4 錨框
- 10 自然語言處理
- 10.1 詞嵌入(word2vec)
- 10.2 近似訓練
- 10.3 word2vec實現
- 10.4 子詞嵌入(fastText)
- 10.5 全局向量的詞嵌入(Glove)
- 10.6 求近義詞和類比詞
- 10.7 文本情感分類:使用循環神經網絡
- 10.8 文本情感分類:使用卷積網絡
- 10.9 編碼器--解碼器(seq2seq)
- 10.10 束搜索
- 10.11 注意力機制
- 10.12 機器翻譯