我可以使用tf.keras.utils.image_dataset_from_directory的输出来训练自动编码器吗?

up9lanfz  于 2023-01-30  发布在  其他
关注(0)|答案(1)|浏览(150)

简单地说,我希望能够使用从本Map像目录创建的keras数据集来训练自动编码器。为了澄清,这是一个近似于图像的Identity函数的模型:理想的是,输出正好等于输入。
数据集太大,内存无法容纳,因此使用np.concatenate将数据集转换为numpy数组在这里没有帮助。
或者换句话说,我想要一个Identity图像数据集,其中数据集中每个图像的标签都与图像本身完全相同。
下面是我的(非工作)示例代码:

train_ds, validate_ds = tf.keras.utils.image_dataset_from_directory(
  data_dir,
  labels=None,
  validation_split=0.1,
  subset="both",
  shuffle=True,
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size,
  crop_to_aspect_ratio=True)

history = autoencoder.fit(
  x=train_ds,
  y=train_ds,
  validation_data=(validate_ds, validate_ds),
  epochs=epochs,
  batch_size=16
)

image_dataset_from_directory函数提供了一个没有标签的图像数据集,到目前为止一切顺利。
第二个命令失败,并显示错误消息:

ValueError: `y` argument is not supported when using dataset as input.

另一方面,如果我排除y变量,我得到这个错误:

ValueError: Target data is missing. Your model was compiled with loss=binary_crossentropy, and therefore expects target data to be provided in `fit()`.

这一点也不奇怪,因为没有标签,正如我所要求的那样,但是它不允许我使用数据集作为标签,这是我需要做的。
任何帮助都将不胜感激。

epggiuax

epggiuax1#

虽然有很多方法可以修改数据集,但我认为最好的选择是编写一个自定义模型类,这是从the official tutorial修改而来的:

class Autoencoder(tf.keras.Model):
    def train_step(self, data):
        # Unpack the data. Its structure depends on your model and
        # on what you pass to `fit()`.
        x = data  # CHANGE 1: changed from x, y = data

        with tf.GradientTape() as tape:
            y_pred = self(x, training=True)  # Forward pass
            # Compute the loss value
            # (the loss function is configured in `compile()`)
            loss = self.compiled_loss(x, y_pred, regularization_losses=self.losses)  # CHANGE 2: replaced y by x as label

        # Compute gradients
        trainable_vars = self.trainable_variables
        gradients = tape.gradient(loss, trainable_vars)
        # Update weights
        self.optimizer.apply_gradients(zip(gradients, trainable_vars))
        # Update metrics (includes the metric that tracks the loss)
        self.compiled_metrics.update_state(x, y_pred)  # CHANGE 3: like change 2
        # Return a dict mapping metric names to current value
        return {m.name: m.result() for m in self.metrics}

    def test_step(self, data):
        # CHANGED in the same way
        x = data
        # Compute predictions
        y_pred = self(x, training=False)
        # Updates the metrics tracking the loss
        self.compiled_loss(x, y_pred, regularization_losses=self.losses)
        # Update the metrics.
        self.compiled_metrics.update_state(x, y_pred)
        # Return a dict mapping metric names to current value.
        # Note that it will include the loss (tracked in self.metrics).
        return {m.name: m.result() for m in self.metrics}

这是函数API(tf.keras.Model),如果你使用的是Sequential模型,你应该从它继承,你可以直接用它来代替普通的模型构造函数。
另一种选择是使用train_zipped = tf.data.Dataset.zip((train_ds, train_ds))创建一个input, target数据集,您可以将其直接放入常用的模型和损失函数中。就我个人而言,我不喜欢复制。此外,我不确定这是否会正确地用于混洗数据(train_ds的两个副本是否会以相同的方式混洗?)
您可以通过在image_dataset_from_directory中设置shuffle=False,然后使用train_zipped = train_zipped.shuffle(buffer_size)来避免这种情况,但是,根据我的经验,这非常慢。

相关问题