tf.nn.embedding_lookup函数有什么作用?

Poo*_*Pzm 146 python deep-learning tensorflow word-embedding natural-language-processing

tf.nn.embedding_lookup(params, ids, partition_strategy='mod', name=None)
Run Code Online (Sandbox Code Playgroud)

我无法理解这个功能的职责.它是否像查找表?这意味着返回与每个id(在id中)对应的参数?

例如,skip-gram如果我们使用模型tf.nn.embedding_lookup(embeddings, train_inputs),那么每个模型都会train_input找到相应的嵌入?

小智 212

是的,这个功能很难理解,直到你明白这一点.

最简单的形式,它类似于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()
Run Code Online (Sandbox Code Playgroud)

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

会回来的[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)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,指定的索引ids对应于根据分区策略的张量元素,其中默认分区策略是"mod".

在'mod'策略中,索引0对应于列表中第一个张量的第一个元素.索引1对应于第二张量的第一个元素.索引2对应于第三张量的第一个元素,依此类推.对于所有索引,简单索引对应于第(i + 1)个张量的第一个元素,假设params是张量列表.i0..(n-1)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)
Run Code Online (Sandbox Code Playgroud)

index 0对应于第一个张量的第一个元素:1

index 1对应于第二张量的第一个元素:10

index 2对应于第一张量的第二个元素:2

index 3对应于第二张量的第二个元素:20

因此,结果将是:

[ 2  1  2 10  2 20]
Run Code Online (Sandbox Code Playgroud)

  • 注意:你可以使用`partition_strategy ='div',并得到`[10,1,10,2,10,20]`,即`id = 1`是第一个参数的第二个元素.基本上:`partition_strategy = mod`(默认)`id%len(params)`:参数中的参数索引`id // len(params)`:上面参数中的元素索引`partition_strategy =*div*`另一种方式 (7认同)
  • @ asher-stern你能解释为什么"mod"策略是默认的吗?似乎"div"策略更类似于标准张量切片(给定索引的选择行).在"div"的情况下是否存在一些性能问题? (3认同)

Raf*_*icz 139

embedding_lookup函数检索params张量的行.该行为类似于在numpy中使用数组索引.例如

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

params参数也可以是张量列表,在这种情况下,ids将在张量之间分配.例如,给定的3张量列表[2, 64],默认行为是,他们将代表ids:[0, 3],[1, 4],[2, 5].

partition_strategy控制ids在列表中分配的方式.当矩阵可能太大而不能保持整体时,分区对于较大规模的问题是有用的.

  • 为什么他们会这样称呼而不是`select_rows`? (21认同)
  • @vgoklani,不,`embedding_lookup`只是提供了一种方便(和并行)的方法来检索与`ids`中的id相对应的嵌入.`params`张量通常是一个tf变量,作为训练过程的一部分学习 - 一个tf变量,其组件直接或间接地用于损失函数(例如`tf.l2_loss`),该变量由优化器(例如`tf.train.AdamOptimizer`). (18认同)
  • @LenarHoyt因为这种查找的想法来自Word嵌入.并且"行"是单词的表示(嵌入),进入向量空间 - 并且在它们自己中是有用的.通常比实际网络更多. (12认同)
  • @RafałJózefowicz为什么"默认行为是它们代表id:[0,3],[1,4],[2,5]."?你能解释一下吗? (5认同)
  • tensorflow如何学习嵌入结构?这个功能也管理这个过程吗? (2认同)
  • 例如,给定 3 个张量 [2, 64] 的列表,默认行为是它们将表示 id:[0, 3]、[1, 4]、[2, 5]。` - 需要解释。 (2认同)

kma*_*o23 44

是的,tf.nn.embedding_lookup()函数的目的是在嵌入矩阵中执行查找并返回单词的嵌入(或简单地说是向量表示).

一个简单的嵌入矩阵(形状:) vocabulary_size x embedding_dimension将如下所示.(即每个单词将由数字向量表示;因此名称为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 
Run Code Online (Sandbox Code Playgroud)

我分裂上述嵌入基质和仅加载的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)
Run Code Online (Sandbox Code Playgroud)

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

注意我们是怎么得到的嵌入使用从我们原来的嵌入矩阵(文字)的话指数在我们的词汇.

通常,这种嵌入查找由第一层(称为嵌入层)执行,然后第一层将这些嵌入传递到RNN/LSTM/GRU层以进行进一步处理.


旁注:通常词汇表也会有一个特殊的unk标记.因此,如果我们的词汇表中没有来自输入句子的标记,那么unk将在嵌入矩阵中查找对应的索引.


PS注意,embedding_dimension是一个超参数是一个具有调整他们的应用程序,但像受欢迎的机型Word2Vec手套使用300维向量表示每个字.

奖金阅读 word2vec skip-gram模型


thu*_*v89 13

这是一张描述嵌入查找过程的图像.

图像:嵌入查找过程

简而言之,它获取嵌入层的相应行,由ID列表指定并将其作为张量提供.它通过以下过程实现.

  1. 定义占位符 lookup_ids = tf.placeholder([10])
  2. 定义嵌入层 embeddings = tf.Variable([100,10],...)
  3. 定义tensorflow操作 embed_lookup = tf.embedding_lookup(embeddings, lookup_ids)
  4. 通过运行获得结果 lookup = session.run(embed_lookup, feed_dict={lookup_ids:[95,4,14]})


Yan*_*hao 5

当参数张量为高维时,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)
Run Code Online (Sandbox Code Playgroud)

只是尝试“ 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]]]
Run Code Online (Sandbox Code Playgroud)