在执行第一个 epoch 后,Tensorflow 无法将批次附加在一起

Posted

技术标签:

【中文标题】在执行第一个 epoch 后,Tensorflow 无法将批次附加在一起【英文标题】:Tensorflow can't append batches together after doing the first epoch 【发布时间】:2021-12-09 07:28:32 【问题描述】:

在我删除compile 步骤的损失函数(将其设置为loss=None)并添加一个以通过add_loss 方法添加另一个损失函数后,我的代码遇到了问题.我可以打电话给fit,它会训练一个纪元,但后来我得到了这个错误:

ValueError: operands could not be broadcast together with shapes (128,) (117,) (128,) 

我的批量大小是 128。看起来117 在某种程度上取决于我使用的示例数量。当我改变示例的数量时,我从117 得到不同的数字。它们都是我的示例数量以及我的批量大小。我不知道如何解决这个问题。我使用tf.data.TFRecordDataset 作为输入。

我有以下简化模型:

class MyModel(Model):

  def __init__(self):
    super(MyModel, self).__init__()

    encoder_input = layers.Input(shape=INPUT_SHAPE, name='encoder_input')
    x = encoder_input
    x = layers.Conv2D(64, (3, 3), activation='relu', padding='same', strides=2)(x)
    x = layers.BatchNormalization()(x)
    x = layers.Conv2D(32, (3, 3), activation='relu', padding='same', strides=2)(x)
    x = layers.BatchNormalization()(x)
    x = layers.Flatten()(x)

    encoded = layers.Dense(LATENT_DIM, name='encoded')(x)

    self.encoder = Model(encoder_input, outputs=[encoded])

    self.decoder = tf.keras.Sequential([
      layers.Input(shape=LATENT_DIM),
      layers.Dense(32 * 32 * 32),
      layers.Reshape((32, 32, 32)),
      layers.Conv2DTranspose(32, kernel_size=3, strides=2, activation='relu', padding='same'),
      layers.Conv2DTranspose(64, kernel_size=3, strides=2, activation='relu', padding='same'),
      layers.Conv2D(3, kernel_size=(3, 3), activation='sigmoid', padding='same')])

  def call(self, x):
    encoded = self.encoder(x)

    decoded = self.decoder(encoded)

    # Loss function. Has to be here because I intend to add another, more layer-interdependent, loss function.
    r_loss = tf.math.reduce_sum(tf.math.square(x - decoded), axis=[1, 2, 3])
    self.add_loss(r_loss)

    return decoded


def read_tfrecord(example):
  example = tf.io.parse_single_example(example, CELEB_A_FORMAT)
  image = decode_image(example['image'])

  return image, image

def load_dataset(filenames, func):
  dataset = tf.data.TFRecordDataset(
    filenames
  )

  dataset = dataset.map(partial(func), num_parallel_calls=tf.data.AUTOTUNE)

  return dataset

def train_autoencoder():
  filenames_train = glob.glob(TRAIN_PATH)
  train_dataset_x_x = load_dataset(filenames_train[:4], func=read_tfrecord)

  autoencoder = Autoencoder()

  # The loss function used to be defined here and everything worked fine before.
  def r_loss(y_true, y_pred):
    return tf.math.reduce_sum(tf.math.square(y_true - y_pred), axis=[1, 2, 3])

  optimizer = tf.keras.optimizers.Adam(1e-4)

  autoencoder.compile(optimizer=optimizer, loss=None)

  autoencoder.fit(train_dataset_x_x.batch(AUTOENCODER_BATCH_SIZE),
                  epochs=AUTOENCODER_NUM_EPOCHS,
                  shuffle=True)

【问题讨论】:

出于好奇,INPUT_SHAPE的值是多少? @dsillman2000,我是INPUT_SHAPE = (128, 128, 3) 如果您将其更改为 (None, 128, 3),批量大小可能会更灵活 【参考方案1】:

如果您只想摆脱错误而不关心数据集的最后一个“剩余”批次,您可以在 train_dataset_x_x.batch() 中使用关键字参数 drop_remainder=True,这样您的所有批次大小相同。

仅供参考,通常更好的做法是在 fit 的函数调用之外对数据集进行批处理:

data = data.batch(32)
model.fit(data)

【讨论】:

删除剩余部分是目前可接受的解决方法。很好的快速回答!【参考方案2】:

调用方法中不能设置损失函数。 call 方法旨在进行前向传递而不是计算损失。

你需要在编译方法中或之后添加损失函数

【讨论】:

这不能回答问题。这是对作者的有效建议,但应该是评论而不是答案。

以上是关于在执行第一个 epoch 后,Tensorflow 无法将批次附加在一起的主要内容,如果未能解决你的问题,请参考以下文章

训练神经网络时,Tensorflow 完成后会自动恢复到最佳 epoch 吗?

TensorFlow 中的 step 和 epoch 有啥区别?

为啥 Keras 损失在第一个 epoch 之后急剧下降?

如何修改 Tensorflow 2.0 中的 epoch 数?

Tensorflow 在每个 epoch 结束时卡住了几秒钟

PyTorch-lightning 模型在第一个 epoch 后内存不足