文本表示(Word Representation)
one-hot表征
最简单的词汇的表达方式是建立一个较大的词汇表(例如10000),然后使用one-hot的方式对每个单词进行编码。例如单词Man,Woman分别出现在词汇表的第12,557的位置,则它们分别用表示
O
12
,
O
557
O_{12},O_{557}
O12?,O557? 这种方法优点是比较简答,直观,缺点就是每个单词是正交的,即任意两个单词内积都为零,也即任意两个单词都是独立的,没有任何的关系,还有就是当词汇表很大的时候,那么表示一个单词的维度就会变得非常大。
词嵌入(word embedding)
用不同的特征来对各个词汇进行表征,相同特征的词汇在线性空间中非常相近,即相似的词汇向量表示方法差不多。
将其放在空间去看,或者映射到低维去看,相似的词汇总是聚集在一块。
使用word embedding时,就算当前的遇到的词汇是陌生词汇,即没有在词汇表中出现,也可以根据word embedding的结果得到与其词性相近的单词,从而得到与该单词相近的结果
词嵌入的特征
如上图所示,,通过不同词向量之间的相减计算,可以发现不同词之间的类比关系,man——woman、king——queen,可以发现这两对主要区别是性别。 词与词之间的相似度
s
i
m
(
u
,
v
)
=
u
T
v
∥
u
∥
2
∥
v
∥
2
sim(u,v) = \frac{u^Tv}{\lVert u \rVert _2 \lVert v \rVert _2}
sim(u,v)=∥u∥2?∥v∥2?uTv?
- 欧式距离:
∥
u
?
v
∥
2
\lVert u-v \lVert ^2
∥u?v∥2
词嵌入矩阵
e
w
=
E
?
O
w
e_w = E*O_w
ew?=E?Ow?
- E 表示嵌入矩阵
-
O
w
O_w
Ow?表示一个词汇的one-hot编码
-
e
w
e_w
ew? embedding vertor
Word2vec
上面讨论了嵌入矩阵能够生成分布式词向量,那么怎么得到这个嵌入式矩阵呢?
word2vec和word embdding的关系:word embedding 是将一个词向量化,将单词原先所属的空间映射到新的多维空间中。而word2vec是word embedding的一种工具或方法
skip-gram和Cbow
Word2Vec模型中,主要有Skip-Gram和CBOW两种模型,从直观上理解,Skip-Gram是给定input word来预测上下文。而CBOW是给定上下文,来预测input word。 先看skip-gram
假如我们选定句子“The quick brown fox jumps over lazy dog”,设定我们的窗口大小为2,即skip_window=2,也就是选取中心词的左右两个词汇进行组合。num_skip表示从组合的词汇中选取多少个用作训练。下图中,蓝色代表input word,方框内代表位于窗口内的单词。 训练细节
- 对词汇进行编码,一开始使用one-hot编码,有多少词汇,one-hot编码就有多少维度
- 设置参数skip_window和num_skip,这样得到num_skip组词汇对,这些作为训练数据
训练完之后,我们需要的是隐藏层的权重矩阵,也就是嵌入矩阵,将one-hot编码的词向量和这个矩阵相乘就得到分布式词向量。
CBOW
大致的过程和方法和skip-gram差不多,只是CBOW是多个输入来预测一个输出。
- 输入层:n个上下文词的one-hot编码和矩阵W相乘
- 投影层:将n个词向量求加权平均数
- 输出层:对应一个预测的单词,标签是中心词
word2vec两种优化方法
一般神经网络语言模型在预测的时候,输出的是预测目标词的概率,也就是说我每一次预测都要基于全部的数据集进行计算,这无疑会带来很大的时间开销,下面开始讨论两种优化方法。
hierarchical softmax
hierarchical softmax结构是把输出层改成了一颗哈夫曼树,哈夫曼树的每一个叶子结点是词汇表中的一个词汇,构造树的时候依照词频来决定每个词汇的位置(学过数据结构的应该都会构造一颗哈夫曼树)
- h表示隐藏层状态
- v表示非叶子节点对应的参数向量
我们根据隐藏层状态和各个非叶子节点进行运算来判断往左边还是右边继续走,重复以上运算,直到到达叶子结点,将此时所预测的词汇和标签进行比较,假设标签词汇是
W
0
W_0
W0?,预测词汇
W
1
W_1
W1?,那么我只需要去更新从根结点到
W
1
W_1
W1?这一个叶子结点的路径上面节点的向量即可,而不需要更新所有的词的出现概率,这样大大的缩小了模型训练更新的时间。
负采样(negative sampling)
当我们用训练样本 ( input word: “fox”,output word: “quick”) 来训练我们的神经网络时,“ fox”和“quick”都是经过one-hot编码的。如果我们的vocabulary大小为10000时,在输出层,我们期望对应“quick”单词的那个神经元结点输出1,其余9999个都应该输出0。在这里,这9999个我们期望输出为0的神经元结点所对应的单词我们称为“negative” word。
当使用负采样时,我们将随机选择一小部分的negative words(比如选5个negative words)来更新对应的权重。我们也会对我们的“positive” word进行权重更新(在我们上面的例子中,这个单词指的是”quick“)。 回忆一下我们的隐层-输出层拥有300 x 10000的权重矩阵。如果使用了负采样的方法我们仅仅去更新我们的positive word-“quick”的和我们选择的其他5个negative words的结点对应的权重,共计6个输出神经元,相当于每次只更新[公式]个权重。对于3百万的权重来说,相当于只计算了0.06%的权重,这样计算效率就大幅度提高。
一个单词被选作negative sample的概率跟它出现的频次有关,出现频次越高的单词越容易被选作negative words。
参考
https://zhuanlan.zhihu.com/p/35074402
https://zhuanlan.zhihu.com/p/27234078
https://blog.csdn.net/red_stone1/article/details/79648626
|