【问题标题】:tf keras SparseCategoricalCrossentropy and sparse_categorical_accuracy reporting wrong values during trainingtf keras SparseCategoricalCrossentropy 和 sparse_categorical_accuracy 在训练期间报告错误值
【发布时间】:2021-02-01 01:20:39
【问题描述】:

这是 tf 2.3.0。在训练期间,报告的 SparseCategoricalCrossentropy 损失和 sparse_categorical_accuracy 的值似乎很遥远。我查看了我的代码,但还没有发现任何错误。这是要重现的代码:

import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

x = np.random.randint(0, 255, size=(64, 224, 224, 3)).astype('float32')
y = np.random.randint(0, 3, (64, 1)).astype('int32')

ds = tf.data.Dataset.from_tensor_slices((x, y)).batch(32)

def create_model():
  input_layer = tf.keras.layers.Input(shape=(224, 224, 3), name='img_input')
  x = tf.keras.layers.experimental.preprocessing.Rescaling(1./255, name='rescale_1_over_255')(input_layer)

  base_model = tf.keras.applications.ResNet50(input_tensor=x, weights='imagenet', include_top=False)

  x = tf.keras.layers.GlobalAveragePooling2D(name='global_avg_pool_2d')(base_model.output)

  output = Dense(3, activation='softmax', name='predictions')(x)

  return tf.keras.models.Model(inputs=input_layer, outputs=output)

model = create_model()

model.compile(
  optimizer=tf.keras.optimizers.Adam(learning_rate=1e-4),
  loss=tf.keras.losses.SparseCategoricalCrossentropy(), 
  metrics=['sparse_categorical_accuracy']
)

model.fit(ds, steps_per_epoch=2, epochs=5)

这是打印出来的:

Epoch 1/5
2/2 [==============================] - 0s 91ms/step - loss: 1.5160 - sparse_categorical_accuracy: 0.2969
Epoch 2/5
2/2 [==============================] - 0s 85ms/step - loss: 0.0892 - sparse_categorical_accuracy: 1.0000
Epoch 3/5
2/2 [==============================] - 0s 84ms/step - loss: 0.0230 - sparse_categorical_accuracy: 1.0000
Epoch 4/5
2/2 [==============================] - 0s 82ms/step - loss: 0.0109 - sparse_categorical_accuracy: 1.0000
Epoch 5/5
2/2 [==============================] - 0s 82ms/step - loss: 0.0065 - sparse_categorical_accuracy: 1.0000

但是,如果我仔细检查 model.evaluate,并“手动”检查准确性:

model.evaluate(ds)

2/2 [==============================] - 0s 25ms/step - loss: 1.2681 - sparse_categorical_accuracy: 0.2188
[1.268101453781128, 0.21875]

y_pred = model.predict(ds)
y_pred = np.argmax(y_pred, axis=-1)
y_pred = y_pred.reshape(-1, 1)
np.sum(y == y_pred)/len(y)

0.21875

model.evaluate(...) 的结果与“手动”检查的指标一致。但如果你盯着训练中的损失/指标,它们看起来很遥远。因为从来没有抛出错误或异常,所以很难看出哪里出了问题。

