Как сохранить и загрузить слой нормализации пакетов в этой модели тензорного потока?

#python #tensorflow #keras #tf.keras #keras-layer

Вопрос:

Я пытаюсь сохранить модель , а затем загрузить ее позже, чтобы сделать некоторые прогнозы; происходит то, что точность модели после обучения равна 95% , но когда я сохраняю ее, а затем загружаю, точность падает почти 10% до того же набора данных.

Чтобы воспроизвести этот ошибочный результат, вы можете запустить этот действительно маленький блокнот.

Модель определяется следующим образом:

 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 , но я не могу понять, как ее исправить. Как правильно сохранить и загрузить модель, чтобы она давала те же результаты?

Комментарии:

1. Взгляните на это: tensorflow.org/tutorials/keras/save_and_load Это должно быть так, как вы хотите.

2. Какую версию Tensorflow вы используете?

3. Недавно я обновил TensorFlow до версии 2.6.0, и он дает те же результаты, вы также можете запустить его на Colab, используя ссылку, которую я упомянул в вопросе, которая также дает те же результаты

Ответ №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]
 

Комментарии:

1. Ты имеешь в виду test_model или test_model.h5 ?

2. Нет, есть 2 способа сохранения модели: с помощью 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) сохранения не сохраняет костюмную часть модели, поэтому точность была низкой. Но с помощью другого метода все сохраняется.