将正整数(索引)转换为固定大小的密集向量。例如。
[[4], [20]]
- >[[0.25, 0.1], [0.6, -0.2]]
我相信这也可以通过将输入编码为长度为vocabulary_size
的单热矢量并将它们输入Embedding Layer来实现。
嵌入层是否仅仅是这个两步过程的便利,还是引人入胜的东西?
答案 0 :(得分:21)
数学上,区别在于:
嵌入层执行选择操作。在keras中,该层相当于:
K.gather(self.embeddings, inputs) # just one matrix
密集层执行 dot-product 操作,以及可选的激活:
outputs = matmul(inputs, self.kernel) # a kernel matrix
outputs = bias_add(outputs, self.bias) # a bias vector
return self.activation(outputs) # an activation function
您可以通过单热编码模拟具有完全连接层的嵌入层,但是密集嵌入的整个要点是避免单热表示。在NLP中,词汇量大小可以是100k(有时甚至是一百万)。最重要的是,通常需要批量处理单词序列。处理一批字索引序列将比一批热矢量序列更有效。此外,gather
操作本身比矩阵点积更快,无论是向前还是向后传递。
答案 1 :(得分:7)
嵌入层更快,因为它基本上等同于简化假设的密集层。
想象一下具有以下权重的单词到嵌入层:
w = [[0.1, 0.2, 0.3, 0.4],
[0.5, 0.6, 0.7, 0.8],
[0.9, 0.0, 0.1, 0.2]]
Dense
层将像对待执行矩阵乘法的实际权重一样对待。嵌入层会将这些权重简单地视为向量列表,每个向量代表一个单词;词汇表中的第0个单词是w[0]
,第1个单词是w[1]
,等等。
例如,使用上面的权重和这句话:
[0, 2, 1, 2]
基于Dense
的幼稚网络需要将该句子转换为1-hot编码
[[1, 0, 0],
[0, 0, 1],
[0, 1, 0],
[0, 0, 1]]
然后进行矩阵乘法
[[1 * 0.1 + 0 * 0.5 + 0 * 0.9, 1 * 0.2 + 0 * 0.6 + 0 * 0.0, 1 * 0.3 + 0 * 0.7 + 0 * 0.1, 1 * 0.4 + 0 * 0.8 + 0 * 0.2],
[0 * 0.1 + 0 * 0.5 + 1 * 0.9, 0 * 0.2 + 0 * 0.6 + 1 * 0.0, 0 * 0.3 + 0 * 0.7 + 1 * 0.1, 0 * 0.4 + 0 * 0.8 + 1 * 0.2],
[0 * 0.1 + 1 * 0.5 + 0 * 0.9, 0 * 0.2 + 1 * 0.6 + 0 * 0.0, 0 * 0.3 + 1 * 0.7 + 0 * 0.1, 0 * 0.4 + 1 * 0.8 + 0 * 0.2],
[0 * 0.1 + 0 * 0.5 + 1 * 0.9, 0 * 0.2 + 0 * 0.6 + 1 * 0.0, 0 * 0.3 + 0 * 0.7 + 1 * 0.1, 0 * 0.4 + 0 * 0.8 + 1 * 0.2]]
=
[[0.1, 0.2, 0.3, 0.4],
[0.9, 0.0, 0.1, 0.2],
[0.5, 0.6, 0.7, 0.8],
[0.9, 0.0, 0.1, 0.2]]
但是,Embedding
层只是看[0, 2, 1, 2]
并采用索引为零,二,一和二的权重来立即获得
[w[0],
w[2],
w[1],
w[2]]
=
[[0.1, 0.2, 0.3, 0.4],
[0.9, 0.0, 0.1, 0.2],
[0.5, 0.6, 0.7, 0.8],
[0.9, 0.0, 0.1, 0.2]]
所以是相同的结果,只是希望以更快的方式获得。
Embedding
层确实有局限性:
但是,如果您只想将整数编码的单词转换为嵌入内容,那么这些限制都不重要。