具有数据集API的Tensorflow自定义Estimator:嵌入查找(feature_column)NMT任务

时间:2018-02-21 20:31:53

标签: tensorflow tensorflow-serving tensorflow-datasets tensorflow-estimator

我的问题与Feature Columns Embedding lookup的性质接近,但是我无法对那里给出的答案发表评论(没有足够的代表),我认为回答者要么没有完全理解这个问题,要么回答是不完全是被问到的。

目标

提供使用数据集API输入数据的自定义Estimator。任务是NMT(seq2seq)。

问题

Estimator需要feature_columns作为服务的输入。我的NMT任务只有一个特征,即要翻译的输入句子(或者句子中的每个单词都是一个特征?)。所以我不确定如何使用我的输入句子构建feature_column(因此是一个embedding_column,最后是一个input_layer),这个特性可以输入RNN(期望embedding_lookup [batch_size,max_seqence_len,embedding_dim])请允许我为Estimator服务。

背景

我正在尝试使用自定义估算器来提供seq2seq样式的NMT实现。我需要能够通过服务提供服务模型,这些估算器似乎相对容易。

然而,我遇到了一个路障,如何'为模特服务。据我所知,我需要' feature_columns'这将作为模型的输入。

https://github.com/MtDersvan/tf_playground/blob/master/wide_and_deep_tutorial/wide_and_deep_basic_serving.md

显示您需要一个export_input_fn,它使用一个feature_spec,需要一个feature_column作为输入。这是有道理的,但是,对于我的用例,我没有一堆(不同的)功能,而是我有输入句子(每个单词都是一个特征),需要通过嵌入查找并用作特征...

所以我知道我需要将模型中的输入作为特征列。我对NMT的输入只是[batch_size,max_sequence_len]的张量,它填充了句子中单词的索引(例如,对于batch_size = 1 [3,17,132,2,1,0,...]其中每个索引应映射到嵌入向量)。通常我会通过

将其提供给embedding_lookup
    embs = tf.get_variable('embedding', [vocab_size, embedding_dim])
    tf.nn.embedding_lookup(embs, inputs)

我很乐意去,我可以把它作为输入提供给RNN,剩下的就是历史,而不是问题。

但是,这是我遇到问题的地方,我需要使用feature_columns(所以我可以为模型提供服务)。我在开头提到的问题的答案显示了如何使用embedding_column,但他建议嵌入应该查找整个句子作为一个单一的功能,但传统上你会查找句子中的每个单词都得到它的嵌入。

同样,https://www.damienpontifex.com/2018/01/02/using-tensorflow-feature-columns-in-your-custom-estimator-model/

显示'如何在自定义估算工具中实现功能列'事实上他的'之前'代码是完全正确的(正如我写的那样),tf.get_variable到tf.nn.embedding_lookup中,但他的'之后'代码,再次,只接受1个功能(整个句子?)。

我已经通过使用他们的代码并将[batch_size,max_seq_len]中的数据提供给tf.feature_column.categorical_column_with_identity来验证了这一点,输出张量是[batch_size,embedding_dim]

序列信息丢失?还是只是变得平坦?当我打印输出它的大小(?,embedding_dim)在哪里?通常是我的batch_size。

编辑:我已经验证了形状是[batch_size,embedding_dim],它不仅仅是扁平...所以序列信息丢失了

我猜测它必须将输入视为1个单输入要素(因此batch_size = 1 ex [3,17,132,2,1,0,...],其中每个索引映射到一个嵌入矢量)将映射到一个不是想要的单个特征,我们希望每个索引映射到嵌入,所需的输出是[batch_size,max_seq_len,embedding_dim]。

这听起来像我需要的,不是一个categorical_column_with_ *,而是max_seq_len的数量(我的序列中的每个单词都是1),这听起来不错吗?每个单词都是我模型的一个特征,所以我倾向于这是正确的方法,但这也有问题。我正在使用数据集API,所以在我的input_train_fn()中我从一个文件加载我的数据,然后使用tf.data.Dataset.from_tensor_slices(数据,标签)将数据拆分成张量,然后我可以使用dataset.batch( batch_size).make_one_shot_iterator()。get_next()以提供给我的Estimator。我无法对每个批处理进行迭代(测试器不可迭代)所以我不能简单地为每个输入批处理生成100个feature_columns ...

有没有人知道如何做到这一点?这种嵌入查找与简单的占位符或变量(以及NLP任务中的常用方法)非常简单。但是当我冒险进入数据集API和估算器时,我遇到的信息很少(这不是一个基本的例子)。

我承认我的理解可能存在差距,自定义估算器和数据集API对我来说是新的,有时很难找到有关它们的信息。所以随时向我发消息。

