【问题标题】:Keras model.fit() with tf.dataset fails while using tf.train works fine使用 tf.train 时带有 tf.dataset 的 Keras model.fit() 工作正常
【发布时间】:2019-01-05 19:55:30
【问题描述】:

总结:根据documentation,Kerasmodel.fit() 应该接受 tf.dataset 作为输入(我使用的是 TF 版本 1.12.0)。如果我手动执行训练步骤,我可以训练我的模型,但在同一模型上使用 model.fit(),我得到一个我无法解决的错误。

这是我所做工作的草图:我的数据集太大而无法放入内存,它由许多文件组成,每个文件都有不同的行数(100 个特征,标签)。我想使用tf.data 来构建我的数据管道:

def data_loader(filename):
    '''load a single data file with many rows'''
    features, labels = load_hdf5(filename)
    ...
    return features, labels

def make_dataset(filenames, batch_size):
    '''read files one by one, pick individual rows, batch them and repeat'''
    dataset = tf.data.Dataset.from_tensor_slices(filenames)
    dataset = dataset.map(      # Problem here! See edit for solution
        lambda filename: tuple(tf.py_func(data_loader, [filename], [float32, tf.float32])))
    dataset = dataset.flat_map(
        lambda features, labels: tf.data.Dataset.from_tensor_slices((features, labels)))
    dataset = dataset.batch(batch_size)
    dataset = dataset.repeat()
    dataset = dataset.prefetch(1000)
    return dataset

_BATCH_SIZE = 128
training_set = make_dataset(training_files, batch_size=_BATCH_SIZE)

我想尝试一个非常基本的逻辑回归模型:

inputs = tf.keras.layers.Input(shape=(100,))
outputs = tf.keras.layers.Dense(1, activation='softmax')(inputs)
model = tf.keras.Model(inputs, outputs)

如果我手动训练它一切正常,例如:

labels = tf.placeholder(tf.float32)
loss = tf.reduce_mean(tf.keras.backend.categorical_crossentropy(labels, outputs))
train_step = tf.train.GradientDescentOptimizer(.05).minimize(loss)

iterator = training_set.make_one_shot_iterator()
next_element = iterator.get_next()
init_op = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init_op)
    for i in range(training_size // _BATCH_SIZE):
        x, y = sess.run(next_element)
        train_step.run(feed_dict={inputs: x, labels: y})

但是,如果我尝试像这样使用model.fit

model.compile('adam', 'categorical_crossentropy', metrics=['acc'])
model.fit(training_set.make_one_shot_iterator(),
          steps_per_epoch=training_size // _BATCH_SIZE,
          epochs=1,
          verbose=1)

我在 keras'es _standardize_user_data 函数中收到一条错误消息 ValueError: Cannot take the length of Shape with unknown rank.

我尝试了很多方法,但无法解决问题。有什么想法吗?

编辑: 基于@kvish 的回答,解决方案是将映射从 lambda 更改为指定正确张量维度的函数,例如:

def data_loader(filename):
    def loader_impl(filename):
        features, labels, _ = load_hdf5(filename)
        ...
        return features, labels

    features, labels = tf.py_func(loader_impl, [filename], [tf.float32, tf.float32])
    features.set_shape((None, 100))
    labels.set_shape((None, 1))
    return features, labels

现在,需要做的就是从map调用这个函数:

dataset = dataset.map(data_loader)

【问题讨论】:

  • 如果只是将training_set 传递给fit 方法,是否仍然会出现错误?
  • 是的,同样的问题。
  • @AlefSin 既然您使用的是 tf.py_func,也许它在使用 Keras 时需要知道形状?您可以使用 set_shape(your_shape) 方法设置从 tf.py_func 获得的张量的形状,看看是否有什么不同?
  • @kvish 哇!精彩的。这成功了,非常感谢!如果您提交您的评论作为答案,我会接受。
  • @AlefSin 当然!很高兴它有帮助!

标签: python tensorflow keras


【解决方案1】:

可能 tf.py_func 会产生 Keras 无法推断的未知形状。我们可以使用 set_shape(your_shape) 方法设置它返回的张量的形状,这将有助于 Keras 推断结果的形状。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-22
    • 2022-01-07
    • 2018-07-24
    • 2021-01-13
    • 1970-01-01
    • 2019-08-08
    • 2017-12-14
    相关资源
    最近更新 更多