🔎大家好,我是Sonhhxg_柒,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎
📝个人主页-Sonhhxg_柒的博客_CSDN博客 📃
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝
📣系列专栏 - 机器学习【ML】 自然语言处理【NLP】 深度学习【DL】
🖍foreword
✔说明⇢本人讲解主要包括Python、机器学习(ML)、深度学习(DL)、自然语言处理(NLP)等内容。
如果你对这个系列感兴趣的话,可以关注订阅哟👋
文章目录
什么是词向量/词嵌入
词向量的理解 TODO
Word2Vec
基于层次 SoftMax 的 CBOW 模型
层次 SoftMax 的正向传播
层次 Softmax 的反向传播 TODO
基于层次 Softmax 的 Skip-gram 模型
---
基于负采样的 CBOW 和 Skip-gram
负采样算法
Word2Vec 中的做法
一些源码细节
σ(x) 的近似计算
低频词的处理
高频词的处理
自适应学习率
参数初始化
GloVe
共现矩阵
构架共现矩阵的细节
GloVe 的基本思想
GloVe 的目标函数
GloVe 目标函数的推导过程
GloVe 与 Word2Vec 的区别
FastText
gensim.models.FastText 使用示例
获取单个词的 ngrams 表示
计算一个未登录词的词向量
WordRank TODO
CharCNN 字向量
其他实践
一般 embedding 维度的选择
word2vec 中的数学原理详解(三)背景知识 - CSDN博客
One-hot 表示
分布式表示 (distributed representation)
Word2Vec 本质上也是一个神经语言模型,但是它的目标并不是语言模型本身,而是词向量;因此,其所作的一系列优化,都是为了更快更好的得到词向量
Word2Vec 提供了两套模型:CBOW 和 Skip-Gram(SG)
context(w) 的情况下,预测 ww 的情况下预测 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 (负采样)
【输入层】将 context(w) 中的词映射为 m 维词向量,共 2c 个
【投影层】将输入层的 2c 个词向量累加求和,得到新的 m 维词向量
【输出层】输出层对应一棵哈夫曼树,以词表中词作为叶子节点,各词的出现频率作为权重——共 N 个叶子节点,N-1 个非叶子节点

对比 N-gram 神经语言模型的网络结构
w 的前 n-1 个词,后者使用 w 两边的词 这是后者词向量的性能优于前者的主要原因
模型改进
层 Softmax 实际上是把一个超大的多分类问题转化成一系列二分类问题
示例:求 P("足球"|context("足球"))

从根节点到“足球”所在的叶子节点,需要经过 4 个分支,每次分支相当于一次二分类(逻辑斯蒂回归,二元Softmax)

这里遵从原文,将 0 作为正类,1 作为负类
而 P("足球"|context("足球")) 就是每次分类正确的概率之积,即
![]()
这里每个非叶子都对应一个参数
θ_i
为什么层次 SoftMax 能加速
word2vec 中的数学原理详解(四)基于 Hierarchical Softmax 的模型 - CSDN博客
这里保留了【投影层】,但实际上只是一个恒等变换

从模型的角度看:CBOW 与 SG 模型的区别仅在于 x_w 的构造方式不同,前者是 context(w) 的词向量累加;后者就是 w 的词向量
虽然 SG 模型用中心词做特征,上下文词做类标,但实际上两者的地位是等价的
噪音对比估计(NCE) - CSDN博客
(context(w), w) 二元对;对于给定的 context(w),w 就是它的正样本,而其他所有词都是负样本。w ,生成相应负样本的方法
记

以这 N+1 个点对区间 [0,1] 做非等距切分
引入的一个在区间 [0,1] 上的 M 等距切分,其中 M >> N

源码中取
M = 10^8
然后对两个切分做投影,得到映射关系
![]()
采样时,每次生成一个 [1, M-1] 之间的整数 i,则 Table(i) 就对应一个样本;当采样到正例时,跳过(拒绝采样)。
特别的,Word2Vec 在计算 len(w) 时做了一些改动——为 count(·) 加了一个指数

σ(x) 的近似计算类似带权采样的策略,用查表来代替计算

具体计算公式如下

因为
σ(x)函数的饱和性,当x < -6 || x > 6时,函数值基本不变了
Sub-sampling 技巧
t,将 w 以 p(w) 的概率舍弃,p(w) 的计算如下 
Word2Vec 中的Sub-sampling
t 的词p(w),效果是类似的 
预先设置一个初始的学习率 η_0(默认 0.025),每处理完 M(默认 10000)个词,就根据以下公式调整学习率
![]()
随着训练的进行,学习率会主键减小,并趋向于 0
为了方式学习率过小,Word2Vec 设置了一个阈值 η_min(默认 0.0001 * η_0);当学习率小于 η_min,则固定为 η_min。
[-0.5/m, 0.5/m],其中 m 为词向量的维度0CS224d - L2&3-词向量
基于文档 - LSA 模型(SVD分解)
基于窗口 - 类似 skip-gram 模型中的方法

