TensorFlow 中的计划采样
Posted
技术标签:
【中文标题】TensorFlow 中的计划采样【英文标题】:scheduled sampling in Tensorflow 【发布时间】:2017-10-03 08:57:45 【问题描述】:关于 seq2seq 模型的最新 Tensorflow api 已包含定时采样:
https://www.tensorflow.org/api_docs/python/tf/contrib/seq2seq/ScheduledEmbeddingTrainingHelper https://www.tensorflow.org/api_docs/python/tf/contrib/seq2seq/ScheduledOutputTrainingHelper
预定抽样的原始论文可以在这里找到: https://arxiv.org/abs/1506.03099
我阅读了论文,但我无法理解 ScheduledEmbeddingTrainingHelper
和 ScheduledOutputTrainingHelper
之间的区别。文档中只说ScheduledEmbeddingTrainingHelper
是一个训练助手,它添加了预定采样,而ScheduledOutputTrainingHelper
是一个训练助手,它直接将定时采样添加到输出中。
我想知道这两个助手有什么区别?
【问题讨论】:
【参考方案1】:我联系了这背后的工程师,他回复:
输出采样器在该时间步发出原始 rnn 输出或原始地面实况。嵌入采样器将 rnn 输出视为一个分布的 logits,并从该分类分布或该时间步的原始地面实况中发出采样 id 的嵌入查找。
【讨论】:
谢谢!我想知道在哪里可以找到有关预定采样和 seq2seq api 的一些示例用法? 如果我可以稍有不同的说法 -ScheduledOutputTrainingHelper
和 ScheduledEmbeddingTrainingHelper
之间的区别在于前者直接将 RNN 的输出作为输入提供给下一个时间步(当不使用当前时间步长目标作为下一个输入),而后者(同样,当不使用当前时间步长目标作为下一个输入时)将 RNN 的输出视为对其应用 softmax 函数的 logit,对来自结果分布的令牌,它反过来使用它来索引嵌入矩阵中下一个时间步的输入。【参考方案2】:
这是一个使用ScheduledEmbeddingTrainingHelper
、TensorFlow 1.3 和一些更高级别的 tf.contrib API 的基本示例。这是一个 sequence2sequence 模型,其中解码器的初始隐藏状态是编码器的最终隐藏状态。它仅显示如何在单个批次上进行训练(显然任务是“反转此序列”)。对于实际的训练任务,我建议查看 tf.contrib.learn API,例如 learn_runner、Experiment 和 tf.estimator.Estimator。
import tensorflow as tf
import numpy as np
from tensorflow.python.layers.core import Dense
vocab_size = 7
embedding_size = 5
lstm_units = 10
src_batch = np.array([[1, 2, 3], [4, 5, 6]])
trg_batch = np.array([[3, 2, 1], [6, 5, 4]])
# *_seq will have shape (2, 3), *_seq_len will have shape (2)
source_seq = tf.placeholder(shape=(None, None), dtype=tf.int32)
target_seq = tf.placeholder(shape=(None, None), dtype=tf.int32)
source_seq_len = tf.placeholder(shape=(None,), dtype=tf.int32)
target_seq_len = tf.placeholder(shape=(None,), dtype=tf.int32)
# add Start of Sequence (SOS) tokens to each sequence
batch_size, sequence_size = tf.unstack(tf.shape(target_seq))
sos_slice = tf.zeros([batch_size, 1], dtype=tf.int32) # 0 = start of sentence token
decoder_input = tf.concat([sos_slice, target_seq], axis=1)
embedding_matrix = tf.get_variable(
name="embedding_matrix",
shape=[vocab_size, embedding_size],
dtype=tf.float32)
source_seq_embedded = tf.nn.embedding_lookup(embedding_matrix, source_seq) # shape=(2, 3, 5)
decoder_input_embedded = tf.nn.embedding_lookup(embedding_matrix, decoder_input) # shape=(2, 4, 5)
unused_encoder_outputs, encoder_state = tf.nn.dynamic_rnn(
tf.contrib.rnn.LSTMCell(lstm_units),
source_seq_embedded,
sequence_length=source_seq_len,
dtype=tf.float32)
# Decoder:
# At each time step t and for each sequence in the batch, we get x_t by either
# (1) sampling from the distribution output_layer(t-1), or
# (2) reading from decoder_input_embedded.
# We do (1) with probability sampling_probability and (2) with 1 - sampling_probability.
# Using sampling_probability=0.0 is equivalent to using TrainingHelper (no sampling).
# Using sampling_probability=1.0 is equivalent to doing inference,
# where we don't supervise the decoder at all: output at t-1 is the input at t.
sampling_prob = tf.Variable(0.0, dtype=tf.float32)
helper = tf.contrib.seq2seq.ScheduledEmbeddingTrainingHelper(
decoder_input_embedded,
target_seq_len,
embedding_matrix,
sampling_probability=sampling_prob)
output_layer = Dense(vocab_size)
decoder = tf.contrib.seq2seq.BasicDecoder(
tf.contrib.rnn.LSTMCell(lstm_units),
helper,
encoder_state,
output_layer=output_layer)
outputs, state, seq_len = tf.contrib.seq2seq.dynamic_decode(decoder)
loss = tf.contrib.seq2seq.sequence_loss(
logits=outputs.rnn_output,
targets=target_seq,
weights=tf.ones(trg_batch.shape))
train_op = tf.contrib.layers.optimize_loss(
loss=loss,
global_step=tf.contrib.framework.get_global_step(),
optimizer=tf.train.AdamOptimizer,
learning_rate=0.001)
with tf.Session() as session:
session.run(tf.global_variables_initializer())
_, _loss = session.run([train_op, loss],
source_seq: src_batch,
target_seq: trg_batch,
source_seq_len: [3, 3],
target_seq_len: [3, 3],
sampling_prob: 0.5
)
print("Loss: " + str(_loss))
对于ScheduledOutputTrainingHelper
,我希望只换掉助手并使用:
helper = tf.contrib.seq2seq.ScheduledOutputTrainingHelper(
target_seq,
target_seq_len,
sampling_probability=sampling_prob)
但是这会产生错误,因为 LSTM 单元要求每个时间步长有一个多维输入(形状为 (batch_size, input_dims))。我会在 GitHub 上提出一个问题,看看这是否是一个错误,或者还有其他方法可以使用 ScheduledOutputTrainingHelper
。
【讨论】:
您能否提供一个指向您的 GitHub 问题的链接? 我有点忙,最终没有提出来。 @MattiasArro 碰巧有解决您在ScheduledOutputTrainingHelper
中指出的问题的方法。如果将target_seq
(整数标记序列)转换为单热向量序列,则不会遇到此错误,如下所示:tf.contrib.seq2seq.ScheduledOutputTrainingHelper(tf.one_hot(target_seq), target_seq_len, sampling_probability=sampling_prob)
。
如果架构中没有编码器-解码器,你将如何使用这个ScheduledOutputTrainingHelper
?假设它是一个简单的堆叠 LSTM。像这样this【参考方案3】:
这也可能对您有所帮助。这适用于您希望在每个解码步骤分别进行预定采样的情况。
import tensorflow as tf
import numpy as np
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import gen_array_ops
from tensorflow.python.ops import math_ops
from tensorflow.python.ops.distributions import categorical
from tensorflow.python.ops.distributions import bernoulli
batch_size = 64
vocab_size = 50000
emb_dim = 128
output = tf.get_variable('output',
initializer=tf.constant(np.random.rand(batch_size,vocab_size)))
base_next_inputs = tf.get_variable('input',
initializer=tf.constant(np.random.rand(batch_size,emb_dim)))
embedding = tf.get_variable('embedding',
initializer=tf.constant(np.random.rand(vocab_size,emb_dim)))
select_sampler = bernoulli.Bernoulli(probs=0.99, dtype=tf.bool)
select_sample = select_sampler.sample(sample_shape=batch_size,
seed=123)
sample_id_sampler = categorical.Categorical(logits=output)
sample_ids = array_ops.where(
select_sample,
sample_id_sampler.sample(seed=123),
gen_array_ops.fill([batch_size], -1))
where_sampling = math_ops.cast(
array_ops.where(sample_ids > -1), tf.int32)
where_not_sampling = math_ops.cast(
array_ops.where(sample_ids <= -1), tf.int32)
sample_ids_sampling = array_ops.gather_nd(sample_ids, where_sampling)
inputs_not_sampling = array_ops.gather_nd(base_next_inputs,
where_not_sampling)
sampled_next_inputs = tf.nn.embedding_lookup(embedding,
sample_ids_sampling)
base_shape = array_ops.shape(base_next_inputs)
result1 = array_ops.scatter_nd(indices=where_sampling,
updates=sampled_next_inputs, shape=base_shape)
result2 = array_ops.scatter_nd(indices=where_not_sampling,
updates=inputs_not_sampling, shape=base_shape)
result = result1 + result2
我使用了 tensorflow 文档代码来制作这个示例。 https://github.com/tensorflow/tensorflow/blob/r1.5/tensorflow/contrib/seq2seq/python/ops/helper.py
【讨论】:
如果架构中没有编码器-解码器,你将如何使用这个ScheduledOutputTrainingHelper
?假设它是一个简单的堆叠 LSTM。像这样this以上是关于TensorFlow 中的计划采样的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Keras 模型中使用 TensorFlow 的采样 softmax 损失函数?