【问题标题】:How do I save and load BatchNormalization Layer in this Tensorflow model?如何在这个 Tensorflow 模型中保存和加载 BatchNormalization 层?
【发布时间】:2021-11-02 14:27:27
【问题描述】:

我正在尝试保存一个模型,然后稍后加载它以进行一些预测;发生的情况是模型训练后的准确率是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 函数是否可能导致一些问题,我多次重新运行加载部分以及类定义,以查看加载的模型中是否存在一些随机性,但每次都返回相同的更差结果。然后我看到删除批量标准化层得到了几乎相同的结果。

所以我能够将问题缩小到BatchNormalizationAutoSRELU,但我不明白如何纠正它。如何正确保存和加载模型以使其得到相同的结果?

【问题讨论】:

  • 看看这个:tensorflow.org/tutorials/keras/save_and_load它应该是你想要的。
  • 你运行的是什么版本的 Tensorflow?
  • 我最近将 TensorFlow 更新到 2.6.0,它给出了相同的结果,您也可以使用我在问题中提到的链接在 Colab 上运行它,这也给出了相同的结果

标签: python tensorflow keras tf.keras keras-layer


【解决方案1】:

替换模型从 Keras 到 TF 的保存。

tf.keras.models.save_model(model_scratch_auto, "test_model")

我在你的笔记本上做了,它成功了 :)

model_scratch_auto.evaluate(X_train, y_train)
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0848 - acc: 0.9747 - f1_m: 0.9749 - precision_m: 0.9781 - recall_m: 0.9718
[0.08477196097373962,
 0.9746833443641663,
 0.9748622179031372,
 0.9780662059783936,
 0.9717833399772644]

test_model.evaluate(X_train, y_train)
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0791 - acc: 0.9821 - f1_m: 0.9822 - precision_m: 0.9827 - recall_m: 0.9817
[0.07907719910144806,
 0.9820666909217834,
 0.9821747541427612,
 0.9827000498771667,
 0.9816666841506958]

【讨论】:

  • 你的意思是test_model还是test_model.h5
  • 不,有两种保存模型的方法,使用 Keras (model.save()) 和使用 TensorFlow (tf.keras.models.save_model())。因此,将 model.save("test_model.h5") 替换为 tf.keras.models.save_model(model_scratch_auto, "test_model")。我认为第一种类型(Keras)的保存并没有保留模型的服装部分,这就是为什么准确性低的原因。但是用另一种方法,一切都得到了保护。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-12
  • 2020-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多