Keras:当相同的输入被传递给两个函数时,为什么 train_on_batch() 和 test_on_batch() 的损失不同?

Uma*_*aid 3 python deep-learning keras tensorflow

我将相同的输入(即相同的数据和相同的真实标签)传递给 keras train_on_batch() 和 test_on_batch()。我想知道为什么我的两个函数得到不同的损失值。

代码:

model_del_fin.compile(optimizer=SGD(lr=0.001,decay=0.001/15), loss='categorical_crossentropy',metrics=['accuracy'])
iters_per_epoch = 1285 // 50
print(iters_per_epoch)
num_epochs = 15
outs_store_freq = 20 # in iters
print_loss_freq = 20 # in iters

iter_num = 0
epoch_num = 0
model_outputs = []
loss_history  = []

while epoch_num < num_epochs:
  print("ok")
  while iter_num < iters_per_epoch:
    x_train, y_train = next(train_it2)
    loss_history += [model_del_fin.train_on_batch([x_train,x_train], y_train)]
    print("Iter {} loss: {}".format(iter_num, loss_history[-1]))
    print(model_del_fin.test_on_batch([x_train,x_train], y_train))
    iter_num += 1
  print("EPOCH {} FINISHED".format(epoch_num + 1))

  epoch_num += 1
  iter_num = 0 # reset counter
Run Code Online (Sandbox Code Playgroud)

**结果: **

Iter 0 loss: [5.860205, 0.24] [2.5426426, 0.68] Iter 1 loss: [3.5718067, 0.48] [1.7102847, 0.68] Iter 2 loss: [2.0221960, 16.16, 16.16, 16.16] ] [1.2987132, 0.92]

Ove*_*gon 5

问题源于在训练模式推理模式下向模型提供数据;差异包括:

  • 训练模式Dropout处于活动状态,BatchNormalization使用批量统计来计算均值和方差
  • 推理:所有Dropout比率都设置为零,并BatchNormalization使用指数移动平均统计来计算均值和方差,在训练期间计算

其他差异也适用。假设您的代码中使用的模型基于其他问题(即 VGG)中的模型 - 它将是 BN 层。作为解决方法,您可以通过以下方式临时设置全局学习阶段:

K.set_learning_phase(0) # INFERENCE MODE
K.set_learning_phase(1) # TRAIN MODE
Run Code Online (Sandbox Code Playgroud)

但是请注意,其中任何一个都必须在实例化模型之前执行,否则更改将不适用。此外,这可能无法完全解决问题,因为众所周知 BN 有其他问题(我目前正在调查)——但结果应该更接近一致。

最后,如果你第一次调用train_on_batch()调用test_on_batch(),这两个会不同意,因为test执行后train已更新的权重-这样,调用test_on_batch()第一,然后 train_on_batch()


完整示例

from tensorflow.keras.layers import Input, Dense, Dropout
from tensorflow.keras.models import Model
import tensorflow.keras.backend as K
import numpy as np

K.set_learning_phase(0)

ipt = Input((12,))
x   = Dropout(0.1)(ipt)
out = Dense(12)(x)

model = Model(ipt, out)
model.compile('adam', 'mse')
X = np.random.randn(32, 12)

print(model.train_on_batch(X, X))
print(model.test_on_batch(X, X))
print(model.train_on_batch(X, X))
Run Code Online (Sandbox Code Playgroud)
2.1212778 # train_on_batch()
2.1128066 # test_on_batch()
2.1128066 # train_on_batch()
Run Code Online (Sandbox Code Playgroud)

尝试K.set_learning_phase(1)改为使用以查看差异 - 或完全将其注释掉,1无论如何都是默认值。