对一个中心词,与窗口内的context词出现的概率:
通过极大似然方法最大化整个文本出现的概率:
损失函数:
假设vocabulary包含m个词,每个词向量长度为n, 对于每一个词,作为中心词(center)和非中心词(outside)时分别使用v和u两个向量表示。在计算完成后将两个向量平均作为最终词向量表示。
对每一个词作为中心词时,计算概率分布。这里假定第4个词作为中心词时,有
其中,d为与m个outside词的点积,由于两个向量的点乘可以表示其相似度,进一步可用于表示其出现的概率大小,从而得到概率表示:
这里原理就很明显了,我们接下来需要做的,就是通过优化问题来更新矩阵U和V,从而使词向量模型需对出现在同一个context中的词赋予较大的概率。
通过以上计算过程可以知道,如果两个词出现在一个context的次数越频繁,那么他们的词向量就会越接近,这样一来像the这样的高频词,就会使它前后的词向量高度集中,从而导致一些问题。
梯度是指多元函数在某个点上升最快的方向,那么梯度的反方向当然就是下降最快的方向。从而得到直观的优化公式:
此处∇thetaJ(θ)为损失函数的梯度,α为学习率或步长,是一个超参数。以上是对整个问题的矩阵表示,但在计算过程中,需要一个个的更新参数,所以有对单个参数θj表示为:
在高等数学(同济)中关于梯度的定义如下,及梯度是各个自变量的偏导组成的向量。
在上一小节中提到的梯度下降,为了计算出参数的梯度,需要代入整个数据集,这样一次更新计算量非常大,因此提出随机梯度下降方法,即每一个更新都是从数据及中随机抽样部分数据(batch), 在词向量计算中对每一个window数据计算一次更新。
带有负采样的Skip-grams(HW2)
1)softmax的正则化因子(分母)计算消耗巨大
2)带有负采样(negative sampling)的Skip-grams:
训练一对真词(上下文窗口中的中心词和单词)与几个噪声对(中心词和随机词)的二元逻辑回归(在标准的word2vec和HW2中都使用了负采样)
2)需要最大化目标函数
4)使用与HW2更类似的符号表示
选取了k个负样例(选取概率为P(w)=U(w)3/4/Z)
最大化真实上下文词出现在中心词的概率,最小化随机词出现在中心词的概率
由于使用一个窗口更新一次,由于∇θJt(θ)各个词向量的偏导组成的向量,如果这个词没有出现,其偏导也就为0,因此梯度将非常稀疏。
对应方案:使用稀疏矩阵或者将词hash映射到具体向量,如果是分布式计算,必须避免大量的中间数据在节点之间的传送。
1)Skip-gram(SG):给定中心词预测窗口context(outsides)
2)Continous Bag of Words(CBOW):给定窗口context预测中心词
优点:
缺点:
存在的问题:
解决方法:
使用较低纬度的向量
想法:将“大多数”重要信息存储在一个固定的、少量的维度中:一个密集的向量
通常为25—100维,与word2vec类似
如何减小维度:
1)奇异值分解(SVD)
2)缩放单元格中的计数(Hacks to X (several used in Rohde et al. 2005))
功能词出现太频繁,语法有太大的影响:
左边是基于计数的方法的一些特点:训练快、有效利用了统计信息、初步统计了词的相似性
右边是基于预测的方法的一些特点:可以捕获超出单词相似度的复杂模式
只使用一个大小固定且维度较少的稠密向量来存储最重要的信息。现在的问题是,如何才能有效地降低向量的维度呢?
重要信息:共现概率的比值能够编码单词相似度的信息
从这个例子的最后一行中可以看出,x 与 ice 意思更加接近的话,概率比值远大于 1,x 与 steam 意思更加接近的话,概率比值远小于 1;如果 x 的意思既不与 ice 接近也不与 steam 接近,或者既与 ice 接近又与 steam 接近,那么概率比值在 1 附近
功能:基于语料库构建词的共现矩阵,然后基于共现矩阵和GloVe模型对词汇进行向量化表示
输入:语料库
输出:词向量
例如:句子为"dog barked at the mailman" ,目标单词为’at’
Skip-gram模型:Skip-gram模型只关注单个输入/输出元组中的目标词和上下文中的单个单词,输入为[“dog”, “at”]
CBOW模型:关注目标单词和单个样本中上下文的所有单词,则输入为
[["dog","barked","the","mailman"],"at"]
因此,在给定数据集中,对于指定单词的上下文而言,CBOW比Skip-gram会获取更多的信息。Global Vector融合了矩阵分解的全局统计信息和上下文信息。
1)构建共现矩阵
例如句子为:i love you but you love him i am sad
包括7个单词:i、love、you、but、him、am、sad
设context = 5,则目标单词的左右长度都为2,以下为统计窗口:
注:中心词为目标单词,窗口内容为目标单词的左右各两个单词。
如:“i"左边无单词,右边有两个单词"love”,“you”,所以窗口内容为[“i”,“love”,“you”]
窗口0、1长度小于5是因为中心词左侧内容少于2个,同理窗口8、9长度也小于5。
以窗口5为例说明如何构造共现矩阵。
中心词为love,语境词为but、you、him、i;则执行:
使用窗口将整个语料库遍历一遍,即可得到共现矩阵X。
1)Intrinsic(内部评价)
(1)词向量类比(Word Vector Analogies)
通过捕获直观的语义和句法类比问题之后的余弦距离来评价词向量
问题:如果信息不是线性的?
(2)另一种内部评价
词向量距离及其与人类判断的关系
词义与词义歧义
Improving Word Representations Via Global Context And Multiple Word Prototypes (Huang et al. 2012)
想法:将单词窗口聚集在单词周围,重新训练每个单词,并将其分配给多个不同的集群bank1、bank2等
Linear Algebraic Structure of Word Senses, with Applications to Polysemy (Arora, …, Ma, …, TACL 2018)
# -*- coding: utf-8 -*-
"""
word2vec embeddings start with a line with the number of lines (tokens?) and
the number of dimensions of the file. This allows gensim to allocate memory
accordingly for querying the model. Larger dimensions mean larger memory is
held captive. Accordingly, this line has to be inserted into the GloVe
embeddings file.
"""
import os
import shutil
import smart_open
from sys import platform
import gensim
def prepend_line(infile, outfile, line):
"""
Function use to prepend lines using bash utilities in Linux.
(source: http://stackoverflow.com/a/10850588/610569)
"""
with open(infile, 'r', encoding='UTF-8') as old:
with open(outfile, 'w', encoding='UTF-8') as new:
new.write(str(line) + "\n")
shutil.copyfileobj(old, new)
def prepend_slow(infile, outfile, line):
"""
Slower way to prepend the line by re-creating the inputfile.
"""
with open(infile, 'r', encoding='UTF-8') as fin:
with open(outfile, 'w', encoding='UTF-8') as fout:
fout.write(line + "\n")
for line in fin:
fout.write(line)
def get_lines(glove_file_name):
"""Return the number of vectors and dimensions in a file in GloVe format."""
with smart_open.smart_open(glove_file_name, 'r', encoding='UTF-8') as f:
num_lines = sum(1 for line in f)
with smart_open.smart_open(glove_file_name, 'r', encoding='UTF-8') as f:
num_dims = len(f.readline().split()) - 1
return num_lines, num_dims
# Input: GloVe Model File
# More models can be downloaded from http://nlp.stanford.edu/projects/glove/
glove_file="glove.6B.300d.txt"
num_lines, dims = get_lines(glove_file)
# Output: Gensim Model text format.
gensim_file='glove_model2.txt'
gensim_first_line = "{} {}".format(num_lines, dims)
# Prepends the line.
if platform == "linux" or platform == "linux2":
prepend_line(glove_file, gensim_file, gensim_first_line)
else:
prepend_slow(glove_file, gensim_file, gensim_first_line)
# Demo: Loads the newly created glove_model.txt into gensim API.
model=gensim.models.KeyedVectors.load_word2vec_format(gensim_file, binary=False) #GloVe Model
print(model.most_similar(positive=['australia'], topn=10))
print(model.similarity('woman', 'man'))
斯坦福cs224n-2019链接:https://web.stanford.edu/class/archive/cs/cs224n/cs224n.1194/
bilibili 视频:https://www.bilibili.com/video/BV1s4411N7fC?p=2