2

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


目标

为使用 Dataset API 提供数据的自定义 Estimator 提供服务。任务是 NMT (seq2seq)。


问题

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


背景

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

但是,我遇到了“如何”为模型服务的路障。据我所知,我需要“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(s) 作为输入。这是有道理的,但是,对于我的用例,我没有一堆(不同的)特征,而是我有需要通过嵌入查找并用作特征的输入句子(其中每个单词都是一个特征)......

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

    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 个),这听起来对吗?每个单词都是我模型的一个特征,所以我倾向于这是正确的方法,但这也有问题。我正在使用 Dataset API,所以在我的 input_train_fn() 中,我从文件中加载数据,然后使用 tf.data.Dataset.from_tensor_slices(data, labels) 将数据拆分为张量,然后我可以使用 dataset.batch( batch_size).make_one_shot_iterator().get_next() 输入我的估算器。我不能对每个批次进行迭代(Tesors 不可迭代)所以我不能简单地为每个输入批次制作 100 个 feature_columns ...

有谁知道如何做到这一点?这种嵌入查找对于简单的占位符或变量(以及 NLP 任务中的常用方法)来说是一件非常简单的事情。但是当我冒险使用 Dataset API 和 Estimators 时,我遇到了一个信息量很少的墙(这不是一个基本的例子)。

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

感谢您阅读我的文字墙并希望对我有所帮助(以及我见过的其他人提出类似的问题但没有得到答案https://groups.google.com/a/tensorflow.org/forum/#!searchin /discuss/embeddings $20in$20custom$20estimator/discuss/U3vFQF_jeaY/EjgwRQ3RDQAJ 我为这个家伙感到难过,他的问题没有得到真正的回答(出于与此处所述相同的原因,他的线程被劫持了......)。

4

4 回答 4

0

如果我理解正确,您想使用 Estimator API 来构建 SeqSeq 模型。从这里开始的好地方,查看Problems-Solutions/text文件夹。

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

vocab_table = lookup.index_table_from_file(vocabulary_file='data/vocab.csv', num_oov_buckets=1, default_value=-1)
text = features[commons.FEATURE_COL]
words = tf.string_split(text)
dense_words = tf.sparse_tensor_to_dense(words, default_value=commons.PAD_WORD)
word_ids = vocab_table.lookup(dense_words)

padding = tf.constant([[0, 0], [0, commons.MAX_DOCUMENT_LENGTH]])
# Pad all the word_ids entries to the maximum document length
word_ids_padded = tf.pad(word_ids, padding)
word_id_vector = tf.slice(word_ids_padded, [0, 0], [-1, commons.MAX_DOCUMENT_LENGTH])

word_id_vector = {commons.FEATURE_COL: word_id_vector}

bow_column = tf.feature_column.categorical_column_with_identity(commons.FEATURE_COL, num_buckets=params.N_WORDS)
bow_embedding_column = tf.feature_column.embedding_column(bow_column, dimension=50, combiner='sqrtn')
bow = tf.feature_column.input_layer(word_id_vector, feature_columns=[bow_embedding_column])
logits = tf.layers.dense(bow, 2, activation=None)

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

于 2018-02-22T05:44:18.530 回答
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] 作为输入。

最好的

于 2019-02-21T16:42:55.113 回答
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)]
于 2019-08-21T02:21:43.450 回答
0

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

我将把它作为公认的答案,并希望在未来的某个时候我能找到更好的方法,或者其他人可以启发我解决这个问题的最佳方法。

于 2018-02-23T19:18:07.890 回答