我正在尝试使BatchNormalization在Keras(2.2.4)中正常工作,并且还没有运气。在model.fit()
和model.predict()
/ evaluate()
中,其行为似乎不一致。
我最初的问题是在一个复杂的GAN设置的背景下,它具有在冻结和未冻结之间切换的各个层。为了弄清失败的原因,我创建了这个玩具示例,其中只有一个BatchNormalization层试图学习身份函数,并且不再冻结/解冻废话了:
import numpy as np
import keras
from keras.layers import Input, BatchNormalization
if __name__ == '__main__':
x = np.random.uniform(low=-1.0, high=1.0, size=(20,1,))
y = x
ip = tx =Input(shape=[1,])
tx = BatchNormalization()(tx)
mod = keras.Model(inputs=ip, outputs=tx)
mod.compile(optimizer=keras.optimizers.SGD(lr=0.01), loss="mse")
mod.fit(x, y, epochs=2000)
print("mod evaluate", mod.evaluate(x, y))
我还创建了一个纯tensorflow实现,尝试执行完全相同的操作:
import tensorflow as tf
import numpy as np
if __name__ == '__main__':
x = np.random.uniform(low=-1.0, high=1.0, size=(20,1))
y = x
input = tx = tf.Variable(initial_value=x)
is_training = tf.Variable(initial_value=False)
tx = tf.layers.batch_normalization(tx, training=is_training)
output = tx
train_output = tf.placeholder(tf.float32, shape=(None, 1))
update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
loss = tf.losses.mean_squared_error(train_output, output)
train_op = tf.train.MomentumOptimizer(learning_rate=0.01, momentum=0.9).minimize(loss)
train_op = tf.group([train_op, update_ops])
sess = tf.Session()
sess.run(tf.global_variables_initializer())
is_training.load(False, sess)
py = sess.run(output)
print("py", py)
print("mse", np.mean(np.square(py - x)))
print("training...")
for i in range(2000):
is_training.load(True, sess)
sess.run(train_op, {train_output: y})
is_training.load(False, sess)
py = sess.run(output)
print("step", i, "mse", np.mean(np.square(py - x)))
is_training.load(False, sess)
py = sess.run(output)
print("mse", np.mean(np.square(py - x)))
我希望Keras和Tensorflow的结果相似。但是Keras代码最后会打印出约0.0002的MSE错误,而在训练过程中损失约1e-12。 Tensorflow代码为训练和测试提供了一种更低的误差,大约为1e-16。 Tensorflow结果是预期结果,因为学习恒等函数应该是微不足道的,并且一旦BN的移动平均值和方差收敛,在整个训练/测试中结果应该是相同的。
为什么会这样?为什么Tensorflow和Keras之间的行为不一致,如何使用纯Keras获得较低的错误?对情况有任何见识将不胜感激。