【问题标题】:tf.data with multiple inputs / outputs in KerasKeras 中具有多个输入/输出的 tf.data
【发布时间】:2019-03-06 01:00:10
【问题描述】:

对于应用,如pair textsimilarity,输入数据类似:pair_1, pair_2。在这些问题中,我们通常有多个输入数据。以前,我成功地实现了我的模型:

model.fit([pair_1, pair_2], labels, epochs=50)

我决定用tf.data API 替换我的输入管道。为此,我创建了一个类似于以下内容的数据集:

dataset = tf.data.Dataset.from_tensor_slices((pair_1, pair2, labels))

编译成功,但开始训练时抛出以下异常:

AttributeError: 'tuple' object has no attribute 'ndim'

我的 Keras 和 Tensorflow 版本分别是 2.1.61.11.0。我在 Tensorflow 存储库中发现了一个类似的问题: tf.keras multi-input models don't work when using tf.data.Dataset.

有人知道如何解决这个问题吗?

这是代码的一些主要部分

(q1_test, q2_test, label_test) = test
(q1_train, q2_train, label_train) = train

    def tfdata_generator(sent1, sent2, labels, is_training):
        '''Construct a data generator using tf.Dataset'''

        dataset = tf.data.Dataset.from_tensor_slices((sent1, sent2, labels))
        if is_training:
            dataset = dataset.shuffle(1000)  # depends on sample size

        dataset = dataset.repeat()
        dataset = dataset.prefetch(tf.contrib.data.AUTOTUNE)

        return dataset

train_dataset = tfdata_generator(q1_train, q2_train, label_train, is_training=True, batch_size=_BATCH_SIZE)
test_dataset = tfdata_generator(q1_test, q2_test, label_test, is_training=False, batch_size=_BATCH_SIZE)


inps1 = keras.layers.Input(shape=(50,))
inps2 = keras.layers.Input(shape=(50,))

embed = keras.layers.Embedding(input_dim=nb_vocab, output_dim=300, weights=[embedding], trainable=False)
embed1 = embed(inps1)
embed2 = embed(inps2)

gru = keras.layers.CuDNNGRU(256)
gru1 = gru(embed1)
gru2 = gru(embed2)

concat = keras.layers.concatenate([gru1, gru2])

preds = keras.layers.Dense(1, 'sigmoid')(concat)

model = keras.models.Model(inputs=[inps1, inps2], outputs=preds)
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
print(model.summary())

model.fit(
    train_dataset.make_one_shot_iterator(),
    steps_per_epoch=len(q1_train) // _BATCH_SIZE,
    epochs=50,
    validation_data=test_dataset.make_one_shot_iterator(),
    validation_steps=len(q1_test) // _BATCH_SIZE,
    verbose=1)

【问题讨论】:

  • 也许错误与在另一个元组中嵌套元组有关?它不将内部元组识别为张量对象?你可以尝试喂它(pair1,pair2,labels)之类的东西,然后自己喂它,看看它是否有效?
  • 我修改了我的示例代码,现在应该可以使用了。您可以使用以下键传递字典而不是元组:“input_1”和“input_2”。
  • @lhlmgr 我可以用 from_tensor_slices() 做同样的事情吗?
  • @AmirHadifar 是的,看我的编辑
  • 试试 dataset = tf.data.Dataset.from_tensor_slices(((pair_1, pair2), labels))

标签: tensorflow keras tensorflow-datasets


【解决方案1】:

我没有使用 Keras,但我会使用 tf.data.Dataset.from_generator() - 比如:

