keras: Bugs found in Normalization() and load_model()

First and foremost I reported these bugs at the tensorflow github section which some of the staff told me to post it here.

Setup: OS: Windows 10 x64 tensorflow-gpu: 2.6.0 Python: 3.9.7 CUDA: 11.2.2 cuDNN: 8.1.1

As in the code below, when loading a model that was normalized by not passing arguments to Normalization() it throws an exception when that model is loaded by load_model(), however before loading the model I can use it without any apparent issues which makes you think it’s all good since Normalization() did NOT complain and took care of the input shape. When loading a model that was normalized by Normalization(input_dim=5) it does NOT thrown any exception since a known shape is specified. That is weird I mean it should warn you that when normalizing it without passing arguments to Normalization() you should expect an exception when loading it. This bug also happens in tensorflow-gpu 2.5.0.

bug_1.py:

import numpy as np
import tensorflow as tf


def main():
    train_data = np.array([[1, 2, 3, 4, 5]])

    train_label = np.array([123])

    normalizer = tf.keras.layers.experimental.preprocessing.Normalization()

    normalizer.adapt(train_data)

    model = tf.keras.Sequential([normalizer, tf.keras.layers.Dense(units=1)])

    model.compile(optimizer=tf.optimizers.Adam(learning_rate=0.1), loss='mean_absolute_error')

    model.fit(train_data, train_label, epochs=3000)

    model.save('test.h5')

    model = tf.keras.models.load_model('test.h5')  # Exception is thrown.

    unseen_data = np.array([[1, 2, 3, 4, 6]])

    prediction = model.predict(unseen_data)

    print(prediction)


if __name__ == "__main__":
    main()

Exception:

