word2Vec初步理解(上)
2026/8/7 12:46:27 网站建设 项目流程

一、Efficient Estimation of Word Representations in Vector Space

论文中提到了skip-gram 和 CBOW,这里重点理解skip-gram

1.1原始Skip-gram

importtorchimporttorch.nnasnnclassSkipGram(nn.Module):def__init__(self,vocab_size,embed_dim):super().__init__()# Projection layerself.embedding=nn.Embedding(vocab_size,embed_dim)# Output layerself.output=nn.Linear(embed_dim,vocab_size)defforward(self,center_word):h=self.embedding(center_word)logits=self.output(h)returnlogits

训练skip-gram
I love deep learning, windows = 2,即中心词前一个词,和后一个词
center=[love, love, deep, deep]
target = [I , deep, love, learning]
训练代码

model=SkipGram(vocab_size,300)criterion=nn.CrossEntropyLoss()optimizer=torch.optim.Adam(model.parameters(),lr=1e-3)forcenter,targetinloader:logits=model(center)loss=criterion(logits,target)optimizer.zero_grad()loss.backward()optimizer.step()

logits = model(center) 中的logits 是 词汇表中每个词出现的概率
target 是 词汇表中,第几个词
如果窗口变成5, 例如 0:I 1:love 2:deep 3:learning 4:and 5:neural 6:networks 7:very 8:much
以 neural 为中心词,windows = 5 , 可以生成10个样本
(neural , I) (neural , love ) (neural , deep ) (neural , learning) (neural , and )
(neural , networks ) (neural , very ) (neural , much)

如果是 CBOW模式,只能生成1个样本
([w0 w1 w2 w3 w4,)
w6 w7 w8 w9 w10],
w5)

  • 在word2Vec 中,windows=5指的是,左右各5个
  • 根据上面的例子,可以看到CBOW的基本思想是,根据上下文,预测中心词,所以训练样本是中心词的左右各5个词,目标是中心词;Skip-Gram 是根据中心词,预测周围词,所以输入样本是这样的,[中性词,左边第3个]、[中性词,左边第2个]、[中性词,左边第1个]、[中性词,右边第1个]、[中性词,右边第2个]、[中性词,右边第3个]

二、 Distributed Representations of Words and Phrasesand their Compositionality

观察上面的网络模型发现,例如词向量的维度300,如果词汇表是10w,那么网络每次都输出10w x 300,然后softmax(10w个词),计算量很大,从我们的认知来说,其实每次预测,根本就不用将词汇表里面的词汇都预测一遍,词与之间是有联系的,真正需要更新的其实只是一个正样本词和少量负样本词。

2.1 Negative Sampling

正常情况下,skip-gram 中的 I love deep learning
中心词:love 上下文: I deep,训练对input -> target: love -> I love -> deep
预测这两个,需要在整个词表中做softmax
在 Negative Sampling 思想中,
正样本: (love, I)
负样本:(love, apple)(love, banana) (love, car) (love, tiger)(love, phone)
变成了二分类:是不是上下文词?
原来的损失函数:
−logP(wo∣wI)-logP(w_o|w_I)logP(wowI)
变成了:
logσ(−vOTvI)+∑i=1klogσ(−vNiTvI)log\sigma(-v_O^Tv_I)+\sum_{i=1}^klog\sigma(-v_{N_i}^Tv_I)logσ(vOTvI)+i=1klogσ(vNiTvI)
其中:正样本1个,负样本k个,通常k=5

SkipGramNS

importtorchimporttorch.nnasnnimporttorch.nn.functionalasFclassSkipGramNS(nn.Module):def__init__(self,vocab_size,embed_dim):super().__init__()# syn0self.in_embed=nn.Embedding(vocab_size,embed_dim)# syn1negself.out_embed=nn.Embedding(vocab_size,embed_dim)defforward(self,center_words,pos_words,neg_words):""" center_words : [B] pos_words : [B] neg_words : [B,K] """center=self.in_embed(center_words)pos=self.out_embed(pos_words)# 正样本pos_score=torch.sum(center*pos,dim=1)pos_loss=F.logsigmoid(pos_score)# 负样本neg=self.out_embed(neg_words)neg_score=torch.bmm(neg,center.unsqueeze(2)).squeeze(2)neg_loss=F.logsigmoid(-neg_score).sum(1)loss=-(pos_loss+neg_loss)returnloss.mean()

