![]() | ![]() | ![]() | ![]() | ![]() |
Neste exemplo, trabalharemos por meio do ajuste fino de um modelo de BERT usando o pacote tensorflow-models PIP.
O modelo BERT pré-treinado este tutorial baseia-se também está disponível no TensorFlow Hub , para ver como usá-lo se referir ao Apêndice Hub
Configurar
Instale o pacote TensorFlow Model Garden pip
-
tf-models-official
é o estábulo pacote Modelo Garden. Note-se que ele pode não incluir as últimas alterações ocorridas nostensorflow_models
repositório no GitHub. Para incluir as últimas alterações, você pode instalartf-models-nightly
, que é o pacote Modelo Garden noturno criados diariamente automaticamente. - pip instalará todos os modelos e dependências automaticamente.
pip install -q -U tensorflow-text
pip install -q tf-models-official==2.4.0
Importações
import os
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
import tensorflow_hub as hub
import tensorflow_datasets as tfds
tfds.disable_progress_bar()
from official.modeling import tf_utils
from official import nlp
from official.nlp import bert
# Load the required submodules
import official.nlp.optimization
import official.nlp.bert.bert_models
import official.nlp.bert.configs
import official.nlp.bert.run_classifier
import official.nlp.bert.tokenization
import official.nlp.data.classifier_data_lib
import official.nlp.modeling.losses
import official.nlp.modeling.models
import official.nlp.modeling.networks
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/pkg_resources/__init__.py:119: PkgResourcesDeprecationWarning: 0.18ubuntu0.18.04.1 is an invalid version and will not be supported in a future release PkgResourcesDeprecationWarning,
Recursos
Este diretório contém a configuração, vocabulário e um ponto de verificação pré-treinado usado neste tutorial:
gs_folder_bert = "gs://cloud-tpu-checkpoints/bert/v3/uncased_L-12_H-768_A-12"
tf.io.gfile.listdir(gs_folder_bert)
['bert_config.json', 'bert_model.ckpt.data-00000-of-00001', 'bert_model.ckpt.index', 'vocab.txt']
Você pode obter um codificador BERT pré-treinados desde TensorFlow Hub :
hub_url_bert = "https://tfhub.dev/tensorflow/bert_en_uncased_L-12_H-768_A-12/3"
Os dados
Para este exemplo, utilizamos o conjunto de dados COLA MRPC de TFDS .
Este conjunto de dados não está configurado de forma que possa ser alimentado diretamente no modelo BERT, portanto, esta seção também trata do pré-processamento necessário.
Obtenha o conjunto de dados do TensorFlow Datasets
O Microsoft Research Paraphrase Corpus (Dolan & Brockett, 2005) é um corpus de pares de frases extraído automaticamente de fontes de notícias online, com anotações humanas para determinar se as frases do par são semanticamente equivalentes.
- Número de etiquetas: 2.
- Tamanho do conjunto de dados de treinamento: 3668.
- Tamanho do conjunto de dados de avaliação: 408.
- Comprimento máximo da sequência do conjunto de dados de treinamento e avaliação: 128.
glue, info = tfds.load('glue/mrpc', with_info=True,
# It's small, load the whole dataset
batch_size=-1)
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow_datasets/core/dataset_builder.py:622: get_single_element (from tensorflow.python.data.experimental.ops.get_single_element) is deprecated and will be removed in a future version. Instructions for updating: Use `tf.data.Dataset.get_single_element()`. WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow_datasets/core/dataset_builder.py:622: get_single_element (from tensorflow.python.data.experimental.ops.get_single_element) is deprecated and will be removed in a future version. Instructions for updating: Use `tf.data.Dataset.get_single_element()`.
list(glue.keys())
['train', 'validation', 'test']
O info
objeto descreve o conjunto de dados e suas características:
info.features
FeaturesDict({ 'idx': tf.int32, 'label': ClassLabel(shape=(), dtype=tf.int64, num_classes=2), 'sentence1': Text(shape=(), dtype=tf.string), 'sentence2': Text(shape=(), dtype=tf.string), })
As duas classes são:
info.features['label'].names
['not_equivalent', 'equivalent']
Aqui está um exemplo do conjunto de treinamento:
glue_train = glue['train']
for key, value in glue_train.items():
print(f"{key:9s}: {value[0].numpy()}")
idx : 1680 label : 0 sentence1: b'The identical rovers will act as robotic geologists , searching for evidence of past water .' sentence2: b'The rovers act as robotic geologists , moving on six wheels .'
O tokenizer BERT
Para ajustar um modelo pré-treinado, você precisa ter certeza de que está usando exatamente a mesma tokenização, vocabulário e mapeamento de índice que usou durante o treinamento.
O tokenizer BERT usado neste tutorial foi escrito em Python puro (não é construído a partir de operações do TensorFlow). Então você não pode simplesmente ligá-lo em seu modelo como um keras.layer
como você pode com preprocessing.TextVectorization
.
O código a seguir reconstrói o tokenizer que foi usado pelo modelo básico:
# Set up tokenizer to generate Tensorflow dataset
tokenizer = bert.tokenization.FullTokenizer(
vocab_file=os.path.join(gs_folder_bert, "vocab.txt"),
do_lower_case=True)
print("Vocab size:", len(tokenizer.vocab))
Vocab size: 30522
Tokenizar uma frase:
tokens = tokenizer.tokenize("Hello TensorFlow!")
print(tokens)
ids = tokenizer.convert_tokens_to_ids(tokens)
print(ids)
['hello', 'tensor', '##flow', '!'] [7592, 23435, 12314, 999]
Pré-processar os dados
A seção pré-processou manualmente o conjunto de dados no formato esperado pelo modelo.
Este conjunto de dados é pequeno, então o pré-processamento pode ser feito de forma rápida e fácil na memória. Para conjuntos de dados maiores do tf_models
biblioteca inclui algumas ferramentas para pré-processamento e re-serialização de um conjunto de dados. Veja Apêndice: Re-codificando um grande conjunto de dados para obter detalhes.
Codifique as sentenças
O modelo espera que suas duas sentenças de entrada sejam concatenadas. Esta entrada é esperado para começar com [CLS]
"Este é um problema de classificação" forma, e cada frase deve terminar com um [SEP]
"Separator" token:
tokenizer.convert_tokens_to_ids(['[CLS]', '[SEP]'])
[101, 102]
Comece por codificação de todas as frases, enquanto acrescentando um [SEP]
símbolo, e embalando-os em Ragged-tensores:
def encode_sentence(s):
tokens = list(tokenizer.tokenize(s.numpy()))
tokens.append('[SEP]')
return tokenizer.convert_tokens_to_ids(tokens)
sentence1 = tf.ragged.constant([
encode_sentence(s) for s in glue_train["sentence1"]])
sentence2 = tf.ragged.constant([
encode_sentence(s) for s in glue_train["sentence2"]])
print("Sentence1 shape:", sentence1.shape.as_list())
print("Sentence2 shape:", sentence2.shape.as_list())
Sentence1 shape: [3668, None] Sentence2 shape: [3668, None]
Agora preceder um [CLS]
símbolo, e concatenar os tensores ásperas de modo a formar um único input_word_ids
tensor para cada exemplo. RaggedTensor.to_tensor()
zero de almofadas para a sequência mais longa.
cls = [tokenizer.convert_tokens_to_ids(['[CLS]'])]*sentence1.shape[0]
input_word_ids = tf.concat([cls, sentence1, sentence2], axis=-1)
_ = plt.pcolormesh(input_word_ids.to_tensor())
Máscara e tipo de entrada
O modelo espera duas entradas adicionais:
- A máscara de entrada
- O tipo de entrada
A máscara permite que o modelo diferencie claramente entre o conteúdo e o preenchimento. A máscara tem a mesma forma que os input_word_ids
, e contém um 1
em qualquer lugar as input_word_ids
não é acolchoar.
input_mask = tf.ones_like(input_word_ids).to_tensor()
plt.pcolormesh(input_mask)
<matplotlib.collections.QuadMesh at 0x7fa22c0ecc50>
O "input type" também tem a mesma forma, mas no interior da região não acolchoada, contém um 0
ou um 1
, indicando que a frase token é uma parte de.
type_cls = tf.zeros_like(cls)
type_s1 = tf.zeros_like(sentence1)
type_s2 = tf.ones_like(sentence2)
input_type_ids = tf.concat([type_cls, type_s1, type_s2], axis=-1).to_tensor()
plt.pcolormesh(input_type_ids)
<matplotlib.collections.QuadMesh at 0x7fa1cc682490>
Junte tudo
Recolhe-se o código de texto de análise acima em uma única função, e aplicá-lo para cada divisão da glue/mrpc
conjunto de dados.
def encode_sentence(s, tokenizer):
tokens = list(tokenizer.tokenize(s))
tokens.append('[SEP]')
return tokenizer.convert_tokens_to_ids(tokens)
def bert_encode(glue_dict, tokenizer):
num_examples = len(glue_dict["sentence1"])
sentence1 = tf.ragged.constant([
encode_sentence(s, tokenizer)
for s in np.array(glue_dict["sentence1"])])
sentence2 = tf.ragged.constant([
encode_sentence(s, tokenizer)
for s in np.array(glue_dict["sentence2"])])
cls = [tokenizer.convert_tokens_to_ids(['[CLS]'])]*sentence1.shape[0]
input_word_ids = tf.concat([cls, sentence1, sentence2], axis=-1)
input_mask = tf.ones_like(input_word_ids).to_tensor()
type_cls = tf.zeros_like(cls)
type_s1 = tf.zeros_like(sentence1)
type_s2 = tf.ones_like(sentence2)
input_type_ids = tf.concat(
[type_cls, type_s1, type_s2], axis=-1).to_tensor()
inputs = {
'input_word_ids': input_word_ids.to_tensor(),
'input_mask': input_mask,
'input_type_ids': input_type_ids}
return inputs
glue_train = bert_encode(glue['train'], tokenizer)
glue_train_labels = glue['train']['label']
glue_validation = bert_encode(glue['validation'], tokenizer)
glue_validation_labels = glue['validation']['label']
glue_test = bert_encode(glue['test'], tokenizer)
glue_test_labels = glue['test']['label']
Cada subconjunto dos dados foi convertido em um dicionário de recursos e um conjunto de rótulos. Cada recurso no dicionário de entrada tem a mesma forma e o número de rótulos deve corresponder a:
for key, value in glue_train.items():
print(f'{key:15s} shape: {value.shape}')
print(f'glue_train_labels shape: {glue_train_labels.shape}')
input_word_ids shape: (3668, 103) input_mask shape: (3668, 103) input_type_ids shape: (3668, 103) glue_train_labels shape: (3668,)
O modelo
Construir o modelo
A primeira etapa é baixar a configuração do modelo pré-treinado.
import json
bert_config_file = os.path.join(gs_folder_bert, "bert_config.json")
config_dict = json.loads(tf.io.gfile.GFile(bert_config_file).read())
bert_config = bert.configs.BertConfig.from_dict(config_dict)
config_dict
{'attention_probs_dropout_prob': 0.1, 'hidden_act': 'gelu', 'hidden_dropout_prob': 0.1, 'hidden_size': 768, 'initializer_range': 0.02, 'intermediate_size': 3072, 'max_position_embeddings': 512, 'num_attention_heads': 12, 'num_hidden_layers': 12, 'type_vocab_size': 2, 'vocab_size': 30522}
A config
define o núcleo BERT modelo, que é um modelo para prever Keras as saídas de num_classes
das entradas com comprimento máximo sequência max_seq_length
.
Esta função retorna o codificador e o classificador.
bert_classifier, bert_encoder = bert.bert_models.classifier_model(
bert_config, num_labels=2)
O classificador tem três entradas e uma saída:
tf.keras.utils.plot_model(bert_classifier, show_shapes=True, dpi=48)
Execute-o em um lote de teste de 10 exemplos de dados do conjunto de treinamento. A saída são os logits para as duas classes:
glue_batch = {key: val[:10] for key, val in glue_train.items()}
bert_classifier(
glue_batch, training=True
).numpy()
array([[ 0.10071337, 0.05758326], [ 0.05382514, 0.30056837], [ 0.00795104, 0.1443476 ], [ 0.03538848, -0.04541291], [ 0.0905486 , 0.3010756 ], [-0.09503749, 0.26234314], [-0.00378452, 0.19791688], [-0.09037939, 0.2433937 ], [-0.03041902, 0.07568075], [ 0.30516896, 0.08384045]], dtype=float32)
O TransformerEncoder
no centro do classificador acima é o bert_encoder
.
Inspecionando o codificador, vemos a sua pilha de Transformer
camadas ligado a esses mesmos três entradas:
tf.keras.utils.plot_model(bert_encoder, show_shapes=True, dpi=48)
Restaura os pesos do codificador
Quando construído, o codificador é inicializado aleatoriamente. Restaure os pesos do codificador do ponto de verificação:
checkpoint = tf.train.Checkpoint(encoder=bert_encoder)
checkpoint.read(
os.path.join(gs_folder_bert, 'bert_model.ckpt')).assert_consumed()
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7fa18848bb50>
Configure o otimizador
BERT adota o otimizador de Adam com a decadência de peso (aka " AdamW "). Ele também emprega uma programação de taxa de aprendizagem que primeiro aquece de 0 e depois diminui para 0.
# Set up epochs and steps
epochs = 3
batch_size = 32
eval_batch_size = 32
train_data_size = len(glue_train_labels)
steps_per_epoch = int(train_data_size / batch_size)
num_train_steps = steps_per_epoch * epochs
warmup_steps = int(epochs * train_data_size * 0.1 / batch_size)
# creates an optimizer with learning rate schedule
optimizer = nlp.optimization.create_optimizer(
2e-5, num_train_steps=num_train_steps, num_warmup_steps=warmup_steps)
Isso retorna um AdamWeightDecay
otimizador com o conjunto cronograma taxa de aprendizagem:
type(optimizer)
official.nlp.optimization.AdamWeightDecay
Para ver um exemplo de como personalizar o otimizador e da agenda, consulte a agenda apêndice Optimizer .
Treine o modelo
A métrica é a precisão e usamos entropia cruzada categórica esparsa como perda.
metrics = [tf.keras.metrics.SparseCategoricalAccuracy('accuracy', dtype=tf.float32)]
loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
bert_classifier.compile(
optimizer=optimizer,
loss=loss,
metrics=metrics)
bert_classifier.fit(
glue_train, glue_train_labels,
validation_data=(glue_validation, glue_validation_labels),
batch_size=32,
epochs=epochs)
Epoch 1/3 115/115 [==============================] - 37s 220ms/step - loss: 0.5972 - accuracy: 0.7034 - val_loss: 0.4941 - val_accuracy: 0.7794 Epoch 2/3 115/115 [==============================] - 24s 211ms/step - loss: 0.4228 - accuracy: 0.8171 - val_loss: 0.4503 - val_accuracy: 0.8137 Epoch 3/3 115/115 [==============================] - 24s 211ms/step - loss: 0.2852 - accuracy: 0.8956 - val_loss: 0.4061 - val_accuracy: 0.8162 <keras.callbacks.History at 0x7fa1884d0b50>
Agora execute o modelo ajustado em um exemplo personalizado para ver se funciona.
Comece codificando alguns pares de frases:
my_examples = bert_encode(
glue_dict = {
'sentence1':[
'The rain in Spain falls mainly on the plain.',
'Look I fine tuned BERT.'],
'sentence2':[
'It mostly rains on the flat lands of Spain.',
'Is it working? This does not match.']
},
tokenizer=tokenizer)
O modelo deve reportar classe 1
"jogo" para o primeiro exemplo e classe 0
"no-match" para a segunda:
result = bert_classifier(my_examples, training=False)
result = tf.argmax(result).numpy()
result
array([1, 0])
np.array(info.features['label'].names)[result]
array(['equivalent', 'not_equivalent'], dtype='<U14')
Salve o modelo
Muitas vezes, o objetivo do treinamento de um modelo é usá-lo para alguma coisa, então exportar o modelo e, em seguida, restaurá-lo para ter certeza de que ele funciona.
export_dir='./saved_model'
tf.saved_model.save(bert_classifier, export_dir=export_dir)
2021-11-12 13:12:55.273917: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them. WARNING:absl:Found untraced functions such as self_attention_layer_call_fn, self_attention_layer_call_and_return_conditional_losses, dropout_layer_call_fn, dropout_layer_call_and_return_conditional_losses, self_attention_layer_norm_layer_call_fn while saving (showing 5 of 900). These functions will not be directly callable after loading. INFO:tensorflow:Assets written to: ./saved_model/assets INFO:tensorflow:Assets written to: ./saved_model/assets
reloaded = tf.saved_model.load(export_dir)
reloaded_result = reloaded([my_examples['input_word_ids'],
my_examples['input_mask'],
my_examples['input_type_ids']], training=False)
original_result = bert_classifier(my_examples, training=False)
# The results are (nearly) identical:
print(original_result.numpy())
print()
print(reloaded_result.numpy())
[[-1.0493996 1.3163755 ] [ 0.674296 -0.87380654]] [[-1.0493993 1.3163751] [ 0.6742962 -0.873807 ]]
Apêndice
Recodificando um grande conjunto de dados
Neste tutorial, você recodificou o conjunto de dados na memória, para maior clareza.
Isto só foi possível por causa glue/mrpc
é um conjunto de dados muito pequeno. Para lidar com conjuntos de dados maiores tf_models
biblioteca inclui algumas ferramentas para o processamento e re-codificação de um conjunto de dados para treinamento eficiente.
A primeira etapa é descrever quais recursos do conjunto de dados devem ser transformados:
processor = nlp.data.classifier_data_lib.TfdsProcessor(
tfds_params="dataset=glue/mrpc,text_key=sentence1,text_b_key=sentence2",
process_text_fn=bert.tokenization.convert_to_unicode)
Em seguida, aplique a transformação para gerar novos arquivos TFRecord.
# Set up output of training and evaluation Tensorflow dataset
train_data_output_path="./mrpc_train.tf_record"
eval_data_output_path="./mrpc_eval.tf_record"
max_seq_length = 128
batch_size = 32
eval_batch_size = 32
# Generate and save training data into a tf record file
input_meta_data = (
nlp.data.classifier_data_lib.generate_tf_record_from_data_file(
processor=processor,
data_dir=None, # It is `None` because data is from tfds, not local dir.
tokenizer=tokenizer,
train_data_output_path=train_data_output_path,
eval_data_output_path=eval_data_output_path,
max_seq_length=max_seq_length))
Finalmente criar tf.data
dutos de entrada desses arquivos TFRecord:
training_dataset = bert.run_classifier.get_dataset_fn(
train_data_output_path,
max_seq_length,
batch_size,
is_training=True)()
evaluation_dataset = bert.run_classifier.get_dataset_fn(
eval_data_output_path,
max_seq_length,
eval_batch_size,
is_training=False)()
O resultando tf.data.Datasets
retorno (features, labels)
pares, como esperado por keras.Model.fit
:
training_dataset.element_spec
({'input_word_ids': TensorSpec(shape=(32, 128), dtype=tf.int32, name=None), 'input_mask': TensorSpec(shape=(32, 128), dtype=tf.int32, name=None), 'input_type_ids': TensorSpec(shape=(32, 128), dtype=tf.int32, name=None)}, TensorSpec(shape=(32,), dtype=tf.int32, name=None))
Crie tf.data.Dataset para treinamento e avaliação
Se você precisar modificar o carregamento de dados, aqui está um código para você começar:
def create_classifier_dataset(file_path, seq_length, batch_size, is_training):
"""Creates input dataset from (tf)records files for train/eval."""
dataset = tf.data.TFRecordDataset(file_path)
if is_training:
dataset = dataset.shuffle(100)
dataset = dataset.repeat()
def decode_record(record):
name_to_features = {
'input_ids': tf.io.FixedLenFeature([seq_length], tf.int64),
'input_mask': tf.io.FixedLenFeature([seq_length], tf.int64),
'segment_ids': tf.io.FixedLenFeature([seq_length], tf.int64),
'label_ids': tf.io.FixedLenFeature([], tf.int64),
}
return tf.io.parse_single_example(record, name_to_features)
def _select_data_from_record(record):
x = {
'input_word_ids': record['input_ids'],
'input_mask': record['input_mask'],
'input_type_ids': record['segment_ids']
}
y = record['label_ids']
return (x, y)
dataset = dataset.map(decode_record,
num_parallel_calls=tf.data.AUTOTUNE)
dataset = dataset.map(
_select_data_from_record,
num_parallel_calls=tf.data.AUTOTUNE)
dataset = dataset.batch(batch_size, drop_remainder=is_training)
dataset = dataset.prefetch(tf.data.AUTOTUNE)
return dataset
# Set up batch sizes
batch_size = 32
eval_batch_size = 32
# Return Tensorflow dataset
training_dataset = create_classifier_dataset(
train_data_output_path,
input_meta_data['max_seq_length'],
batch_size,
is_training=True)
evaluation_dataset = create_classifier_dataset(
eval_data_output_path,
input_meta_data['max_seq_length'],
eval_batch_size,
is_training=False)
training_dataset.element_spec
({'input_word_ids': TensorSpec(shape=(32, 128), dtype=tf.int64, name=None), 'input_mask': TensorSpec(shape=(32, 128), dtype=tf.int64, name=None), 'input_type_ids': TensorSpec(shape=(32, 128), dtype=tf.int64, name=None)}, TensorSpec(shape=(32,), dtype=tf.int64, name=None))
TFModels BERT no TFHub
Você pode obter o modelo BERT da prateleira de TFHub . Não seria difícil adicionar uma cabeça de classificação no topo desta hub.KerasLayer
# Note: 350MB download.
import tensorflow_hub as hub
hub_model_name = "bert_en_uncased_L-12_H-768_A-12"
hub_encoder = hub.KerasLayer(f"https://tfhub.dev/tensorflow/{hub_model_name}/3",
trainable=True)
print(f"The Hub encoder has {len(hub_encoder.trainable_variables)} trainable variables")
The Hub encoder has 199 trainable variables
Teste-o em um lote de dados:
result = hub_encoder(
inputs=dict(
input_word_ids=glue_train['input_word_ids'][:10],
input_mask=glue_train['input_mask'][:10],
input_type_ids=glue_train['input_type_ids'][:10],),
training=False,
)
print("Pooled output shape:", result['pooled_output'].shape)
print("Sequence output shape:", result['sequence_output'].shape)
Pooled output shape: (10, 768) Sequence output shape: (10, 103, 768)
Nesse ponto, seria simples adicionar você mesmo um cabeçalho de classificação.
O bert_models.classifier_model
função também pode construir um classificador para o codificador de TensorFlow Hub:
hub_classifier = nlp.modeling.models.BertClassifier(
bert_encoder,
num_classes=2,
dropout_rate=0.1,
initializer=tf.keras.initializers.TruncatedNormal(
stddev=0.02))
A única desvantagem de carregar este modelo do TFHub é que a estrutura das camadas keras internas não é restaurada. Portanto, é mais difícil inspecionar ou modificar o modelo. O BertEncoder
modelo é agora uma camada única:
tf.keras.utils.plot_model(hub_classifier, show_shapes=True, dpi=64)
try:
tf.keras.utils.plot_model(hub_encoder, show_shapes=True, dpi=64)
assert False
except Exception as e:
print(f"{type(e).__name__}: {e}")
AttributeError: 'KerasLayer' object has no attribute 'layers'
Construção de modelo de baixo nível
Se você precisa de um maior controle sobre a construção do modelo é importante notar que o classifier_model
função usada anteriormente é realmente apenas um invólucro fino sobre os nlp.modeling.networks.BertEncoder
e nlp.modeling.models.BertClassifier
classes. Lembre-se de que, se você começar a modificar a arquitetura, pode não ser correto ou possível recarregar o ponto de verificação pré-treinado, portanto, você precisará treinar do zero.
Crie o codificador:
bert_encoder_config = config_dict.copy()
# You need to rename a few fields to make this work:
bert_encoder_config['attention_dropout_rate'] = bert_encoder_config.pop('attention_probs_dropout_prob')
bert_encoder_config['activation'] = tf_utils.get_activation(bert_encoder_config.pop('hidden_act'))
bert_encoder_config['dropout_rate'] = bert_encoder_config.pop('hidden_dropout_prob')
bert_encoder_config['initializer'] = tf.keras.initializers.TruncatedNormal(
stddev=bert_encoder_config.pop('initializer_range'))
bert_encoder_config['max_sequence_length'] = bert_encoder_config.pop('max_position_embeddings')
bert_encoder_config['num_layers'] = bert_encoder_config.pop('num_hidden_layers')
bert_encoder_config
{'hidden_size': 768, 'intermediate_size': 3072, 'num_attention_heads': 12, 'type_vocab_size': 2, 'vocab_size': 30522, 'attention_dropout_rate': 0.1, 'activation': <function official.modeling.activations.gelu.gelu(x)>, 'dropout_rate': 0.1, 'initializer': <keras.initializers.initializers_v2.TruncatedNormal at 0x7f9d1011da50>, 'max_sequence_length': 512, 'num_layers': 12}
manual_encoder = nlp.modeling.networks.BertEncoder(**bert_encoder_config)
Restaure os pesos:
checkpoint = tf.train.Checkpoint(encoder=manual_encoder)
checkpoint.read(
os.path.join(gs_folder_bert, 'bert_model.ckpt')).assert_consumed()
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7f9d10142d50>
Faça um teste:
result = manual_encoder(my_examples, training=True)
print("Sequence output shape:", result[0].shape)
print("Pooled output shape:", result[1].shape)
Sequence output shape: (2, 23, 768) Pooled output shape: (2, 768)
Envolva-o em um classificador:
manual_classifier = nlp.modeling.models.BertClassifier(
bert_encoder,
num_classes=2,
dropout_rate=bert_encoder_config['dropout_rate'],
initializer=bert_encoder_config['initializer'])
manual_classifier(my_examples, training=True).numpy()
array([[-0.23401603, -0.3458405 ], [ 0.2552695 , -0.28906718]], dtype=float32)
Otimizadores e programações
O otimizador usados para treinar o modelo foi criada usando o nlp.optimization.create_optimizer
função:
optimizer = nlp.optimization.create_optimizer(
2e-5, num_train_steps=num_train_steps, num_warmup_steps=warmup_steps)
Esse wrapper de alto nível configura as programações de taxa de aprendizagem e o otimizador.
O cronograma de taxa de aprendizado básico usado aqui é uma queda linear a zero durante a execução do treinamento:
epochs = 3
batch_size = 32
eval_batch_size = 32
train_data_size = len(glue_train_labels)
steps_per_epoch = int(train_data_size / batch_size)
num_train_steps = steps_per_epoch * epochs
decay_schedule = tf.keras.optimizers.schedules.PolynomialDecay(
initial_learning_rate=2e-5,
decay_steps=num_train_steps,
end_learning_rate=0)
plt.plot([decay_schedule(n) for n in range(num_train_steps)])
[<matplotlib.lines.Line2D at 0x7f9d11235d90>]
Este, por sua vez, é enrolada num WarmUp
programação que aumenta linearmente a taxa de aprendizagem para o valor alvo em relação ao primeiro 10% de formação:
warmup_steps = num_train_steps * 0.1
warmup_schedule = nlp.optimization.WarmUp(
initial_learning_rate=2e-5,
decay_schedule_fn=decay_schedule,
warmup_steps=warmup_steps)
# The warmup overshoots, because it warms up to the `initial_learning_rate`
# following the original implementation. You can set
# `initial_learning_rate=decay_schedule(warmup_steps)` if you don't like the
# overshoot.
plt.plot([warmup_schedule(n) for n in range(num_train_steps)])
[<matplotlib.lines.Line2D at 0x7f9d109551d0>]
Em seguida, criar o nlp.optimization.AdamWeightDecay
usando programação que, configurado para o modelo BERT:
optimizer = nlp.optimization.AdamWeightDecay(
learning_rate=warmup_schedule,
weight_decay_rate=0.01,
epsilon=1e-6,
exclude_from_weight_decay=['LayerNorm', 'layer_norm', 'bias'])