词嵌入进阶

在“Word2Vec的实现”一节中,我们在小规模数据集上训练了一个 Word2Vec 词嵌入模型,并通过词向量的余弦相似度搜索近义词。虽然 Word2Vec 已经能够成功地将离散的单词转换为连续的词向量,并能一定程度上地保存词与词之间的近似关系,但 Word2Vec 模型仍不是完美的,它还可以被进一步地改进:

  1. 子词嵌入(subword embedding):FastText 以固定大小的 n-gram 形式将单词更细致地表示为了子词的集合,而 BPE (byte pair encoding) 算法则能根据语料库的统计信息,自动且动态地生成高频子词的集合;
  2. GloVe 全局向量的词嵌入: 通过等价转换 Word2Vec 模型的条件概率公式,我们可以得到一个全局的损失函数表达,并在此基础上进一步优化模型。

实际中,我们常常在大规模的语料上训练这些词嵌入模型,并将预训练得到的词向量应用到下游的自然语言处理任务中。本节就将以 GloVe 模型为例,演示如何用预训练好的词向量来求近义词和类比词。

GloVe 全局向量的词嵌入

GloVe 模型

先简单回顾以下 Word2Vec 的损失函数(以 Skip-Gram 模型为例,不考虑负采样近似):

−∑t=1T∑−m≤j≤m,j≠0log⁡P(w(t+j)∣w(t))-\sum_{t=1}^T\sum_{-m\le j\le m,j\ne 0} \log P(w^{(t+j)}\mid w^{(t)}) t=1Tmjm,j=0logP(w(t+j)w(t))

其中

P(wj∣wi)=exp⁡(uj⊤vi)∑k∈Vexp⁡(uk⊤vi)P(w_j\mid w_i) = \frac{\exp(\boldsymbol{u}_j^\top\boldsymbol{v}_i)}{\sum_{k\in\mathcal{V}}\exp(\boldsymbol{u}_k^\top\boldsymbol{v}_i)} P(wjwi)=kVexp(ukvi)exp(ujvi)

wiw_iwi 为中心词,wjw_jwj 为背景词时 Skip-Gram 模型所假设的条件概率计算公式,我们将其简写为 qijq_{ij}qij

注意到此时我们的损失函数中包含两个求和符号,它们分别枚举了语料库中的每个中心词和其对应的每个背景词。实际上我们还可以采用另一种计数方式,那就是直接枚举每个词分别作为中心词和背景词的情况:

−∑i∈V∑j∈Vxijlog⁡qij-\sum_{i\in\mathcal{V}}\sum_{j\in\mathcal{V}} x_{ij}\log q_{ij} iVjVxijlogqij

其中 xijx_{ij}xij 表示整个数据集中 wjw_jwj 作为 wiw_iwi 的背景词的次数总和。

我们还可以将该式进一步地改写为交叉熵 (cross-entropy) 的形式如下:

−∑i∈Vxi∑j∈Vpijlog⁡qij-\sum_{i\in\mathcal{V}}x_i\sum_{j\in\mathcal{V}}p_{ij} \log q_{ij} iVxijVpijlogqij

其中 xix_ixiwiw_iwi 的背景词窗大小总和,pij=xij/xip_{ij}=x_{ij}/x_ipij=xij/xiwjw_jwjwiw_iwi 的背景词窗中所占的比例。

从这里可以看出,我们的词嵌入方法实际上就是想让模型学出 wjw_jwj 有多大概率是 wiw_iwi 的背景词,而真实的标签则是语料库上的统计数据。同时,语料库中的每个词根据 xix_ixi 的不同,在损失函数中所占的比重也不同。

