tf.nn.embedding_lookup(params, ids, partition_strategy='mod', name=None)
我无法理解这个功能的职责。它是否像查找表?这意味着返回与每个id相对应的参数(在ids中)?
例如,如果我们使用skip-gram
,则在tf.nn.embedding_lookup(embeddings, train_inputs)
模型中,对于每个train_input
,它会找到相应的嵌入?
答案 0 :(得分:199)
是的,这个功能很难理解,直到你明白这一点。
最简单的形式与tf.gather
类似。它根据params
指定的索引返回ids
的元素。
例如(假设你在tf.InteractiveSession()
内)
params = tf.constant([10,20,30,40])
ids = tf.constant([0,1,2,3])
print tf.nn.embedding_lookup(params,ids).eval()
将返回[10 20 30 40]
,因为params的第一个元素(索引0)是10
,params的第二个元素(索引1)是20
等。
同样,
params = tf.constant([10,20,30,40])
ids = tf.constant([1,1,3])
print tf.nn.embedding_lookup(params,ids).eval()
会返回[20 20 40]
。
但embedding_lookup
不止于此。 params
参数可以是张量的列表,而不是单个张量。
params1 = tf.constant([1,2])
params2 = tf.constant([10,20])
ids = tf.constant([2,0,2,1,2,3])
result = tf.nn.embedding_lookup([params1, params2], ids)
在这种情况下,ids
中指定的索引对应于根据分区策略的张量元素,默认分区策略为' mod&#39 ;
在' mod'策略,索引0对应于列表中第一个张量的第一个元素。索引1对应于第二张量的第一元素。索引2对应于第三张量的第一元素,依此类推。对于所有索引i
,简单地索引0..(n-1)
对应于第(i + 1)个张量的第一个元素,假设params是n
张量的列表。
现在,索引n
无法与张量n + 1对应,因为列表params
仅包含n
个张量。因此,索引n
对应于第一张量的第二元素。类似地,索引n+1
对应于第二张量的第二个元素,等等。
所以,在代码中
params1 = tf.constant([1,2])
params2 = tf.constant([10,20])
ids = tf.constant([2,0,2,1,2,3])
result = tf.nn.embedding_lookup([params1, params2], ids)
索引0对应于第一个张量的第一个元素:1
索引1对应于第二张量的第一个元素:10
索引2对应于第一张量的第二个元素:2
索引3对应于第二张量的第二个元素:20
因此,结果将是:
[ 2 1 2 10 2 20]
答案 1 :(得分:135)
embedding_lookup
函数检索params
张量的行。该行为类似于在numpy中使用数组索引。 E.g。
matrix = np.random.random([1024, 64]) # 64-dimensional embeddings
ids = np.array([0, 5, 17, 33])
print matrix[ids] # prints a matrix of shape [4, 64]
params
参数也可以是张量列表,在这种情况下,ids
将在张量之间分配。例如,给定3个张量[2, 64]
的列表,默认行为是它们代表ids
:[0, 3]
,[1, 4]
,[2, 5]
。
partition_strategy
控制ids
在列表中的分配方式。当矩阵可能太大而无法保持整体时,分区对于较大规模的问题很有用。
答案 2 :(得分:37)
是的,tf.nn.embedding_lookup()
函数的目的是在嵌入矩阵中执行查找并返回嵌入(或简单地说是向量表示)的话。
简单的嵌入矩阵(形状: vocabulary_size x embedding_dimension
)如下所示。 (即每个单词将由 vector 数字表示;因此名称 word2vec )
嵌入矩阵
the 0.418 0.24968 -0.41242 0.1217 0.34527 -0.044457 -0.49688 -0.17862
like 0.36808 0.20834 -0.22319 0.046283 0.20098 0.27515 -0.77127 -0.76804
between 0.7503 0.71623 -0.27033 0.20059 -0.17008 0.68568 -0.061672 -0.054638
did 0.042523 -0.21172 0.044739 -0.19248 0.26224 0.0043991 -0.88195 0.55184
just 0.17698 0.065221 0.28548 -0.4243 0.7499 -0.14892 -0.66786 0.11788
national -1.1105 0.94945 -0.17078 0.93037 -0.2477 -0.70633 -0.8649 -0.56118
day 0.11626 0.53897 -0.39514 -0.26027 0.57706 -0.79198 -0.88374 0.30119
country -0.13531 0.15485 -0.07309 0.034013 -0.054457 -0.20541 -0.60086 -0.22407
under 0.13721 -0.295 -0.05916 -0.59235 0.02301 0.21884 -0.34254 -0.70213
such 0.61012 0.33512 -0.53499 0.36139 -0.39866 0.70627 -0.18699 -0.77246
second -0.29809 0.28069 0.087102 0.54455 0.70003 0.44778 -0.72565 0.62309
我拆分了上面的嵌入矩阵,只加载vocab
中的字,它们是我们的词汇表和emb
数组中的相应矢量。
vocab = ['the','like','between','did','just','national','day','country','under','such','second']
emb = np.array([[0.418, 0.24968, -0.41242, 0.1217, 0.34527, -0.044457, -0.49688, -0.17862],
[0.36808, 0.20834, -0.22319, 0.046283, 0.20098, 0.27515, -0.77127, -0.76804],
[0.7503, 0.71623, -0.27033, 0.20059, -0.17008, 0.68568, -0.061672, -0.054638],
[0.042523, -0.21172, 0.044739, -0.19248, 0.26224, 0.0043991, -0.88195, 0.55184],
[0.17698, 0.065221, 0.28548, -0.4243, 0.7499, -0.14892, -0.66786, 0.11788],
[-1.1105, 0.94945, -0.17078, 0.93037, -0.2477, -0.70633, -0.8649, -0.56118],
[0.11626, 0.53897, -0.39514, -0.26027, 0.57706, -0.79198, -0.88374, 0.30119],
[-0.13531, 0.15485, -0.07309, 0.034013, -0.054457, -0.20541, -0.60086, -0.22407],
[ 0.13721, -0.295, -0.05916, -0.59235, 0.02301, 0.21884, -0.34254, -0.70213],
[ 0.61012, 0.33512, -0.53499, 0.36139, -0.39866, 0.70627, -0.18699, -0.77246 ],
[ -0.29809, 0.28069, 0.087102, 0.54455, 0.70003, 0.44778, -0.72565, 0.62309 ]])
emb.shape
# (11, 8)
在TensorFlow中嵌入查找
现在我们将看到如何为某些任意输入句子执行嵌入查找。
In [54]: from collections import OrderedDict
# embedding as TF tensor (for now constant; could be tf.Variable() during training)
In [55]: tf_embedding = tf.constant(emb, dtype=tf.float32)
# input for which we need the embedding
In [56]: input_str = "like the country"
# build index based on our `vocabulary`
In [57]: word_to_idx = OrderedDict({w:vocab.index(w) for w in input_str.split() if w in vocab})
# lookup in embedding matrix & return the vectors for the input words
In [58]: tf.nn.embedding_lookup(tf_embedding, list(word_to_idx.values())).eval()
Out[58]:
array([[ 0.36807999, 0.20834 , -0.22318999, 0.046283 , 0.20097999,
0.27515 , -0.77126998, -0.76804 ],
[ 0.41800001, 0.24968 , -0.41242 , 0.1217 , 0.34527001,
-0.044457 , -0.49687999, -0.17862 ],
[-0.13530999, 0.15485001, -0.07309 , 0.034013 , -0.054457 ,
-0.20541 , -0.60086 , -0.22407 ]], dtype=float32)
观察我们如何使用词汇表中索引从原始嵌入矩阵(带有单词)中获取嵌入。
通常,这样的嵌入查找由第一层(称为嵌入层)执行,然后将这些嵌入传递到RNN / LSTM / GRU层以进行进一步处理。
旁注:通常,词汇表也会有一个特殊的unk
标记。因此,如果我们的词汇表中没有输入句子中的标记,那么将在嵌入矩阵中查找与 unk
对应的索引。
PS 请注意,embedding_dimension
是一个超参数,必须针对其应用进行调整,但 Word2Vec 和 {等热门模型{3}} 使用300
维度向量来表示每个单词。
奖励阅读 GloVe
答案 3 :(得分:12)
这是描述嵌入查找过程的图像。
简而言之,它获取由ID列表指定的嵌入层的相应行,并将其提供为张量。它是通过以下过程实现的。
lookup_ids = tf.placeholder([10])
embeddings = tf.Variable([100,10],...)
embed_lookup = tf.embedding_lookup(embeddings, lookup_ids)
lookup = session.run(embed_lookup, feed_dict={lookup_ids:[95,4,14]})
答案 4 :(得分:4)
当参数张量处于高维时,id仅指顶部维度。也许这对大多数人来说很明显,但我必须运行以下代码才能理解:
embeddings = tf.constant([[[1,1],[2,2],[3,3],[4,4]],[[11,11],[12,12],[13,13],[14,14]],
[[21,21],[22,22],[23,23],[24,24]]])
ids=tf.constant([0,2,1])
embed = tf.nn.embedding_lookup(embeddings, ids, partition_strategy='div')
with tf.Session() as session:
result = session.run(embed)
print (result)
试试' div'战略和一个张量,它没有任何区别。
这是输出:
[[[ 1 1]
[ 2 2]
[ 3 3]
[ 4 4]]
[[21 21]
[22 22]
[23 23]
[24 24]]
[[11 11]
[12 12]
[13 13]
[14 14]]]
答案 5 :(得分:3)
另一种看待它的方法是,假设你将张量展平为一维数组,然后你正在执行查找
(例如)Tensor0 = [1,2,3],Tensor1 = [4,5,6],Tensor2 = [7,8,9]
平坦的张量将如下 [1,4,7,2,5,8,3,6,9]
现在当你查找[0,3,4,1,7]它会产生[1,2,5,4,6]
(i,e)如果查找值为7,例如,我们有3个张量(或3个张量),
7/3 :(提醒为1,商数为2)因此将显示Tensor1的第2个元素,即6
答案 6 :(得分:2)
由于我对此功能也很感兴趣,我会给出两分钱。
我在2D情况下看到它的方式就像矩阵乘法一样(它易于推广到其他维度)。
考虑带有N个符号的词汇表。 然后,您可以将符号 x 表示为尺寸为Nx1的矢量,即单热编码。
但是你希望这个符号的表示不是Nx1的矢量,而是尺寸为Mx1的一个,称为 y 。
因此,要将 x 转换为 y ,您可以使用并嵌入矩阵 E < / strong>,尺寸为MxN:
y = E x 。
这基本上就是tf.nn.embedding_lookup(params,ids,...)正在做的事情, ids 只是一个数字代表一个中1的位置的细微差别-hot-encoded vector x 。
答案 7 :(得分:0)
添加Asher Stern的答案,
params
是
解释为大嵌入张量的分区。它可以是表示完整嵌入张量的单个张量,
或者除了第一维之外,所有相同形状的X张量列表,
表示分片嵌入张量。
考虑到嵌入(params)很大这一事实,编写了函数tf.nn.embedding_lookup
。因此,我们需要partition_strategy
。