Traceback (most recent call last):
  File "E:\Backup\Desktop\bug_1.py", line 28, in <module>
    main()
  File "E:\Backup\Desktop\bug_1.py", line 19, in main
    model = tf.keras.models.load_model('test.h5')
  File "C:\Users\censored\AppData\Local\Programs\Python\Python39\lib\site-packages\keras\saving\save.py", line 200, in load_model
    return hdf5_format.load_model_from_hdf5(filepath, custom_objects,
  File "C:\Users\censored\AppData\Local\Programs\Python\Python39\lib\site-packages\keras\saving\hdf5_format.py", line 180, in load_model_from_hdf5
    model = model_config_lib.model_from_config(model_config,
  File "C:\Users\censored\AppData\Local\Programs\Python\Python39\lib\site-packages\keras\saving\model_config.py", line 52, in model_from_config
    return deserialize(config, custom_objects=custom_objects)
  File "C:\Users\censored\AppData\Local\Programs\Python\Python39\lib\site-packages\keras\layers\serialization.py", line 208, in deserialize
    return generic_utils.deserialize_keras_object(
  File "C:\Users\censored\AppData\Local\Programs\Python\Python39\lib\site-packages\keras\utils\generic_utils.py", line 674, in deserialize_keras_object
    deserialized_obj = cls.from_config(
  File "C:\Users\censored\AppData\Local\Programs\Python\Python39\lib\site-packages\keras\engine\sequential.py", line 434, in from_config
    model.add(layer)
  File "C:\Users\censored\AppData\Local\Programs\Python\Python39\lib\site-packages\tensorflow\python\training\tracking\base.py", line 530, in _method_wrapper
    result = method(self, *args, **kwargs)
  File "C:\Users\censored\AppData\Local\Programs\Python\Python39\lib\site-packages\keras\engine\sequential.py", line 217, in add
    output_tensor = layer(self.outputs[0])
  File "C:\Users\censored\AppData\Local\Programs\Python\Python39\lib\site-packages\keras\engine\base_layer.py", line 976, in __call__
    return self._functional_construction_call(inputs, args, kwargs,
  File "C:\Users\censored\AppData\Local\Programs\Python\Python39\lib\site-packages\keras\engine\base_layer.py", line 1114, in _functional_construction_call
    outputs = self._keras_tensor_symbolic_call(
  File "C:\Users\censored\AppData\Local\Programs\Python\Python39\lib\site-packages\keras\engine\base_layer.py", line 848, in _keras_tensor_symbolic_call
    return self._infer_output_signature(inputs, args, kwargs, input_masks)
  File "C:\Users\censored\AppData\Local\Programs\Python\Python39\lib\site-packages\keras\engine\base_layer.py", line 886, in _infer_output_signature
    self._maybe_build(inputs)
  File "C:\Users\censored\AppData\Local\Programs\Python\Python39\lib\site-packages\keras\engine\base_layer.py", line 2659, in _maybe_build
    self.build(input_shapes)  # pylint:disable=not-callable
  File "C:\Users\censored\AppData\Local\Programs\Python\Python39\lib\site-packages\keras\layers\preprocessing\normalization.py", line 145, in build
    raise ValueError(
ValueError: All `axis` values to be kept must have known shape. Got axis: (-1,), input shape: [None, None], with unknown axis at index: 1

Process finished with exit code 1

In addition to that, there is another bug when you load a model, that model gets a significant loss of accuracy, however that does NOT happen in tensorflow-gpu 2.5.0 which means tensorflow-gpu 2.6.0 has more bugs than expected.

bug_2.py:

import numpy as np
import tensorflow as tf


def main():
    train_data = np.array([[1, 2, 3, 4, 5]])

    train_label = np.array([123])

    normalizer = tf.keras.layers.experimental.preprocessing.Normalization(input_dim=5, axis=None)

    normalizer.adapt(train_data)

    model = tf.keras.Sequential([normalizer, tf.keras.layers.Dense(units=1)])

    model.compile(optimizer=tf.optimizers.Adam(learning_rate=0.1), loss='mean_absolute_error')

    model.fit(train_data, train_label, epochs=3000)

    model.save('test.h5')

    model_loaded = tf.keras.models.load_model('test.h5')

    seen_data = np.array([[1, 2, 3, 4, 5]])

    model_prediction = model.predict(seen_data)

    model_loaded_prediction = model_loaded.predict(seen_data)

    print(f'model prediction:{model_prediction}')  # Expected value close to 123.

    print(f'model loaded prediction: {model_loaded_prediction}')   # Wrong, not even close to 123.


if __name__ == "__main__":
    main()

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 1
  • Comments: 28 (8 by maintainers)

Commits related to this issue

Most upvoted comments

add “input_shape=[1,], axis=None” in the Normalization function Ex: single_feature_normalizer = layers.Normalization(input_shape=[1,], axis=None)

I am facing the same error, any solution for it? Here is my code: https://colab.research.google.com/drive/1RHgQ6KsOF7FDmbRAHPyQtXGCtsrAzD0h?usp=sharing

You should specify the input_dim according to your input dimensions and set the axis to None (see @mattdangerw’s answer for more details) in its preprocessing.Normalization() parameters.

I did what you said and my problem has been solved.

But they mention in the tutorial that the layer can inspect the input shape ( assum that I assign axis to None).

https://www.tensorflow.org/tutorials/keras/regression#linear_regression

I’m glad I helped you. Unfortunately the tutorial is out of date as many other tensorflow and keras documentations.

I am facing the same error, any solution for it?

Here is my code: https://colab.research.google.com/drive/1RHgQ6KsOF7FDmbRAHPyQtXGCtsrAzD0h?usp=sharing

You should specify the input_dim according to your input dimensions and set the axis to None (see @mattdangerw’s answer for more details) in its preprocessing.Normalization() parameters.

Bug 2 should now be fixed on tf-nightly. Discretization and normalization should now load back with proper state with h5. Note that the lookup preprocessing layers (StringLookup, IntegerLookup and TextVectorization) will still not function properly with h5. Fix should go out in 2.8, workaround until it releases will be to use the tf save format or use nightly.

For bug 1, the fix most people will want is probably to pass axis=None to the Normalization layer. That will have the layer compute a single mean and variance over all the input. The default to the layer is axis=-1 which computes a separate mean and variance for each position along the last axis. In that case, I think bug 1 is still valid, for some reason we are building the restored model with different input shape that when originally building it, triggering the error in the colab.

h5 format limitations listed in the Keras page mentioned that Does not support preprocessing layers.. Please check the page https://github.com/keras-team/keras-io/blob/master/guides/ipynb/serialization_and_saving.ipynb

H5 limitations:

  • External losses & metrics added via model.add_loss() & model.add_metric() are not saved (unlike SavedModel). If you have such losses & metrics on your model and you want to resume training, you need to add these losses back yourself after loading the model. Note that this does not apply to losses/metrics created inside layers via self.add_loss() & self.add_metric(). As long as the layer gets loaded, these losses & metrics are kept, since they are part of the call method of the layer.
  • The computation graph of custom objects such as custom layers is not included in the saved file. At loading time, Keras will need access to the Python classes/functions of these objects in order to reconstruct the model. See Custom objects.
  • Does not support preprocessing layers.