当前位置:网站首页>Word2vec词向量
Word2vec词向量
2022-08-02 14:07:00 【lq_fly_pig】
前文也零散的写了些 关于神经网络模型的篇幅,如NNLM,本文着重讲解有关词向量的内容,从静态词向量到动态词向量等,其实相关的内容,网上也有很多,本人主要是为了做些记录和巩固下基础的知识点
一、词向量概述
前面篇幅中介绍了NNLM 神经网络语言模型的计算原理,NNLM生成的产物初始化的矩阵也可以作为词向量。基于NNLM(神经网络语言模型)预训练方法存在一个问题,主要是通过 t 时刻的单词预测t+1时刻的单词,只能通过历史信息预测未来时刻的信息,损失了 当前单词与"未来"单词之间的 共现信息
本篇介绍新的词向量预训练方法——Word2Vec,其中包括skip-gram模型和CBOW(Continuous Bags of Words)模型,这两种模型是2013年提出,严格上来讲不算是语言模型,因为其是基于词语与词语之间的共现信息实现词向量的学习。不再是基于整句(句子长度为n )中前 n-1个 单词预测第n个单词
1.1 CBOW模型
输入一句query,CBOW的中心思想是,根据上下文预测目标词汇,例如query为,... , ,,, .... CBOW的任务就是根据 的上下文 = { , ,, } 来预测 t 时刻的单词 , 由于窗口大小设置为5 所以 的上下文文本中包含4个单词。 从上文中NNLM的文章得到 NNLM训练词向量的思想是,按照query的顺序进行输入前 n-1 个 word 来预测第 n 个word ,但是
CBOW模型不考虑上下文的顺序,因此CBOW模型也算是一个词袋子模型,后续有人验证 按照顺序输入在某些特定的任务(词性标注、句法分析)等表现更好
(1). 输入层,以大小为5的窗口,在目标词的左边和右边各选择2个词语,作为模型的输入,输入层是由4个维度为词表长度的 |V|的 one-hot表示
(2). 初始化一个矩阵 E,维度为{V,dim}, dim 表示词向量维度,一般(50-300)之间,V表示的是词表的长度。矩阵E类似于tensorflow中的 look_up操作。如下图所示:
(3).对上下文词向量取平均,就得到了 的上下文表示,使用 表示单个word对应的列向量:
(4).输出层,对目标词汇进行预测,进行多分类预测,分类的类别大小为词汇的size 大小 |V|,损失函数为常见的 交叉熵损失函数
1.2 skip-gram模型
skip-gram 模型和CBOW模型反过来,使用当前词汇预测上下文词汇,使用词汇预测上下文信息, , ,, ,上下文中每一个词语当做独立的词汇进行预测,因此skip-gram模型是计算词与词之间的共现关系,
具体运算过程如下所示:
1.原始文本为“The quick brown fox jumps over the laze dog”,设置窗口大小为2;上图中蓝色的word 为目标词汇,右边的 Training Samples为构建的训练样本
2.从上文中发现一个问题,就是很多常见类似于"the" 这种词汇对于其上下文并不能带来很多有用的语义信息,因为几乎很多词汇中都会出现"the"这个单词,对于这种高频的词汇,原论文中使用的是通过抽样来删除该类单词;基本思想是,对于一开始训练的单词,每一个单词都有一定概率被删除,概率和单词出现的频率有关。
3.对于输出层也是类似于 NNLM的方式进行多分类预测,使用交叉熵进行损失迭代
二、负采样
2.1 CBOW和skip-gram模型的问题
我们从上文中的思路得到具体的流程如下:
从章节一中,我们知道了 skip-gram和CBOW模型的输入层,词向量层,输出层,其中我们知道最终的预测是多分类,分类的类别数量和词汇的size相关,词汇表很大导致,训练过程中的矩阵很大,严重影响训练的效率
2.2 skip-gram模型的负采样训练
针对训练的效率问题,skip-gram 采用 负采样来加速训练,具体例子如下:
如:当前词汇是 quick,目标词汇是 brow,假设词汇表的大小是10000,在模型的输出层是10000分类,单词brow的score得分最高,其他的9999的分类的score较低。对于这些9999得分低的单词 我们称之为 "negative " word.
负采样的方法提供一种新的任务视角:给定当前词语和其上下文。最大化两者之间的共现概率,问题简化成一种二分类问题,也就是说 quick—> brown 的分类为1, quick—>dong 的分类为0
对于 "negative " word 的选择,一个单词被选作negative sample的概率跟它出现的频次有关,出现频次越高的单词越容易被选作negative words,原来论文中指的是使用"一元分布模型",一般的情况 "negative " word 选择(5-20)个
2.3 word2vec无法处理一词多义
由上文得到 bank有银行的意思,也有河岸的意思,对于这种静态词向量无法表达其多义性
三、总结以及代码展示
3.1总结
1.CBOW 是通过上下文进行预测当前值
2. SKip-gram 是通过当前值来预测上下文
优点: (1).考虑到上下文,跟之前的Embedding 相比,效果更好
(2).相比较之前的Embedding 维度更少,速度更快
(3). 通用性较强,使用于各种NLP任务中
缺点:(1).词和向量是一对一的关系,无法处理多义词问题
(2).word2vec 是一种静态方式,无法处理特定任务做动态优化
3.2 代码展示
#code by 2021.8.1
# learning by https://github.com/graykode
import numpy as np
from numpy import random
import torch
import torch.nn as nn
import torch.optim as optim
import pdb
batch_size = 2 # mini-batch size
embedding_size = 2 # embedding size
##随机选取 训练数据 从skip_gram中选取
def random_batch():
random_inputs = []
random_labels = []
random_index = np.random.choice(range(len(skip_gram)),batch_size,replace=False) ## 选取 len(skip_gram) 范围内 batch_size长度的数组
for i in random_index:
random_inputs.append(np.eye(voc_size)[skip_gram[i][0]]) ## skip_gram[i][0] 表示的是获取 中心词 target
### np.eye(voc_size) 表示的是 生成one-hot的向量 大小是 voc_size * voc_size ,word2vec的数据输入是one-hot的形式
random_labels.append(skip_gram[i][1])
return random_inputs, random_labels
class word2vec(nn.Module):
def __init__(self) -> None:
super().__init__()
self.W = nn.Linear(voc_size,embedding_size,bias=False) ## word-embedding的 初始化
self.WT = nn.Linear(embedding_size,voc_size,bias=False) ## fc 输出
def forward(self,X):
### X [batch_size , voc_size] one-hot 编码
hidden_layers = self.W(X)
out_layers = self.WT(hidden_layers)
return out_layers
if __name__ == '__main__':
### 训练数据
sentences = ["apple banana fruit", "banana orange fruit", "orange banana fruit",
"dog cat animal", "cat monkey animal", "monkey dog animal"]
word_sequence = " ".join(sentences).split()
word_list = " ".join(sentences).split()
word_list = list(set(word_list)) ###所有的字典大小,去重统计
word_dict = {w:i for i, w in enumerate(word_list)}
voc_size = len(word_dict)
### create skip_gram data and window size = 1 , skip_window = 1, num_skips = 2
## skip_window的参数,它代表着我们从当前input word的一侧(左边或右边)选取词的数量
# 另一个参数 num_skips ,表示从 window中选取多少个不同的 词 作为训练数据
skip_gram = []
for i in range(1,len(word_sequence) -1):
target = word_dict[word_sequence[i]] ## 当前的 word
context = [word_dict[word_sequence[i-1]],word_dict[word_sequence[i+1]]] ##获取前后的 words
for w in context:
skip_gram.append([target,w])
model = word2vec()
loss_fuc = nn.CrossEntropyLoss() ## 交叉熵 损失
optimizer = optim.Adam(model.parameters(), lr=0.001) ## 定义优化器
for epoch in range(50000):
input_batch, target_batch = random_batch()
input_batch = torch.Tensor(input_batch)
target_batch = torch.LongTensor(target_batch)
# pdb.set_trace()
## input_batch shape = [2,8] target_batch shape = [2]
optimizer.zero_grad() ## 优化器初始化 梯度值设置为0
output = model(input_batch) ## output : [batch_size, voc_size]
loss = loss_fuc(output,target_batch)
if(epoch + 1) % 1000 == 0:
print(' Epoch:','%04d'%(epoch + 1), 'loss = ','{:.6f}'.format(loss))
loss.backward() ## 反向传播
optimizer.step() ## 每一步更新参数
边栏推荐
猜你喜欢
随机推荐
Using the cloud GPU + pycharm training model to realize automatic background run programs, save training results, the server automatically power off
spark写sql的方式
C语言日记 5、7setprecision()问题
Scala连接Mysql数据库
What?It's 2020, you still can't adapt the screen?
DataX 的使用
ng-style:动态控制样式
MySQL知识总结 (二) 存储引擎
liunx下mysql遇到的简单问题
ConstraintLayout从入门到放弃
使用flutter小记
spark中RDD与DF的关系
C语言日记 1“Hello world“
Flink依赖汇总
浏览器报错数字代表的大概意思
YOLOv7 uses cloud GPU to train its own dataset
拥抱Jetpack之印象篇
数据的表示方法和转换(二进制、八进制、十进制、十六进制)
关于UDF
Ehcache基础学习