参考博客:


  1. https://spaces.ac.cn/archives/4122 (力荐)

embedding的作用大体上有两点:

  1. 降低one-hot编码带来的特征稀疏与维度过大的问题。
  2. 通过嵌入矩阵将one-hot编码的输入样例转换为非稀疏向量后,可以通过各种方法(余弦等方法)计算样例之间的相似度,便于理解。

one-hot编码矩阵的优点与问题:

对于由多个词组成的一个句子而言(英文句子),one-hot编码矩阵的shape为(词的数量,词表的长度),当词表特别大的时候,编码矩阵的列数就非常大,同时这样的矩阵是稀疏的。当然,这样也有优点,那就是在计算的时候会容易一些(大量的0,少量的1,计算方便)。但是它的维度太大了,同时大部分都是0,这就造成了存储空间的浪费。

嵌入矩阵的引入

如果有一种方法,能在保持甚至是降低计算量的同时,减少one-hot矩阵的维度与稀疏程度就好了。由此embedding被引入。嵌入矩阵的shape为(词表的长度, 自己定义的输出维度)。可以看到one-hot编码矩阵的列数与嵌入矩阵的行数一致。由此它们可以进行内积,如下图所示。

embedding层 作用 embedding的作用_embedding


它们内积的结果就是embedding层的输出结果。在代码实现中,没有进行实际的矩阵运算,而是通过映射(查表)的方式实现。拿上面的例子来说,由于编码矩阵第一行的第一个元素是1,那么我们取右面嵌入矩阵的第一行,编码矩阵的第二行第二个元素是1,那么我们取右面嵌入矩阵的第二行。由此,我们避免了计算,同时降低了原矩阵的稀疏度和维度。

NLP中的word2vec

对于NLP来说,其word2vec有两种算法来进行embedding,这两篇博客讲的很好:


个人认为:

  1. 传统的embedding层是对每个特征训练一个与之对应的embedding层,通过训练得到的label与真实label来进行反馈。
  2. word2vec是拿全部语料进行训练,CBOW通过真实的中心词对应的V维向量(y_true:one hot向量,只有中心词对应的位置是1,其余都为0)与前向传播得到的V维向量(y_pred:softmax计算得到的各个类别的概率)进行反馈。同理,skip-gram是通过背景词对应的V维向量与前向传播得到的V维向量进行反馈。

看代码的是时候我发现,embedding层的输入都是词表的索引而不是编码好的one-hot矩阵,去官网看了下。

https://tensorflow.google.cn/api_docs/python/tf/keras/layers/Embedding?hl=en&version=stable

上面这么说的:

Turns positive integers (indexes) into dense vectors of fixed size.

所以,函数的输入维度为index的最大值+1,也就是转换后的one-hot矩阵的列数,输入长度一般为padding的长度(一般为maxlen)。

由word2vec训练好的词向量可以通过设置embedding层weights的方法来使用,同时trainable设置为False

  1. https://github.com/MoyanZitto/keras-cn/blob/master/docs/legacy/blog/word_embedding.md
from keras.layers import Embedding

embedding_layer = Embedding(len(word_index) + 1,
                            EMBEDDING_DIM,
                            weights=[embedding_matrix],
                            input_length=MAX_SEQUENCE_LENGTH,
                            trainable=False)