skip_window = 1的共现矩阵
min(x, t) x 为功能词语其他词的共现次数,t 为设置的阈值但是似乎没有人这么做
GloVe 模型的是基于共现矩阵构建的
GloVe 认为共现矩阵可以通过一些统计信息得到词之间的关系,这些关系可以一定程度上表达词的含义

说明 TODO
GloVe 的基本思想:

其中
w_i 和 w_j 为词向量
x_ij 为 w_i 和 w_j 的共现次数
f(x) 是一个权重函数,为了限制高频词和防止 x_ij = 0

x_ij = 0 时,有 ![]()
以前整理在 OneNote 上的,有时间在整理
目标函数





w_i 的权重函数

实际 Word2Vec 已结有了一些对高频词的措施 > 高频词的处理
FastText 是从 Word2Vec 的 CBOW 模型演化而来的;
从网络的角度来看,两者的模型基本一致;区别仅在于两者的输入和目标函数不同;

基于层次 SoftMax 的 CBOW 模型
FastText 与 CBOW 的相同点:
不同点:
skip_window内的上下文词;FastText 除了上下文词外,还包括这些词的字符级 N-gram 特征注意,字符级 N-gram 只限制在单个词内,以英文为例
// 源码中计算 n-grams 的声明,只计算单个词的字符级 n-gram
compute_ngrams(word, unsigned int min_n, unsigned int max_n); # > https://github.com/vrasneur/pyfasttext#get-the-subwords
>>> model.args.get('minn'), model.args.get('maxn')
(2, 4)
# 调用源码的 Python 接口,源码上也会添加 '<' 和 '>'
>>> model.get_all_subwords('hello') # word + subwords from 2 to 4 characters
['hello', '', 'lo', 'lo>', 'o>']
>>> # model.get_all_subwords('hello world') # warning 值得一提的是,因为 FastText 使用了字符级的 N-gram 向量作为额外的特征,使其能够对未登录词也能输出相应的词向量;
具体来说,未登录词的词向量等于其 N-gram 向量的叠加
gensim.models.FastText 使用示例../codes/FastText
# gensim 示例
import gensim
import numpy as np
from gensim.test.utils import common_texts
from gensim.models.keyedvectors import FastTextKeyedVectors
from gensim.models._utils_any2vec import compute_ngrams, ft_hash
from gensim.models import FastText# 构建 FastText 模型
sentences = [["Hello", "World", "!"], ["I", "am", "huay", "."]]
min_ngrams, max_ngrams = 2, 4 # ngrams 范围
model = FastText(sentences, size=5, min_count=1, min_n=min_ngrams, max_n=max_ngrams)# 可以通过相同的方式获取每个单词以及任一个 n-gram 的向量
print(model.wv['hello'])
print(model.wv[' compute_ngrams 方法,gensim 提供了该方法的 Python 接口 sum_ngrams = 0
for s in sentences:for w in s:w = w.lower()# from gensim.models._utils_any2vec import compute_ngramsret = compute_ngrams(w, min_ngrams, max_ngrams) print(ret)sum_ngrams += len(ret)
"""
['', '', '']
['', '', '']
['', '']
['', '']
['', '', '']
['', '', '']
['<.', '.>', '<.>']
"""
assert sum_ngrams == len(model.wv.vectors_ngrams)
print(sum_ngrams) # 57
print() 未登录词实际上是已知 n-grams 向量的叠加平均
# 因为 "a", "aa", "aaa" 中都只含有 " 只要未登录词能被已知的 n-grams 组合,就能得到该词的词向量
gensim.models.keyedvectors.FastTextKeyedVectors.word_vec(token)的内部实现
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.bucketif ngram_hash in model.wv.hash2index:word_vec += model.wv.vectors_ngrams[model.wv.hash2index[ngram_hash]]ngrams_found += 1if 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_vectorreturn self.word_vec(word)File "D:\program\work\Python\Anaconda3\envs\tf\lib\site-packages\gensim\models \keyedvectors.py", line 1989, in word_vecraise KeyError('all ngrams for word %s absent from model' % word)
KeyError: 'all ngrams for word z absent from model'
""" [1509] Character-level Convolutional Networks for Text Classification
Feature Columns | TensorFlow
embedding_size = n_categories ** 0.25100~300 如果根据经验公式,是不需要这么大的,比如 200W 词表的词向量维度只需要
200W ** 0.25 ≈ 37