此外,我创建了一个非常简单的案例来尝试重现这一点,但它实际上在这里无法重现。请注意,batch_size == 数据长度,因此这不是小批量 GD,而是全批量 GD(以消除与小批量损失/指标的混淆:

x = np.random.randn(1024, 1).astype('float32')
y = np.random.randint(0, 3, (1024, 1)).astype('int32')
ds = tf.data.Dataset.from_tensor_slices((x, y)).batch(1024)
model = Sequential()
model.add(Dense(3, activation='softmax'))
model.compile(
    optimizer=tf.keras.optimizers.Adam(learning_rate=1e-4),
    loss=tf.keras.losses.SparseCategoricalCrossentropy(), 
    metrics=['sparse_categorical_accuracy']
)
model.fit(ds, epochs=5)
model.evaluate(ds)

正如我在评论中提到的,一个嫌疑人是批量规范层,对于无法重现的情况,我没有。

【问题讨论】:

  • 这是什么tf.__version__
  • 我想我可以用colab.research.google.com/github/keras-team/keras-io/blob/… 重现这个,我删除了 dropout 和 data_aug 以避免潜在的混淆。该笔记本中的损失/指标是不同的。我开始怀疑是否有一个良性的直截了当的解释
  • @NicolasGervais 2.3.0,我是在 google colab 上完成的
  • 我怀疑这与模型中存在批处理规范层有关。我认为它的行为会有所不同,具体取决于 is_training 是否为真。
  • 在重现这个错误时,我使用了非常非常小的数据集,我想知道批量规范是否会导致进度条上打印的损失/指标与小型集的真实数据存在如此大的偏差。指标比损失更可怕(我知道损失是小批量与整个批次),因为我认为它是通过 update_state(...) 调用“累积”的。

标签: tensorflow keras cross-entropy


【解决方案1】:

模型中存在batch norm 可以解释(或至少部分如此)指标中的巨大差异。将提出 2 种情况,其中一种是不可重现的,另一种是在引入批量规范时重现。在这两种情况下,batch_size 都等于数据的全长(也就是没有“随机”的全梯度下降),以最大限度地减少对小批量统计的混淆。

不可重现:

  x = np.random.randn(1024, 1).astype('float32')
  y = np.random.randint(0, 3, (1024, 1)).astype('int32')
  ds = tf.data.Dataset.from_tensor_slices((x, y)).batch(1024)

  model = Sequential()
  model.add(Dense(10, activation='relu'))
  model.add(Dense(10, activation='relu'))
  model.add(Dense(10, activation='relu'))
  model.add(Dense(3, activation='softmax'))

可重现:

  model = Sequential()
  model.add(Dense(10))
  model.add(BatchNormalization())
  model.add(Activation('relu'))
  model.add(Dense(10))
  model.add(BatchNormalization())
  model.add(Activation('relu'))
  model.add(Dense(10))
  model.add(BatchNormalization())
  model.add(Activation('relu'))

  model.add(Dense(3, activation='softmax'))

其实你可以试试model.predict(x), model(x, training=True),你会发现y_pred有很大的不同。此外,根据 keras 文档,此结果还取决于批次中的内容。因此,x[0] 的预测模型(x[0:1], training=True) 与模型(x[0:2], training=True) 的不同之处在于包含一个额外的样本。

可能最好转到 Keras 文档和原始论文了解详细信息,但我确实认为您将不得不忍受这一点并相应地解释您在进度栏中看到的内容。如果您尝试使用训练损失/准确性来查看您是否有偏差(而不是方差)问题,这看起来很可疑。如有疑问,我认为我们可以在火车上运行评估,以确定您的模型何时“收敛”到一个极小的最小值。在我之前的工作中,我有点忽略了这个细节,因为在深度网络中欠拟合(偏差)很少见,所以我通过验证损失/指标来确定何时停止训练。但我可能会回到同一个模型并在训练集上进行评估(只是为了看看模型是否具有容量(而不是偏差)。

【讨论】:

    【解决方案2】:

    您会得到不同的结果,因为 fit() 将训练损失显示为当前时期内每批训练数据的损失平均值。这可以降低历元平均值。并且计算出的损失被进一步用于更新模型。然而,evaluate() 是在训练结束时使用模型计算的,导致不同的损失。可以查看官方的Keras FAQ和相关的StackOverflow post

    另外,尝试提高学习率。

    【讨论】:

    • 我认为您可能部分正确,但可能无法完全解释我观察到的巨大差异。我可以在colab.research.google.com/github/keras-team/keras-io/blob/… 上重现这个。如果是这样,那么进度条损失/指标作为指南非常不可靠
    • 另外,为了消除批次平均的问题,我用全批次梯度下降法重现了这一点,从而在 1 步中实现了 1 个 epoch。我仍然看到准确度存在巨大差异,例如 1.0 与 0.3125。
    • 另外,我验证了稀疏分类准确度正在“累积”平均,不仅在当前批次上,因此在最后,指标适用于整个数据集(1 个时期)。由于 TPU 的错误,我出于必要重新实现了我自己的“稀疏猫精度”,并确认这与 tf.keras.metrics.SparseCategoricalAccuracy 和预期的行为完全匹配。我相当有信心我原来的问题现在完全是由于批处理规范层。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-20
    • 2020-07-01
    • 2019-09-02
    • 2021-12-25
    • 2016-11-16
    • 1970-01-01
    相关资源
    最近更新 更多