def _input_fn():
  sent1 = np.array([1, 2, 3, 4, 5, 6, 7, 8], dtype=np.int64)
  sent2 = np.array([20, 25, 35, 40, 600, 30, 20, 30], dtype=np.int64)
  sent1 = np.reshape(sent1, (8, 1, 1))
  sent2 = np.reshape(sent2, (8, 1, 1))

  labels = np.array([40, 30, 20, 10, 80, 70, 50, 60], dtype=np.int64)
  labels = np.reshape(labels, (8, 1))

  def generator():
    for s1, s2, l in zip(sent1, sent2, labels):
      yield {"input_1": s1, "input_2": s2}, l

  dataset = tf.data.Dataset.from_generator(generator, output_types=({"input_1": tf.int64, "input_2": tf.int64}, tf.int64))
  dataset = dataset.batch(2)
  return dataset

...

model.fit(_input_fn(), epochs=10, steps_per_epoch=4)

这个生成器可以遍历你的例如 text-files / numpy 数组并在每次调用时产生一个示例。 在此示例中,我假设句子中的单词已经转换为词汇表中的索引。

编辑: 既然OP问了,Dataset.from_tensor_slices()应该也可以:

def _input_fn():
  sent1 = np.array([1, 2, 3, 4, 5, 6, 7, 8], dtype=np.int64)
  sent2 = np.array([20, 25, 35, 40, 600, 30, 20, 30], dtype=np.int64)
  sent1 = np.reshape(sent1, (8, 1))
  sent2 = np.reshape(sent2, (8, 1))

  labels = np.array([40, 30, 20, 10, 80, 70, 50, 60], dtype=np.int64)
  labels = np.reshape(labels, (8))

  dataset = tf.data.Dataset.from_tensor_slices(({"input_1": sent1, "input_2": sent2}, labels))
  dataset = dataset.batch(2, drop_remainder=True)
  return dataset

【讨论】:

  • 感谢您的回复。我的数据集相对较小,我更喜欢将所有这些都保存在内存中你有什么建议来解决** from_tensor_slices**的问题
  • 嗨,阿米尔。 2个问题,对不起,如果他们有点......愚蠢:github上的一个人提到:'因此,将迭代器直接提供给model.fit()的新功能仅在您使用时才有效 tf .Keras 不是独立的 Keras。 (他和你一样有同样的错误,并通过包含“正确”的 keras 来修复它。)另一个问题是,你 postet 两次 from_tensor_slices() 一个带有一个元组,一个带有一个三元组,哪一个是你使用的行?
  • 我使用了 tf.keras API。你是对的,但在这两种情况下,元组或三元组都不起作用。
  • 感谢这为我节省了很多精力
  • 感谢您的回复,但在 tensorflow 2.3.2 上有些东西对我不起作用。如果要问的不是太多,您能否更新您的答案以包含模型,以便进行复制/粘贴测试?再次感谢
【解决方案2】:

解决您的问题的一种方法是使用zip 数据集来组合您的各种输入:

sent1 = np.array([1, 2, 3, 4, 5, 6, 7, 8], dtype=np.float32)
sent2 = np.array([20, 25, 35, 40, 600, 30, 20, 30], dtype=np.float32)
sent1 = np.reshape(sent1, (8, 1, 1))
sent2 = np.reshape(sent2, (8, 1, 1))

labels = np.array([40, 30, 20, 10, 80, 70, 50, 60], dtype=np.float32)
labels = np.reshape(labels, (8, 1))

dataset_12 = tf.data.Dataset.from_tensor_slices((sent_1, sent_2))
dataset_label = tf.data.Dataset.from_tensor_slices(labels)

dataset = tf.data.Dataset.zip((dataset_12, dataset_label)).batch(2).repeat()
model.fit(dataset, epochs=10, steps_per_epoch=4)

将打印: Epoch 1/10 4/4 [==============================] - 2s 503ms/step...

【讨论】:

  • 谢谢@pfm。这听起来是个好主意。如果没有人提供另一种优雅的方式来解决问题,我会接受它。
  • @pfm 我也有类似的问题,你能帮我吗here
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-09
  • 2019-09-17
  • 2019-03-28
  • 2019-08-28
  • 2022-01-08
  • 2018-04-08
相关资源
最近更新 更多