我的 NMT 模型有 2 层,512 个隐藏单元。我以最大句子长度 = 50,批量大小 = 32 进行训练,发现 feed_dict 和队列之间的速度相似,大约每秒 2400-2500 个目标词(我根据 paper 使用这个速度指标)。
我发现 feed_dict 非常直观且易于使用。排队很困难。使用队列,您必须:
1/ 将您的数据转换为 tfrecords。我实际上需要用谷歌搜索一下,以了解如何将我的 seq2seq 数据转换为 tfrecords,因为文档不是很有帮助。
2/ 从 tfrecords 中解码您的数据。您会发现用于生成 tfrecord 并对其进行解码的函数在直观上并不匹配。例如,如果我的每个训练示例都有 3 个序列(只有 3 个整数列表)src_input, trg_input, trg_target,并且我也想记录 src_input 的长度(它的一些元素可能是 PADDING,所以不要计算) ,下面是如何从每个示例中生成 tfrecord:
def _make_example(src_input, src_seq_length, trg_input, trg_seq_length, trg_target, target_weight):
context = tf.train.Features(
feature={
'src_seq_length': int64_feature(src_seq_length)
})
feature_lists = tf.train.FeatureLists(
feature_list={
'src_input': int64_featurelist(src_input),
'trg_input': int64_featurelist(trg_input),
'trg_target': int64_featurelist(trg_target)
})
return tf.train.SequenceExample(context=context, feature_lists=feature_lists)
解码方法如下:
def _read_and_decode(filename_queue):
reader = tf.TFRecordReader(options=self.tfrecord_option)
_, serialized_ex = reader.read(filename_queue)
context_features = {
'src_seq_length': tf.FixedLenFeature([], dtype=tf.int64)
}
sequence_features = {
'src_input': tf.FixedLenSequenceFeature([], dtype=tf.int64),
'trg_input': tf.FixedLenSequenceFeature([], dtype=tf.int64),
'trg_target': tf.FixedLenSequenceFeature([], dtype=tf.int64)
}
context, sequences = tf.parse_single_sequence_example(
serialized_ex,
context_features=context_features,
sequence_features=sequence_features)
src_seq_length = tf.cast(context['src_seq_length'], tf.int32)
src_input = tf.cast(sequences['src_input'], tf.int32)
trg_input = tf.cast(sequences['trg_input'], tf.int32)
trg_target = tf.cast(sequences['trg_target'], tf.int32)
return src_input, src_seq_length, trg_input, trg_target
并生成每个 tfrecord 特征/特征列表:
def int64_feature(value):
return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))
def int64_featurelist(l):
feature = [tf.train.Feature(int64_list=tf.train.Int64List(value=[x])) for x in l]
return tf.train.FeatureList(feature=feature)
3/ 训练/开发设置。我相信定期训练你的模型一段时间,然后在开发集上评估,然后重复是一种常见的做法。我不知道如何用队列做到这一点。使用 feed_dict,您只需在同一会话下构建两个具有共享参数的图表,一个用于训练,一个用于开发。当您评估开发集时,只需将开发数据提供给开发图即可。但是对于队列,队列的输出是图形本身的一部分。要运行队列,你必须启动队列运行器,创建一个协调器,使用这个协调器来管理队列。完成后,队列已关闭!!!!目前,我不知道如何最好地编写代码以使训练/开发设置与队列保持一致,除了打开新会话、每次评估时为开发构建新图表。 here 提出了同样的问题,您可以在 Stackoverflow 上搜索类似问题。
但是,很多人说 queue 比 feed_dict 快。我的猜测是,如果您以分布式方式训练,队列是有益的。但对我来说,我经常只在 1 个 GPU 上训练,到目前为止,我对队列完全没有印象。嗯,只是我的猜测。