def test_functional_model_saving(self): saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() with ops.Graph().as_default(), self.cached_session(): inputs = keras.layers.Input(shape=(3,)) x = keras.layers.Dense(2)(inputs) output = keras.layers.Dense(3)(x) model = keras.models.Model(inputs, output) model.compile( loss=keras.losses.MSE, optimizer=keras.optimizers.RMSprop(lr=0.0001), metrics=[ keras.metrics.categorical_accuracy, keras.metrics.CategoricalAccuracy() ], weighted_metrics=[ keras.metrics.categorical_accuracy, keras.metrics.CategoricalAccuracy() ]) x = np.random.random((1, 3)) y = np.random.random((1, 3)) model.train_on_batch(x, y) out = model.predict(x) keras.models.save_model(model, saved_model_dir, save_format=save_format) model = keras.models.load_model(saved_model_dir) out2 = model.predict(x) self.assertAllClose(out, out2, atol=1e-05)
def test_nested_model_weight_loading(self): save_format = testing_utils.get_save_format() saved_model_dir = self._save_model_dir() batch_size = 5 shape = (None, None, 3) with self.cached_session(): def gen_model(): def seq_model(): model = keras.models.Sequential([ keras.layers.Conv2D(3, 1, input_shape=shape), keras.layers.BatchNormalization()]) return model x = inner_inputs = keras.layers.Input((None, None, 3)) x = seq_model()(x) x = seq_model()(x) inner_model = keras.models.Model(inner_inputs, x) inputs = keras.layers.Input(shape) return keras.models.Model(inputs, inner_model(inputs)) model = gen_model() x = np.random.random((batch_size, 1, 1, 3)) ref_y = model.predict(x) model.save_weights(saved_model_dir, save_format=save_format) model = gen_model() model.load_weights(saved_model_dir) y = model.predict(x) self.assertAllClose(y, ref_y)
def test_multi_output_metrics_name_stay_same(self): """Tests that metric names don't change with each save/load cycle. e.g. "head_0_accuracy" should not become "head_0_head_0_accuracy" after saving and loading a model. """ input_ = keras.Input((4,)) model = keras.Model( input_, [keras.layers.Softmax(name='head_0')(keras.layers.Dense(3)(input_)), keras.layers.Softmax(name='head_1')(keras.layers.Dense(5)(input_))]) metric = keras.metrics.BinaryAccuracy() model.compile(optimizer='rmsprop', loss='mse', metrics={'head_0': [metric, 'accuracy']}) # Run one iteration. x = np.random.rand(2, 4) y = {'head_0': np.random.randint(2, size=(2, 3)), 'head_1': np.random.randint(2, size=(2, 5))} model.fit(x, y, verbose=0) # Save and reload. save_format = testing_utils.get_save_format() saved_model_dir = self._save_model_dir() keras.models.save_model(model, saved_model_dir, save_format=save_format) loaded = keras.models.load_model(saved_model_dir) # Make sure the metrics names from the model before saving match the loaded # model. self.assertSequenceEqual(model.metrics_names, loaded.metrics_names)
def test_functional_model_with_getitem_op_layer(self): inp = keras.Input(shape=(8)) out = inp[:] model = keras.Model( inputs=[inp], outputs=out) batch_size = 7 x = array_ops.stack([ math_ops.range(8) for _ in range(batch_size)]) args = [x] expected = x[:] self.assertAllEqual(model(args), expected) self.assertAllEqual(model.predict(args, batch_size=batch_size), expected) # Make sure it can be successfully saved and loaded save_format = testing_utils.get_save_format() saved_model_dir = self._save_model_dir() keras.models.save_model(model, saved_model_dir, save_format=save_format) loaded_model = keras.models.load_model(saved_model_dir) self.assertAllEqual(loaded_model(args), expected) self.assertAllEqual(loaded_model.predict(args, batch_size=batch_size), expected)
def test_basic_saving_and_loading(self, model_fn): save_format = testing_utils.get_save_format() if ('subclassed' in model_fn.__name__ and save_format in ['h5', 'hdf5', 'keras']): self.skipTest('h5 save format does not support subclass model.') # TODO(b/147493902): Remove this skipTest once fixed. if ('stacked_rnn' in model_fn.__name__ and save_format in ['h5', 'hdf5', 'keras']): self.skipTest('Stacked RNN model is not compatible with h5 save format.') saved_model_dir = self._save_model_dir() model_data = model_fn() model = model_data.model x_test, y_test = self.get_test_data( model_data.input_shape, model_data.target_shape) model.compile('rmsprop', 'mse') model.train_on_batch(x_test, y_test) # Save model. out1 = model.predict(x_test) keras.models.save_model(model, saved_model_dir, save_format=save_format) # Load model. loaded_model = keras.models.load_model(saved_model_dir) out2 = loaded_model.predict(x_test) self.assertAllClose(out1, out2, atol=1e-05)
def _assert_same_weights_and_metrics(self, model, loaded_model): """Checks that the loaded weights and metrics are the same as the original. Args: model: original model loaded_model: loaded model """ self.assertAllClose(model.weights, loaded_model.weights) if loaded_model.optimizer: if testing_utils.get_save_format() == 'tf': # TODO(b/153110928): Keras TF format doesn't restore optimizer weights # currently. return self.assertAllClose(model.optimizer.weights, loaded_model.optimizer.weights) # In V1/Graph mode, the model isn't built, so the metrics are not loaded # immediately (requires model to be called on some data before building # metrics). check_metrics = tf2.enabled() and context.executing_eagerly() if check_metrics: self.assertAllEqual([m.name for m in model.metrics], [m.name for m in loaded_model.metrics])
def test_saving_lambda_numpy_array_arguments(self): saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() if h5py is None: self.skipTest('h5py required to run this test') mean = np.random.random((4, 2, 3)) std = np.abs(np.random.random((4, 2, 3))) + 1e-5 inputs = keras.layers.Input(shape=(4, 2, 3)) output = keras.layers.Lambda(lambda image, mu, std: (image - mu) / std, arguments={'mu': mean, 'std': std})(inputs) model = keras.models.Model(inputs, output) model.compile(loss='mse', optimizer='sgd', metrics=['acc']) keras.models.save_model(model, saved_model_dir, save_format=save_format) model = keras.models.load_model(saved_model_dir) # TODO(b/145150660): skip the checking for tf format. if save_format in ['tf', 'tensorflow']: return self.assertAllClose(mean, model.layers[1].arguments['mu']) self.assertAllClose(std, model.layers[1].arguments['std'])
def test_sequential_model_saving_without_input_shape(self): saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() with self.cached_session(): model = keras.models.Sequential() model.add(keras.layers.Dense(2)) model.add(keras.layers.RepeatVector(3)) model.add(keras.layers.TimeDistributed(keras.layers.Dense(3))) model.compile( loss=keras.losses.MSE, optimizer='rmsprop', metrics=[ keras.metrics.categorical_accuracy, keras.metrics.CategoricalAccuracy(name='cat_acc') ], weighted_metrics=[ keras.metrics.categorical_accuracy, keras.metrics.CategoricalAccuracy(name='cat_acc2') ], sample_weight_mode='temporal') x = np.random.random((1, 3)) y = np.random.random((1, 3, 3)) model.train_on_batch(x, y) out = model.predict(x) model.save(saved_model_dir, save_format=save_format) new_model = keras.models.load_model(saved_model_dir) self._assert_same_weights_and_metrics(model, new_model) out2 = new_model.predict(x) self.assertAllClose(out, out2, atol=1e-05)
def test_sequential_model_saving_2(self): saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() with ops.Graph().as_default(), self.cached_session(): # test with custom optimizer, loss class CustomOp(optimizer_v1.RMSprop): pass def custom_loss(y_true, y_pred): return keras.losses.mse(y_true, y_pred) model = keras.models.Sequential() model.add(keras.layers.Dense(2, input_shape=(3,))) model.add(keras.layers.Dense(3)) model.compile(loss=custom_loss, optimizer=CustomOp(), metrics=['acc']) x = np.random.random((1, 3)) y = np.random.random((1, 3)) model.train_on_batch(x, y) out = model.predict(x) keras.models.save_model(model, saved_model_dir, save_format=save_format) new_model = keras.models.load_model( saved_model_dir, custom_objects={'CustomOp': CustomOp, 'custom_loss': custom_loss}) self._assert_same_weights_and_metrics(model, new_model) out2 = new_model.predict(x) self.assertAllClose(out, out2, atol=1e-05)
def test_sequential_model_saving_2(self): saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() # TODO(b/145133418): skip tf format for now. if save_format in ['tf', 'tensorflow']: return with self.cached_session(): # test with custom optimizer, loss class CustomOp(keras.optimizers.RMSprop): pass def custom_loss(y_true, y_pred): return keras.losses.mse(y_true, y_pred) model = keras.models.Sequential() model.add(keras.layers.Dense(2, input_shape=(3,))) model.add(keras.layers.Dense(3)) model.compile(loss=custom_loss, optimizer=CustomOp(), metrics=['acc']) x = np.random.random((1, 3)) y = np.random.random((1, 3)) model.train_on_batch(x, y) out = model.predict(x) keras.models.save_model(model, saved_model_dir, save_format=save_format) model = keras.models.load_model( saved_model_dir, custom_objects={'CustomOp': CustomOp, 'custom_loss': custom_loss}) out2 = model.predict(x) self.assertAllClose(out, out2, atol=1e-05)
def test_basic_saving_and_loading(self, model_fn): save_format = testing_utils.get_save_format() custom_objects = self.get_custom_objects() if 'subclassed_in_functional' in model_fn.__name__: subclass_custom_objects = { 'MySubclassModel': model_architectures.MySubclassModel, } custom_objects.update(subclass_custom_objects) elif ('subclassed' in model_fn.__name__ and save_format == 'h5'): self.skipTest( 'Saving the model to HDF5 format requires the model to be ' 'a Functional model or a Sequential model.') saved_model_dir = self._save_model_dir() model_data = model_fn() model = model_data.model x_test, y_test = self.get_test_data(model_data.input_shape, model_data.target_shape) model.compile('rmsprop', 'mse') model.train_on_batch(x_test, y_test) # Save model. out1 = model.predict(x_test) keras.models.save_model(model, saved_model_dir, save_format=save_format) # Load model. loaded_model = keras.models.load_model(saved_model_dir, custom_objects=custom_objects) out2 = loaded_model.predict(x_test) self.assertAllClose(out1, out2, atol=1e-05)
def test_weight_loading(self): temp_dir = self.get_temp_dir() self.addCleanup(shutil.rmtree, temp_dir) saved_model_dir = os.path.join(temp_dir, 'saved_model') save_format = testing_utils.get_save_format() with self.cached_session(): a = keras.layers.Input(shape=(2,)) x = keras.layers.Dense(3)(a) b = keras.layers.Dense(1)(x) model = keras.models.Model(a, b) x = np.random.random((3, 2)) ref_y = model.predict(x) weights = model.get_weights() model.set_weights(weights) y = model.predict(x) self.assertAllClose(ref_y, y) with self.assertRaises(ValueError): model.set_weights(weights[1:]) with self.assertRaises(ValueError): model.set_weights(weights[::-1]) model.save_weights(saved_model_dir, save_format=save_format) model.load_weights(saved_model_dir) y = model.predict(x) self.assertAllClose(ref_y, y)
def test_warning_when_saving_invalid_custom_mask_layer(self): class MyMasking(keras.layers.Layer): def call(self, inputs): return inputs def compute_mask(self, inputs, mask=None): mask = math_ops.not_equal(inputs, 0) return mask class MyLayer(keras.layers.Layer): def call(self, inputs, mask=None): return array_ops.identity(inputs) samples = np.random.random((2, 2)) model = keras.Sequential([MyMasking(), MyLayer()]) model.predict(samples) with warnings.catch_warnings(record=True) as w: model.save(self._save_model_dir(), testing_utils.get_save_format()) self.assertIn(generic_utils.CustomMaskWarning, {warning.category for warning in w}) # Test that setting up a custom mask correctly does not issue a warning. class MyCorrectMasking(keras.layers.Layer): def call(self, inputs): return inputs def compute_mask(self, inputs, mask=None): mask = math_ops.not_equal(inputs, 0) return mask # This get_config doesn't actually do anything because our mask is # static and doesn't need any external information to work. We do need a # dummy get_config method to prevent the warning from appearing, however. def get_config(self, *args, **kwargs): return {} model = keras.Sequential([MyCorrectMasking(), MyLayer()]) model.predict(samples) with warnings.catch_warnings(record=True) as w: model.save(self._save_model_dir(), testing_utils.get_save_format()) self.assertNotIn(generic_utils.CustomMaskWarning, {warning.category for warning in w})
def test_sequential_model_saving(self): saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() # TODO(b/145951332): skip TF format for now. if save_format in ['tf', 'tensorflow']: return with self.cached_session(): model = keras.models.Sequential() model.add(keras.layers.Dense(2, input_shape=(3,))) model.add(keras.layers.RepeatVector(3)) model.add(keras.layers.TimeDistributed(keras.layers.Dense(3))) model.compile( loss=keras.losses.MSE, optimizer=keras.optimizer_v2.rmsprop.RMSprop(lr=0.0001), metrics=[ keras.metrics.categorical_accuracy, keras.metrics.CategoricalCrossentropy( name='cce', label_smoothing=constant_op.constant(0.2)), ], weighted_metrics=[ keras.metrics.categorical_crossentropy, keras.metrics.CategoricalCrossentropy( name='cce', label_smoothing=constant_op.constant(0.2)), ], sample_weight_mode='temporal') x = np.random.random((1, 3)) y = np.random.random((1, 3, 3)) model.train_on_batch(x, y) out = model.predict(x) keras.models.save_model(model, saved_model_dir, save_format=save_format) new_model = keras.models.load_model(saved_model_dir) out2 = new_model.predict(x) self.assertAllClose(out, out2, atol=1e-05) # test that new updates are the same with both models x = np.random.random((1, 3)) y = np.random.random((1, 3, 3)) model.train_on_batch(x, y) new_model.train_on_batch(x, y) x = np.random.random((1, 3)) y = np.random.random((1, 3, 3)) eval_out = model.evaluate(x, y) eval_out2 = new_model.evaluate(x, y) self.assertArrayNear(eval_out, eval_out2, 0.001) out = model.predict(x) out2 = new_model.predict(x) # TODO(b/120930751) This tolerance should be 1e-05, # very concerning that its not. self.assertAllClose(out, out2, atol=1e-03)
def test_saving_without_compilation(self): saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() model = keras.models.Sequential() model.add(keras.layers.Dense(2, input_shape=(3,))) model.add(keras.layers.Dense(3)) model.compile(loss='mse', optimizer='sgd', metrics=['acc']) keras.models.save_model(model, saved_model_dir, save_format=save_format) model = keras.models.load_model(saved_model_dir)
def test_save_and_load(self): saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() save_kwargs = testing_utils.get_save_kwargs() if ((save_format == 'h5' or not save_kwargs.get('save_traces', True)) and testing_utils.get_model_type() == 'subclass'): # HDF5 format currently does not allow saving subclassed models. # When saving with `save_traces=False`, the subclassed model must have a # get_config/from_config, which the autogenerated model does not have. return with self.cached_session(): model = testing_utils.get_model_from_layers([ keras.layers.Dense(2), keras.layers.RepeatVector(3), keras.layers.TimeDistributed(keras.layers.Dense(3)) ], input_shape=(3, )) model.compile( loss=keras.losses.MSE, optimizer=keras.optimizer_v2.rmsprop.RMSprop(lr=0.0001), metrics=[ keras.metrics.categorical_accuracy, keras.metrics.CategoricalCrossentropy( name='cce', label_smoothing=constant_op.constant(0.2)), ], weighted_metrics=[ keras.metrics.categorical_crossentropy, keras.metrics.CategoricalCrossentropy( name='cce', label_smoothing=constant_op.constant(0.2)), ], sample_weight_mode='temporal') x = np.random.random((1, 3)) y = np.random.random((1, 3, 3)) model.train_on_batch(x, y) out = model.predict(x) keras.models.save_model(model, saved_model_dir, save_format=save_format, **save_kwargs) loaded_model = keras.models.load_model(saved_model_dir) self._assert_same_weights_and_metrics(model, loaded_model) out2 = loaded_model.predict(x) self.assertAllClose(out, out2, atol=1e-05) eval_out = model.evaluate(x, y) eval_out2 = loaded_model.evaluate(x, y) self.assertArrayNear(eval_out, eval_out2, 0.001)
def test_saving_right_after_compilation(self): saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() with self.cached_session(): model = keras.models.Sequential() model.add(keras.layers.Dense(2, input_shape=(3,))) model.add(keras.layers.Dense(3)) model.compile(loss='mse', optimizer='sgd', metrics=['acc']) if not ops.executing_eagerly_outside_functions(): model._make_train_function() keras.models.save_model(model, saved_model_dir, save_format=save_format) model = keras.models.load_model(saved_model_dir)
def test_saving_with_tf_optimizer(self): saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() model = keras.models.Sequential() model.add(keras.layers.Dense(2, input_shape=(3,))) model.add(keras.layers.Dense(3)) model.compile(loss='mse', optimizer=training_module.AdadeltaOptimizer(0.1), metrics=['acc']) keras.models.save_model(model, saved_model_dir, save_format=save_format) model = keras.models.load_model(saved_model_dir)
def test_save_uncompiled_model_with_optimizer(self): saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() model = keras.models.Sequential([keras.layers.Dense(1, input_shape=(3,))]) # Set the model's optimizer but don't compile. This can happen if the model # is trained with a custom training loop. model.optimizer = keras.optimizer_v2.rmsprop.RMSprop(lr=0.0001) model.save(saved_model_dir, save_format=save_format) if save_format in ['tf', 'tensorflow']: loaded = keras.models.load_model(saved_model_dir) self.assertIsInstance(loaded.optimizer, keras.optimizer_v2.optimizer_v2.OptimizerV2)
def test_primitive_attrs_contain_no_extraneous_strings(self): if h5py is None: self.skipTest('h5py required to run this test') saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() model = keras.models.Sequential() model.add(keras.layers.Dense(1, input_shape=[2])) model.save(saved_model_dir, save_format=save_format) if save_format in ['tf', 'tensorflow']: return h5file = h5py.File(saved_model_dir, 'r') self.assertRegex(h5file.attrs['keras_version'], r'^[\d]+\.[\d]+\.[\S]+$')
def test_saving_constant_initializer_with_numpy(self): saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() model = keras.models.Sequential() model.add( keras.layers.Dense( 2, input_shape=(3,), kernel_initializer=keras.initializers.Constant(np.ones((3, 2))))) model.add(keras.layers.Dense(3)) model.compile(loss='mse', optimizer='sgd', metrics=['acc']) keras.models.save_model(model, saved_model_dir, save_format=save_format) model = keras.models.load_model(saved_model_dir)
def test_saving_model_with_long_weights_names(self): saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() with self.cached_session(): x = keras.Input(shape=(2, ), name='nested_model_input') f = x for i in range(4): f = keras.layers.Dense(2, name='nested_model_dense_%d' % (i, ))(f) # This layer name will make the `weights_name` # HDF5 attribute blow out of proportion. f = keras.layers.Dense(2, name='nested_model_output' + ('x' * (2**14)))(f) nested_model = keras.Model(inputs=[x], outputs=[f], name='nested_model') x = keras.Input(shape=(2, ), name='outer_model_input') f = nested_model(x) f = keras.layers.Dense(2, name='outer_model_output')(f) model = keras.Model(inputs=[x], outputs=[f]) model.compile(loss='mse', optimizer='adam', metrics=['acc']) x = np.random.random((1, 2)) y = np.random.random((1, 2)) model.train_on_batch(x, y) out = model.predict(x) keras.models.save_model(model, saved_model_dir, save_format=save_format) model = keras.models.load_model(saved_model_dir) if save_format in ['h5', 'hdf5', 'keras']: # Check that the HDF5 files contains chunked array # of weight names. with h5py.File(saved_model_dir, 'r') as h5file: num_weight_arrays = len([ attr for attr in h5file['model_weights'] ['nested_model'].attrs if attr.startswith('weight_names') ]) # The chunking of layer names array should have happened. self.assertGreater(num_weight_arrays, 0) out2 = model.predict(x) self.assertAllClose(out, out2, atol=1e-05)
def test_model_saving_to_pre_created_h5py_file(self): saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() with ops.Graph().as_default(), self.cached_session(): inputs = keras.Input(shape=(3, )) x = keras.layers.Dense(2)(inputs) outputs = keras.layers.Dense(3)(x) model = keras.Model(inputs, outputs) model.compile(loss=keras.losses.MSE, optimizer=optimizer_v1.Adam(), metrics=[ keras.metrics.categorical_accuracy, keras.metrics.CategoricalAccuracy() ]) x = np.random.random((1, 3)) y = np.random.random((1, 3)) model.train_on_batch(x, y) out = model.predict(x) keras.models.save_model(model, saved_model_dir, save_format=save_format) loaded_model = keras.models.load_model(saved_model_dir) out1 = loaded_model.predict(x) self.assertAllClose(out, out1, atol=1e-05) if save_format in ['tf', 'tensorflow']: return # Test h5 format specifically fd, fname = tempfile.mkstemp('.h5') with h5py.File(fname, mode='r+') as h5file: keras.models.save_model(model, h5file) loaded_model = keras.models.load_model(h5file) out2 = loaded_model.predict(x) self.assertAllClose(out, out2, atol=1e-05) # Test non-default options in h5 with h5py.File('_', driver='core', mode='w', backing_store=False) as h5file: keras.models.save_model(model, h5file) loaded_model = keras.models.load_model(h5file) out2 = loaded_model.predict(x) self.assertAllClose(out, out2, atol=1e-05) # Cleanup os.close(fd) os.remove(fname)
def test_sequential_model_saving(self): saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() with self.cached_session(): model = keras.models.Sequential() model.add(keras.layers.Dense(2, input_shape=(3,))) model.add(keras.layers.RepeatVector(3)) model.add(keras.layers.TimeDistributed(keras.layers.Dense(3))) model.compile( loss=keras.losses.MSE, optimizer=keras.optimizer_v2.rmsprop.RMSprop(lr=0.0001), metrics=[ keras.metrics.categorical_accuracy, keras.metrics.CategoricalCrossentropy( name='cce', label_smoothing=constant_op.constant(0.2)), ], weighted_metrics=[ keras.metrics.categorical_crossentropy, keras.metrics.CategoricalCrossentropy( name='cce', label_smoothing=constant_op.constant(0.2)), ], sample_weight_mode='temporal') x = np.random.random((1, 3)) y = np.random.random((1, 3, 3)) model.train_on_batch(x, y) out = model.predict(x) keras.models.save_model(model, saved_model_dir, save_format=save_format) new_model = keras.models.load_model(saved_model_dir) out2 = new_model.predict(x) self.assertAllClose(out, out2, atol=1e-05) # test that new updates are the same with both models model.train_on_batch(x, y) new_model.train_on_batch(x, y) eval_out = model.evaluate(x, y) eval_out2 = new_model.evaluate(x, y) self.assertArrayNear(eval_out, eval_out2, 0.001) out = model.predict(x) out2 = new_model.predict(x) # The model has been trained on two batches. So the tolerance is larger. self.assertAllClose(out, out2, atol=0.01)
def test_save_uncompiled_model_with_optimizer(self): with self.cached_session() as session: saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() model = keras.models.Sequential([keras.layers.Dense(1, input_shape=(3,))]) # Set the model's optimizer but don't compile. This can happen if the # model is trained with a custom training loop. model.optimizer = keras.optimizer_v2.rmsprop.RMSprop(lr=0.0001) if not context.executing_eagerly(): session.run([v.initializer for v in model.variables]) model.save(saved_model_dir, save_format=save_format) if save_format in ['tf', 'tensorflow']: loaded = keras.models.load_model(saved_model_dir) self.assertIsInstance(loaded.optimizer, keras.optimizer_v2.optimizer_v2.OptimizerV2)
def test_shared_objects_wrapper(self): """Tests that shared layers wrapped with `Wrapper` restore correctly.""" input_ = keras.Input(shape=(1,)) unwrapped = keras.layers.Layer(name='unwrapped') wrapped = keras.layers.Wrapper(unwrapped, name='wrapped') model = keras.Model(inputs=input_, outputs=[unwrapped(input_), wrapped(input_)]) # Test recreating directly from config config = model.get_config() loaded = keras.Model.from_config(config) self.assertIs(loaded.layers[1], loaded.layers[2].layer) # Test saving and loading to disk save_format = testing_utils.get_save_format() saved_model_dir = self._save_model_dir() keras.models.save_model(model, saved_model_dir, save_format=save_format) loaded = keras.models.load_model(saved_model_dir) self.assertIs(loaded.layers[1], loaded.layers[2].layer)
def test_functional_model_with_custom_loss_and_metric(self): def _make_model(): inputs = keras.Input(shape=(4, )) x = keras.layers.Dense(8, activation='relu')(inputs) outputs = keras.layers.Dense(3, activation='softmax')(x) model = keras.Model(inputs=inputs, outputs=outputs) custom_loss = keras.layers.Lambda( lambda x: keras.backend.sum(x * x))(x) model.add_loss(custom_loss) model.add_metric(custom_loss, aggregation='mean', name='custom_loss') return model saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() with self.cached_session(): model = _make_model() model.compile( loss=keras.losses.SparseCategoricalCrossentropy(), optimizer=optimizers.gradient_descent_v2.SGD(), metrics=[keras.metrics.SparseCategoricalCrossentropy()]) x = np.random.normal(size=(32, 4)) y = np.random.randint(0, 3, size=32) model.train_on_batch(x, y) evaluation_results = model.evaluate(x, y) # Save and reload model. model.save(saved_model_dir, save_format=save_format) del model # Prevent misuse. loaded_model = keras.models.load_model(saved_model_dir) loaded_model_eval_results = loaded_model.evaluate(x, y) # Assert all evaluation results are the same. self.assertAllClose(evaluation_results, loaded_model_eval_results, 1e-9) # Check correctness of the loss calculation. self.assertAllGreater(evaluation_results, 0.) evaluation_results = dict( zip(loaded_model.metrics_names, evaluation_results)) self.assertNear( evaluation_results['sparse_categorical_crossentropy'] + evaluation_results['custom_loss'], evaluation_results['loss'], 1e-6)
def test_multi_output_metrics_name_stay_same(self, fit): """Tests that metric names don't change with each save/load cycle. e.g. "head_0_accuracy" should not become "head_0_head_0_accuracy" after saving and loading a model. Arguments: fit: Whether the model should be fit before saving. """ # This doesn't work at all, so we can't check whether metric names are # correct. if not context.executing_eagerly() and not fit: self.skipTest('b/181767784') with self.cached_session(): input_ = keras.Input((4,)) model = keras.Model( input_, [keras.layers.Softmax(name='head_0')(keras.layers.Dense(3)(input_)), keras.layers.Softmax(name='head_1')(keras.layers.Dense(5)(input_))]) metric = keras.metrics.BinaryAccuracy() model.compile(optimizer='rmsprop', loss='mse', metrics={'head_0': [metric, 'accuracy']}) x = np.random.rand(2, 4) y = {'head_0': np.random.randint(2, size=(2, 3)), 'head_1': np.random.randint(2, size=(2, 5))} # Make sure metrix prefixing works the same regardless of whether the user # has fit the model before saving. if fit: model.fit(x, y, verbose=0) # Save and reload. save_format = testing_utils.get_save_format() saved_model_dir = self._save_model_dir() keras.models.save_model(model, saved_model_dir, save_format=save_format) loaded = keras.models.load_model(saved_model_dir) # Make sure the metrics names from the model before saving match the loaded # model. self.assertSequenceEqual(model.metrics_names, loaded.metrics_names)
def test_sequential_model_saving_without_compile(self): saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() with self.cached_session(): model = keras.models.Sequential() model.add(keras.layers.Dense(2, input_shape=(3,))) model.add(keras.layers.RepeatVector(3)) model.add(keras.layers.TimeDistributed(keras.layers.Dense(3))) x = np.random.random((1, 3)) out = model.predict(x) # Save the model without any compilation or training. keras.models.save_model(model, saved_model_dir, save_format=save_format) new_model = keras.models.load_model(saved_model_dir) out2 = new_model.predict(x) self.assertAllClose(out, out2, atol=1e-05)
def test_saving_model_with_long_layer_names(self): saved_model_dir = self._save_model_dir() save_format = testing_utils.get_save_format() with self.cached_session(): # This layer name will make the `layers_name` HDF5 attribute blow # out of proportion. Note that it fits into the internal HDF5 # attribute memory limit on its own but because h5py converts # the list of layer names into numpy array, which uses the same # amount of memory for every item, it increases the memory # requirements substantially. x = keras.Input(shape=(2, ), name='input_' + ('x' * (2**15))) f = x for i in range(4): f = keras.layers.Dense(2, name='dense_%d' % (i, ))(f) model = keras.Model(inputs=[x], outputs=[f]) model.compile('adam', loss=keras.losses.MeanSquaredError(), metrics=['acc']) x = np.random.random((1, 2)) y = np.random.random((1, 2)) model.train_on_batch(x, y) out = model.predict(x) keras.models.save_model(model, saved_model_dir, save_format=save_format) model = keras.models.load_model(saved_model_dir) if save_format in ['tf', 'tensorflow']: return # Check that the HDF5 files contains chunked array # of layer names. with h5py.File(saved_model_dir, 'r') as h5file: num_names_arrays = len([ attr for attr in h5file['model_weights'].attrs if attr.startswith('layer_names') ]) # The chunking of layer names array should have happened. self.assertGreater(num_names_arrays, 0) out2 = model.predict(x) self.assertAllClose(out, out2, atol=1e-05)