注意到目前为止,我们只是改写了 Skip-Gram 模型损失函数的表面形式,还没有对模型做任何实质上的改动。而在 Word2Vec 之后提出的 GloVe 模型,则是在之前的基础上做出了以下几点改动:

  1. 使用非概率分布的变量 pij′=xijp'_{ij}=x_{ij}pij=xijq′ij=exp⁡(uj⊤vi)q′_{ij}=\exp(\boldsymbol{u}^\top_j\boldsymbol{v}_i)qij=exp(ujvi),并对它们取对数;
  2. 为每个词 wiw_iwi 增加两个标量模型参数:中心词偏差项 bib_ibi 和背景词偏差项 cic_ici,松弛了概率定义中的规范性;
  3. 将每个损失项的权重 xix_ixi 替换成函数 h(xij)h(x_{ij})h(xij),权重函数 h(x)h(x)h(x) 是值域在 [0,1][0,1][0,1] 上的单调递增函数,松弛了中心词重要性与 xix_ixi 线性相关的隐含假设;
  4. 用平方损失函数替代了交叉熵损失函数。

综上,我们获得了 GloVe 模型的损失函数表达式:

∑i∈V∑j∈Vh(xij)(uj⊤vi+bi+cj−log⁡xij)2\sum_{i\in\mathcal{V}}\sum_{j\in\mathcal{V}} h(x_{ij}) (\boldsymbol{u}^\top_j\boldsymbol{v}_i+b_i+c_j-\log x_{ij})^2 iVjVh(xij)(ujvi+bi+cjlogxij)2

由于这些非零 xijx_{ij}xij 是预先基于整个数据集计算得到的,包含了数据集的全局统计信息,因此 GloVe 模型的命名取“全局向量”(Global Vectors)之意。

载入预训练的 GloVe 向量

GloVe 官方 提供了多种规格的预训练词向量,语料库分别采用了维基百科、CommonCrawl和推特等,语料库中词语总数也涵盖了从60亿到8,400亿的不同规模,同时还提供了多种词向量维度供下游模型使用。

torchtext.vocab 中已经支持了 GloVe, FastText, CharNGram 等常用的预训练词向量,我们可以通过声明 torchtext.vocab.GloVe 类的实例来加载预训练好的 GloVe 词向量。

import torch
import torchtext.vocab as vocab
print(vocab.pretrained_aliases.keys())
print([key for key in vocab.pretrained_aliases.keys() if "glove" in key])
# 查看所支持的所有词向量
cache_dir = "/home/kesci/input/GloVe6B5429"
glove = vocab.GloVe(name='6B', dim=50, cache=cache_dir)
# name:多大规模,dim多大维度
print("一共包含%d个词。" % len(glove.stoi))
print(glove.stoi['beautiful'], glove.itos[3366])
# stoi –指向向量输入参数中相关向量索引的字符串字典
  0%|          | 0/400000 [00:00<?, ?it/s]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.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']99%|█████████▉| 397720/400000 [00:09<00:00, 44795.30it/s]一共包含400000个词。
3366 beautiful

求近义词和类比词

求近义词

由于词向量空间中的余弦相似性可以衡量词语含义的相似性(为什么?),我们可以通过寻找空间中的 k 近邻,来查询单词的近义词。

  • 我们可以把它们想象成空间中的两条线段,都是从原点([0, 0, …])出发,指向不同的方向。两条线段之间形成一个夹角,如果夹角为0度,意味着方向相同、线段重合,这是表示两个向量代表的文本完全相等;如果夹角为90度,意味着形成直角,方向完全不相似;如果夹角为180度,意味着方向正好相反。因此,我们可以通过夹角的大小,来判断向量的相似程度。夹角越小,就代表越相似。
