我正试图保存一个模型,然后稍后加载它进行一些预测;问题在于,训练后模型的准确率为95%+
,但是当我保存并加载它时,在相同数据集上准确率降至近10%
。
要重现这个错误的结果,您可以运行this非常小的笔记本。
该模型定义如下:
model_scratch_auto = models.Sequential()
model_scratch_auto.add(Flatten(input_shape=(28,28)))
model_scratch_auto.add(Dense(80, activation='relu'))
model_scratch_auto.add(Dense(100, activation='relu'))
model_scratch_auto.add(Dense(120, activation='relu'))
model_scratch_auto.add(Dense(100, activation='relu'))
auto_srelu=AutoSRELU()
model_scratch_auto.add(auto_srelu)
model_scratch_auto.add(Dense(120, activation='relu'))
model_scratch_auto.add(auto_srelu)
model_scratch_auto.add(BatchNormalization())
model_scratch_auto.add(Dense(10, activation='softmax'))
model_scratch_auto.compile(optimizer = tf.optimizers.Adam(),loss='categorical_crossentropy', metrics=['acc',f1_m,precision_m, recall_m])
model_scratch_auto.fit(X_train, y_train , batch_size=64, epochs=5, validation_data=(X_test, y_test),verbose=1)
自定义层AutoSRELU
的定义如下:
initializer0 = keras.initializers.RandomUniform(minval = -1, maxval =1)
initializer1 = keras.initializers.RandomUniform(minval = 0.5, maxval =3)
class MinMaxConstraint(keras.constraints.Constraint):
def __init__(self, minval, maxval):
self.minval = tf.constant(minval ,dtype='float32')
self.maxval = tf.constant(maxval ,dtype='float32')
def __call__(self, w):
tf.cond(tf.greater(self.minval,w)
, lambda: w + (self.minval - w)
, lambda: tf.cond(tf.greater(w,self.maxval)
, lambda: w - (w - self.maxval)
, lambda: w))
def get_config(self):
return {'Lower Bound': self.minval, 'Upper Bound':self.maxval}
def srelu(inputs, k1, k2):
cond1 = tf.cast(tf.math.less(inputs, 0.0), tf.float32)
cond2 = tf.cast(tf.math.greater_equal(inputs, 0.0), tf.float32)
a = tf.math.multiply(cond1, tf.add(k1,tf.multiply(0.3, inputs)))
b = tf.math.multiply(cond2, tf.add(k1,tf.multiply(k2, inputs)))
outputs = a + b
return outputs
class AutoSRELU(keras.layers.Layer):
def __init__(self, trainable = True, **kwargs):
super(AutoSRELU, self).__init__()
self.k1 = self.add_weight(name='k', shape = (), initializer=initializer0, trainable=trainable)#, constraint=keras.constraints.NonNeg())
self.k2 = self.add_weight(name='n', shape = (), initializer=initializer1, trainable=trainable)#, constraint=MinMaxConstraint(1,10))
def call(self, inputs):
return srelu(inputs, self.k1, self.k2)
然后我使用
evaluate()
函数评估模型性能,得到以下结果:model_scratch_auto.evaluate(X_train, y_train)
输出:
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0517 - acc: 0.9834 - f1_m: 0.9836 - precision_m: 0.9851 - recall_m: 0.9823
[0.05167238786816597,
0.9834166765213013,
0.983639121055603,
0.9850572943687439,
0.9822666645050049]
然后我将模型保存为:
model_scratch_auto.save('test_model.h5')
当我按照以下设置依赖项加载相同的模型时:
dependencies = {
'f1_m': f1_m,
'precision_m': precision_m,
'recall_m': recall_m,
'AutoSRELU': AutoSRELU
}
test_model = models.load_model('test_model.h5', custom_objects=dependencies)
当我在相同的数据集上评估这个模型时,我得到了以下结果:
test_model.evaluate(X_train, y_train)
输出:
1875/1875 [==============================] - 2s 1ms/step - loss: 8.5696 - acc: 0.1047 - f1_m: 0.1047 - precision_m: 0.1047 - recall_m: 0.1047
[8.569587707519531,
0.10468333214521408,
0.10468332469463348,
0.10468333214521408,
0.10468333214521408]
如您所见,将同一模型保存并在同一数据集上进行评估显著地降低了性能。我尝试了很多方法来查明原因,发现删除
BatchNormalization()
和AutoSRELU
可以解决问题,但我似乎无法理解它们为什么会导致这个问题。为了确定RandomUniform
函数是否可能引起一些问题,我多次重新运行加载部分以及类定义,以查看加载的模型中是否存在一些随机性,但每次都会返回相同且更差的结果。然后我发现删除批量归一化层几乎给出了相同的结果。因此,我能够将问题缩小到
BatchNormalization
AutoSRELU
,但我不知道如何纠正它。如何正确保存和加载模型,以便它给出相同的结果?