所以我试图使用tf.datasets切换到input_fn(),如question所述。虽然我使用带有下面的input_fn()的tf.datasets可以获得更高的步数/秒,但是在GCMLE上运行此实验时,我似乎在1个纪元后遇到错误。考虑一下这个input_fn():
def input_fn(...):
files = tf.data.Dataset.list_files(filenames).shuffle(num_shards)
dataset = files.apply(tf.contrib.data.parallel_interleave(lambda filename: tf.data.TextLineDataset(filename).skip(1), cycle_length=num_shards))
dataset = dataset.apply(tf.contrib.data.map_and_batch(lambda row:
parse_csv_dataset(row, hparams = hparams),
batch_size = batch_size,
num_parallel_batches = multiprocessing.cpu_count()))
dataset = dataset.prefetch(1)
if shuffle:
dataset = dataset.shuffle(buffer_size = 10000)
dataset = dataset.repeat(num_epochs)
iterator = dataset.make_initializable_iterator()
features = iterator.get_next()
tf.add_to_collection(tf.GraphKeys.TABLE_INITIALIZERS, iterator.initializer)
labels = {key: features.pop(key) for key in LABEL_COLUMNS}
return features, labels
我在GCMLE上收到以下错误:
disable=protected-access InvalidArgumentError (see above for traceback): Inputs to operation loss/sparse_softmax_cross_entropy_loss/num_present/Select of type Select must have the same size and shape. Input 0: [74] != input 1: [110] [[Node: loss/sparse_softmax_cross_entropy_loss/num_present/Select = Select[T=DT_FLOAT, _device="/job:localhost/replica:0/task:0/device:GPU:0"](loss/sparse_softmax_cross_entropy_loss/num_present/Equal, loss/sparse_softmax_cross_entropy_loss/num_present/zeros_like, loss/sparse_softmax_cross_entropy_loss/num_present/ones_like)]] [[Node: global_step/add/_1509 = _Recv[client_terminated=false, recv_device="/job:localhost/replica:0/task:0/device:CPU:0", send_device="/job:localhost/replica:0/task:0/device:GPU:0", send_device_incarnation=1, tensor_name="edge_3099_global_step/add", tensor_type=DT_INT64, _device="/job:localhost/replica:0/task:0/device:CPU:0"]()]]
这意味着存在形状不匹配Input 0: [74] != input 1: [110]
,但是我的旧基于队列的input_fn()在相同的确切数据上工作正常,因此我不认为它与底层数据有任何问题。这是在我认为是时代的结束时发生的(因为当GCMLE错误结束时num_steps
正好在num_train_examples/batch_size
左右,所以我猜这个问题可能是最后一批不等于batch_size
是110(因为它显示在错误中)而只有74个例子。任何人都可以确认这是错误吗?假设它是,是否有一些其他标志我需要设置,以便最后一批可以是除了spcified批量大小110?
为了它的价值,我用两个不同的数据集复制了这个行为(基于input_fn的旧队列的多个纪元的列车,在tf.datasets input_fn的第一个纪元的末尾被挂起)
答案 0 :(得分:1)
您的图表中的某些操作(来自错误消息,可能是sparse_softmax_cross_entropy_loss
)似乎需要固定的批量大小。它可能是你的代码(不是input_fn
的一部分)强制执行此操作(例如,将batch_size作为op中使用的某个张量的形状传递),或者它可能是TF库之一。
这本身并不总是一个问题。但是,tf.data.Dataset.batch
的{{3}}是:
注意:如果此数据集中的元素数(N)不准确 batch_size的倍数,最后一批包含较小的张量 在批量维度中形成N%batch_size。如果你的程序取决于 在具有相同形状的批次上,考虑使用 改为tf.contrib.data.batch_and_drop_remainder转换。
按照目前的编写,您的(非input_fn)代码属于具有相同形状的批次的类别。
您的选择是跟踪代码通过静态批处理大小的位置或“删除剩余部分”。我相信前者更可取,但更多的工作。
如果您选择后者,请注意您实际上并未使用tf.data.Dataset.batch
,而是documented behavior接受drop_remainder
参数。
答案 1 :(得分:1)
正如Robbie在other answer中所建议的,看起来您的旧实现始终使用固定批量大小(可能使用类似tf.train.batch()
的API或其包装器之一,默认参数为{{1} }),allow_smaller_final_batch=False
(通过tf.data.Dataset.batch()
和tf.contrib.data.map_and_batch()
)批量处理的默认行为是包含较小的最终批次。
该错误最有可能出现在tf.data
中。在没有看到该函数的情况下,很难猜测,但我怀疑通过Tensor.set_shape()
(可能在库代码中)存在张量形状的显式(和不正确)断言或者{{的实现中的错误3}}
首先,我假设从model_fn
返回的features
和labels
张量具有静态未知的批量大小。您是否可以通过打印input_fn()
和features
个对象来确认,并确保其报告的tf.losses.sparse_softmax_cross_entropy()
属性的第0维度为labels
?
接下来,找到None
中对tf.losses.sparse_softmax_cross_entropy()
的来电。将作为model_fn
参数传递的对象打印到此函数,该对象应为weights
,并找到其静态形状。鉴于您看到的错误,我怀疑它会有tf.Tensor
这样的形状,其中(110,)
是您指定的批量大小。如果是这种情况,110
中有一个错误,它错误地断言权重的形状是完整的批次,当它可能不是时。 (如果情况并非如此,那么model_fn
中就会出现错误!请打开一个Tensor.shape
,其中包含一个示例,可让我们重现问题。)
旁白:为什么这会解释这个错误?失败
tf.losses.sparse_softmax_cross_entropy()
操作的GitHub issue看起来像这样(为了便于阅读而编辑):tf.where()
由于历史原因,这种
num_present = tf.where(tf.equal(weights, 0.0), # This input is shape [74] tf.zeros_like(weights), # This input is shape [110] tf.ones_like(weights) # This input is probably [110] )
op(在错误消息中名为tf.where()
}的味道要求所有三个输入具有相同的大小。从表面上看,"Select"
,tf.equal(weights, 0.0)
和tf.ones_like(weights)
都具有相同的形状,即tf.zeros_like(weights)
的形状。但是,如果静态形状(weights
的结果)与code that calls不同,则行为未定义。实际发生了什么?在这种特殊情况下,假设
Tensor.shape
的静态形状为weights
,但动态形状为[110]
。[74]
的三个参数的静态形状为tf.where()
。[110]
的实现并不关心是否存在不匹配,因此其动态形状将为tf.equal()
。[74]
和tf.zeros_like()
的实现使用dynamic shape,当静态形状完全定义时忽略该动态形状,因此它们的动态形状将为tf.ones_like()
,从而导致错误你看到了。
正确的解决方法是找到在[110]
中声明固定批量大小的代码,然后将其删除。 TensorFlow中的优化和评估逻辑对于可变批量大小是稳健的,这将确保您的所有数据都用于培训和评估过程。
不太理想的短期修复方法是在数据末尾删除小批量。这里有几个选项:
在每个纪元的末尾随机丢弃一些数据:
model_fn
传递给drop_remainder=False
。 tf.contrib.data.map_and_batch()
。dataset = dataset.filter(lambda features: tf.equal(tf.shape(features[LABEL_COLUMNS[0]])[0], batch_size))
删除最后一批数据:
map_and_batch
之前移动dataset.repeat(NUM_EPOCHS)
,然后应用上述两个修复中的一个。