def test_trace_multi_io_model_outputs(self): input_dim = 5 num_classes = 3 num_classes_b = 4 input_a = keras.layers.Input(shape=(input_dim, ), name='input_a') input_b = keras.layers.Input(shape=(input_dim, ), name='input_b') dense = keras.layers.Dense(num_classes, name='dense') dense2 = keras.layers.Dense(num_classes_b, name='dense2') dropout = keras.layers.Dropout(0.5, name='dropout') branch_a = [input_a, dense] branch_b = [input_b, dense, dense2, dropout] model = test_utils.get_multi_io_model(branch_a, branch_b) input_a_ts = tf.constant( np.random.random((10, input_dim)).astype(np.float32)) input_b_ts = tf.constant( np.random.random((10, input_dim)).astype(np.float32)) if test_utils.get_model_type() == 'subclass': with self.assertRaisesRegex(ValueError, '.*input shape is not availabl*'): saving_utils.trace_model_call(model) model.compile(optimizer='sgd', loss='mse', run_eagerly=test_utils.should_run_eagerly()) model.fit(x=[ np.random.random((8, input_dim)).astype(np.float32), np.random.random((8, input_dim)).astype(np.float32) ], y=[ np.random.random((8, num_classes)).astype(np.float32), np.random.random((8, num_classes_b)).astype(np.float32) ], epochs=2) fn = saving_utils.trace_model_call(model) # tf.function requires that the input structures match when calling a # ConcreteFunction. For some reason V1 models defines the inputs as a list, # while V2 models sets the inputs as a tuple. if (not tf.executing_eagerly() and test_utils.get_model_type() != 'functional'): signature_outputs = fn([input_a_ts, input_b_ts]) else: signature_outputs = fn((input_a_ts, input_b_ts)) outputs = model([input_a_ts, input_b_ts]) if model.output_names: expected_outputs = { model.output_names[0]: outputs[0], model.output_names[1]: outputs[1] } else: expected_outputs = {'output_1': outputs[0], 'output_2': outputs[1]} self._assert_all_close(expected_outputs, signature_outputs)
def testBody(self, arg): del arg mode = "eager" if tf.executing_eagerly() else "graph" should_run_eagerly = test_utils.should_run_eagerly() test_cases.append( (mode, should_run_eagerly, test_utils.get_model_type()) )
def test_sparse_scipy_eval_input_dicts(self): # Create a model that accepts a sparse input and converts the sparse tensor # back to a dense tensor. Scipy sparse matrices are limited to 2D, so use # a one-dimensional shape; note also that scipy's default dtype is int64. if test_utils.get_model_type() == "subclass": input_name = "input_1" # Subclass models don"t support input names. else: input_name = "test_input_name" model_input = input_layer.Input(shape=(3, ), sparse=True, name=input_name, dtype=tf.int64) layers = [ToDense(default_value=-1)] model = get_model_from_layers_with_input(layers, model_input=model_input) model.compile(optimizer="sgd", loss="mse", metrics=["accuracy"]) input_data = { input_name: scipy.sparse.coo_matrix(([1, 2, 3], ([0, 1, 1], [0, 0, 1])), shape=[2, 3]) } expected_output = np.array([[1, -1, -1], [2, 3, -1]]) output = model.evaluate(input_data, expected_output, steps=1) self.assertAllEqual(1.0, output[-1]) input_data_2 = { input_name: scipy.sparse.coo_matrix( ([5, 6, 7, 8], ([0, 1, 1, 2], [0, 0, 1, 1])), shape=[3, 3]) } expected_output_2 = np.array([[5, -1, -1], [6, 7, -1], [-1, 8, -1]]) output_2 = model.evaluate(input_data_2, expected_output_2, steps=1) self.assertAllEqual(1.0, output_2[-1])
def test_revive(self): input_shape = None if test_utils.get_model_type() == 'functional': input_shape = (2, 3) layer_with_config = CustomLayerWithConfig(1., 2) layer_without_config = CustomLayerNoConfig(3., 4) subclassed_with_config = SubclassedModelWithConfig(4., 6.) subclassed_without_config = SubclassedModelNoConfig(7., 8.) inputs = keras.Input((2, 3)) x = CustomLayerWithConfig(1., 2)(inputs) x = CustomLayerNoConfig(3., 4)(x) x = SubclassedModelWithConfig(4., 6.)(x) x = SubclassedModelNoConfig(7., 8.)(x) inner_model_functional = keras.Model(inputs, x) inner_model_sequential = keras.Sequential([ CustomLayerWithConfig(1., 2), CustomLayerNoConfig(3., 4), SubclassedModelWithConfig(4., 6.), SubclassedModelNoConfig(7., 8.) ]) class SubclassedModel(keras.Model): def __init__(self): super().__init__() self.all_layers = [ CustomLayerWithConfig(1., 2), CustomLayerNoConfig(3., 4), SubclassedModelWithConfig(4., 6.), SubclassedModelNoConfig(7., 8.) ] def call(self, inputs): x = inputs for layer in self.all_layers: x = layer(x) return x inner_model_subclassed = SubclassedModel() layers = [ layer_with_config, layer_without_config, subclassed_with_config, subclassed_without_config, inner_model_functional, inner_model_sequential, inner_model_subclassed ] model = test_utils.get_model_from_layers(layers, input_shape=input_shape) # Run data through the Model to create save spec and weights. model.predict(np.ones((10, 2, 3)), batch_size=10) # Test that the correct checkpointed values are loaded, whether the layer is # created from the config or SavedModel. layer_with_config.c.assign(2 * layer_with_config.c) layer_without_config.c.assign(3 * layer_without_config.c) model.save(self.path, save_format='tf') revived = keras_load.load(self.path) self._assert_revived_correctness(model, revived)
def test_sparse_scipy_predict_input_dicts_via_input_layer_args(self): # Create a model that accepts a sparse input and converts the sparse # tensor back to a dense tensor. Scipy sparse matrices are limited to # 2D, so use a one-dimensional shape; note also that scipy's default # dtype is int64. if test_utils.get_model_type() == "subclass": input_name = "input_1" # Subclass models don"t support input names. else: input_name = "test_input_name" model_input = input_layer.Input(shape=(3, ), sparse=True, name=input_name, dtype=tf.int64) layers = [ToDense(default_value=-1)] model = get_model_from_layers_with_input(layers, model_input=model_input) input_data = { input_name: scipy.sparse.coo_matrix(([1, 2, 3], ([0, 1, 1], [0, 0, 1])), shape=[2, 3]) } expected_output = np.array([[1, -1, -1], [2, 3, -1]]) output = model.predict(input_data, steps=1) self.assertAllEqual(expected_output, output) input_data_2 = { input_name: scipy.sparse.coo_matrix( ([5, 6, 7, 8], ([0, 1, 1, 2], [0, 0, 1, 1])), shape=[3, 3]) } expected_output_2 = np.array([[5, -1, -1], [6, 7, -1], [-1, 8, -1]]) output_2 = model.predict(input_data_2, steps=1) self.assertAllEqual(expected_output_2, output_2)
def test_clone_and_build_compiled(self): model = _get_model() model.compile(test_utils.get_v2_optimizer('rmsprop'), 'mse', metrics=['acc', metrics.categorical_accuracy], run_eagerly=test_utils.should_run_eagerly()) self._clone_and_build_test_helper(model, test_utils.get_model_type())
def get_input_name(use_dict): # Define the input name. if not use_dict: return None # This is the same as not setting 'name'. elif test_utils.get_model_type() == "subclass": return "input_1" # Subclass models don"t support input names. else: return "test_input_name"
def _skip_if_strategy_unsupported(self, strategy_fn): if ( strategy_fn != default_strategy_fn and test_utils.get_model_type() == "subclass" ): self.skipTest( "Non-default strategies are unsupported with subclassed " "models" )
def _skip_if_save_format_unsupported(self, save_format): model_type = test_utils.get_model_type() if save_format == 'h5' and model_type == 'subclass': self.skipTest('Saving subclassed models with the HDF5 format is ' 'unsupported') if (save_format == 'tf' and model_type == 'subclass' and not tf.executing_eagerly()): self.skipTest( 'b/148820505: This combination of features is currently ' 'broken.')
def _skip_if_save_format_unsupported(self, save_format): model_type = test_utils.get_model_type() if save_format == "h5" and model_type == "subclass": self.skipTest("Saving subclassed models with the HDF5 format is " "unsupported") if (save_format == "tf" and model_type == "subclass" and not tf.executing_eagerly()): self.skipTest( "b/148820505: This combination of features is currently " "broken.")
def test_load_weights_from_saved_model(self): save_path = self._save_model_dir() save_format = test_utils.get_save_format() if save_format == "h5" and test_utils.get_model_type() == "subclass": # TODO(b/173646281): HDF5 format currently does not allow saving # subclassed models. return with self.cached_session(): model = test_utils.get_small_mlp(1, 4, input_dim=3) data = np.random.random((1, 3)) labels = np.random.random((1, 4)) model.compile(loss="mse", optimizer="rmsprop") model.fit(data, labels) model.save(save_path, save_format=save_format) new_model = test_utils.get_small_mlp(1, 4, input_dim=3) if test_utils.get_model_type() == "subclass": # Call on test data to build the model. new_model.predict(data) new_model.load_weights(save_path) self.assertAllClose(model.weights, new_model.weights)
def test_save_and_load(self): saved_model_dir = self._save_model_dir() save_format = test_utils.get_save_format() save_kwargs = test_utils.get_save_kwargs() if ((save_format == 'h5' or not save_kwargs.get('save_traces', True)) and test_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 = test_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.optimizers.optimizer_v2.rmsprop.RMSprop(lr=0.0001), metrics=[ keras.metrics.categorical_accuracy, keras.metrics.CategoricalCrossentropy( name='cce', label_smoothing=tf.constant(0.2)), ], weighted_metrics=[ keras.metrics.categorical_crossentropy, keras.metrics.CategoricalCrossentropy( name='cce', label_smoothing=tf.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_training_and_eval_methods_on_multi_input_output_dataset(self): input_a = keras.layers.Input(shape=(3, ), name="input_1") input_b = keras.layers.Input(shape=(3, ), name="input_2") dense = keras.layers.Dense(4, name="dense") dropout = keras.layers.Dropout(0.5, name="dropout") branch_a = [input_a, dense] branch_b = [input_b, dense, dropout] model = test_utils.get_multi_io_model(branch_a, branch_b) model.compile( optimizer="rmsprop", loss="mse", run_eagerly=test_utils.should_run_eagerly(), ) input_a_np = np.random.random((10, 3)).astype(dtype=np.float32) input_b_np = np.random.random((10, 3)).astype(dtype=np.float32) output_d_np = np.random.random((10, 4)).astype(dtype=np.float32) output_e_np = np.random.random((10, 4)).astype(dtype=np.float32) # Test with tuples dataset_tuple = tf.data.Dataset.from_tensor_slices( ((input_a_np, input_b_np), (output_d_np, output_e_np))) dataset_tuple = dataset_tuple.repeat(100) dataset_tuple = dataset_tuple.batch(10) model.fit(dataset_tuple, epochs=1, steps_per_epoch=2, verbose=1) model.evaluate(dataset_tuple, steps=2, verbose=1) # Test with dict input_dict = {"input_1": input_a_np, "input_2": input_b_np} if test_utils.get_model_type() == "subclass": output_dict = {"output_1": output_d_np, "output_2": output_e_np} else: output_dict = {"dense": output_d_np, "dropout": output_e_np} dataset_dict = tf.data.Dataset.from_tensor_slices( (input_dict, output_dict)) dataset_dict = dataset_dict.repeat(100) dataset_dict = dataset_dict.batch(10) model.fit(dataset_dict, epochs=1, steps_per_epoch=2, verbose=1) model.evaluate(dataset_dict, steps=2, verbose=1) predict_dataset_dict = tf.data.Dataset.from_tensor_slices(input_dict) predict_dataset_dict = predict_dataset_dict.repeat(100) predict_dataset_dict = predict_dataset_dict.batch(10) model.predict(predict_dataset_dict, steps=1)
def assert_optimizer_iterations_increases(self, optimizer): model = _get_model() model.compile( optimizer, 'mse', metrics=['acc', metrics.categorical_accuracy], run_eagerly=test_utils.should_run_eagerly()) global_step = keras.backend.variable(123, dtype=tf.int64) clone_model = models.clone_and_build_model( model, compile_clone=True, optimizer_iterations=global_step, in_place_reset=(test_utils.get_model_type() == 'subclass')) inp = np.random.random((10, 4)) out = np.random.random((10, 4)) clone_model.train_on_batch(inp, out) self.assertEqual(backend.eval(global_step), 124)
def test_trace_model_outputs(self): input_dim = 5 if test_utils.get_model_type() == 'functional' else None model = test_utils.get_small_mlp(10, 3, input_dim) inputs = tf.ones((8, 5)) if input_dim is None: with self.assertRaisesRegex(ValueError, '.*input shape is not availabl*'): saving_utils.trace_model_call(model) model._set_inputs(inputs) fn = saving_utils.trace_model_call(model) signature_outputs = fn(inputs) if model.output_names: expected_outputs = {model.output_names[0]: model(inputs)} else: expected_outputs = {'output_1': model(inputs)} self._assert_all_close(expected_outputs, signature_outputs)
def test_clone_and_build_non_compiled_model(self): inp = np.random.random((10, 4)) out = np.random.random((10, 4)) model = _get_model() with self.assertRaisesRegex(ValueError, "has not been compiled"): models.clone_and_build_model(model, compile_clone=True) is_subclassed = test_utils.get_model_type() == "subclass" # With placeholder creation new_model = models.clone_and_build_model( model, compile_clone=False, in_place_reset=is_subclassed ) with self.assertRaisesRegex(RuntimeError, "must compile"): new_model.evaluate(inp, out) with self.assertRaisesRegex(RuntimeError, "must compile"): new_model.train_on_batch(inp, out) new_model.compile( test_utils.get_v2_optimizer("rmsprop"), "mse", run_eagerly=test_utils.should_run_eagerly(), ) new_model.train_on_batch(inp, out) # Create new tensors for inputs. input_a = keras.Input(shape=(4,)) new_model = models.clone_and_build_model( model, input_tensors=input_a, compile_clone=False, in_place_reset=is_subclassed, ) with self.assertRaisesRegex(RuntimeError, "must compile"): new_model.evaluate(inp, out) with self.assertRaisesRegex(RuntimeError, "must compile"): new_model.train_on_batch(inp, out) new_model.compile( test_utils.get_v2_optimizer("rmsprop"), "mse", run_eagerly=test_utils.should_run_eagerly(), ) new_model.train_on_batch(inp, out)
def test_trace_model_outputs_after_fitting(self): input_dim = 5 if test_utils.get_model_type() == 'functional' else None model = test_utils.get_small_mlp(10, 3, input_dim) model.compile(optimizer='sgd', loss='mse', run_eagerly=test_utils.should_run_eagerly()) model.fit(x=np.random.random((8, 5)).astype(np.float32), y=np.random.random((8, 3)).astype(np.float32), epochs=2) inputs = tf.ones((8, 5)) fn = saving_utils.trace_model_call(model) signature_outputs = fn(inputs) if model.output_names: expected_outputs = {model.output_names[0]: model(inputs)} else: expected_outputs = {'output_1': model(inputs)} self._assert_all_close(expected_outputs, signature_outputs)
def test_model_save(self): input_dim = 5 model = test_utils.get_small_mlp(10, 3, input_dim) inputs = tf.ones((8, 5)) if test_utils.get_model_type() == 'subclass': model._set_inputs(inputs) save_dir = os.path.join(self.get_temp_dir(), 'saved_model') tf.saved_model.save(model, save_dir) if model.output_names: output_name = model.output_names[0] input_name = model.input_names[0] else: output_name = 'output_1' input_name = 'input_1' self.assertAllClose({output_name: model.predict_on_batch(inputs)}, _import_and_infer(save_dir, {input_name: np.ones((8, 5))}))
def get_model_from_layers_with_input(layers, input_shape=None, input_dtype=None, model_input=None): """Builds a model from a sequence of layers.""" if model_input is not None and input_shape is not None: raise ValueError("Cannot specify a model_input and an input shape.") model_type = test_utils.get_model_type() if model_type == "subclass": return _SubclassModel(layers, model_input) if model_type == "sequential": model = keras.models.Sequential() if model_input is not None: model.add(model_input) elif input_shape is not None: model.add(keras.Input(shape=input_shape, dtype=input_dtype)) for layer in layers: model.add(layer) return model if model_type == "functional": if model_input is not None: inputs = model_input else: if not input_shape: raise ValueError( "Cannot create a functional model from layers with no " "input shape.") inputs = keras.Input(shape=input_shape, dtype=input_dtype) outputs = inputs for layer in layers: outputs = layer(outputs) return keras.Model(inputs, outputs) raise ValueError("Unknown model type {}".format(model_type))
def testBody(self): mode = "eager" if tf.executing_eagerly() else "graph" should_run_eagerly = test_utils.should_run_eagerly() l.append( (mode, should_run_eagerly, test_utils.get_model_type()))
def testBody(self): model_types.append(test_utils.get_model_type()) models.append(test_utils.get_small_mlp(1, 4, input_dim=3))
def testBody(self, with_brackets): with_brackets = ("with_brackets" if with_brackets else "without_brackets") model_types.append( (with_brackets, test_utils.get_model_type())) models.append(test_utils.get_small_mlp(1, 4, input_dim=3))