def knn(W, x, k):'''@params:W: 所有向量的集合x: 给定向量k: 查询的数量@outputs:topk: 余弦相似性最大k个的下标[...]: 余弦相似度'''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]# torch.topk(input, k, dim=None, largest=True, sorted=True, out=None) -> (Tensor, LongTensor)
#     沿给定dim维度返回输入张量input中 k 个最大值。
# 如果不指定dim,则默认为input的最后一维。
# 如果为largest为 False ,则返回最小的 k 个值。# 返回一个元组 (values,indices),其中indices是原始输入张量input中测元素下标。
# 如果设定布尔值sorted 为_True_,将会确保返回的 k 个值被排序。def get_similar_tokens(query_token, k, embed):'''@params:query_token: 给定的单词k: 所需近义词的个数embed: 预训练词向量'''topk, cos = knn(embed.vectors,embed.vectors[embed.stoi[query_token]], k+1)for i, c in zip(topk[0:], cos[0:]):  # 第一个词语就是它本身print('cosine sim=%.3f: %s' % (c, (embed.itos[i])))get_similar_tokens('chip', 3, glove)#包含GloVe,CharNGram或Vectors类的实例化的一个或列表。或者,可用预训练向量之一或列表
cosine sim=1.000: chip
cosine sim=0.856: chips
cosine sim=0.749: intel
cosine sim=0.749: electronics
get_similar_tokens('baby', 3, glove)
cosine sim=1.000: baby
cosine sim=0.839: babies
cosine sim=0.800: boy
cosine sim=0.792: girl
get_similar_tokens('beautiful', 3, glove)
cosine sim=1.000: beautiful
cosine sim=0.921: lovely
cosine sim=0.893: gorgeous
cosine sim=0.830: wonderful

求类比词

除了求近义词以外,我们还可以使用预训练词向量求词与词之间的类比关系,例如“man”之于“woman”相当于“son”之于“daughter”。求类比词问题可以定义为:对于类比关系中的4个词“aaa 之于 bbb 相当于 ccc 之于 ddd”,给定前3个词 a,b,ca,b,ca,b,cddd。求类比词的思路是,搜索与 vec(c)+vec(b)−vec(a)\text{vec}(c)+\text{vec}(b)−\text{vec}(a)vec(c)+vec(b)vec(a) 的结果向量最相似的词向量,其中 vec(w)\text{vec}(w)vec(w)www 的词向量。

def get_analogy(token_a, token_b, token_c, embed):'''@params:token_a: 词atoken_b: 词btoken_c: 词cembed: 预训练词向量@outputs:res: 类比词d'''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)res = embed.itos[topk[0]]return resget_analogy('man', 'woman', 'son', glove)
'daughter'
get_analogy('beijing', 'china', 'tokyo', glove)
'japan'
get_analogy('bad', 'worst', 'big', glove)
'biggest'
get_analogy('do', 'did', 'go', glove)
'went'

总结

  • 由于他人训练词向量时用到的语料库和当前任务上的语料库通常都不相同,所以词典中包含的词语以及词语的顺序都可能有很大差别,此时应当根据当前数据集上词典的顺序,来依次读入词向量,同时,为了避免训练好的词向量在训练的最初被破坏,还可以适当调整嵌入层的学习速率甚至设定其不参与梯度下降
  • 在进行预训练词向量的载入时,我们需要根据任务的特性来选定语料库的大小和词向量的维度,以均衡模型的表达能力和泛化能力,同时还要兼顾计算的时间复杂度

