【发布时间】:2019-06-05 18:41:59
【问题描述】:
我一直在使用 tensorflow 的 Dataset API 来轻松地将不同的数据集提供给 RNN 模型。
在没有那么多博客以及 tensorflow 网站上的文档之后,我得到了一切正常工作。我的工作示例执行以下操作:
--- 在训练数据集中训练 X 个 epoch -> 在验证数据集中所有训练结束后进行验证。
但是,我无法开发以下示例:
--- 在训练数据集中训练 X 个 epoch -> 在每个 epoch 中使用验证数据集验证训练模型(有点像 Keras 所做的)
问题出在下面这段代码:
train_dataset = tf.data.Dataset.from_tensor_slices((x,y)).batch(BATCH_SIZE, drop_remainder=True).repeat()
val_dataset = tf.data.Dataset.from_tensor_slices((x,y)).batch(BATCH_SIZE_VAL, drop_remainder=True).repeat()
itr = tf.data.Iterator.from_structure(train_dataset.output_types, train_dataset.output_shapes)
train_init_op = itr.make_initializer(train_dataset)
validation_init_op = itr.make_initializer(val_dataset)
当我从结构创建迭代器时,我需要指定一个输出形状。显然,训练数据集和验证数据集的输出形状并不相同,因为它们具有不同的 batch_size。但是,validation_init_op 抛出以下错误,这似乎违反直觉,因为验证集总是具有不同的 batch_size:
TypeError: Expected output shapes compatible with (TensorShape([Dimension(256), Dimension(11), Dimension(74)]), TensorShape([Dimension(256), Dimension(3)])) but got dataset with output shapes (TensorShape([Dimension(28), Dimension(11), Dimension(74)]), TensorShape([Dimension(28), Dimension(3)])).
我想使用第二种方法来评估我的模型,并查看同时开发的常见训练和验证图,看看我该如何改进它(尽早停止学习等)。然而,第一种简单的方法我没有得到所有这些。
所以,问题是:¿我做错了吗? ¿ 我的第二种方法是否必须以不同的方式处理? 我可以考虑创建两个迭代器,但我不知道这是否是正确的方法。此外,@MatthewScarpino 的这个答案指出了一个 feedable 迭代器,因为在可重新初始化的迭代器之间切换会使它们重新开始;但是,上述错误与代码的那部分无关——¿也许可重新初始化的迭代器并不打算为验证集设置不同的批量大小,并且只在训练后迭代一次,无论它是什么大小并且没有在.batch() 方法中设置它?
非常感谢任何帮助。
完整代码供参考:
N_TIMESTEPS_X = xt.shape[0] ## The stack number
BATCH_SIZE = 256
#N_OBSERVATIONS = xt.shape[1]
N_FEATURES = xt.shape[2]
N_OUTPUTS = yt.shape[1]
N_NEURONS_LSTM = 128 ## Number of units in the LSTMCell
N_EPOCHS = 350
LEARNING_RATE = 0.001
### Define the placeholders anda gather the data.
xt = xt.transpose([1,0,2])
xval = xval.transpose([1,0,2])
train_data = (xt, yt)
validation_data = (xval, yval)
N_BATCHES = train_data[0].shape[0] // BATCH_SIZE
print('The number of batches is: {}'.format(N_BATCHES))
BATCH_SIZE_VAL = validation_data[0].shape[0] // N_BATCHES
print('The validation batch size is: {}'.format(BATCH_SIZE_VAL))
## We define the placeholders as a trick so that we do not break into memory problems, associated with feeding the data directly.
'''As an alternative, you can define the Dataset in terms of tf.placeholder() tensors, and feed the NumPy arrays when you initialize an Iterator over the dataset.'''
batch_size = tf.placeholder(tf.int64)
x = tf.placeholder(tf.float32, shape=[None, N_TIMESTEPS_X, N_FEATURES], name='XPlaceholder')
y = tf.placeholder(tf.float32, shape=[None, N_OUTPUTS], name='YPlaceholder')
# Creating the two different dataset objects.
train_dataset = tf.data.Dataset.from_tensor_slices((x,y)).batch(BATCH_SIZE, drop_remainder=True).repeat()
val_dataset = tf.data.Dataset.from_tensor_slices((x,y)).batch(BATCH_SIZE_VAL, drop_remainder=True).repeat()
# Creating the Iterator type that permits to switch between datasets.
itr = tf.data.Iterator.from_structure(train_dataset.output_types, train_dataset.output_shapes)
train_init_op = itr.make_initializer(train_dataset)
validation_init_op = itr.make_initializer(val_dataset)
next_features, next_labels = itr.get_next()
【问题讨论】:
-
你能解释一下为什么 feedable 迭代器不起作用,因为它看起来像解决方案吗?因为现在如果不查看更多代码,特别是在整个过程中使用这些数据集的训练和验证代码,很难说出问题所在。
-
我认为在这种情况下使用 2 个迭代器可能是最好的,因为它可以让您灵活地以适合您的内存要求的形状定义数据
-
如果定义了 2 个迭代器,则可以定义 2 个可初始化的迭代器,在使用它们之前运行它们的迭代器初始化器。它仍然可以很好地工作。会出现复杂性的情况是,如果您在训练过程中的某个地方设置了检查点并且必须从那里恢复,在这种情况下,您需要保存迭代器状态以从您停止的地方恢复。否则,您可以在使用之前对迭代器进行一次又一次的初始化,对吗?
-
关于批量大小的要求,对于训练和验证来说,你会很舒服。这是因为您只是在评估损失和准确性,并且不会因为批量大小而有所不同。这使您可以同时使用可重新初始化的迭代器或可馈送的迭代器,而不必担心如何处理图形
-
关于形状,数据集中的形状包括第一个维度,即批量大小。因此,在这种情况下,形状本身会有所不同,因为批次中的元素数量不同。正如你所说,其他维度具有相同的形状。
标签: python-3.x tensorflow