词向量
NLP-词向量
Index
背景知识
神经语言模型
什么是词向量/词嵌入
词向量(word embedding)是一个固定长度的实值向量
词向量是神经语言模型的副产品。
词向量是针对“词”提出的。事实上,也可以针对更细或更粗的粒度来进行推广——比如字向量、句向量、文档向量等
词向量的理解 TODO
word2vec 中的数学原理详解(三)背景知识 - CSDN博客
在 NLP 任务中,因为机器无法直接理解自然语言,所以首先要做的就是将语言数学化——词向量就是一种将自然语言数学化的方法。
One-hot 表示
TODO
分布式表示 (distributed representation)
分布式假设
TODO
常见的分布式表示方法
潜在语义分析 (Latent Semantic Analysis, LSA)
SVD 分解
隐含狄利克雷分布 (Latent Dirichlet Allocation, LDA),主题模型
神经网络、深度学习
Word2Vec
Word2Vec 本质上也是一个神经语言模型,但是它的目标并不是语言模型本身,而是词向量;因此,其所作的一系列优化,都是为了更快更好的得到词向量
Word2Vec 提供了两套模型:CBOW 和 Skip-Gram(SG)
CBOW 在已知
context(w)
的情况下,预测w
SG 在已知
w
的情况下预测context(w)
从训练集的构建方式可以更好的理解和区别 CBOW 和 SG 模型
每个训练样本为一个二元组
(x, y)
,其中x
为特征,y
为标签假设上下文窗口的大小
context_window =5
,即或者说
skip_window = 2
,有context_window = skip_window*2 + 1
CBOW 的训练样本为:
SG 的训练样本为:
一般来说,
skip_window <= 10
除了两套模型,Word2Vec 还提供了两套优化方案,分别基于 Hierarchical Softmax (层次SoftMax) 和 Negative Sampling (负采样)
基于层次 SoftMax 的 CBOW 模型
【输入层】将
context(w)
中的词映射为m
维词向量,共2c
个【投影层】将输入层的
2c
个词向量累加求和,得到新的m
维词向量【输入层】前者使用的是
w
的前n-1
个词,后者使用w
两边的词这是后者词向量的性能优于前者的主要原因
【投影层】前者通过拼接,后者通过累加求和
【隐藏层】后者无隐藏层
【输出层】前者为线性结构,后者为树形结构
模型改进
从对比中可以看出,CBOW 模型的主要改进都是为了减少计算量——取消隐藏层、使用层Softmax代替基本Softmax
层次 SoftMax 的正向传播
层 Softmax 实际上是把一个超大的多分类问题转化成一系列二分类问题
从根节点到“足球”所在的叶子节点,需要经过 4 个分支,每次分支相当于一次二分类(逻辑斯蒂回归,二元Softmax)
这里遵从原文,将 0 作为正类,1 作为负类
而
P("足球"|context("足球"))
就是每次分类正确的概率之积,即这里每个非叶子都对应一个参数
θ_i
为什么层次 SoftMax 能加速
Softmax 大部分的计算量在于分母部分,它需要求出所有分量的和
而层次 SoftMax 每次只需要计算两个分量,因此极大的提升了速度
层次 Softmax 的反向传播 TODO
基于层次 Softmax 的 Skip-gram 模型
从模型的角度看:CBOW 与 SG 模型的区别仅在于
x_w
的构造方式不同,前者是context(w)
的词向量累加;后者就是w
的词向量虽然 SG 模型用中心词做特征,上下文词做类标,但实际上两者的地位是等价的
---
基于负采样的 CBOW 和 Skip-gram
层次 Softmax 还不够简单,于是提出了基于负采样的方法进一步提升性能
负采样(Negative Sampling)是 NCE(Noise Contrastive Estimation) 的简化版本
噪音对比估计(NCE) - CSDN博客
CBOW 的训练样本是一个
(context(w), w)
二元对;对于给定的context(w)
,w
就是它的正样本,而其他所有词都是负样本。如果不使用负采样,即 N-gram 神经语言模型中的做法,就是对整个词表 Softmax 和交叉熵
负采样相当于选取所有负例中的一部分作为负样本,从而减少计算量
Skip-gram 模型同理
负采样算法
负采样算法,即对给定的
w
,生成相应负样本的方法最简单的方法是随机采样,但这会产生一点问题,词表中的词出现频率并不相同
如果不是从词表中采样,而是从语料中采样;显然,那些高频词被选为负样本的概率要大于低频词
在词表中采样时也应该遵循这个
因此,负采样算法实际上就是一个带权采样过程
Word2Vec 中的做法
记
以这
N+1
个点对区间[0,1]
做非等距切分源码中取
M = 10^8
然后对两个切分做投影,得到映射关系
采样时,每次生成一个
[1, M-1]
之间的整数i
,则Table(i)
就对应一个样本;当采样到正例时,跳过(拒绝采样)。特别的,Word2Vec 在计算
len(w)
时做了一些改动——为count(·)
加了一个指数
一些源码细节
σ(x)
的近似计算
σ(x)
的近似计算具体计算公式如下
因为
σ(x)
函数的饱和性,当x < -6 || x > 6
时,函数值基本不变了
低频词的处理
对于低频词,会设置阈值(默认 5),对于出现频次低于该阈值的词会直接舍弃,同时训练集中也会被删除
高频词的处理
高频词提供的信息相对较少,为了提高低频词的词向量质量,有必要对高频词进行限制
高频词对应的词向量在训练时,不会发生明显的变化,因此在训练是可以减少对这些词的训练,从而提升速度
Sub-sampling 技巧
源码中使用 Sub-sampling 技巧来解决高频词的问题,能带来 2~10 倍的训练速度提升,同时提高低频词的词向量精度
给定一个词频阈值
t
,将w
以p(w)
的概率舍弃,p(w)
的计算如下
Word2Vec 中的Sub-sampling
显然,Sub-Sampling 只会针对 出现频次大于
t
的词特别的,Word2Vec 使用如下公式计算
p(w)
,效果是类似的
自适应学习率
预先设置一个初始的学习率
η_0
(默认 0.025),每处理完M
(默认 10000)个词,就根据以下公式调整学习率随着训练的进行,学习率会主键减小,并趋向于 0
为了方式学习率过小,Word2Vec 设置了一个阈值
η_min
(默认0.0001 * η_0
);当学习率小于η_min
,则固定为η_min
。
参数初始化
词向量服从均匀分布
[-0.5/m, 0.5/m]
,其中m
为词向量的维度所有网络参数初始化为
0
GloVe
CS224d - L2&3-词向量
共现矩阵
共现矩阵的实现方式
基于文档 - LSA 模型(SVD分解)
skip_window = 1
的共现矩阵
构架共现矩阵的细节
功能词的处理
功能词:如 "the", "he", "has", ...
法1)直接忽略
在一些分类问题上可以这么做;如果目标是词向量,则不建议使用这种方法
法2)设置阈值
min(x, t)
其中
x
为功能词语其他词的共现次数,t
为设置的阈值
可以尝试使用一些方法代替单纯的计数,如皮尔逊相关系数,负数记为 0
但是似乎没有人这么做
GloVe 的基本思想
GloVe 模型的是基于共现矩阵构建的
solid related to ice but not steam
gas related to stream but not ice
water related to both
fashion relate not to both
说明 TODO
GloVe 的基本思想:
假设词向量已知,如果这些词向量通过某个函数(目标函数)可以拟合共现矩阵中的统计信息,那么可以认为这些词向量也拥有了共现矩阵中蕴含的语义
模型的训练过程就是拟合词向量的过程
GloVe 的目标函数
其中
w_i
和w_j
为词向量x_ij
为w_i
和w_j
的共现次数当
x_ij = 0
时,有
GloVe 目标函数的推导过程
以前整理在 OneNote 上的,有时间在整理
目标函数
w_i
的权重函数
GloVe 与 Word2Vec 的区别
Word2Vec 本质上是一个神经网络;
Glove 也利用了反向传播来更新词向量,但是结构要更简单,所以 GloVe 的速度更快
Glove 认为 Word2Vec 对高频词的处理还不够,导致速度慢;GloVe 认为共现矩阵可以解决这个问题
实际 Word2Vec 已结有了一些对高频词的措施 > 高频词的处理
从效果上看,虽然 GloVe 的训练速度更快,但是词向量的性能在通用性上要弱一些: 在一些任务上表现优于 Word2Vec,但是在更多的任务上要比 Word2Vec 差
FastText
FastText 与 CBOW 的相同点:
包含三层:输入层、隐含层、输出层(Hierarchical Softmax)
输入都是多个单词的词向量
隐藏层(投影层)都是对多个词向量的叠加平均
输出都是一个特定的 target
从网络的角度看,两者基本一致
不同点:
CBOW 的输入是中心词两侧
skip_window
内的上下文词;FastText 除了上下文词外,还包括这些词的字符级 N-gram 特征
注意,字符级 N-gram 只限制在单个词内,以英文为例
值得一提的是,因为 FastText 使用了字符级的 N-gram 向量作为额外的特征,使其能够对未登录词也能输出相应的词向量;
具体来说,未登录词的词向量等于其 N-gram 向量的叠加
gensim.models.FastText
使用示例
gensim.models.FastText
使用示例../codes/FastText
构建 FastText 以及获取词向量
获取单个词的 ngrams 表示
利用源码中
compute_ngrams
方法,gensim 提供了该方法的 Python 接口
计算一个未登录词的词向量
未登录词实际上是已知 n-grams 向量的叠加平均
只要未登录词能被已知的 n-grams 组合,就能得到该词的词向量
gensim.models.keyedvectors.FastTextKeyedVectors.word_vec(token)
的内部实现```Python word_unk = "aam" ngrams = compute_ngrams(word_unk, min_ngrams, max_ngrams) # min_ngrams, max_ngrams = 2, 4 word_vec = np.zeros(model.vector_size, dtype=np.float32) ngrams_found = 0 for ngram in ngrams: ngram_hash = ft_hash(ngram) % model.bucket if ngram_hash in model.wv.hash2index: word_vec += model.wv.vectors_ngrams[model.wv.hash2index[ngram_hash]] ngrams_found += 1
if word_vec.any(): # word_vec = word_vec / max(1, ngrams_found) else: # 如果一个 ngram 都没找到,gensim 会报错;个人认为把 0 向量传出来也可以 raise KeyError('all ngrams for word %s absent from model' % word_unk)
print(word_vec) print(model.wv["aam"]) """ [ 0.02210762 -0.10488641 0.05512805 0.09150169 0.00725085] [ 0.02210762 -0.10488641 0.05512805 0.09150169 0.00725085] """
如果一个 ngram 都没找到,gensim 会报错
其实可以返回一个 0 向量的,它内部实际上是从一个 0 向量开始累加的;
但返回时做了一个判断——如果依然是 0 向量,则报错
print(model.wv['z'])
""" Traceback (most recent call last): File "D:/OneDrive/workspace/github/DL-Notes-for-Interview/code/工具库 /gensim/FastText.py", line 53, in print(model.wv['z']) File "D:\program\work\Python\Anaconda3\envs\tf\lib\site-packages\gensim\models \keyedvectors.py", line 336, in getitem return self.get_vector(entities) File "D:\program\work\Python\Anaconda3\envs\tf\lib\site-packages\gensim\models \keyedvectors.py", line 454, in get_vector return self.word_vec(word) File "D:\program\work\Python\Anaconda3\envs\tf\lib\site-packages\gensim\models \keyedvectors.py", line 1989, in word_vec raise KeyError('all ngrams for word %s absent from model' % word) KeyError: 'all ngrams for word z absent from model' """
```
WordRank TODO
CharCNN 字向量
CharCNN 的思想是通过字符向量得到词向量
[1509] Character-level Convolutional Networks for Text Classification
其他实践
一般 embedding 维度的选择
Feature Columns | TensorFlow
经验公式
embedding_size = n_categories ** 0.25
在大型语料上训练的词向量维度通常会设置的更大一些,比如
100~300
如果根据经验公式,是不需要这么大的,比如 200W 词表的词向量维度只需要
200W ** 0.25 ≈ 37
最后更新于