感谢您阅读我的文字墙并希望帮助我(以及我见过的其他人提出类似的问题,但却得不到答案https://groups.google.com/a/tensorflow.org/forum/#!searchin/discuss/embeddings 20美元20美元定制20美元/讨论/讨论/ U3vFQF_jeaY / EjgwRQ3RDQAJ我觉得这个家伙不好,他的问题没有得到真正的回答(出于同样的原因,他的线程被劫持了......)。

4 个答案:

答案 0 :(得分:0)

如果我理解正确,您希望使用Estimator API构建SeqSeq模型。一个开始here的好地方,请查看 Problems-Solutions / text 文件夹。

要回答关于如何使用emedding查找的问题,这里有一个例子

[psobject]

以上代码可以包含在Estimator model_fn中。上面的repo包含此代码。请看一下。

答案 1 :(得分:0)

所以我最终完成这项工作的方式是我将每个单词作为输入要素,然后我只是进行wrd_2_idx转换,将其作为numeric_column中的一个要素传递(s,你有max_seq_lens这些)然后传递那些列到input_layer。然后在我的图表中,我使用这些功能并正常查找嵌入。基本上绕过了embedding_column查找,因为我无法弄清楚如何让它按照我想要的方式运行。这可能不是最佳的,但它起作用并训练......

我将此作为公认的答案,并希望将来某个时候或者我想出更好的方法,或者其他人可以启发我以最好的方式来解决这个问题。

答案 2 :(得分:0)

我设法使这项工作成功了……RNN并没有消耗嵌入的事实,这也使我出轨了。

我做了什么才能使它工作(在最简单的情况下):

#features[VALUE_FEATURE_NAME] is shape (?, 200), ie. 200 words per row
inputs = tf.contrib.layers.embed_sequence(
  features[VALUES_FEATURE_NAME], 3000, 5,
)

# create an LSTM cell of size 100
lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(200)

# create the complete LSTM
_, final_states = tf.nn.dynamic_rnn(
    lstm_cell, inputs, dtype=tf.float32)
outputs = final_states.h 

所以我想答案就在于动态rnn的tensorflow文档中

  

创建由RNNCell单元指定的递归神经网络。

     

执行输入的完全动态展开。

因此,这里展开意味着RNN将[batch,time_steps,values]用作输入。

最佳

答案 3 :(得分:0)

您可以使用tf.contrib.feature_column.sequence_categorical_column_with_vocabulary_listtf.contrib.feature_column.sequence_input_layer来解决它。

演示代码如下:

import tensorflow as tf
if __name__ == "__main__":
  #tf.enable_eager_execution()
  feature = {
      'aa': [['1', '2', '3'], 
             ['-1', '4', '-1'], 
             ['2', '-1', '-1'],
             ['4', '5', '6']]
  }

  aa_id = tf.contrib.feature_column.sequence_categorical_column_with_vocabulary_list(
      'aa', ['1', '2', '3', '4', '5']
    )
  seq_emb_matrix = tf.feature_column.embedding_column(aa_id, 2)
  seq_tensor, seq_length = tf.contrib.feature_column.sequence_input_layer(feature, [seq_emb_matrix])
  seq_tensor1, seq_length1 = tf.contrib.feature_column.sequence_input_layer(feature1, [seq_emb_matrix])
  seq_tensor2 = tf.squeeze(seq_tensor1)
  # print(tensor)
  with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    sess.run(tf.tables_initializer())
    a, a_len = sess.run([seq_tensor, seq_length])
    b, b_len = sess.run([seq_tensor1, seq_length1])
    print(a)
    print('a_len', a_len)
    print(a.shape)
    print('-'*50)
    print(b)
    print('b_len', b_len)
    print(b.shape)
    print(sess.run([seq_tensor2]))

打印结果如下:

[[[ 0.5333682  -0.39895234]
  [ 0.5335079   0.64998794]
  [-1.0432893  -0.8391434 ]]

 [[ 0.          0.        ]
  [-0.29623085 -0.17570129]
  [ 0.          0.        ]]

 [[ 0.5335079   0.64998794]
  [ 0.          0.        ]
  [ 0.          0.        ]]

 [[-0.29623085 -0.17570129]
  [ 0.7100604   0.9935588 ]
  [ 0.          0.        ]]]
('a_len', array([3, 3, 3, 3]))
(4, 3, 2)
--------------------------------------------------
[[[-0.24147142 -0.37740025]]

 [[-0.6222648   1.3862932 ]]

 [[ 1.2226609  -0.68292266]]]
('b_len', array([1, 1, 1]))
(3, 1, 2)
[array([[-0.24147142, -0.37740025],
       [-0.6222648 ,  1.3862932 ],
       [ 1.2226609 , -0.68292266]], dtype=float32)]