![]() | ![]() | ![]() | ![]() | ![]() |
이 예에서는 tensorflow-models PIP 패키지를 사용하여 BERT 모델을 미세 조정하는 작업을 수행합니다.
이 가이드의 기반이되는 사전 학습 된 BERT 모델은 TensorFlow Hub 에서도 사용할 수 있습니다. 사용 방법은 Hub 부록을 참조하세요.
설정
TensorFlow Model Garden pip 패키지 설치
-
tf-models-official
은 안정적인 모델 가든 패키지입니다.tensorflow_models
github repo의 최신 변경 사항이 포함되지 않을 수 있습니다. 최신 변경 사항을 포함하려면 매일 자동으로 생성되는 야간 Model Garden 패키지 인tf-models-nightly
설치할 수 있습니다. - pip는 모든 모델과 종속성을 자동으로 설치합니다.
pip install -q tf-models-official==2.3.0
WARNING: You are using pip version 20.2.3; however, version 20.2.4 is available. You should consider upgrading via the '/tmpfs/src/tf_docs_env/bin/python -m pip install --upgrade pip' command.
수입품
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
자원
이 디렉토리에는이 가이드에서 사용되는 구성, 어휘 및 사전 학습 된 체크 포인트가 포함되어 있습니다.
gs_folder_bert = "gs://cloud-tpu-checkpoints/bert/keras_bert/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']
TensorFlow Hub 에서 사전 학습 된 BERT 인코더를 얻을 수 있습니다.
hub_url_bert = "https://tfhub.dev/tensorflow/bert_en_uncased_L-12_H-768_A-12/2"
자료
이 예에서는 TFDS의 GLUE MRPC 데이터 세트를 사용했습니다 .
이 데이터 세트는 BERT 모델에 직접 공급할 수 있도록 설정되지 않았으므로이 섹션에서는 필요한 전처리도 처리합니다.
TensorFlow 데이터 세트에서 데이터 세트 가져 오기
Microsoft Research Paraphrase Corpus (Dolan & Brockett, 2005)는 온라인 뉴스 소스에서 자동으로 추출 된 문장 쌍의 모음이며 쌍의 문장이 의미 상 동일한 지 여부에 대한 사람 주석이 포함되어 있습니다.
- 라벨 수 : 2.
- 훈련 데이터 세트의 크기 : 3668.
- 평가 데이터 세트의 크기 : 408.
- 훈련 및 평가 데이터 세트의 최대 시퀀스 길이 : 128.
glue, info = tfds.load('glue/mrpc', with_info=True,
# It's small, load the whole dataset
batch_size=-1)
Downloading and preparing dataset glue/mrpc/1.0.0 (download: 1.43 MiB, generated: Unknown size, total: 1.43 MiB) to /home/kbuilder/tensorflow_datasets/glue/mrpc/1.0.0... Shuffling and writing examples to /home/kbuilder/tensorflow_datasets/glue/mrpc/1.0.0.incompleteKZIBN9/glue-train.tfrecord Shuffling and writing examples to /home/kbuilder/tensorflow_datasets/glue/mrpc/1.0.0.incompleteKZIBN9/glue-validation.tfrecord Shuffling and writing examples to /home/kbuilder/tensorflow_datasets/glue/mrpc/1.0.0.incompleteKZIBN9/glue-test.tfrecord Dataset glue downloaded and prepared to /home/kbuilder/tensorflow_datasets/glue/mrpc/1.0.0. Subsequent calls will reuse this data.
list(glue.keys())
['test', 'train', 'validation']
info
객체는 데이터 세트와 그 기능을 설명합니다.
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), })
두 클래스는 다음과 같습니다.
info.features['label'].names
['not_equivalent', 'equivalent']
다음은 훈련 세트의 한 가지 예입니다.
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 .'
BERT 토크 나이저
사전 훈련 된 모델을 미세 조정하려면 훈련 중에 사용한 것과 정확히 동일한 토큰 화, 어휘 및 인덱스 매핑을 사용하고 있는지 확인해야합니다.
이 자습서에서 사용되는 BERT 토크 나이 저는 순수 Python으로 작성되었습니다 (TensorFlow 작업으로 빌드되지 않음). 따라서 preprocessing.TextVectorization
와 같이 keras.layer
로 모델에 연결할 수 없습니다.
다음 코드는 기본 모델에서 사용 된 토크 나이저를 다시 빌드합니다.
# 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
문장 토큰 화 :
tokens = tokenizer.tokenize("Hello TensorFlow!")
print(tokens)
ids = tokenizer.convert_tokens_to_ids(tokens)
print(ids)
['hello', 'tensor', '##flow', '!'] [7592, 23435, 12314, 999]
데이터 전처리
이 섹션에서는 모델에서 예상하는 형식으로 데이터 세트를 수동으로 사전 처리했습니다.
이 데이터 세트는 작기 때문에 메모리에서 빠르고 쉽게 전처리를 수행 할 수 있습니다. 더 큰 데이터 세트의 경우 tf_models
라이브러리에는 데이터 세트를 사전 처리하고 다시 직렬화하기위한 몇 가지 도구가 포함되어 있습니다. 자세한 내용은 부록 : 대규모 데이터 세트 다시 인코딩 을 참조하세요.
문장 인코딩
모델은 두 개의 입력 문장이 함께 연결될 것으로 예상합니다. 이 입력은 [CLS]
"This is a classification problem"토큰으로 시작해야하며 각 문장은 [SEP]
"Separator"토큰으로 끝나야합니다.
tokenizer.convert_tokens_to_ids(['[CLS]', '[SEP]'])
[101, 102]
[SEP]
토큰을 추가하면서 모든 문장을 인코딩하고 비정형 텐서로 압축하여 시작합니다.
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]
이제 [CLS]
토큰을 앞에 추가하고 비정형 텐서를 연결하여 각 예제에 대해 단일 input_word_ids
텐서를 형성합니다. RaggedTensor.to_tensor()
0은 가장 긴 시퀀스를 RaggedTensor.to_tensor()
.
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())
마스크 및 입력 유형
이 모델에는 두 가지 추가 입력이 필요합니다.
- 입력 마스크
- 입력 유형
마스크를 사용하면 모델이 콘텐츠와 패딩을 명확하게 구분할 수 있습니다. 마스크는 input_word_ids
와 모양이 input_word_ids
가 패딩이 아닌 곳에 1
포함합니다.
input_mask = tf.ones_like(input_word_ids).to_tensor()
plt.pcolormesh(input_mask)
<matplotlib.collections.QuadMesh at 0x7fad1c07ed30>
"입력 유형"도 같은 모양이지만 패딩되지 않은 영역 내부에는 토큰이 속한 문장을 나타내는 0
또는 1
이 포함됩니다.
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 0x7fad143c1710>
모두 모아
위의 텍스트 구문 분석 코드를 단일 함수로 수집하고 glue/mrpc
데이터 세트의 각 분할에 적용합니다.
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']
데이터의 각 하위 집합은 기능 사전 및 레이블 집합으로 변환되었습니다. 입력 사전의 각 기능은 모양이 같고 레이블 수가 일치해야합니다.
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,)
모델
모델 구축
첫 번째 단계는 사전 학습 된 모델의 구성을 다운로드하는 것입니다.
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}
config
은 최대 시퀀스 길이가 max_seq_length
입력에서 num_classes
의 출력을 예측하는 num_classes
모델 인 핵심 BERT 모델을 정의합니다.
이 함수는 인코더와 분류기를 모두 반환합니다.
bert_classifier, bert_encoder = bert.bert_models.classifier_model(
bert_config, num_labels=2)
분류기에는 3 개의 입력과 1 개의 출력이 있습니다.
tf.keras.utils.plot_model(bert_classifier, show_shapes=True, dpi=48)
학습 세트의 데이터 10 개 예제의 테스트 배치에서 실행합니다. 출력은 두 클래스에 대한 로짓입니다.
glue_batch = {key: val[:10] for key, val in glue_train.items()}
bert_classifier(
glue_batch, training=True
).numpy()
array([[ 0.08382261, 0.34465584], [ 0.02057236, 0.24053624], [ 0.04930754, 0.1117427 ], [ 0.17041089, 0.20810834], [ 0.21667874, 0.2840511 ], [ 0.02325345, 0.33799925], [-0.06198866, 0.13532838], [ 0.084592 , 0.20711854], [-0.04323687, 0.17096342], [ 0.23759182, 0.16801538]], dtype=float32)
TransformerEncoder
분류의 중앙에 위입니다 bert_encoder
.
인코더를 검사하면 동일한 3 개의 입력에 연결된 Transformer
레이어 스택을 볼 수 있습니다.
tf.keras.utils.plot_model(bert_encoder, show_shapes=True, dpi=48)
인코더 가중치 복원
빌드시 인코더는 무작위로 초기화됩니다. 체크 포인트에서 인코더의 가중치를 복원합니다.
checkpoint = tf.train.Checkpoint(model=bert_encoder)
checkpoint.restore(
os.path.join(gs_folder_bert, 'bert_model.ckpt')).assert_consumed()
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7fad4580ffd0>
최적화 프로그램 설정
BERT는 가중치 감소 ( " AdamW "라고도 함)가있는 Adam 최적화 프로그램을 채택합니다. 또한 먼저 0에서 워밍업 한 다음 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)
그러면 AdamWeightDecay
일정이 설정된 AdamWeightDecay
최적화 프로그램이 반환됩니다.
type(optimizer)
official.nlp.optimization.AdamWeightDecay
최적화 프로그램과 일정을 사용자 지정하는 방법의 예를 보려면 Optimizer 일정 부록을 참조하십시오.
모델 훈련
측정 항목은 정확성이며 우리는 희소 범주 형 교차 엔트로피를 손실로 사용합니다.
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 [==============================] - 26s 222ms/step - loss: 0.6151 - accuracy: 0.6611 - val_loss: 0.5462 - val_accuracy: 0.7451 Epoch 2/3 115/115 [==============================] - 24s 212ms/step - loss: 0.4447 - accuracy: 0.8010 - val_loss: 0.4150 - val_accuracy: 0.8309 Epoch 3/3 115/115 [==============================] - 24s 213ms/step - loss: 0.2830 - accuracy: 0.8964 - val_loss: 0.3697 - val_accuracy: 0.8480 <tensorflow.python.keras.callbacks.History at 0x7fad000ebda0>
이제 사용자 지정 예제에서 미세 조정 된 모델을 실행하여 작동하는지 확인합니다.
일부 문장 쌍을 인코딩하여 시작하십시오.
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)
모델은 첫 번째 예제에 대해 클래스 1
"일치"를보고하고 두 번째 예제에 대해 클래스 0
"불일치"를보고해야합니다.
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')
모델 저장
모델 학습의 목표는 종종 모델을 사용 하는 것이므로 모델을 내 보낸 다음 복원하여 작동하는지 확인합니다.
export_dir='./saved_model'
tf.saved_model.save(bert_classifier, export_dir=export_dir)
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Model.state_updates (from tensorflow.python.keras.engine.training) is deprecated and will be removed in a future version. Instructions for updating: This property should not be used in TensorFlow 2.0, as updates are applied automatically. Warning:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Model.state_updates (from tensorflow.python.keras.engine.training) is deprecated and will be removed in a future version. Instructions for updating: This property should not be used in TensorFlow 2.0, as updates are applied automatically. Warning:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Layer.updates (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version. Instructions for updating: This property should not be used in TensorFlow 2.0, as updates are applied automatically. Warning:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Layer.updates (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version. Instructions for updating: This property should not be used in TensorFlow 2.0, as updates are applied automatically. 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())
[[-0.95450354 1.1227685 ] [ 0.40344787 -0.58954155]] [[-0.95450354 1.1227684 ] [ 0.4034478 -0.5895414 ]]
부록
대규모 데이터 세트 다시 인코딩
이 가이드에서는 명확성을 위해 데이터 세트를 메모리에 다시 인코딩했습니다.
이는 glue/mrpc
가 매우 작은 데이터 세트이기 때문에 가능했습니다. 더 큰 데이터 세트를 처리하기 위해 tf_models
라이브러리에는 효율적인 학습을 위해 데이터 세트를 처리하고 다시 인코딩하는 몇 가지 도구가 포함되어 있습니다.
첫 번째 단계는 데이터 세트의 어떤 기능을 변환해야하는지 설명하는 것입니다.
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)
그런 다음 변환을 적용하여 새 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))
마지막으로 해당 TFRecord 파일에서 tf.data
입력 파이프 라인을 만듭니다.
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)()
결과 tf.data.Datasets
에서 예상 한대로 (features, labels)
쌍을 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))
학습 및 평가를위한 tf.data.Dataset 만들기
데이터 로딩을 수정해야하는 경우 시작하는 데 필요한 몇 가지 코드가 있습니다.
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.experimental.AUTOTUNE)
dataset = dataset.map(
_select_data_from_record,
num_parallel_calls=tf.data.experimental.AUTOTUNE)
dataset = dataset.batch(batch_size, drop_remainder=is_training)
dataset = dataset.prefetch(tf.data.experimental.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))
TFHub의 TFModels BERT
TFHub 에서 BERT 모델 을 선반에서 가져올 수 있습니다. 이 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}/2",
trainable=True)
print(f"The Hub encoder has {len(hub_encoder.trainable_variables)} trainable variables")
The Hub encoder has 199 trainable variables
데이터 배치에서 테스트 실행 :
result = hub_encoder(
inputs=[glue_train['input_word_ids'][:10],
glue_train['input_mask'][:10],
glue_train['input_type_ids'][:10],],
training=False,
)
print("Pooled output shape:", result[0].shape)
print("Sequence output shape:", result[1].shape)
Pooled output shape: (10, 768) Sequence output shape: (10, 103, 768)
이 시점에서 분류 헤드를 직접 추가하는 것은 간단합니다.
bert_models.classifier_model
함수는 TensorFlow Hub의 인코더에 분류기를 빌드 할 수도 있습니다.
hub_classifier, hub_encoder = bert.bert_models.classifier_model(
# Caution: Most of `bert_config` is ignored if you pass a hub url.
bert_config=bert_config, hub_module_url=hub_url_bert, num_labels=2)
TFHub에서이 모델을로드하는 한 가지 단점은 내부 keras 레이어의 구조가 복원되지 않는다는 것입니다. 따라서 모델을 검사하거나 수정하는 것이 더 어렵습니다. TransformerEncoder
모델은 이제 단일 계층입니다.
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'
저수준 모델 구축
모델 구성에 대한 더 많은 제어가 필요한 경우 이전에 사용 된 classifier_model
함수가 실제로 nlp.modeling.networks.TransformerEncoder
및 nlp.modeling.models.BertClassifier
클래스에 대한 얇은 래퍼라는 점에 주목할 가치가 있습니다. 아키텍처 수정을 시작하면 정확하지 않거나 사전 학습 된 체크 포인트를 다시로드하는 것이 가능하지 않을 수 있으므로 처음부터 다시 학습해야합니다.
인코더 빌드 :
transformer_config = config_dict.copy()
# You need to rename a few fields to make this work:
transformer_config['attention_dropout_rate'] = transformer_config.pop('attention_probs_dropout_prob')
transformer_config['activation'] = tf_utils.get_activation(transformer_config.pop('hidden_act'))
transformer_config['dropout_rate'] = transformer_config.pop('hidden_dropout_prob')
transformer_config['initializer'] = tf.keras.initializers.TruncatedNormal(
stddev=transformer_config.pop('initializer_range'))
transformer_config['max_sequence_length'] = transformer_config.pop('max_position_embeddings')
transformer_config['num_layers'] = transformer_config.pop('num_hidden_layers')
transformer_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': <tensorflow.python.keras.initializers.initializers_v2.TruncatedNormal at 0x7fac08046e10>, 'max_sequence_length': 512, 'num_layers': 12}
manual_encoder = nlp.modeling.networks.TransformerEncoder(**transformer_config)
가중치를 복원합니다.
checkpoint = tf.train.Checkpoint(model=manual_encoder)
checkpoint.restore(
os.path.join(gs_folder_bert, 'bert_model.ckpt')).assert_consumed()
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7fabefa596d8>
테스트 실행 :
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)
분류기로 감싸십시오.
manual_classifier = nlp.modeling.models.BertClassifier(
bert_encoder,
num_classes=2,
dropout_rate=transformer_config['dropout_rate'],
initializer=tf.keras.initializers.TruncatedNormal(
stddev=bert_config.initializer_range))
manual_classifier(my_examples, training=True).numpy()
array([[ 0.07863025, -0.02940944], [ 0.30274656, 0.27299827]], dtype=float32)
최적화 도구 및 일정
모델 학습에 사용 된 최적화 프로그램은 nlp.optimization.create_optimizer
함수를 사용하여 생성되었습니다.
optimizer = nlp.optimization.create_optimizer(
2e-5, num_train_steps=num_train_steps, num_warmup_steps=warmup_steps)
이 높은 수준의 래퍼는 학습률 일정과 최적화 프로그램을 설정합니다.
여기에 사용 된 기본 학습률 일정은 학습 실행 동안 0으로 선형 감소합니다.
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 0x7fabef5e69e8>]
이는 학습의 처음 10 %에 걸쳐 학습률을 목표 값으로 선형 적으로 증가시키는 WarmUp
일정에 래핑됩니다.
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 0x7fabef559630>]
그런 다음 BERT 모델에 대해 구성된 해당 일정을 사용하여 nlp.optimization.AdamWeightDecay
를 만듭니다.
optimizer = nlp.optimization.AdamWeightDecay(
learning_rate=warmup_schedule,
weight_decay_rate=0.01,
epsilon=1e-6,
exclude_from_weight_decay=['LayerNorm', 'layer_norm', 'bias'])