目录
1.代码实现
2.知识点:
两个网站可以下载预训练词向量
- GloVe网站:GloVe: Global Vectors for Word Representation
- fastText网站:https://fasttext.cc
1.代码实现
import os
import torch
from torch import nn
import dltools
class TokenEmbedding: #没写括号,就是继承python默认的Object类
def __init__(self, file_path):
self.idx_to_token, self.idx_to_vec= self._load_embedding(file_path)
self.unknown_idx = 0
#创建 词与索引 对应的词典
self.token_to_idx = {token: idx for idx, token in enumerate(self.idx_to_token)}
#加载预训练好的词向量
def _load_embedding(self, file_path):
#创建列表,分别存放词与词向量对应的索引
idx_to_token, idx_to_vec = ['<unk>'], [] #在存放词索引的列表中先加一个未知字符<unk>
with open(file_path, 'r', encoding='utf-8') as f:
#对于数据量非常大的文件读取,把其当做迭代器,一行行遍历输出,避免一下子把整个文件加载进来
for line in f:
#strip()移除字符串头尾指定的字符 ( 默认为空白符 ) 空格 ( ' ' ) 、制表符 ( \t ) 、换行符 (\r\ ) 统称为空白符
#rstrip()只对右边进行移除空白符操作
elems = line.rstrip().split(' ') #输出的elems就是一个列表
token, elems = elems[0], [float(elem) for elem in elems[1:]]
#跳过fasttext的第一行 fasttext的第一行只有两个元素(一个token, 一个elem)
if len(elems) > 1:
idx_to_token.append(token)
idx_to_vec.append(elems)
#在idx_to_vec中为<unk>添加一个全是0的词向量 #idx_to_vec是一个二维列表
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):
"""根据输入的tokens返回对应的词向量"""
#根据tokens获取对应的词索引
#dict[token]索引字典中没有的元素会报错, dict.get(token, 0) 索引字典中没有的元素会返回0
indices = [self.token_to_idx.get(token, self.unknown_idx) for token in tokens]
#根据索引indices来获取对应的词向量
vecs = self.idx_to_vec[torch.tensor(indices)]
return vecs
def __len__(self):
"""返回tokens的数量长度"""
return len(self.idx_to_token)
glove_6b50d = TokenEmbedding(r'E:/ALOT/10_deep_learning/data/glove.6B/glove.6B.50d.txt')
len(glove_6b50d)
400001
glove_6b50d.token_to_idx['beautiful']
3367
glove_6b50d.idx_to_token[3367] #idx_to_token是列表,可以根据索引来获取值
'beautiful'
#计算余弦相似度来衡量词的相似度
def knn(W, x, k):
cos = torch.mv(W,x.reshape(-1, )) / (torch.sqrt(torch.sum(W * W, axis=1) + 1e-9) * torch.sqrt((x * x).sum()))
#筛选cos前10位
_, topk = torch.topk(cos, k=k)
return topk, [cos[int(i)] for i in topk]
def get_similar_tokens(query_token, k, embed):
#获取topk, cos
#embed.idx_to_vec 已经做了embed的词向量
#embed[[query_token]]获取查询词的词向量
topk, cos = knn(embed.idx_to_vec, embed[[query_token]], k+1)
for i, c in zip(topk[1:], cos[1:]): #排除查询词query_token它本身
print(f'{embed.idx_to_token[int(i)]} : cosine相似度={float(c):.3f}')
#查询“chip芯片”的相似词
get_similar_tokens('chip', 3, glove_6b50d)
chips : cosine相似度=0.856 intel : cosine相似度=0.749 electronics : cosine相似度=0.749
#词类比
#例如: man - woman : son - daughter
#上面相当于
#-->daughter = woman - man + son
def get_analogy(token_a, token_b, token_c, embed):
#分别获取token_a, token_b, token_c的词向量
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])]
get_analogy('man', 'woman', 'son', glove_6b50d)
'daughter'
#加载fastText词向量
fasttext_16b300d = TokenEmbedding(r'E:/ALOT/10_deep_learning/data/wiki-news-300d-1M.vec')
len(fasttext_16b300d)
999995
fasttext_16b300d.token_to_idx['boy']
2033
fasttext_16b300d.idx_to_token[2033]
'boy'
fasttext_16b300d.idx_to_vec[2033].shape
fasttext_16b300d.idx_to_vec[2033].reshape(-1,).shape
两个形状输出都是:
torch.Size([300])
get_similar_tokens('boy', 2, fasttext_16b300d)
girl : cosine相似度=0.862 boys : cosine相似度=0.772
get_analogy('man', 'woman', 'son', fasttext_16b300d) #词类比效果比较差
'son'
2.知识点: