class ConvLSTM3DTest(test_combinations.TestCase): @parameterized.named_parameters( *test_utils.generate_combinations_with_testcase_name( data_format=['channels_first', 'channels_last'], return_sequences=[True, False])) def test_conv_lstm(self, data_format, return_sequences): num_height = 3 num_width = 3 num_depth = 3 filters = 3 num_samples = 1 input_channel = 2 input_height = 5 input_width = 5 input_depth = 5 sequence_len = 2 if data_format == 'channels_first': inputs = np.random.rand(num_samples, sequence_len, input_channel, input_height, input_width, input_depth) else: inputs = np.random.rand(num_samples, sequence_len, input_height, input_width, input_depth, input_channel) # test for return state: x = keras.Input(batch_shape=inputs.shape) kwargs = { 'data_format': data_format, 'return_sequences': return_sequences, 'return_state': True, 'stateful': True, 'filters': filters, 'kernel_size': (num_height, num_width, num_depth), 'padding': 'same' } layer = keras.layers.ConvLSTM3D(**kwargs) layer.build(inputs.shape) outputs = layer(x) _, states = outputs[0], outputs[1:] self.assertEqual(len(states), 2) model = keras.models.Model(x, states[0]) state = model.predict(inputs) self.assertAllClose(keras.backend.eval(layer.states[0]), state, atol=1e-4) # test for output shape: test_utils.layer_test(keras.layers.ConvLSTM3D, kwargs={ 'data_format': data_format, 'return_sequences': return_sequences, 'filters': filters, 'kernel_size': (num_height, num_width, num_depth), 'padding': 'valid' }, input_shape=inputs.shape)
class ConvLSTM1DTest(test_combinations.TestCase): @parameterized.named_parameters( *test_utils.generate_combinations_with_testcase_name( data_format=["channels_first", "channels_last"], return_sequences=[True, False], )) def test_conv_lstm(self, data_format, return_sequences): num_row = 3 filters = 3 num_samples = 1 input_channel = 2 input_num_row = 5 sequence_len = 2 if data_format == "channels_first": inputs = np.random.rand(num_samples, sequence_len, input_channel, input_num_row) else: inputs = np.random.rand(num_samples, sequence_len, input_num_row, input_channel) # test for return state: x = keras.Input(batch_shape=inputs.shape) kwargs = { "data_format": data_format, "return_sequences": return_sequences, "return_state": True, "stateful": True, "filters": filters, "kernel_size": num_row, "padding": "valid", } layer = keras.layers.ConvLSTM1D(**kwargs) layer.build(inputs.shape) outputs = layer(x) _, states = outputs[0], outputs[1:] self.assertEqual(len(states), 2) model = keras.models.Model(x, states[0]) state = model.predict(inputs) self.assertAllClose(keras.backend.eval(layer.states[0]), state, atol=1e-4) # test for output shape: test_utils.layer_test( keras.layers.ConvLSTM1D, kwargs={ "data_format": data_format, "return_sequences": return_sequences, "filters": filters, "kernel_size": num_row, "padding": "valid", }, input_shape=inputs.shape, )
if action == "predict": input_data = tf.data.Dataset.from_tensor_slices(input_data).batch( batch_size) else: input_data = tf.data.Dataset.from_tensor_slices( (input_data, expected_output)).batch(batch_size) expected_output = None return (input_data, expected_output) @test_combinations.run_with_all_model_types @test_combinations.run_all_keras_modes @parameterized.named_parameters( *test_utils.generate_combinations_with_testcase_name( use_dict=[True, False], use_dataset=[True, False], action=["predict", "evaluate", "fit"], )) class SparseTensorInputTest(test_combinations.TestCase): def test_sparse_tensors(self, use_dict, use_dataset, action): data = [ ( tf.SparseTensor([[0, 0, 0], [1, 0, 0], [1, 0, 1]], [1, 2, 3], [2, 1, 3]), np.array([[[1, -1, -1]], [[2, 3, -1]]]), ), ( tf.SparseTensor( [[0, 0, 0], [1, 0, 0], [1, 0, 1], [2, 0, 1]], [5, 6, 7, 8], [3, 1, 4],
class CuDNNTest(test_combinations.TestCase): @parameterized.named_parameters( *test_utils.generate_combinations_with_testcase_name( layer_class=[keras.layers.CuDNNGRU, keras.layers.CuDNNLSTM], return_sequences=[True, False], )) @tf_test_utils.run_gpu_only def test_cudnn_rnn_return_sequence(self, layer_class, return_sequences): input_size = 10 timesteps = 6 units = 2 num_samples = 32 test_utils.layer_test( layer_class, kwargs={ "units": units, "return_sequences": return_sequences }, input_shape=(num_samples, timesteps, input_size), ) @parameterized.named_parameters( *test_utils.generate_combinations_with_testcase_name( layer_class=[keras.layers.CuDNNGRU, keras.layers.CuDNNLSTM], go_backwards=[True, False], )) @tf_test_utils.run_gpu_only def test_cudnn_rnn_go_backward(self, layer_class, go_backwards): input_size = 10 timesteps = 6 units = 2 num_samples = 32 test_utils.layer_test( layer_class, kwargs={ "units": units, "go_backwards": go_backwards }, input_shape=(num_samples, timesteps, input_size), ) @parameterized.named_parameters( ("cudnngru", keras.layers.CuDNNGRU), ("cudnnlstm", keras.layers.CuDNNLSTM), ) @tf_test_utils.run_gpu_only def test_return_state(self, layer_class): input_size = 10 timesteps = 6 units = 2 num_samples = 32 num_states = 2 if layer_class is keras.layers.CuDNNLSTM else 1 inputs = keras.Input(batch_shape=(num_samples, timesteps, input_size)) layer = layer_class(units, return_state=True, stateful=True) outputs = layer(inputs) _, state = outputs[0], outputs[1:] self.assertEqual(len(state), num_states) model = keras.models.Model(inputs, state[0]) model.run_eagerly = test_utils.should_run_eagerly() inputs = np.random.random((num_samples, timesteps, input_size)) state = model.predict(inputs) np.testing.assert_allclose(keras.backend.eval(layer.states[0]), state, atol=1e-4) @parameterized.named_parameters( ("cudnngru", keras.layers.CuDNNGRU), ("cudnnlstm", keras.layers.CuDNNLSTM), ) @tf_test_utils.run_gpu_only def test_time_major_input(self, layer_class): input_size = 10 timesteps = 6 units = 2 num_samples = 32 model = keras.models.Sequential() model.add(keras.layers.Lambda(lambda t: tf.transpose(t, [1, 0, 2]))) layer = layer_class(units, time_major=True, return_sequences=True) model.add(layer) model.add(keras.layers.Lambda(lambda t: tf.transpose(t, [1, 0, 2]))) model.compile( loss="categorical_crossentropy", optimizer=RMSprop(learning_rate=0.001), ) model.fit( np.ones((num_samples, timesteps, input_size)), np.ones((num_samples, timesteps, units)), ) out = model.predict(np.ones((num_samples, timesteps, input_size))) self.assertEqual(out.shape, (num_samples, timesteps, units)) @parameterized.named_parameters( ("cudnngru", keras.layers.CuDNNGRU), ("cudnnlstm", keras.layers.CuDNNLSTM), ) @tf_test_utils.run_gpu_only def test_specify_initial_state_keras_tensor(self, layer_class): input_size = 10 timesteps = 6 units = 2 num_samples = 32 num_states = 2 if layer_class is keras.layers.CuDNNLSTM else 1 inputs = keras.Input((timesteps, input_size)) initial_state = [keras.Input((units, )) for _ in range(num_states)] layer = layer_class(units) if len(initial_state) == 1: output = layer(inputs, initial_state=initial_state[0]) else: output = layer(inputs, initial_state=initial_state) self.assertTrue( any(initial_state[0] is t for t in layer._inbound_nodes[0].input_tensors)) model = keras.models.Model([inputs] + initial_state, output) model.compile( loss="categorical_crossentropy", optimizer=RMSprop(learning_rate=0.001), run_eagerly=test_utils.should_run_eagerly(), ) inputs = np.random.random((num_samples, timesteps, input_size)) initial_state = [ np.random.random((num_samples, units)) for _ in range(num_states) ] targets = np.random.random((num_samples, units)) model.fit([inputs] + initial_state, targets)
class CuDNNV1OnlyTest(test_combinations.TestCase): @tf_test_utils.run_gpu_only def test_trainability(self): input_size = 10 units = 2 for layer_class in [keras.layers.CuDNNGRU, keras.layers.CuDNNLSTM]: layer = layer_class(units) layer.build((None, None, input_size)) self.assertEqual(len(layer.weights), 3) self.assertEqual(len(layer.trainable_weights), 3) self.assertEqual(len(layer.non_trainable_weights), 0) layer.trainable = False self.assertEqual(len(layer.weights), 3) self.assertEqual(len(layer.non_trainable_weights), 3) self.assertEqual(len(layer.trainable_weights), 0) layer.trainable = True self.assertEqual(len(layer.weights), 3) self.assertEqual(len(layer.trainable_weights), 3) self.assertEqual(len(layer.non_trainable_weights), 0) @parameterized.named_parameters( *test_utils.generate_combinations_with_testcase_name( rnn_type=["LSTM", "GRU"], to_cudnn=[True, False], bidirectional=[True, False], implementation=[1, 2], model_nest_level=[1, 2], model_type=["seq", "func"], )) @tf_test_utils.run_v1_only("b/120911602, b/112083752") @tf_test_utils.run_gpu_only def test_load_weights_between_noncudnn_rnn( self, rnn_type, to_cudnn, bidirectional, implementation, model_nest_level, model_type, ): input_size = 10 timesteps = 6 input_shape = (timesteps, input_size) units = 2 num_samples = 32 inputs = np.random.random((num_samples, timesteps, input_size)) rnn_layer_kwargs = { "recurrent_activation": "sigmoid", # ensure biases are non-zero and properly converted "bias_initializer": "random_uniform", "implementation": implementation, } if rnn_type == "LSTM": rnn_layer_class = keras.layers.LSTM cudnn_rnn_layer_class = keras.layers.CuDNNLSTM else: rnn_layer_class = keras.layers.GRU cudnn_rnn_layer_class = keras.layers.CuDNNGRU rnn_layer_kwargs["reset_after"] = True layer = rnn_layer_class(units, **rnn_layer_kwargs) if bidirectional: layer = keras.layers.Bidirectional(layer) cudnn_layer = cudnn_rnn_layer_class(units) if bidirectional: cudnn_layer = keras.layers.Bidirectional(cudnn_layer) model = self._make_nested_model(input_shape, layer, model_nest_level, model_type) cudnn_model = self._make_nested_model(input_shape, cudnn_layer, model_nest_level, model_type) if to_cudnn: self._convert_model_weights(model, cudnn_model) else: self._convert_model_weights(cudnn_model, model) self.assertAllClose(model.predict(inputs), cudnn_model.predict(inputs), atol=1e-4) def _make_nested_model(self, input_shape, layer, level=1, model_type="func"): # example: make_nested_seq_model((1,), Dense(10), level=2).summary() def make_nested_seq_model(input_shape, layer, level=1): model = layer for i in range(1, level + 1): layers = ([keras.layers.InputLayer(input_shape), model] if (i == 1) else [model]) model = keras.models.Sequential(layers) if i > 1: model.build((None, ) + input_shape) return model # example: make_nested_func_model((1,), Dense(10), level=2).summary() def make_nested_func_model(input_shape, layer, level=1): model_input = keras.layers.Input(input_shape) model = layer for _ in range(level): model = keras.models.Model(model_input, model(model_input)) return model if model_type == "func": return make_nested_func_model(input_shape, layer, level) elif model_type == "seq": return make_nested_seq_model(input_shape, layer, level) def _convert_model_weights(self, source_model, target_model): _, fname = tempfile.mkstemp(".h5") source_model.save_weights(fname) target_model.load_weights(fname) os.remove(fname) @parameterized.named_parameters( *test_utils.generate_combinations_with_testcase_name( rnn_type=["LSTM", "GRU"], to_cudnn=[True, False])) @tf_test_utils.run_v1_only("b/120911602") @tf_test_utils.run_gpu_only def test_load_weights_between_noncudnn_rnn_time_distributed( self, rnn_type, to_cudnn): # Similar test as test_load_weights_between_noncudnn_rnn() but has # different rank of input due to usage of TimeDistributed. Issue: # #10356. input_size = 10 steps = 6 timesteps = 6 input_shape = (timesteps, steps, input_size) units = 2 num_samples = 32 inputs = np.random.random((num_samples, timesteps, steps, input_size)) rnn_layer_kwargs = { "recurrent_activation": "sigmoid", # ensure biases are non-zero and properly converted "bias_initializer": "random_uniform", } if rnn_type == "LSTM": rnn_layer_class = keras.layers.LSTM cudnn_rnn_layer_class = keras.layers.CuDNNLSTM else: rnn_layer_class = keras.layers.GRU cudnn_rnn_layer_class = keras.layers.CuDNNGRU rnn_layer_kwargs["reset_after"] = True layer = rnn_layer_class(units, **rnn_layer_kwargs) layer = keras.layers.TimeDistributed(layer) cudnn_layer = cudnn_rnn_layer_class(units) cudnn_layer = keras.layers.TimeDistributed(cudnn_layer) model = self._make_nested_model(input_shape, layer) cudnn_model = self._make_nested_model(input_shape, cudnn_layer) if to_cudnn: self._convert_model_weights(model, cudnn_model) else: self._convert_model_weights(cudnn_model, model) self.assertAllClose(model.predict(inputs), cudnn_model.predict(inputs), atol=1e-4) @tf_test_utils.run_gpu_only def test_cudnnrnn_bidirectional(self): rnn = keras.layers.CuDNNGRU samples = 2 dim = 2 timesteps = 2 output_dim = 2 mode = "concat" x = np.random.random((samples, timesteps, dim)) target_dim = 2 * output_dim if mode == "concat" else output_dim y = np.random.random((samples, target_dim)) # test with Sequential model model = keras.Sequential() model.add( keras.layers.Bidirectional(rnn(output_dim), merge_mode=mode, input_shape=(None, dim))) model.compile(loss="mse", optimizer="rmsprop") model.fit(x, y, epochs=1, batch_size=1) # test config model.get_config() model = keras.models.model_from_json(model.to_json()) model.summary() # test stacked bidirectional layers model = keras.Sequential() model.add( keras.layers.Bidirectional( rnn(output_dim, return_sequences=True), merge_mode=mode, input_shape=(None, dim), )) model.add(keras.layers.Bidirectional(rnn(output_dim), merge_mode=mode)) model.compile(loss="mse", optimizer=R"rmsprop") model.fit(x, y, epochs=1, batch_size=1) # test with functional API inputs = keras.Input((timesteps, dim)) outputs = keras.layers.Bidirectional(rnn(output_dim), merge_mode=mode)(inputs) model = keras.Model(inputs, outputs) model.compile(loss="mse", optimizer=R"rmsprop") model.fit(x, y, epochs=1, batch_size=1) # Bidirectional and stateful inputs = keras.Input(batch_shape=(1, timesteps, dim)) outputs = keras.layers.Bidirectional(rnn(output_dim, stateful=True), merge_mode=mode)(inputs) model = keras.Model(inputs, outputs) model.compile(loss="mse", optimizer="rmsprop") model.fit(x, y, epochs=1, batch_size=1) @tf_test_utils.run_gpu_only def test_preprocess_weights_for_loading_gru_incompatible(self): """Test loading weights between incompatible layers. Should fail fast with an exception. """ input_shape = (3, 5) def gru(cudnn=False, **kwargs): layer_class = keras.layers.CuDNNGRU if cudnn else keras.layers.GRUV1 return layer_class(2, input_shape=input_shape, **kwargs) def get_layer_weights(layer): layer.build(input_shape=input_shape) return layer.get_weights() def assert_not_compatible(src, dest, message): with self.assertRaises(ValueError) as ex: keras.saving.hdf5_format.preprocess_weights_for_loading( dest, get_layer_weights(src)) self.assertIn(message, str(ex.exception)) assert_not_compatible( gru(), gru(cudnn=True), "GRU(reset_after=False) is not compatible with CuDNNGRU", ) assert_not_compatible( gru(cudnn=True), gru(), "CuDNNGRU is not compatible with GRU(reset_after=False)", ) assert_not_compatible( gru(), gru(reset_after=True), "GRU(reset_after=False) is not compatible with " "GRU(reset_after=True)", ) assert_not_compatible( gru(reset_after=True), gru(), "GRU(reset_after=True) is not compatible with " "GRU(reset_after=False)", )
class TimeDistributedTest(test_combinations.TestCase): @test_combinations.generate( test_combinations.combine(mode=["graph", "eager"]) ) def test_timedistributed_dense(self): model = keras.models.Sequential() model.add( keras.layers.TimeDistributed( keras.layers.Dense(2), input_shape=(3, 4) ) ) model.compile(optimizer="rmsprop", loss="mse") model.fit( np.random.random((10, 3, 4)), np.random.random((10, 3, 2)), epochs=1, batch_size=10, ) # test config model.get_config() # check whether the model variables are present in the # trackable list of objects checkpointed_object_ids = { id(o) for o in trackable_util.list_objects(model) } for v in model.variables: self.assertIn(id(v), checkpointed_object_ids) def test_timedistributed_static_batch_size(self): model = keras.models.Sequential() model.add( keras.layers.TimeDistributed( keras.layers.Dense(2), input_shape=(3, 4), batch_size=10 ) ) model.compile(optimizer="rmsprop", loss="mse") model.fit( np.random.random((10, 3, 4)), np.random.random((10, 3, 2)), epochs=1, batch_size=10, ) def test_timedistributed_invalid_init(self): x = tf.constant(np.zeros((1, 1)).astype("float32")) with self.assertRaisesRegex( ValueError, "Please initialize `TimeDistributed` layer with a " "`tf.keras.layers.Layer` instance.", ): keras.layers.TimeDistributed(x) def test_timedistributed_conv2d(self): with self.cached_session(): model = keras.models.Sequential() model.add( keras.layers.TimeDistributed( keras.layers.Conv2D(5, (2, 2), padding="same"), input_shape=(2, 4, 4, 3), ) ) model.add(keras.layers.Activation("relu")) model.compile(optimizer="rmsprop", loss="mse") model.train_on_batch( np.random.random((1, 2, 4, 4, 3)), np.random.random((1, 2, 4, 4, 5)), ) model = keras.models.model_from_json(model.to_json()) model.summary() def test_timedistributed_stacked(self): with self.cached_session(): model = keras.models.Sequential() model.add( keras.layers.TimeDistributed( keras.layers.Dense(2), input_shape=(3, 4) ) ) model.add(keras.layers.TimeDistributed(keras.layers.Dense(3))) model.add(keras.layers.Activation("relu")) model.compile(optimizer="rmsprop", loss="mse") model.fit( np.random.random((10, 3, 4)), np.random.random((10, 3, 3)), epochs=1, batch_size=10, ) def test_regularizers(self): with self.cached_session(): model = keras.models.Sequential() model.add( keras.layers.TimeDistributed( keras.layers.Dense( 2, kernel_regularizer="l1", activity_regularizer="l1" ), input_shape=(3, 4), ) ) model.add(keras.layers.Activation("relu")) model.compile(optimizer="rmsprop", loss="mse") self.assertEqual(len(model.losses), 2) def test_TimeDistributed_learning_phase(self): with self.cached_session(): keras.utils.set_random_seed(0) x = keras.layers.Input(shape=(3, 2)) y = keras.layers.TimeDistributed(keras.layers.Dropout(0.999))( x, training=True ) model = keras.models.Model(x, y) y = model.predict(np.random.random((10, 3, 2))) self.assertAllClose(np.mean(y), 0.0, atol=1e-1, rtol=1e-1) def test_TimeDistributed_batchnorm(self): with self.cached_session(): # test that wrapped BN updates still work. model = keras.models.Sequential() model.add( keras.layers.TimeDistributed( keras.layers.BatchNormalization(center=True, scale=True), name="bn", input_shape=(10, 2), ) ) model.compile(optimizer="rmsprop", loss="mse") # Assert that mean and variance are 0 and 1. td = model.layers[0] self.assertAllClose(td.get_weights()[2], np.array([0, 0])) assert np.array_equal(td.get_weights()[3], np.array([1, 1])) # Train model.train_on_batch( np.random.normal(loc=2, scale=2, size=(1, 10, 2)), np.broadcast_to(np.array([0, 1]), (1, 10, 2)), ) # Assert that mean and variance changed. assert not np.array_equal(td.get_weights()[2], np.array([0, 0])) assert not np.array_equal(td.get_weights()[3], np.array([1, 1])) def test_TimeDistributed_trainable(self): # test layers that need learning_phase to be set x = keras.layers.Input(shape=(3, 2)) layer = keras.layers.TimeDistributed(keras.layers.BatchNormalization()) _ = layer(x) self.assertEqual(len(layer.trainable_weights), 2) layer.trainable = False assert not layer.trainable_weights layer.trainable = True assert len(layer.trainable_weights) == 2 def test_TimeDistributed_with_masked_embedding_and_unspecified_shape(self): with self.cached_session(): # test with unspecified shape and Embeddings with mask_zero model = keras.models.Sequential() model.add( keras.layers.TimeDistributed( keras.layers.Embedding(5, 6, mask_zero=True), input_shape=(None, None), ) ) # N by t_1 by t_2 by 6 model.add( keras.layers.TimeDistributed( keras.layers.SimpleRNN(7, return_sequences=True) ) ) model.add( keras.layers.TimeDistributed( keras.layers.SimpleRNN(8, return_sequences=False) ) ) model.add(keras.layers.SimpleRNN(1, return_sequences=False)) model.compile(optimizer="rmsprop", loss="mse") model_input = np.random.randint( low=1, high=5, size=(10, 3, 4), dtype="int32" ) for i in range(4): model_input[i, i:, i:] = 0 model.fit( model_input, np.random.random((10, 1)), epochs=1, batch_size=10 ) mask_outputs = [model.layers[0].compute_mask(model.input)] for layer in model.layers[1:]: mask_outputs.append( layer.compute_mask(layer.input, mask_outputs[-1]) ) func = keras.backend.function([model.input], mask_outputs[:-1]) mask_outputs_val = func([model_input]) ref_mask_val_0 = model_input > 0 # embedding layer ref_mask_val_1 = ref_mask_val_0 # first RNN layer ref_mask_val_2 = np.any(ref_mask_val_1, axis=-1) # second RNN layer ref_mask_val = [ref_mask_val_0, ref_mask_val_1, ref_mask_val_2] for i in range(3): self.assertAllEqual(mask_outputs_val[i], ref_mask_val[i]) self.assertIs(mask_outputs[-1], None) # final layer @test_combinations.generate( test_combinations.combine(mode=["graph", "eager"]) ) def test_TimeDistributed_with_masking_layer(self): # test with Masking layer model = keras.models.Sequential() model.add( keras.layers.TimeDistributed( keras.layers.Masking( mask_value=0.0, ), input_shape=(None, 4), ) ) model.add(keras.layers.TimeDistributed(keras.layers.Dense(5))) model.compile(optimizer="rmsprop", loss="mse") model_input = np.random.randint(low=1, high=5, size=(10, 3, 4)) for i in range(4): model_input[i, i:, :] = 0.0 model.compile(optimizer="rmsprop", loss="mse") model.fit( model_input, np.random.random((10, 3, 5)), epochs=1, batch_size=6 ) mask_outputs = [model.layers[0].compute_mask(model.input)] mask_outputs += [ model.layers[1].compute_mask( model.layers[1].input, mask_outputs[-1] ) ] func = keras.backend.function([model.input], mask_outputs) mask_outputs_val = func([model_input]) self.assertEqual((mask_outputs_val[0]).all(), model_input.all()) self.assertEqual((mask_outputs_val[1]).all(), model_input.all()) def test_TimeDistributed_with_different_time_shapes(self): time_dist = keras.layers.TimeDistributed(keras.layers.Dense(5)) ph_1 = keras.backend.placeholder(shape=(None, 10, 13)) out_1 = time_dist(ph_1) self.assertEqual(out_1.shape.as_list(), [None, 10, 5]) ph_2 = keras.backend.placeholder(shape=(None, 1, 13)) out_2 = time_dist(ph_2) self.assertEqual(out_2.shape.as_list(), [None, 1, 5]) ph_3 = keras.backend.placeholder(shape=(None, 1, 18)) with self.assertRaisesRegex(ValueError, "is incompatible with"): time_dist(ph_3) def test_TimeDistributed_with_invalid_dimensions(self): time_dist = keras.layers.TimeDistributed(keras.layers.Dense(5)) ph = keras.backend.placeholder(shape=(None, 10)) with self.assertRaisesRegex( ValueError, "`TimeDistributed` Layer should be passed an `input_shape `", ): time_dist(ph) @test_combinations.generate( test_combinations.combine(mode=["graph", "eager"]) ) def test_TimeDistributed_reshape(self): class NoReshapeLayer(keras.layers.Layer): def call(self, inputs): return inputs # Built-in layers that aren't stateful use the reshape implementation. td1 = keras.layers.TimeDistributed(keras.layers.Dense(5)) self.assertTrue(td1._always_use_reshape) # Built-in layers that are stateful don't use the reshape # implementation. td2 = keras.layers.TimeDistributed( keras.layers.RNN(keras.layers.SimpleRNNCell(10), stateful=True) ) self.assertFalse(td2._always_use_reshape) # Custom layers are not allowlisted for the fast reshape implementation. td3 = keras.layers.TimeDistributed(NoReshapeLayer()) self.assertFalse(td3._always_use_reshape) @test_combinations.generate( test_combinations.combine(mode=["graph", "eager"]) ) def test_TimeDistributed_output_shape_return_types(self): class TestLayer(keras.layers.Layer): def call(self, inputs): return tf.concat([inputs, inputs], axis=-1) def compute_output_shape(self, input_shape): output_shape = tf.TensorShape(input_shape).as_list() output_shape[-1] = output_shape[-1] * 2 output_shape = tf.TensorShape(output_shape) return output_shape class TestListLayer(TestLayer): def compute_output_shape(self, input_shape): shape = super().compute_output_shape(input_shape) return shape.as_list() class TestTupleLayer(TestLayer): def compute_output_shape(self, input_shape): shape = super().compute_output_shape(input_shape) return tuple(shape.as_list()) # Layers can specify output shape as list/tuple/TensorShape test_layers = [TestLayer, TestListLayer, TestTupleLayer] for layer in test_layers: input_layer = keras.layers.TimeDistributed(layer()) inputs = keras.backend.placeholder(shape=(None, 2, 4)) output = input_layer(inputs) self.assertEqual(output.shape.as_list(), [None, 2, 8]) self.assertEqual( input_layer.compute_output_shape([None, 2, 4]).as_list(), [None, 2, 8], ) @test_combinations.run_all_keras_modes(always_skip_v1=True) # TODO(scottzhu): check why v1 session failed. def test_TimeDistributed_with_mask_first_implementation(self): np.random.seed(100) rnn_layer = keras.layers.LSTM(4, return_sequences=True, stateful=True) data = np.array( [ [[[1.0], [1.0]], [[0.0], [1.0]]], [[[1.0], [0.0]], [[1.0], [1.0]]], [[[1.0], [0.0]], [[1.0], [1.0]]], ] ) x = keras.layers.Input(shape=(2, 2, 1), batch_size=3) x_masking = keras.layers.Masking()(x) y = keras.layers.TimeDistributed(rnn_layer)(x_masking) model_1 = keras.models.Model(x, y) model_1.compile( "rmsprop", "mse", run_eagerly=test_utils.should_run_eagerly() ) output_with_mask = model_1.predict(data, steps=1) y = keras.layers.TimeDistributed(rnn_layer)(x) model_2 = keras.models.Model(x, y) model_2.compile( "rmsprop", "mse", run_eagerly=test_utils.should_run_eagerly() ) output = model_2.predict(data, steps=1) self.assertNotAllClose(output_with_mask, output, atol=1e-7) @test_combinations.run_all_keras_modes @parameterized.named_parameters( *test_utils.generate_combinations_with_testcase_name( layer=[keras.layers.LSTM, keras.layers.Dense] ) ) def test_TimeDistributed_with_ragged_input(self, layer): if tf.executing_eagerly(): self.skipTest("b/143103634") np.random.seed(100) layer = layer(4) ragged_data = tf.ragged.constant( [ [[[1.0], [1.0]], [[2.0], [2.0]]], [[[4.0], [4.0]], [[5.0], [5.0]], [[6.0], [6.0]]], [[[7.0], [7.0]], [[8.0], [8.0]], [[9.0], [9.0]]], ], ragged_rank=1, ) x_ragged = keras.Input(shape=(None, 2, 1), dtype="float32", ragged=True) y_ragged = keras.layers.TimeDistributed(layer)(x_ragged) model_1 = keras.models.Model(x_ragged, y_ragged) model_1._run_eagerly = test_utils.should_run_eagerly() output_ragged = model_1.predict(ragged_data, steps=1) x_dense = keras.Input(shape=(None, 2, 1), dtype="float32") masking = keras.layers.Masking()(x_dense) y_dense = keras.layers.TimeDistributed(layer)(masking) model_2 = keras.models.Model(x_dense, y_dense) dense_data = ragged_data.to_tensor() model_2._run_eagerly = test_utils.should_run_eagerly() output_dense = model_2.predict(dense_data, steps=1) output_ragged = convert_ragged_tensor_value(output_ragged) self.assertAllEqual(output_ragged.to_tensor(), output_dense) @test_combinations.run_all_keras_modes def test_TimeDistributed_with_ragged_input_with_batch_size(self): np.random.seed(100) layer = keras.layers.Dense(16) ragged_data = tf.ragged.constant( [ [[[1.0], [1.0]], [[2.0], [2.0]]], [[[4.0], [4.0]], [[5.0], [5.0]], [[6.0], [6.0]]], [[[7.0], [7.0]], [[8.0], [8.0]], [[9.0], [9.0]]], ], ragged_rank=1, ) # Use the first implementation by specifying batch_size x_ragged = keras.Input( shape=(None, 2, 1), batch_size=3, dtype="float32", ragged=True ) y_ragged = keras.layers.TimeDistributed(layer)(x_ragged) model_1 = keras.models.Model(x_ragged, y_ragged) output_ragged = model_1.predict(ragged_data, steps=1) x_dense = keras.Input(shape=(None, 2, 1), batch_size=3, dtype="float32") masking = keras.layers.Masking()(x_dense) y_dense = keras.layers.TimeDistributed(layer)(masking) model_2 = keras.models.Model(x_dense, y_dense) dense_data = ragged_data.to_tensor() output_dense = model_2.predict(dense_data, steps=1) output_ragged = convert_ragged_tensor_value(output_ragged) self.assertAllEqual(output_ragged.to_tensor(), output_dense) def test_TimeDistributed_set_static_shape(self): layer = keras.layers.TimeDistributed(keras.layers.Conv2D(16, (3, 3))) inputs = keras.Input(batch_shape=(1, None, 32, 32, 1)) outputs = layer(inputs) # Make sure the batch dim is not lost after array_ops.reshape. self.assertListEqual(outputs.shape.as_list(), [1, None, 30, 30, 16]) @test_combinations.run_all_keras_modes def test_TimeDistributed_with_mimo(self): dense_1 = keras.layers.Dense(8) dense_2 = keras.layers.Dense(16) class TestLayer(keras.layers.Layer): def __init__(self): super().__init__() self.dense_1 = dense_1 self.dense_2 = dense_2 def call(self, inputs): return self.dense_1(inputs[0]), self.dense_2(inputs[1]) def compute_output_shape(self, input_shape): output_shape_1 = self.dense_1.compute_output_shape( input_shape[0] ) output_shape_2 = self.dense_2.compute_output_shape( input_shape[1] ) return output_shape_1, output_shape_2 np.random.seed(100) layer = TestLayer() data_1 = tf.constant( [ [[[1.0], [1.0]], [[2.0], [2.0]]], [[[4.0], [4.0]], [[5.0], [5.0]]], [[[7.0], [7.0]], [[8.0], [8.0]]], ] ) data_2 = tf.constant( [ [[[1.0], [1.0]], [[2.0], [2.0]]], [[[4.0], [4.0]], [[5.0], [5.0]]], [[[7.0], [7.0]], [[8.0], [8.0]]], ] ) x1 = keras.Input(shape=(None, 2, 1), dtype="float32") x2 = keras.Input(shape=(None, 2, 1), dtype="float32") y1, y2 = keras.layers.TimeDistributed(layer)([x1, x2]) model_1 = keras.models.Model([x1, x2], [y1, y2]) model_1.compile( optimizer="rmsprop", loss="mse", run_eagerly=test_utils.should_run_eagerly(), ) output_1 = model_1.predict((data_1, data_2), steps=1) y1 = dense_1(x1) y2 = dense_2(x2) model_2 = keras.models.Model([x1, x2], [y1, y2]) output_2 = model_2.predict((data_1, data_2), steps=1) self.assertAllClose(output_1, output_2) model_1.fit( x=[ np.random.random((10, 2, 2, 1)), np.random.random((10, 2, 2, 1)), ], y=[ np.random.random((10, 2, 2, 8)), np.random.random((10, 2, 2, 16)), ], epochs=1, batch_size=3, ) def test_TimeDistributed_Attention(self): query_input = keras.layers.Input(shape=(None, 1, 10), dtype="float32") value_input = keras.layers.Input(shape=(None, 4, 10), dtype="float32") # Query-value attention of shape [batch_size, Tq, filters]. query_value_attention_seq = keras.layers.TimeDistributed( keras.layers.Attention() )([query_input, value_input]) model = keras.models.Model( [query_input, value_input], query_value_attention_seq ) model.compile(optimizer="rmsprop", loss="mse") model.fit( [ np.random.random((10, 8, 1, 10)), np.random.random((10, 8, 4, 10)), ], np.random.random((10, 8, 1, 10)), epochs=1, batch_size=10, ) # test config and serialization/deserialization model.get_config() model = keras.models.model_from_json(model.to_json()) model.summary()
class ConvLSTM2DTest(test_combinations.TestCase): @parameterized.named_parameters( *test_utils.generate_combinations_with_testcase_name( data_format=["channels_first", "channels_last"], return_sequences=[True, False], )) def test_conv_lstm(self, data_format, return_sequences): num_row = 3 num_col = 3 filters = 2 num_samples = 1 input_channel = 2 input_num_row = 5 input_num_col = 5 sequence_len = 2 if data_format == "channels_first": inputs = np.random.rand( num_samples, sequence_len, input_channel, input_num_row, input_num_col, ) else: inputs = np.random.rand( num_samples, sequence_len, input_num_row, input_num_col, input_channel, ) # test for return state: x = keras.Input(batch_shape=inputs.shape) kwargs = { "data_format": data_format, "return_sequences": return_sequences, "return_state": True, "stateful": True, "filters": filters, "kernel_size": (num_row, num_col), "padding": "valid", } layer = keras.layers.ConvLSTM2D(**kwargs) layer.build(inputs.shape) outputs = layer(x) _, states = outputs[0], outputs[1:] self.assertEqual(len(states), 2) model = keras.models.Model(x, states[0]) state = model.predict(inputs) self.assertAllClose(keras.backend.eval(layer.states[0]), state, atol=1e-4) # test for output shape: test_utils.layer_test( keras.layers.ConvLSTM2D, kwargs={ "data_format": data_format, "return_sequences": return_sequences, "filters": filters, "kernel_size": (num_row, num_col), "padding": "valid", }, input_shape=inputs.shape, ) def test_conv_lstm_statefulness(self): # Tests for statefulness num_row = 3 num_col = 3 filters = 2 num_samples = 1 input_channel = 2 input_num_row = 5 input_num_col = 5 sequence_len = 2 inputs = np.random.rand( num_samples, sequence_len, input_num_row, input_num_col, input_channel, ) with self.cached_session(): model = keras.models.Sequential() kwargs = { "data_format": "channels_last", "return_sequences": False, "filters": filters, "kernel_size": (num_row, num_col), "stateful": True, "batch_input_shape": inputs.shape, "padding": "same", } layer = keras.layers.ConvLSTM2D(**kwargs) model.add(layer) model.compile(optimizer="sgd", loss="mse") out1 = model.predict(np.ones_like(inputs)) # train once so that the states change model.train_on_batch(np.ones_like(inputs), np.random.random(out1.shape)) out2 = model.predict(np.ones_like(inputs)) # if the state is not reset, output should be different self.assertNotEqual(out1.max(), out2.max()) # check that output changes after states are reset # (even though the model itself didn't change) layer.reset_states() out3 = model.predict(np.ones_like(inputs)) self.assertNotEqual(out3.max(), out2.max()) # check that container-level reset_states() works model.reset_states() out4 = model.predict(np.ones_like(inputs)) self.assertAllClose(out3, out4, atol=1e-5) # check that the call to `predict` updated the states out5 = model.predict(np.ones_like(inputs)) self.assertNotEqual(out4.max(), out5.max()) def test_conv_lstm_regularizers(self): # check regularizers num_row = 3 num_col = 3 filters = 2 num_samples = 1 input_channel = 2 input_num_row = 5 input_num_col = 5 sequence_len = 2 inputs = np.random.rand( num_samples, sequence_len, input_num_row, input_num_col, input_channel, ) with self.cached_session(): kwargs = { "data_format": "channels_last", "return_sequences": False, "kernel_size": (num_row, num_col), "stateful": True, "filters": filters, "batch_input_shape": inputs.shape, "kernel_regularizer": keras.regularizers.L1L2(l1=0.01), "recurrent_regularizer": keras.regularizers.L1L2(l1=0.01), "activity_regularizer": "l2", "bias_regularizer": "l2", "kernel_constraint": "max_norm", "recurrent_constraint": "max_norm", "bias_constraint": "max_norm", "padding": "same", } layer = keras.layers.ConvLSTM2D(**kwargs) layer.build(inputs.shape) self.assertEqual(len(layer.losses), 3) layer(keras.backend.variable(np.ones(inputs.shape))) self.assertEqual(len(layer.losses), 4) def test_conv_lstm_dropout(self): # check dropout with self.cached_session(): test_utils.layer_test( keras.layers.ConvLSTM2D, kwargs={ "data_format": "channels_last", "return_sequences": False, "filters": 2, "kernel_size": (3, 3), "padding": "same", "dropout": 0.1, "recurrent_dropout": 0.1, }, input_shape=(1, 2, 5, 5, 2), ) def test_conv_lstm_cloning(self): with self.cached_session(): model = keras.models.Sequential() model.add( keras.layers.ConvLSTM2D(5, 3, input_shape=(None, 5, 5, 3))) test_inputs = np.random.random((2, 4, 5, 5, 3)) reference_outputs = model.predict(test_inputs) weights = model.get_weights() # Use a new graph to clone the model with self.cached_session(): clone = keras.models.clone_model(model) clone.set_weights(weights) outputs = clone.predict(test_inputs) self.assertAllClose(reference_outputs, outputs, atol=1e-5) @tf.test.disable_with_predicate( pred=tf.test.is_built_with_rocm, skip_message="Skipping the test as OOM occurred with 1 GB budget.", ) def test_conv_lstm_with_initial_state(self): num_samples = 32 sequence_len = 5 encoder_inputs = keras.layers.Input((None, 32, 32, 3)) encoder = keras.layers.ConvLSTM2D( filters=32, kernel_size=(3, 3), padding="same", return_sequences=False, return_state=True, ) _, state_h, state_c = encoder(encoder_inputs) encoder_states = [state_h, state_c] decoder_inputs = keras.layers.Input((None, 32, 32, 4)) decoder_lstm = keras.layers.ConvLSTM2D( filters=32, kernel_size=(3, 3), padding="same", return_sequences=False, return_state=False, ) decoder_outputs = decoder_lstm(decoder_inputs, initial_state=encoder_states) output = keras.layers.Conv2D(1, (3, 3), padding="same", activation="relu")(decoder_outputs) model = keras.Model([encoder_inputs, decoder_inputs], output) model.compile( optimizer="sgd", loss="mse", run_eagerly=test_utils.should_run_eagerly(), ) x_1 = np.random.rand(num_samples, sequence_len, 32, 32, 3) x_2 = np.random.rand(num_samples, sequence_len, 32, 32, 4) y = np.random.rand(num_samples, 32, 32, 1) model.fit([x_1, x_2], y) model.predict([x_1, x_2])
class MergingLayersTest(test_combinations.TestCase): def test_add(self): i1 = keras.layers.Input(shape=(4, 5)) i2 = keras.layers.Input(shape=(4, 5)) i3 = keras.layers.Input(shape=(4, 5)) add_layer = keras.layers.Add() o = add_layer([i1, i2, i3]) self.assertListEqual(o.shape.as_list(), [None, 4, 5]) model = keras.models.Model([i1, i2, i3], o) model.run_eagerly = test_utils.should_run_eagerly() x1 = np.random.random((2, 4, 5)) x2 = np.random.random((2, 4, 5)) x3 = np.random.random((2, 4, 5)) out = model.predict([x1, x2, x3]) self.assertEqual(out.shape, (2, 4, 5)) self.assertAllClose(out, x1 + x2 + x3, atol=1e-4) self.assertIsNone( add_layer.compute_mask([i1, i2, i3], [None, None, None])) self.assertTrue( np.all( backend.eval( add_layer.compute_mask( [i1, i2], [backend.variable(x1), backend.variable(x2)])))) with self.assertRaisesRegex(ValueError, "`mask` should be a list."): add_layer.compute_mask([i1, i2, i3], x1) with self.assertRaisesRegex(ValueError, "`inputs` should be a list."): add_layer.compute_mask(i1, [None, None, None]) with self.assertRaisesRegex(ValueError, " should have the same length."): add_layer.compute_mask([i1, i2, i3], [None, None]) def test_subtract(self): i1 = keras.layers.Input(shape=(4, 5)) i2 = keras.layers.Input(shape=(4, 5)) i3 = keras.layers.Input(shape=(4, 5)) subtract_layer = keras.layers.Subtract() o = subtract_layer([i1, i2]) self.assertListEqual(o.shape.as_list(), [None, 4, 5]) model = keras.models.Model([i1, i2], o) model.run_eagerly = test_utils.should_run_eagerly() x1 = np.random.random((2, 4, 5)) x2 = np.random.random((2, 4, 5)) out = model.predict([x1, x2]) self.assertEqual(out.shape, (2, 4, 5)) self.assertAllClose(out, x1 - x2, atol=1e-4) self.assertIsNone(subtract_layer.compute_mask([i1, i2], [None, None])) self.assertTrue( np.all( backend.eval( subtract_layer.compute_mask( [i1, i2], [backend.variable(x1), backend.variable(x2)])))) with self.assertRaisesRegex(ValueError, "`mask` should be a list."): subtract_layer.compute_mask([i1, i2], x1) with self.assertRaisesRegex(ValueError, "`inputs` should be a list."): subtract_layer.compute_mask(i1, [None, None]) with self.assertRaisesRegex( ValueError, "layer should be called on exactly 2 inputs"): subtract_layer([i1, i2, i3]) with self.assertRaisesRegex( ValueError, "layer should be called on exactly 2 inputs"): subtract_layer([i1]) def test_multiply(self): i1 = keras.layers.Input(shape=(4, 5)) i2 = keras.layers.Input(shape=(4, 5)) i3 = keras.layers.Input(shape=(4, 5)) o = keras.layers.multiply([i1, i2, i3]) self.assertListEqual(o.shape.as_list(), [None, 4, 5]) model = keras.models.Model([i1, i2, i3], o) model.run_eagerly = test_utils.should_run_eagerly() x1 = np.random.random((2, 4, 5)) x2 = np.random.random((2, 4, 5)) x3 = np.random.random((2, 4, 5)) out = model.predict([x1, x2, x3]) self.assertEqual(out.shape, (2, 4, 5)) self.assertAllClose(out, x1 * x2 * x3, atol=1e-4) def test_average(self): i1 = keras.layers.Input(shape=(4, 5)) i2 = keras.layers.Input(shape=(4, 5)) o = keras.layers.average([i1, i2]) self.assertListEqual(o.shape.as_list(), [None, 4, 5]) model = keras.models.Model([i1, i2], o) model.run_eagerly = test_utils.should_run_eagerly() x1 = np.random.random((2, 4, 5)) x2 = np.random.random((2, 4, 5)) out = model.predict([x1, x2]) self.assertEqual(out.shape, (2, 4, 5)) self.assertAllClose(out, 0.5 * (x1 + x2), atol=1e-4) def test_maximum(self): i1 = keras.layers.Input(shape=(4, 5)) i2 = keras.layers.Input(shape=(4, 5)) o = keras.layers.maximum([i1, i2]) self.assertListEqual(o.shape.as_list(), [None, 4, 5]) model = keras.models.Model([i1, i2], o) model.run_eagerly = test_utils.should_run_eagerly() x1 = np.random.random((2, 4, 5)) x2 = np.random.random((2, 4, 5)) out = model.predict([x1, x2]) self.assertEqual(out.shape, (2, 4, 5)) self.assertAllClose(out, np.maximum(x1, x2), atol=1e-4) def test_minimum(self): i1 = keras.layers.Input(shape=(4, 5)) i2 = keras.layers.Input(shape=(4, 5)) o = keras.layers.minimum([i1, i2]) self.assertListEqual(o.shape.as_list(), [None, 4, 5]) model = keras.models.Model([i1, i2], o) model.run_eagerly = test_utils.should_run_eagerly() x1 = np.random.random((2, 4, 5)) x2 = np.random.random((2, 4, 5)) out = model.predict([x1, x2]) self.assertEqual(out.shape, (2, 4, 5)) self.assertAllClose(out, np.minimum(x1, x2), atol=1e-4) def test_concatenate(self): i1 = keras.layers.Input(shape=(4, 5)) i2 = keras.layers.Input(shape=(4, 5)) concat_layer = keras.layers.Concatenate(axis=1) o = concat_layer([i1, i2]) self.assertListEqual(o.shape.as_list(), [None, 8, 5]) model = keras.models.Model([i1, i2], o) model.run_eagerly = test_utils.should_run_eagerly() x1 = np.random.random((2, 4, 5)) x2 = np.random.random((2, 4, 5)) out = model.predict([x1, x2]) self.assertEqual(out.shape, (2, 8, 5)) self.assertAllClose(out, np.concatenate([x1, x2], axis=1), atol=1e-4) self.assertIsNone(concat_layer.compute_mask([i1, i2], [None, None])) self.assertTrue( np.all( backend.eval( concat_layer.compute_mask( [i1, i2], [backend.variable(x1), backend.variable(x2)])))) # Should work with unit-length input. unit_length_o = concat_layer([i1]) self.assertListEqual(unit_length_o.shape.as_list(), i1.shape.as_list()) with self.assertRaisesRegex(ValueError, "`mask` should be a list."): concat_layer.compute_mask([i1, i2], x1) with self.assertRaisesRegex(ValueError, "`inputs` should be a list."): concat_layer.compute_mask(i1, [None, None]) with self.assertRaisesRegex(ValueError, "should have the same length"): concat_layer.compute_mask([i1, i2], [None]) with self.assertRaisesRegex( ValueError, "layer should be called on a list of inputs"): concat_layer(i1) def test_concatenate_numpy_inputs(self): if tf.executing_eagerly(): layer = keras.layers.Concatenate() x, y = np.ones((10, 10)), np.ones((10, 10)) self.assertAllEqual(np.ones((10, 20)), layer([x, y])) def test_dot(self): i1 = keras.layers.Input(shape=(4, )) i2 = keras.layers.Input(shape=(4, )) o = keras.layers.dot([i1, i2], axes=1) self.assertListEqual(o.shape.as_list(), [None, 1]) model = keras.models.Model([i1, i2], o) model.run_eagerly = test_utils.should_run_eagerly() _ = keras.layers.Dot(axes=1).get_config() x1 = np.random.random((2, 4)) x2 = np.random.random((2, 4)) out = model.predict([x1, x2]) self.assertEqual(out.shape, (2, 1)) expected = np.zeros((2, 1)) expected[0, 0] = np.dot(x1[0], x2[0]) expected[1, 0] = np.dot(x1[1], x2[1]) self.assertAllClose(out, expected, atol=1e-4) # Test with negative tuple of axes. o = keras.layers.dot([i1, i2], axes=(-1, -1)) self.assertListEqual(o.shape.as_list(), [None, 1]) model = keras.models.Model([i1, i2], o) model.run_eagerly = test_utils.should_run_eagerly() out = model.predict([x1, x2]) self.assertEqual(out.shape, (2, 1)) self.assertAllClose(out, expected, atol=1e-4) # test compute_output_shape layer = keras.layers.Dot(axes=-1) self.assertEqual(layer.compute_output_shape([(4, 5), (4, 5)]), (4, 1)) @parameterized.named_parameters( *test_utils.generate_combinations_with_testcase_name(layer=[ keras.layers.Add, keras.layers.Subtract, keras.layers.Multiply, keras.layers.Minimum, keras.layers.Maximum, keras.layers.Average, ])) def test_merging_with_ragged_input(self, layer): ragged_data = tf.ragged.constant( [[1.0, 1.0, 1.0], [1.0, 1.0], [1.0, 1.0, 1.0, 1.0]], ragged_rank=1) dense_data = ragged_data.to_tensor() input1 = keras.Input(shape=(None, ), ragged=True) input2 = keras.Input(shape=(None, ), ragged=True) out = layer()([input1, input2]) model = keras.models.Model(inputs=[input1, input2], outputs=out) out_ragged = model.predict([ragged_data, ragged_data], steps=1) out_ragged = convert_ragged_tensor_value(out_ragged).to_tensor() input1 = keras.Input(shape=(None, )) input2 = keras.Input(shape=(None, )) out = layer()([input1, input2]) model = keras.models.Model(inputs=[input1, input2], outputs=out) out_dense = model.predict([dense_data, dense_data], steps=1) self.assertAllEqual(out_dense, out_ragged) def test_concatenate_with_ragged_input(self): ragged1 = tf.ragged.constant([[1.0, 1.0], [1.0], [1.0, 1.0, 1.0]], ragged_rank=1) ragged2 = tf.ragged.constant([[2.0, 2.0, 2.0], [2.0], [2.0, 2.0]], ragged_rank=1) expected_concatenated_ragged = tf.ragged.constant( [[1.0, 1.0, 2.0, 2.0, 2.0], [1.0, 2.0], [1.0, 1.0, 1.0, 2.0, 2.0]], ragged_rank=1, ) input1 = keras.Input(shape=(None, ), ragged=True) input2 = keras.Input(shape=(None, ), ragged=True) out = keras.layers.Concatenate(axis=1)([input1, input2]) model = keras.models.Model(inputs=[input1, input2], outputs=out) out_ragged = model.predict([ragged1, ragged2], steps=1) self.assertAllEqual(out_ragged, expected_concatenated_ragged) @parameterized.named_parameters( *test_utils.generate_combinations_with_testcase_name(layer=[ keras.layers.Add, keras.layers.Subtract, keras.layers.Multiply, keras.layers.Minimum, keras.layers.Maximum, keras.layers.Average, ])) def test_merging_with_scalar_input(self, layer): x1 = np.array((1)) x2 = np.array((2)) out = layer()([x1, x2]) self.assertEqual(out.shape, ()) @parameterized.named_parameters( *test_utils.generate_combinations_with_testcase_name(layer=[ keras.layers.Add, keras.layers.add, keras.layers.Average, keras.layers.average, keras.layers.Concatenate, keras.layers.concatenate, keras.layers.Maximum, keras.layers.maximum, keras.layers.Minimum, keras.layers.minimum, keras.layers.Multiply, keras.layers.multiply, ])) def test_single_element(self, layer): # Instantiate the Layer subclasses if tf_inspect.isclass(layer) and issubclass(layer, keras.layers.Layer): layer = layer() # Processing a single element list should behave as identity. i1 = keras.layers.Input(shape=(4, 5)) o = layer([i1]) self.assertListEqual(o.shape.as_list(), [None, 4, 5]) model = keras.models.Model(i1, o) model.run_eagerly = test_utils.should_run_eagerly() x1 = np.random.random((2, 4, 5)) out = model.predict(x1) self.assertEqual(out.shape, (2, 4, 5)) self.assertAllClose(out, x1) # A single element must be passed as a list, not by itself. with self.assertRaisesRegex(ValueError, "called on a list"): layer(i1)