嵌入层和密集层之间有什么区别?

Imr*_*ran 20 machine-learning neural-network deep-learning keras keras-layer

Keras 嵌入层的文档说:

将正整数(索引)转换为固定大小的密集向量.例如.[[4], [20]]- >[[0.25, 0.1], [0.6, -0.2]]

我相信这也可以通过将输入编码为长度的一个热矢量vocabulary_size并将它们馈送到密集层来实现.

嵌入层只是这个两步过程的便利,还是引人入胜的东西?

Max*_*xim 26

在数学上,区别在于:

  • 嵌入层执行选择操作.在keras中,这一层相当于:

    K.gather(self.embeddings, inputs)      # just one matrix
    
    Run Code Online (Sandbox Code Playgroud)
  • 密集层执行点积操作,以及可选的激活:

    outputs = matmul(inputs, self.kernel)  # a kernel matrix
    outputs = bias_add(outputs, self.bias) # a bias vector
    return self.activation(outputs)        # an activation function
    
    Run Code Online (Sandbox Code Playgroud)

您可以通过单热编码模拟具有完全连接层的嵌入层,但是密集嵌入的整个要点是避免单热表示.在NLP中,词汇量大小可以是100k(有时甚至是一百万).最重要的是,通常需要批量处理单词序列.处理一批字索引序列将比一批热矢量序列更有效.此外,gather在前向和后向传递中,操作本身比矩阵点积更快.

  • 文字段落很有帮助,但是我一开始并不理解该部分,因为该部分应该解释嵌入层的工作方式。关心详细吗?选择,收集,自我嵌入到底是什么?这如何用一键编码模拟密集层? (4认同)
  • 有人可以详细说明嵌入层如何避免进行一次热编码吗? (3认同)
  • 大家好,我同意您提到的代表效率。但是,针对查找嵌入与密集层嵌入进行优化的可用参数数量(几乎)相同,即vocab_size x embedding_dim,因此从这一方面来看并没有太大区别。当表示效率不成问题时(例如,对于字符级编码),是否还有其他原因更喜欢查找嵌入而不是密集层?(我看到您提到计算时间) (2认同)
  • @Make42 看看戴帽子的人的回答 (2认同)
  • @sahu 看看戴帽子的人的回答 (2认同)

The*_*Hat 5

嵌入层更快,因为它基本上等同于简化假设的密集层。

想象一下一个具有以下权重的词到嵌入层:

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]]
Run Code Online (Sandbox Code Playgroud)

Dense层将治疗这些像实际重量与要对其执行矩阵乘法。嵌入层会将这些权重简单地视为向量列表,每个向量代表一个单词;词汇表中的第0个单词是w[0],第1个单词是,依此类推w[1]


例如,使用上面的权重和这句话:

[0, 2, 1, 2]
Run Code Online (Sandbox Code Playgroud)

Dense基于幼稚的网络需要将该句子转换为1-hot编码

[[1, 0, 0],
 [0, 0, 1],
 [0, 1, 0],
 [0, 0, 1]]
Run Code Online (Sandbox Code Playgroud)

然后做一个矩阵乘法

[[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]]
Run Code Online (Sandbox Code Playgroud)

=

[[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]]
Run Code Online (Sandbox Code Playgroud)

但是,Embedding一层只是看一下[0, 2, 1, 2]并采用索引为零,二,一和二的权重立即获取

[w[0],
 w[2],
 w[1],
 w[2]]
Run Code Online (Sandbox Code Playgroud)

=

[[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]]
Run Code Online (Sandbox Code Playgroud)

所以这是相同的结果,只是希望以更快的方式获得。


Embedding层确实有局限性:

  • 输入必须是[0,vocab_length)中的整数。
  • 没有偏见。
  • 没有激活。

但是,如果您只想将整数编码的单词转换为嵌入,则这些限制都不重要。

  • 感谢您的明确解释。恕我直言,这应该是公认的答案。 (2认同)