pytorch-词向量进阶相关推荐

  1. 斯坦福NLP名课带学详解 | CS224n 第2讲 - 词向量进阶(NLP通关指南·完结)

    作者:韩信子@ShowMeAI,路遥@ShowMeAI,奇异果@ShowMeAI 教程地址:https://www.showmeai.tech/tutorials/36 本文地址:https://ww ...

  2. [Pytorch系列-58]:循环神经网络 - 词向量的自动构建与模型训练代码示例

    作者主页(文火冰糖的硅基工坊):文火冰糖(王文兵)的博客_文火冰糖的硅基工坊_CSDN博客 本文网址:https://blog.csdn.net/HiWangWenBing/article/detai ...

  3. BERT 词向量理解及训练更新

    1.BERT 词向量理解 在预训练阶段中,词向量是在不断更新的,而在fine-tuning阶段中,词向量是固定不变的.在fine-tuning阶段中,我们使用预训练好的模型参数来对新的数据进行训练. ...

  4. 深度学习与自然语言处理教程(1) - 词向量、SVD分解与Word2Vec(NLP通关指南·完结)

    作者:韩信子@ShowMeAI 教程地址:https://www.showmeai.tech/tutorials/36 本文地址:https://www.showmeai.tech/article-d ...

  5. 深度学习与自然语言处理教程(2) - GloVe及词向量的训练与评估(NLP通关指南·完结)

    作者:韩信子@ShowMeAI 教程地址:https://www.showmeai.tech/tutorials/36 本文地址:https://www.showmeai.tech/article-d ...

  6. PyTorch在NLP任务中使用预训练词向量

    在使用pytorch或tensorflow等神经网络框架进行nlp任务的处理时,可以通过对应的Embedding层做词向量的处理,更多的时候,使用预训练好的词向量会带来更优的性能.下面分别介绍使用ge ...

  7. PyTorch入门-词向量

    一. 概念 1 . 词的表示 在自然语言处理任务中,首先需要考虑词如何在计算机中表示.通常,有两种表示方式:one-hot representation和distribution representa ...

  8. 一个基于PyTorch实现的Glove词向量的实例

    简介 词向量技术,也称为词嵌入技术(word-embedding),是一种将高维稀疏的向量压缩到低维稠密向量的技术.常见于自然语言处理领域对单词的预处理过程,例如将单词的one-hot向量是高维稀疏的 ...

  9. 使用pytorch获取bert词向量

    本文主要为如何使用pytorch来获取bert词向量. 首先安装pytorch-pretrained-bert包: pip install pytorch-pretrained-bert 然后加载预训 ...

  10. 使用pytorch获取bert词向量 将字符转换成词向量

    转载保存: 使用pytorch获取bert词向量_海蓝时见鲸_的博客-CSDN博客_获取bert词向量 pytorch-pretrained-bert简单使用_风吹草地现牛羊的马的博客-CSDN博客_ ...

最新文章

  1. Python 自带IDLE中调试程序
  2. Ubuntu 17.04 Chrome 安装
  3. 你还能再“二”一些吗?
  4. python源码精要(7)-CPython编译
  5. FreeSql (十八)导航属性
  6. 2019上半年这10本新书,技术大牛们都在追着看
  7. linux安装图像界面
  8. 设置,获取和删除Cookies
  9. python控制步进电机代码tx2_步进电机按键控制.lst
  10. Web前端-Vue中给input框赋值
  11. 关于使用canvas时fillRect添加矩形高度问题
  12. 上课笔记-机器学习(5)-美国人口普查数据进行收入预测分类
  13. 你看我像不像学HTML的人(五)——链接标签、注释和特殊字符
  14. Jpress的基本使用
  15. 记录下XPO生成的SQL语句
  16. Efficient Methods for Natural Language Processing: A Survey自然语言处理有效方法综述
  17. 云队友丨拼多多的两个世界
  18. navicat的使用以及学生信息表的操作
  19. OIPF,源于电信阵营的开放IPTV 解决方案
  20. CPC (Contrastive Predictive Coding)

热门文章

  1. 如何将JSON字符串数组转对象集合
  2. Java输出单引号或者双引号
  3. Access to the path 'E:/EIMS/EIMSweb/hshupfile/201006/20100621050801290.xls' is denied.
  4. Currency Assistant for Mac(货币兑换计算器)
  5. STM32HAL库学习笔记--硬件I2C读写AT24C512
  6. mysql驱动表优化_Mysql 驱动表查询优化
  7. 91发票查验助手——批量查验并自动截图保存
  8. java日记_Java实现超级实用的日记本
  9. Advance articles alert 27 July 2019
  10. c语言getchar与putchar