2.2、SkipGramNS我的理解

  • 之前的SkipGram的输入是中心词,以及中心词的一个窗口内的上下文词,SkipGramNS需要再输入k=5该中心词的随机采样词,例如一下:
    center = love
    positive = I
    negative = [apple, car, banana, phone, tiger]
  • 有两个词向量nn.Embedding,中心词独享一个,正样本和负样本共享一个nn.Embedding;
  • 正样本分数,是正样本词向量和中心词向量的向量内积;
  • 负样本分数,是负样本词向量和中心词向量的向量内积;
  • 模型需要拉进正样本和中心词之间的距离,拉大负样本和中心词的距离,因此模型的loss为loss=−logσ(spos)−∑(logσ(−sneg))loss = -log\sigma(s_{pos})-\sum(log\sigma(-s_{neg}))loss=logσ(spos)(logσ(sneg))
    从而推动正样本内积越来越大、负样本内积越来越小,使中心词靠近真实上下文词,远离随机采样词。

2.3、SkipGramNS我的思考

2.3.1 、为什么中心词一个nn.Embedding,正样本和负样本一个,为什么不能三个输入共享一个;
理论上正样本、负样本和中心词,使用一个nn.Embedding也可以,这里作者之所以使用两个,是认为中心词和正负样本在整个优化过程中扮演不同的角色,如果两种角色是相互矛盾的,那么放到一起学习,学到的向量必然是不好的,分开学习,可以让两种角色的特征都学的很好;如果两种角色是相互依赖,相互促进的,那么三个共享一个nn.Embedding效果最好。有时候用几层卷积,几个分支,很多时候是根据设计者对当前任务的理解。
2.3.2、原始的SkipGram的优化目标是,为什么可以由预测词汇表中所有词的概率,求最大的那个,如此丝滑的将优化目标变为,正样本与中心词相似度-负样本与中心词相似度呢?
这里有很多思考,可以看,初版的skip-gram 最后一层的思想:所有词汇表中,我的目标词汇的概率最大,其实就是分类的思想,但是这里词汇表(类别)是如此之大,导致计算效率特别低,
1、导致计算量大的是词汇表的个数,为什么会用到词汇表的个数呢,因为最后一层使用softmax让目标词汇的概率最大,从而逼迫网络学习的词汇向量逼近目标词汇,远离非目标词汇;
2、经分析,softmax的目的其实是学习词向量,并不是真的去预测是哪个词汇,那么是不是可以跳过softmax的方法,于是NS顺势提取,就是不绕弯子了,之间在向量层上计算损失,就是输入正样本的向量与中心向量距离近,负样本向量与中心向量距离远;
3、对,这个思想和人脸中的Triplet Loss(三元组损失)是一致的,通过Triplet Loss训练后的人脸图片,可以生成人脸特征向量,用来做比对。
2.3.3 word2vec 和 lstm 、transformer的区别
1、skip-gram,的目标函数是
P(wo∣wc)P(w_o|w_c)P(wowc)
例如I love deep learning,窗口=2,训练样本(love → I),(love → deep), (love → learning),所以,skip-gram只关系哪些词经常一起出现,但是它不关心语法,顺序,和长距离依赖,本质上skip-gram学的是词共现统计,而不是语言生成,结构如下:

中心词id ↓ Embedding ↓ 词向量 vc ↓ 与目标词向量点积 ↓ sigmoid ↓ loss

2、LSTM是语言模型:
P(wt∣w1,...,wt−1)P(w_t|w_1,...,w_{t-1})P(wtw1,...,wt1)
例如 I love deep ? 预测:learning,在lstm 中,embedding 只是输入特征,核心是隐藏层ttt_ttt携带的上下文信息,结构如下:

Embedding ↓ LSTM ↓ Hidden State ↓ Linear ↓ Softmax ↓ 整个词表

3、Transformer也是语言模型:
P(wt∣w1,...,wt−1)P(w_t|w_1,...,w_{t-1})P(wtw1,...,wt1)
但是上下文建模换成了self-Attention:
H=Attention(Q,K,V)H = Attention(Q,K,V)H=Attention(Q,K,V),所以transformer学到的特征更强
2.3.4 lstm 、transformer都有自己的nn.Embedding, word2vec的作用是什么

1、 在word2vec出现之前,词用的ID来表示,例如cat -> 1001,dog -> 2003, apple -> 501,模型不知道cat 和 dog比较接近,cat 和 apple 不接近;
2、 word2vec出来后,cat , dog, apple 使用向量表示之后,这些向量可以表示语义,所以很多模型直接拿word2vec的结果来用,例如后面之间接LSTM,经常会看到:

embedding=nn.Embedding.from_pretrained(word2vec_weight)

3、后来,BERT 和 GPT 出现后,发现模型完全可以自己学Embedding,不需要先训练word2vec,再训练模型,直接端到端训练。现在大模型训练流程:

文本 ↓ Tokenizer ↓ 随机初始化Embedding ↓ Transformer ↓ 预测下一个Token

4、之前说过,word2vec提取的是静态词之前的关系,后面会看到BERT Embedding GPT Embedding 等不是独立模型,它们是Transformer训练过程中产生的表示。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询