def test_network_invocation(self, output_range, out_seq_len): hidden_size = 32 sequence_length = 21 vocab_size = 57 num_types = 7 # Create a small BertEncoder for testing. test_network = bert_encoder.BertEncoder(vocab_size=vocab_size, hidden_size=hidden_size, num_attention_heads=2, num_layers=3, type_vocab_size=num_types, output_range=output_range) # Create the inputs (note that the first dimension is implicit). word_ids = tf.keras.Input(shape=(sequence_length, ), dtype=tf.int32) mask = tf.keras.Input(shape=(sequence_length, ), dtype=tf.int32) type_ids = tf.keras.Input(shape=(sequence_length, ), dtype=tf.int32) data, pooled = test_network([word_ids, mask, type_ids]) # Create a model based off of this network: model = tf.keras.Model([word_ids, mask, type_ids], [data, pooled]) # Invoke the model. We can't validate the output data here (the model is too # complex) but this will catch structural runtime errors. batch_size = 3 word_id_data = np.random.randint(vocab_size, size=(batch_size, sequence_length)) mask_data = np.random.randint(2, size=(batch_size, sequence_length)) type_id_data = np.random.randint(num_types, size=(batch_size, sequence_length)) outputs = model.predict([word_id_data, mask_data, type_id_data]) self.assertEqual(outputs[0].shape[1], out_seq_len) # Creates a BertEncoder with max_sequence_length != sequence_length max_sequence_length = 128 test_network = bert_encoder.BertEncoder( vocab_size=vocab_size, hidden_size=hidden_size, max_sequence_length=max_sequence_length, num_attention_heads=2, num_layers=3, type_vocab_size=num_types) data, pooled = test_network([word_ids, mask, type_ids]) model = tf.keras.Model([word_ids, mask, type_ids], [data, pooled]) outputs = model.predict([word_id_data, mask_data, type_id_data]) self.assertEqual(outputs[0].shape[1], sequence_length) # Creates a BertEncoder with embedding_width != hidden_size test_network = bert_encoder.BertEncoder( vocab_size=vocab_size, hidden_size=hidden_size, max_sequence_length=max_sequence_length, num_attention_heads=2, num_layers=3, type_vocab_size=num_types, embedding_width=16) data, pooled = test_network([word_ids, mask, type_ids]) model = tf.keras.Model([word_ids, mask, type_ids], [data, pooled]) outputs = model.predict([word_id_data, mask_data, type_id_data]) self.assertEqual(outputs[0].shape[-1], hidden_size) self.assertTrue(hasattr(test_network, "_embedding_projection"))
def test_network_creation(self): hidden_size = 32 sequence_length = 21 # Create a small BertEncoder for testing. test_network = bert_encoder.BertEncoder( vocab_size=100, hidden_size=hidden_size, num_attention_heads=2, num_layers=3) # Create the inputs (note that the first dimension is implicit). word_ids = tf.keras.Input(shape=(sequence_length,), dtype=tf.int32) mask = tf.keras.Input(shape=(sequence_length,), dtype=tf.int32) type_ids = tf.keras.Input(shape=(sequence_length,), dtype=tf.int32) data, pooled = test_network([word_ids, mask, type_ids]) self.assertIsInstance(test_network.transformer_layers, list) self.assertLen(test_network.transformer_layers, 3) self.assertIsInstance(test_network.pooler_layer, tf.keras.layers.Dense) expected_data_shape = [None, sequence_length, hidden_size] expected_pooled_shape = [None, hidden_size] self.assertAllEqual(expected_data_shape, data.shape.as_list()) self.assertAllEqual(expected_pooled_shape, pooled.shape.as_list()) # The default output dtype is float32. self.assertAllEqual(tf.float32, data.dtype) self.assertAllEqual(tf.float32, pooled.dtype) test_network_dict = bert_encoder.BertEncoder( vocab_size=100, hidden_size=hidden_size, num_attention_heads=2, num_layers=3, dict_outputs=True) # Create the inputs (note that the first dimension is implicit). inputs = dict( input_word_ids=word_ids, input_mask=mask, input_type_ids=type_ids) _ = test_network_dict(inputs) test_network_dict.set_weights(test_network.get_weights()) batch_size = 2 vocab_size = 100 num_types = 2 word_id_data = np.random.randint( vocab_size, size=(batch_size, sequence_length)) mask_data = np.random.randint(2, size=(batch_size, sequence_length)) type_id_data = np.random.randint( num_types, size=(batch_size, sequence_length)) list_outputs = test_network([word_id_data, mask_data, type_id_data]) dict_outputs = test_network_dict( dict( input_word_ids=word_id_data, input_mask=mask_data, input_type_ids=type_id_data)) self.assertAllEqual(list_outputs[0], dict_outputs["sequence_output"]) self.assertAllEqual(list_outputs[1], dict_outputs["pooled_output"])
def test_all_encoder_outputs_network_creation(self): hidden_size = 32 sequence_length = 21 # Create a small BertEncoder for testing. test_network = bert_encoder.BertEncoder( vocab_size=100, hidden_size=hidden_size, num_attention_heads=2, num_layers=3, return_all_encoder_outputs=True) # Create the inputs (note that the first dimension is implicit). word_ids = tf.keras.Input(shape=(sequence_length, ), dtype=tf.int32) mask = tf.keras.Input(shape=(sequence_length, ), dtype=tf.int32) type_ids = tf.keras.Input(shape=(sequence_length, ), dtype=tf.int32) all_encoder_outputs, pooled = test_network([word_ids, mask, type_ids]) expected_data_shape = [None, sequence_length, hidden_size] expected_pooled_shape = [None, hidden_size] self.assertLen(all_encoder_outputs, 3) for data in all_encoder_outputs: self.assertAllEqual(expected_data_shape, data.shape.as_list()) self.assertAllEqual(expected_pooled_shape, pooled.shape.as_list()) # The default output dtype is float32. self.assertAllEqual(tf.float32, all_encoder_outputs[-1].dtype) self.assertAllEqual(tf.float32, pooled.dtype)
def test_v2_network_creation_with_float16_dtype(self): hidden_size = 32 sequence_length = 21 tf.keras.mixed_precision.set_global_policy("mixed_float16") # Create a small BertEncoder for testing. test_network = bert_encoder.BertEncoder(vocab_size=100, hidden_size=hidden_size, num_attention_heads=2, num_layers=3, dict_outputs=True) # Create the inputs (note that the first dimension is implicit). word_ids = tf.keras.Input(shape=(sequence_length, ), dtype=tf.int32) mask = tf.keras.Input(shape=(sequence_length, ), dtype=tf.int32) type_ids = tf.keras.Input(shape=(sequence_length, ), dtype=tf.int32) dict_outputs = test_network([word_ids, mask, type_ids]) data = dict_outputs["sequence_output"] pooled = dict_outputs["pooled_output"] expected_data_shape = [None, sequence_length, hidden_size] expected_pooled_shape = [None, hidden_size] self.assertAllEqual(expected_data_shape, data.shape.as_list()) self.assertAllEqual(expected_pooled_shape, pooled.shape.as_list()) # If float_dtype is set to float16, the data output is float32 (from a layer # norm) and pool output should be float16. self.assertAllEqual(tf.float32, data.dtype) self.assertAllEqual(tf.float16, pooled.dtype)
def test_v2_network_creation(self): hidden_size = 32 sequence_length = 21 # Create a small BertEncoder for testing. test_network = bert_encoder.BertEncoder(vocab_size=100, hidden_size=hidden_size, num_attention_heads=2, num_layers=3, dict_outputs=True) # Create the inputs (note that the first dimension is implicit). word_ids = tf.keras.Input(shape=(sequence_length, ), dtype=tf.int32) mask = tf.keras.Input(shape=(sequence_length, ), dtype=tf.int32) type_ids = tf.keras.Input(shape=(sequence_length, ), dtype=tf.int32) dict_outputs = test_network([word_ids, mask, type_ids]) data = dict_outputs["sequence_output"] pooled = dict_outputs["pooled_output"] self.assertIsInstance(test_network.transformer_layers, list) self.assertLen(test_network.transformer_layers, 3) self.assertIsInstance(test_network.pooler_layer, tf.keras.layers.Dense) expected_data_shape = [None, sequence_length, hidden_size] expected_pooled_shape = [None, hidden_size] self.assertAllEqual(expected_data_shape, data.shape.as_list()) self.assertAllEqual(expected_pooled_shape, pooled.shape.as_list()) # The default output dtype is float32. self.assertAllEqual(tf.float32, data.dtype) self.assertAllEqual(tf.float32, pooled.dtype)
def test_serialize_deserialize(self): # Create a network object that sets all of its config options. kwargs = dict(vocab_size=100, hidden_size=32, num_layers=3, num_attention_heads=2, max_sequence_length=21, type_vocab_size=12, inner_dim=1223, inner_activation="relu", output_dropout=0.05, attention_dropout=0.22, initializer="glorot_uniform", output_range=-1, embedding_width=16, embedding_layer=None, norm_first=False) network = bert_encoder.BertEncoder(**kwargs) # Validate that the config can be forced to JSON. _ = network.to_json() # Tests model saving/loading. model_path = self.get_temp_dir() + "/model" network.save(model_path) _ = tf.keras.models.load_model(model_path)
def test_serialize_deserialize(self): tf.keras.mixed_precision.experimental.set_policy("mixed_float16") # Create a network object that sets all of its config options. kwargs = dict( vocab_size=100, hidden_size=32, num_layers=3, num_attention_heads=2, max_sequence_length=21, type_vocab_size=12, intermediate_size=1223, activation="relu", dropout_rate=0.05, attention_dropout_rate=0.22, initializer="glorot_uniform", return_all_encoder_outputs=False, output_range=-1, embedding_width=16) network = bert_encoder.BertEncoder(**kwargs) expected_config = dict(kwargs) expected_config["activation"] = tf.keras.activations.serialize( tf.keras.activations.get(expected_config["activation"])) expected_config["initializer"] = tf.keras.initializers.serialize( tf.keras.initializers.get(expected_config["initializer"])) self.assertEqual(network.get_config(), expected_config) # Create another network object from the first object's config. new_network = bert_encoder.BertEncoder.from_config(network.get_config()) # Validate that the config can be forced to JSON. _ = new_network.to_json() # If the serialization was successful, the new config should match the old. self.assertAllEqual(network.get_config(), new_network.get_config())
def test_weights_forward_compatible(self): batch_size = 3 hidden_size = 32 sequence_length = 21 vocab_size = 57 num_types = 7 kwargs = dict( vocab_size=vocab_size, hidden_size=hidden_size, num_attention_heads=2, num_layers=3, type_vocab_size=num_types, output_range=None) word_id_data = np.random.randint( vocab_size, size=(batch_size, sequence_length)) mask_data = np.random.randint(2, size=(batch_size, sequence_length)) type_id_data = np.random.randint( num_types, size=(batch_size, sequence_length)) data = dict( input_word_ids=word_id_data, input_mask=mask_data, input_type_ids=type_id_data) # Create small BertEncoders for testing. new_net = bert_encoder.BertEncoderV2(**kwargs) _ = new_net(data) kwargs["dict_outputs"] = True old_net = bert_encoder.BertEncoder(**kwargs) _ = old_net(data) new_net._embedding_layer.set_weights(old_net._embedding_layer.get_weights()) new_net._position_embedding_layer.set_weights( old_net._position_embedding_layer.get_weights()) new_net._type_embedding_layer.set_weights( old_net._type_embedding_layer.get_weights()) new_net._embedding_norm_layer.set_weights( old_net._embedding_norm_layer.get_weights()) # embedding_dropout has no weights. if hasattr(old_net, "_embedding_projection"): new_net._embedding_projection.set_weights( old_net._embedding_projection.get_weights()) # attention_mask_layer has no weights. new_net._pooler_layer.set_weights(old_net._pooler_layer.get_weights()) for otl, ntl in zip(old_net._transformer_layers, new_net._transformer_layers): ntl.set_weights(otl.get_weights()) def check_output_close(data, net1, net2): output1 = net1(data) output2 = net2(data) for key in output1: self.assertAllClose(output1[key], output2[key]) check_output_close(data, old_net, new_net)
def test_layer_invocation_with_external_logits(self): vocab_size = 100 sequence_length = 32 hidden_size = 64 num_predictions = 21 xformer_stack = bert_encoder.BertEncoder( vocab_size=vocab_size, num_layers=1, hidden_size=hidden_size, num_attention_heads=4, ) test_layer = self.create_layer(vocab_size=vocab_size, hidden_size=hidden_size, xformer_stack=xformer_stack, output='predictions') logit_layer = self.create_layer(vocab_size=vocab_size, hidden_size=hidden_size, xformer_stack=xformer_stack, output='logits') # Create a model from the masked LM layer. lm_input_tensor = tf.keras.Input(shape=(sequence_length, hidden_size)) masked_positions = tf.keras.Input(shape=(num_predictions, ), dtype=tf.int32) output = test_layer(lm_input_tensor, masked_positions) logit_output = logit_layer(lm_input_tensor, masked_positions) logit_output = tf.keras.layers.Activation( tf.nn.log_softmax)(logit_output) logit_layer.set_weights(test_layer.get_weights()) model = tf.keras.Model([lm_input_tensor, masked_positions], output) logits_model = tf.keras.Model(([lm_input_tensor, masked_positions]), logit_output) # Invoke the masked LM on some fake data to make sure there are no runtime # errors in the code. batch_size = 3 lm_input_data = 10 * np.random.random_sample( (batch_size, sequence_length, hidden_size)) masked_position_data = np.random.randint(sequence_length, size=(batch_size, num_predictions)) # ref_outputs = model.predict([lm_input_data, masked_position_data]) # outputs = logits_model.predict([lm_input_data, masked_position_data]) ref_outputs = model([lm_input_data, masked_position_data]) outputs = logits_model([lm_input_data, masked_position_data]) # Ensure that the tensor shapes are correct. expected_output_shape = (batch_size, num_predictions, vocab_size) self.assertEqual(expected_output_shape, ref_outputs.shape) self.assertEqual(expected_output_shape, outputs.shape) self.assertAllClose(ref_outputs, outputs)
def test_keras_model_checkpoint_forward_compatible(self): batch_size = 3 hidden_size = 32 sequence_length = 21 vocab_size = 57 num_types = 7 kwargs = dict( vocab_size=vocab_size, hidden_size=hidden_size, num_attention_heads=2, num_layers=3, type_vocab_size=num_types, output_range=None) word_id_data = np.random.randint( vocab_size, size=(batch_size, sequence_length)) mask_data = np.random.randint(2, size=(batch_size, sequence_length)) type_id_data = np.random.randint( num_types, size=(batch_size, sequence_length)) data = dict( input_word_ids=word_id_data, input_mask=mask_data, input_type_ids=type_id_data) kwargs["dict_outputs"] = True old_net = bert_encoder.BertEncoder(**kwargs) inputs = old_net.inputs outputs = old_net(inputs) old_model = tf.keras.Model(inputs=inputs, outputs=outputs) old_model_outputs = old_model(data) ckpt = tf.train.Checkpoint(net=old_model) path = ckpt.save(self.get_temp_dir()) del kwargs["dict_outputs"] new_net = bert_encoder.BertEncoderV2(**kwargs) inputs = new_net.inputs outputs = new_net(inputs) new_model = tf.keras.Model(inputs=inputs, outputs=outputs) new_ckpt = tf.train.Checkpoint(net=new_model) status = new_ckpt.restore(path) status.assert_existing_objects_matched() new_model_outputs = new_model(data) self.assertAllEqual(old_model_outputs.keys(), new_model_outputs.keys()) for key in old_model_outputs: self.assertAllClose(old_model_outputs[key], new_model_outputs[key])
def create_layer(self, vocab_size, hidden_size, output='predictions', xformer_stack=None): # First, create a transformer stack that we can use to get the LM's # vocabulary weight. if xformer_stack is None: xformer_stack = bert_encoder.BertEncoder( vocab_size=vocab_size, num_layers=1, hidden_size=hidden_size, num_attention_heads=4, ) # Create a maskedLM from the transformer stack. test_layer = masked_lm.MaskedLM( embedding_table=xformer_stack.get_embedding_table(), output=output) return test_layer
def test_serialize_deserialize(self): # Create a network object that sets all of its config options. kwargs = dict(vocab_size=100, hidden_size=32, num_layers=3, num_attention_heads=2, max_sequence_length=21, type_vocab_size=12, intermediate_size=1223, activation="relu", dropout_rate=0.05, attention_dropout_rate=0.22, initializer="glorot_uniform", return_all_encoder_outputs=False, output_range=-1, embedding_width=16, dict_outputs=True, embedding_layer=None, norm_first=False) network = bert_encoder.BertEncoder(**kwargs) expected_config = dict(kwargs) expected_config["activation"] = tf.keras.activations.serialize( tf.keras.activations.get(expected_config["activation"])) expected_config["initializer"] = tf.keras.initializers.serialize( tf.keras.initializers.get(expected_config["initializer"])) self.assertEqual(network.get_config(), expected_config) # Create another network object from the first object's config. new_network = bert_encoder.BertEncoder.from_config( network.get_config()) # Validate that the config can be forced to JSON. _ = network.to_json() # If the serialization was successful, the new config should match the old. self.assertAllEqual(network.get_config(), new_network.get_config()) # Tests model saving/loading. model_path = self.get_temp_dir() + "/model" network.save(model_path) _ = tf.keras.models.load_model(model_path)