请用示例解释Keras中的嵌入层是如何工作的。

23
我不太理解Keras的嵌入层。虽然有很多文章对此进行了解释,但我仍然感到困惑。例如,下面的代码是从IMDb情感分析中提取出来的:
top_words = 5000
max_review_length = 500
embedding_vecor_length = 32    

model = Sequential()
model.add(Embedding(top_words, embedding_vecor_length, input_length=max_review_length))
model.add(LSTM(100))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
print(model.summary())
model.fit(X_train, y_train, nb_epoch=3, batch_size=64)

在这段代码中,嵌入层究竟在做什么?嵌入层的输出是什么?如果有人能用一些例子来解释就好了!

1
可能是什么是Keras中的嵌入?的重复问题。 - DJK
它用Theano解释了,但如果使用Keras中的示例,理解起来会更容易。 - user1670773
图层的数学原理是相同的。 - DJK
你可以看一下我的回答:https://dev59.com/7VoT5IYBdhLWcg3wxxsl#53101566。 - Outcast
2个回答

14

嵌入层将输入的单词创建为嵌入向量(我自己仍然不理解其中的数学原理),类似于word2vec预先计算的glove

在介绍你的代码之前,让我们做一个简短的例子。

texts = ['This is a text', 'This is not a text']

首先,我们将这些句子转换为整数向量,其中每个单词都是在字典中分配给该单词的数字,向量的顺序创建了单词的序列。

from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences 
from keras.utils import to_categorical

max_review_length = 6  # maximum length of the sentence
embedding_vector_length = 3
top_words = 10

# num_words is the number of unique words in the sequence, if there's more top count words are taken
tokenizer = Tokenizer(top_words)
tokenizer.fit_on_texts(texts)
sequences = tokenizer.texts_to_sequences(texts)
word_index = tokenizer.word_index
input_dim = len(word_index) + 1
print('Found %s unique tokens.' % len(word_index))

# max_review_length is the maximum length of the input text so that we can create vector [... 0,0,1,3,50] where 1,3,50 are individual words
data = pad_sequences(sequences, max_review_length)

print('Shape of data tensor:', data.shape)
print(data)

[Out:] 
'This is a text' --> [0 0 1 2 3 4]
'This is not a text' --> [0 1 2 5 3 4]

现在您可以将它们输入到嵌入层中。
from keras.models import Sequential
from keras.layers import Embedding

model = Sequential()
model.add(Embedding(top_words, embedding_vector_length, input_length=max_review_length, mask_zero=True))
model.compile(optimizer='adam', loss='categorical_crossentropy')
output_array = model.predict(data)

output_array 包含大小为 (2, 6, 3) 的数组: 在我的情况下,2 个输入评论或句子,每个评论最多包含 6 个单词 (max_review_length),而 3 是 embedding_vector_length。例如:

array([[[-0.01494285, -0.007915  ,  0.01764857],
    [-0.01494285, -0.007915  ,  0.01764857],
    [-0.03019481, -0.02910612,  0.03518577],
    [-0.0046863 ,  0.04763055, -0.02629668],
    [ 0.02297204,  0.02146662,  0.03114786],
    [ 0.01634104,  0.02296363, -0.02348827]],

   [[-0.01494285, -0.007915  ,  0.01764857],
    [-0.03019481, -0.02910612,  0.03518577],
    [-0.0046863 ,  0.04763055, -0.02629668],
    [-0.01736645, -0.03719328,  0.02757809],
    [ 0.02297204,  0.02146662,  0.03114786],
    [ 0.01634104,  0.02296363, -0.02348827]]], dtype=float32)

在您的情况下,您有一个包含5000个单词的列表,可以创建最多500个单词的评论(超过部分将被裁剪),并将这500个单词中的每一个转换为大小为32的向量。

您可以通过运行以下命令获取单词索引和嵌入向量之间的映射:

model.layers[0].get_weights()

在下面的情况中,top_words为10,因此我们有10个单词的映射,你可以看到0、1、2、3、4和5的映射等于上面的output_array
[array([[-0.01494285, -0.007915  ,  0.01764857],
    [-0.03019481, -0.02910612,  0.03518577],
    [-0.0046863 ,  0.04763055, -0.02629668],
    [ 0.02297204,  0.02146662,  0.03114786],
    [ 0.01634104,  0.02296363, -0.02348827],
    [-0.01736645, -0.03719328,  0.02757809],
    [ 0.0100757 , -0.03956784,  0.03794377],
    [-0.02672029, -0.00879055, -0.039394  ],
    [-0.00949502, -0.02805768, -0.04179233],
    [ 0.0180716 ,  0.03622523,  0.02232374]], dtype=float32)]

https://stats.stackexchange.com/questions/270546/how-does-keras-embedding-layer-work所述,这些向量是随机初始化的,并且像网络的任何其他参数一样,由网络优化器进行优化。


5
我同意之前详细答案的观点,但我想试着给出更加直观的解释。
为了理解嵌入层的工作原理,最好先退一步,了解为什么我们需要首先使用嵌入。通常情况下,机器学习模型以向量(数字数组)作为输入,并且处理文本时,我们将字符串转换为数字。最简单的方法之一是使用一位有效编码,其中每个字符串被视为分类变量。但第一个问题是,如果您使用包含 10000 个单词的字典(词汇),那么一位有效编码几乎是浪费空间(内存)。此外,由于离散实体被映射为 0 或 1,表示特定类别,因此一位有效编码无法捕获任何单词之间的关系。因此,如果您熟悉 IMDB 电影数据集,则一位有效编码对情感分析没有用处。因为,如果您使用余弦距离来衡量相似性,则不同索引之间的每个比较的相似性始终为零。这应该引导我们找到一种方法——
- 相似的单词可以具有相似的编码, - 要表示分类变量,我们将拥有少于唯一类别数的数字。
进入嵌入。嵌入是一组浮点值的密集向量,这些数字是随机生成的,并且在训练期间,这些值通过反向传播进行更新,就像在密集层中权重在训练期间得到更新一样。如 TensorFlow 文档所定义的:
“嵌入层可以被理解为一个查找表,它将整数索引(代表特定单词)映射到稠密向量(它们的嵌入)。 ”
在使用序贯构建模型之前,您已经使用了 Keras Tokenizer API,输入数据已经编码为整数。现在,一旦您指定了嵌入维度的数量(例如 16、32、64 等),查找表的列数将由此确定。嵌入层的输出始终是一个二维数组,因此在连接到密集层之前通常需要对其进行展平。正如在先前的答案中,您可以看到零层的权重的二维数组,列数等于嵌入向量长度。这就是我对 Keras 中嵌入层的想法。希望这能更好地解释,并作为 @Vaasha 发布的答案的良好补充。
参考:TensorFlow Word Embedding Tutorial。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接