Estoy tratando de guardar un modelo y luego cargarlo más tarde para hacer algunas predicciones; lo que sucede es que la precisión del modelo después del entrenamiento es del 95%+ más, pero cuando lo guardo y luego lo cargo, la precisión cae a casi el 10% en el mismo conjunto de datos.
Para reproducir este resultado erróneo, puede ejecutar este portátil realmente pequeño.
El modelo se define de la siguiente manera:
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) Donde la capa personalizada, AutoSRELU se define de la siguiente manera:
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) Luego evalúo el desempeño del modelo usando la función evaluate() y obtengo el siguiente resultado:
model_scratch_auto.evaluate(X_train, y_train)Producción:
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]Luego guardo el modelo como:
model_scratch_auto.save('test_model.h5')Y cuando cargo el mismo modelo configurando las dependencias de la siguiente manera:
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)Y cuando evalúo este modelo en el mismo conjunto de datos, obtengo el siguiente resultado:
test_model.evaluate(X_train, y_train)Producción:
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] Como puede ver, guardar el mismo modelo y evaluarlo en el mismo conjunto de datos reduce significativamente el rendimiento. Intenté muchas cosas para ver por qué esto debe estar sucediendo y descubrí que eliminar BatchNormalization() y AutoSRELU corrigió el problema, pero parece que no puedo entender por qué están causando este problema. Para ver si la función RandomUniform tal vez estaba causando algunos problemas, volví a ejecutar la parte de carga junto con la definición de la clase varias veces para ver si había algo de aleatoriedad en el modelo cargado, pero arrojaba un resultado idéntico peor cada vez. Luego vi que eliminar la capa de normalización por lotes daba resultados casi idénticos.
Entonces pude reducir el problema a BatchNormalization AutoSRELU pero no puedo entender cómo corregirlo. ¿Cómo guardo y cargo el modelo correctamente para que dé los mismos resultados?
Reemplace el guardado del modelo de Keras a TF.
tf.keras.models.save_model(model_scratch_auto, "test_model")Lo hice en tu cuaderno y funcionó :)
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]