Посмотреть на TensorFlow.org | Запускаем в Google Colab | Посмотреть на GitHub | Скачать блокнот | См. Модель TF Hub |
BERT можно использовать для решения многих проблем при обработке естественного языка. Вы узнаете , как тонкая настройку BERT для многих задач из КЛЕЕВОГО теста :
КОЛА (Corpus Лингвистического Приемлемость): Является ли предложение грамматически правильно?
SST-2 (Stanford Настроение Treebank): Задача состоит в том, чтобы предсказать настроение данного предложения.
МНПК (Microsoft Research парафраз Corpus): Определить , является ли семантически эквивалентны пара предложений.
QQP (Quora Вопрос Pairs2): Определить , является ли семантически эквивалентны пара вопросов.
MNLI (многожанровая Natural Language Умозаключение): Учитывая Предпосылку предложение и гипотеза предложение, задача состоит в том, чтобы предсказать , влечет ли предпосылка гипотезы (следование), противоречит условию (противоречие), или ни (нейтральный).
QNLI (Вопрос-ответив Natural Language Умозаключение): Задача состоит в том, чтобы определить , содержит ли контекст предложение ответ на этот вопрос.
RTE (признавая Textual Воплощение): Определить , если предложение влечет за собой данную гипотезу или нет.
WNLI (Виноград Natural Language Умозаключение): Задача состоит в том, чтобы предсказать , если предложение с местоимением подставляется влекут за первоначальным предложением.
Это руководство содержит полный код для обучения этих моделей на TPU. Вы также можете запустить этот ноутбук на графическом процессоре, изменив одну строку (описано ниже).
В этом блокноте вы:
- Загрузите модель BERT из TensorFlow Hub
- Выберите одну из задач GLUE и загрузите набор данных
- Предварительно обработать текст
- Точная настройка BERT (примеры приведены для наборов данных с одним и несколькими предложениями)
- Сохраните обученную модель и используйте ее
Настраивать
Вы будете использовать отдельную модель для предварительной обработки текста, прежде чем использовать ее для точной настройки BERT. Эта модель зависит от tensorflow / текст , который будет установлен ниже.
pip install -q -U tensorflow-text
Вы будете использовать оптимизатор AdamW из tensorflow / моделей для тонкой настройки BERT, который будет установлен , а также.
pip install -q -U tf-models-official
pip install -U tfds-nightly
import os
import tensorflow as tf
import tensorflow_hub as hub
import tensorflow_datasets as tfds
import tensorflow_text as text # A dependency of the preprocessing model
import tensorflow_addons as tfa
from official.nlp import optimization
import numpy as np
tf.get_logger().setLevel('ERROR')
/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/requests/__init__.py:104: RequestsDependencyWarning: urllib3 (1.26.7) or chardet (2.3.0)/charset_normalizer (2.0.7) doesn't match a supported version! RequestsDependencyWarning)
Затем настройте TFHub для чтения контрольных точек непосредственно из сегментов облачного хранилища TFHub. Это рекомендуется только при запуске моделей TFHub на TPU.
Без этого параметра TFHub загрузит сжатый файл и извлечет контрольную точку локально. Попытка загрузить из этих локальных файлов завершится ошибкой со следующей ошибкой:
InvalidArgumentError: Unimplemented: File system scheme '[local]' not implemented
Это происходит потому , что ТПУ может читать только непосредственно из ведра Cloud Storage .
os.environ["TFHUB_MODEL_LOAD_FORMAT"]="UNCOMPRESSED"
Подключиться к работнику ТПУ
Следующий код подключается к рабочему процессору TPU и изменяет устройство по умолчанию TensorFlow на устройство ЦП на рабочем сервере TPU. Он также определяет стратегию распределения TPU, которую вы будете использовать для распределения обучения модели по 8 отдельным ядрам TPU, доступным для этого одного рабочего TPU. См TensorFlow в руководстве ТПУ для получения дополнительной информации.
import os
if os.environ['COLAB_TPU_ADDR']:
cluster_resolver = tf.distribute.cluster_resolver.TPUClusterResolver(tpu='')
tf.config.experimental_connect_to_cluster(cluster_resolver)
tf.tpu.experimental.initialize_tpu_system(cluster_resolver)
strategy = tf.distribute.TPUStrategy(cluster_resolver)
print('Using TPU')
elif tf.config.list_physical_devices('GPU'):
strategy = tf.distribute.MirroredStrategy()
print('Using GPU')
else:
raise ValueError('Running on CPU is not recommended.')
Using TPU
Загрузка моделей из TensorFlow Hub
Здесь вы можете выбрать, какую модель BERT загрузить из TensorFlow Hub и выполнить точную настройку. На выбор доступно несколько моделей BERT.
- БЕРТ-Base , бескорпусный и еще семь моделей с обученными весами , выпущенных оригинальными авторами BERT.
- Малый Berts имеет одинаковую общую архитектуру , но меньше и / или меньшие Трансформаторные блоки, которая позволяет исследовать компромисс между скоростью, размером и качеством.
- АЛЬБЕРТ : четыре различных размеров «A Lite BERT» , что уменьшает размер модели (но не время вычисления) путем обмена параметров между слоями.
- BERT Эксперты : восемь моделей , которые все имеют БЕРТ-базовую архитектуру , но предлагают выбор между различными предварительно обучением доменами, более тесно увязать с целевой задачей.
- Electra имеет ту же архитектуру, что и BERT (в трех разных размеров), но получает предварительно обучен как дискриминатор в подстроено , который напоминает Generative Состязательность Network (ГАН).
- БЕРТ с Talking Heads-Вниманием и Gated Джелом [ базы , большие ] имеет два улучшений в ядро архитектуры трансформатора.
Дополнительную информацию см. В документации к модели, указанной выше.
В этом руководстве вы начнете с BERT-базы. Вы можете использовать более крупные и более свежие модели для более высокой точности или более мелкие модели для более быстрого обучения. Чтобы изменить модель, вам нужно всего лишь переключить одну строку кода (как показано ниже). Все различия заключены в SavedModel, которую вы загрузите с TensorFlow Hub.
Выберите модель BERT для точной настройки
bert_model_name = 'bert_en_uncased_L-12_H-768_A-12'
map_name_to_handle = {
'bert_en_uncased_L-12_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_uncased_L-12_H-768_A-12/3',
'bert_en_uncased_L-24_H-1024_A-16':
'https://tfhub.dev/tensorflow/bert_en_uncased_L-24_H-1024_A-16/3',
'bert_en_wwm_uncased_L-24_H-1024_A-16':
'https://tfhub.dev/tensorflow/bert_en_wwm_uncased_L-24_H-1024_A-16/3',
'bert_en_cased_L-12_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_cased_L-12_H-768_A-12/3',
'bert_en_cased_L-24_H-1024_A-16':
'https://tfhub.dev/tensorflow/bert_en_cased_L-24_H-1024_A-16/3',
'bert_en_wwm_cased_L-24_H-1024_A-16':
'https://tfhub.dev/tensorflow/bert_en_wwm_cased_L-24_H-1024_A-16/3',
'bert_multi_cased_L-12_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_multi_cased_L-12_H-768_A-12/3',
'small_bert/bert_en_uncased_L-2_H-128_A-2':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-2_H-128_A-2/1',
'small_bert/bert_en_uncased_L-2_H-256_A-4':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-2_H-256_A-4/1',
'small_bert/bert_en_uncased_L-2_H-512_A-8':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-2_H-512_A-8/1',
'small_bert/bert_en_uncased_L-2_H-768_A-12':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-2_H-768_A-12/1',
'small_bert/bert_en_uncased_L-4_H-128_A-2':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-4_H-128_A-2/1',
'small_bert/bert_en_uncased_L-4_H-256_A-4':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-4_H-256_A-4/1',
'small_bert/bert_en_uncased_L-4_H-512_A-8':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-4_H-512_A-8/1',
'small_bert/bert_en_uncased_L-4_H-768_A-12':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-4_H-768_A-12/1',
'small_bert/bert_en_uncased_L-6_H-128_A-2':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-6_H-128_A-2/1',
'small_bert/bert_en_uncased_L-6_H-256_A-4':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-6_H-256_A-4/1',
'small_bert/bert_en_uncased_L-6_H-512_A-8':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-6_H-512_A-8/1',
'small_bert/bert_en_uncased_L-6_H-768_A-12':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-6_H-768_A-12/1',
'small_bert/bert_en_uncased_L-8_H-128_A-2':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-8_H-128_A-2/1',
'small_bert/bert_en_uncased_L-8_H-256_A-4':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-8_H-256_A-4/1',
'small_bert/bert_en_uncased_L-8_H-512_A-8':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-8_H-512_A-8/1',
'small_bert/bert_en_uncased_L-8_H-768_A-12':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-8_H-768_A-12/1',
'small_bert/bert_en_uncased_L-10_H-128_A-2':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-10_H-128_A-2/1',
'small_bert/bert_en_uncased_L-10_H-256_A-4':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-10_H-256_A-4/1',
'small_bert/bert_en_uncased_L-10_H-512_A-8':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-10_H-512_A-8/1',
'small_bert/bert_en_uncased_L-10_H-768_A-12':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-10_H-768_A-12/1',
'small_bert/bert_en_uncased_L-12_H-128_A-2':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-12_H-128_A-2/1',
'small_bert/bert_en_uncased_L-12_H-256_A-4':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-12_H-256_A-4/1',
'small_bert/bert_en_uncased_L-12_H-512_A-8':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-12_H-512_A-8/1',
'small_bert/bert_en_uncased_L-12_H-768_A-12':
'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-12_H-768_A-12/1',
'albert_en_base':
'https://tfhub.dev/tensorflow/albert_en_base/2',
'albert_en_large':
'https://tfhub.dev/tensorflow/albert_en_large/2',
'albert_en_xlarge':
'https://tfhub.dev/tensorflow/albert_en_xlarge/2',
'albert_en_xxlarge':
'https://tfhub.dev/tensorflow/albert_en_xxlarge/2',
'electra_small':
'https://tfhub.dev/google/electra_small/2',
'electra_base':
'https://tfhub.dev/google/electra_base/2',
'experts_pubmed':
'https://tfhub.dev/google/experts/bert/pubmed/2',
'experts_wiki_books':
'https://tfhub.dev/google/experts/bert/wiki_books/2',
'talking-heads_base':
'https://tfhub.dev/tensorflow/talkheads_ggelu_bert_en_base/1',
'talking-heads_large':
'https://tfhub.dev/tensorflow/talkheads_ggelu_bert_en_large/1',
}
map_model_to_preprocess = {
'bert_en_uncased_L-24_H-1024_A-16':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'bert_en_uncased_L-12_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'bert_en_wwm_cased_L-24_H-1024_A-16':
'https://tfhub.dev/tensorflow/bert_en_cased_preprocess/3',
'bert_en_cased_L-24_H-1024_A-16':
'https://tfhub.dev/tensorflow/bert_en_cased_preprocess/3',
'bert_en_cased_L-12_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_cased_preprocess/3',
'bert_en_wwm_uncased_L-24_H-1024_A-16':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-2_H-128_A-2':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-2_H-256_A-4':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-2_H-512_A-8':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-2_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-4_H-128_A-2':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-4_H-256_A-4':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-4_H-512_A-8':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-4_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-6_H-128_A-2':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-6_H-256_A-4':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-6_H-512_A-8':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-6_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-8_H-128_A-2':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-8_H-256_A-4':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-8_H-512_A-8':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-8_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-10_H-128_A-2':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-10_H-256_A-4':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-10_H-512_A-8':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-10_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-12_H-128_A-2':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-12_H-256_A-4':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-12_H-512_A-8':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'small_bert/bert_en_uncased_L-12_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'bert_multi_cased_L-12_H-768_A-12':
'https://tfhub.dev/tensorflow/bert_multi_cased_preprocess/3',
'albert_en_base':
'https://tfhub.dev/tensorflow/albert_en_preprocess/3',
'albert_en_large':
'https://tfhub.dev/tensorflow/albert_en_preprocess/3',
'albert_en_xlarge':
'https://tfhub.dev/tensorflow/albert_en_preprocess/3',
'albert_en_xxlarge':
'https://tfhub.dev/tensorflow/albert_en_preprocess/3',
'electra_small':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'electra_base':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'experts_pubmed':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'experts_wiki_books':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'talking-heads_base':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
'talking-heads_large':
'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3',
}
tfhub_handle_encoder = map_name_to_handle[bert_model_name]
tfhub_handle_preprocess = map_model_to_preprocess[bert_model_name]
print('BERT model selected :', tfhub_handle_encoder)
print('Preprocessing model auto-selected:', tfhub_handle_preprocess)
BERT model selected : https://tfhub.dev/tensorflow/bert_en_uncased_L-12_H-768_A-12/3 Preprocessing model auto-selected: https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3
Предварительно обработать текст
На тексте Classify с Бертом colab модель предварительной обработки используется встраивать непосредственно с кодером BERT.
В этом руководстве показано, как выполнить предварительную обработку как часть вашего входного конвейера для обучения, используя Dataset.map, а затем объединить его с моделью, которая экспортируется для вывода. Таким образом, как обучение, так и логический вывод могут работать с исходным текстовым вводом, хотя сам TPU требует числовых вводов.
Требования ТПУ в сторону, это может помочь производительности у Preprocessing выполняется асинхронно во входном трубопроводе (Вы можете узнать больше в руководстве производительности tf.data ).
В этом руководстве также показано, как создавать модели с несколькими входами и как настроить длину последовательности входных данных для BERT.
Продемонстрируем модель предварительной обработки.
bert_preprocess = hub.load(tfhub_handle_preprocess)
tok = bert_preprocess.tokenize(tf.constant(['Hello TensorFlow!']))
print(tok)
<tf.RaggedTensor [[[7592], [23435, 12314], [999]]]>
Каждая модель предварительной обработки также обеспечивает способ, .bert_pack_inputs(tensors, seq_length)
, который принимает список маркеров (например , tok
выше) и длина последовательности аргумент. Это упаковывает входные данные для создания словаря тензоров в формате, ожидаемом моделью BERT.
text_preprocessed = bert_preprocess.bert_pack_inputs([tok, tok], tf.constant(20))
print('Shape Word Ids : ', text_preprocessed['input_word_ids'].shape)
print('Word Ids : ', text_preprocessed['input_word_ids'][0, :16])
print('Shape Mask : ', text_preprocessed['input_mask'].shape)
print('Input Mask : ', text_preprocessed['input_mask'][0, :16])
print('Shape Type Ids : ', text_preprocessed['input_type_ids'].shape)
print('Type Ids : ', text_preprocessed['input_type_ids'][0, :16])
Shape Word Ids : (1, 20) Word Ids : tf.Tensor( [ 101 7592 23435 12314 999 102 7592 23435 12314 999 102 0 0 0 0 0], shape=(16,), dtype=int32) Shape Mask : (1, 20) Input Mask : tf.Tensor([1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0], shape=(16,), dtype=int32) Shape Type Ids : (1, 20) Type Ids : tf.Tensor([0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0], shape=(16,), dtype=int32)
Вот некоторые детали, на которые следует обратить внимание:
-
input_mask
Маска позволяет модель чисто дифференцируются между содержанием и дополнением. Маска имеет ту же форму, что иinput_word_ids
, и содержит 1 где угодноinput_word_ids
не обивку. -
input_type_ids
имеет такую же форму , какinput_mask
, но внутри НЕДОПОЛНЯЮЩЕЙ области, содержит 0 или 1 , указывающее какое предложение маркера является частью.
Затем вы создадите модель предварительной обработки, которая инкапсулирует всю эту логику. Ваша модель будет принимать строки в качестве входных данных и возвращать должным образом отформатированные объекты, которые могут быть переданы в BERT.
Каждая модель BERT имеет определенную модель предварительной обработки, убедитесь, что вы используете правильную модель, описанную в документации модели BERT.
def make_bert_preprocess_model(sentence_features, seq_length=128):
"""Returns Model mapping string features to BERT inputs.
Args:
sentence_features: a list with the names of string-valued features.
seq_length: an integer that defines the sequence length of BERT inputs.
Returns:
A Keras Model that can be called on a list or dict of string Tensors
(with the order or names, resp., given by sentence_features) and
returns a dict of tensors for input to BERT.
"""
input_segments = [
tf.keras.layers.Input(shape=(), dtype=tf.string, name=ft)
for ft in sentence_features]
# Tokenize the text to word pieces.
bert_preprocess = hub.load(tfhub_handle_preprocess)
tokenizer = hub.KerasLayer(bert_preprocess.tokenize, name='tokenizer')
segments = [tokenizer(s) for s in input_segments]
# Optional: Trim segments in a smart way to fit seq_length.
# Simple cases (like this example) can skip this step and let
# the next step apply a default truncation to approximately equal lengths.
truncated_segments = segments
# Pack inputs. The details (start/end token ids, dict of output tensors)
# are model-dependent, so this gets loaded from the SavedModel.
packer = hub.KerasLayer(bert_preprocess.bert_pack_inputs,
arguments=dict(seq_length=seq_length),
name='packer')
model_inputs = packer(truncated_segments)
return tf.keras.Model(input_segments, model_inputs)
Продемонстрируем модель предварительной обработки. Вы создадите тест с вводом двух предложений (input1 и input2). Выход какая модель БЕРТА бы ожидать в качестве входного: input_word_ids
, input_masks
и input_type_ids
.
test_preprocess_model = make_bert_preprocess_model(['my_input1', 'my_input2'])
test_text = [np.array(['some random test sentence']),
np.array(['another sentence'])]
text_preprocessed = test_preprocess_model(test_text)
print('Keys : ', list(text_preprocessed.keys()))
print('Shape Word Ids : ', text_preprocessed['input_word_ids'].shape)
print('Word Ids : ', text_preprocessed['input_word_ids'][0, :16])
print('Shape Mask : ', text_preprocessed['input_mask'].shape)
print('Input Mask : ', text_preprocessed['input_mask'][0, :16])
print('Shape Type Ids : ', text_preprocessed['input_type_ids'].shape)
print('Type Ids : ', text_preprocessed['input_type_ids'][0, :16])
Keys : ['input_word_ids', 'input_mask', 'input_type_ids'] Shape Word Ids : (1, 128) Word Ids : tf.Tensor( [ 101 2070 6721 3231 6251 102 2178 6251 102 0 0 0 0 0 0 0], shape=(16,), dtype=int32) Shape Mask : (1, 128) Input Mask : tf.Tensor([1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0], shape=(16,), dtype=int32) Shape Type Ids : (1, 128) Type Ids : tf.Tensor([0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0], shape=(16,), dtype=int32)
Давайте посмотрим на структуру модели, обратив внимание на два только что определенных вами входа.
tf.keras.utils.plot_model(test_preprocess_model, show_shapes=True, show_dtype=True)
('You must install pydot (`pip install pydot`) and install graphviz (see instructions at https://graphviz.gitlab.io/download/) ', 'for plot_model/model_to_dot to work.')
Чтобы применить предварительную обработку всех входов из набора данных, вы будете использовать map
функцию из набора данных. Результат сохраняется в кэше для выполнения .
AUTOTUNE = tf.data.AUTOTUNE
def load_dataset_from_tfds(in_memory_ds, info, split, batch_size,
bert_preprocess_model):
is_training = split.startswith('train')
dataset = tf.data.Dataset.from_tensor_slices(in_memory_ds[split])
num_examples = info.splits[split].num_examples
if is_training:
dataset = dataset.shuffle(num_examples)
dataset = dataset.repeat()
dataset = dataset.batch(batch_size)
dataset = dataset.map(lambda ex: (bert_preprocess_model(ex), ex['label']))
dataset = dataset.cache().prefetch(buffer_size=AUTOTUNE)
return dataset, num_examples
Определите вашу модель
Теперь вы готовы определить свою модель для классификации предложений или пар предложений, подав предварительно обработанные входные данные через кодировщик BERT и поместив сверху линейный классификатор (или другое расположение слоев по своему усмотрению) и используя выпадение для регуляризации.
def build_classifier_model(num_classes):
class Classifier(tf.keras.Model):
def __init__(self, num_classes):
super(Classifier, self).__init__(name="prediction")
self.encoder = hub.KerasLayer(tfhub_handle_encoder, trainable=True)
self.dropout = tf.keras.layers.Dropout(0.1)
self.dense = tf.keras.layers.Dense(num_classes)
def call(self, preprocessed_text):
encoder_outputs = self.encoder(preprocessed_text)
pooled_output = encoder_outputs["pooled_output"]
x = self.dropout(pooled_output)
x = self.dense(x)
return x
model = Classifier(num_classes)
return model
Давайте попробуем запустить модель на некоторых предварительно обработанных входных данных.
test_classifier_model = build_classifier_model(2)
bert_raw_result = test_classifier_model(text_preprocessed)
print(tf.sigmoid(bert_raw_result))
tf.Tensor([[0.29329836 0.44367802]], shape=(1, 2), dtype=float32)
Выберите задачу из КЛЕЯ
Вы собираетесь использовать TensorFlow DataSet из КЛЕЯ базового пакета.
Colab позволяет загружать эти небольшие наборы данных в локальную файловую систему, а приведенный ниже код полностью считывает их в память, поскольку отдельный рабочий хост TPU не может получить доступ к локальной файловой системе среды выполнения colab.
Для больших наборов данных, вам нужно создать свой собственный Google Cloud Storage ведро и иметь TPU работник читать данные оттуда. Вы можете узнать больше в руководстве ТПУ .
Рекомендуется начать с набора данных CoLa (для одного предложения) или MRPC (для нескольких предложений), поскольку они небольшие и не требуют много времени на точную настройку.
tfds_name = 'glue/cola'
tfds_info = tfds.builder(tfds_name).info
sentence_features = list(tfds_info.features.keys())
sentence_features.remove('idx')
sentence_features.remove('label')
available_splits = list(tfds_info.splits.keys())
train_split = 'train'
validation_split = 'validation'
test_split = 'test'
if tfds_name == 'glue/mnli':
validation_split = 'validation_matched'
test_split = 'test_matched'
num_classes = tfds_info.features['label'].num_classes
num_examples = tfds_info.splits.total_num_examples
print(f'Using {tfds_name} from TFDS')
print(f'This dataset has {num_examples} examples')
print(f'Number of classes: {num_classes}')
print(f'Features {sentence_features}')
print(f'Splits {available_splits}')
with tf.device('/job:localhost'):
# batch_size=-1 is a way to load the dataset into memory
in_memory_ds = tfds.load(tfds_name, batch_size=-1, shuffle_files=True)
# The code below is just to show some samples from the selected dataset
print(f'Here are some sample rows from {tfds_name} dataset')
sample_dataset = tf.data.Dataset.from_tensor_slices(in_memory_ds[train_split])
labels_names = tfds_info.features['label'].names
print(labels_names)
print()
sample_i = 1
for sample_row in sample_dataset.take(5):
samples = [sample_row[feature] for feature in sentence_features]
print(f'sample row {sample_i}')
for sample in samples:
print(sample.numpy())
sample_label = sample_row['label']
print(f'label: {sample_label} ({labels_names[sample_label]})')
print()
sample_i += 1
Using glue/cola from TFDS This dataset has 10657 examples Number of classes: 2 Features ['sentence'] Splits ['train', 'validation', 'test'] Here are some sample rows from glue/cola dataset ['unacceptable', 'acceptable'] sample row 1 b'It is this hat that it is certain that he was wearing.' label: 1 (acceptable) sample row 2 b'Her efficient looking up of the answer pleased the boss.' label: 1 (acceptable) sample row 3 b'Both the workers will wear carnations.' label: 1 (acceptable) sample row 4 b'John enjoyed drawing trees for his syntax homework.' label: 1 (acceptable) sample row 5 b'We consider Leslie rather foolish, and Lou a complete idiot.' label: 1 (acceptable)
Набор данных также определяет тип проблемы (классификация или регрессия) и соответствующую функцию потерь для обучения.
def get_configuration(glue_task):
loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
if glue_task == 'glue/cola':
metrics = tfa.metrics.MatthewsCorrelationCoefficient(num_classes=2)
else:
metrics = tf.keras.metrics.SparseCategoricalAccuracy(
'accuracy', dtype=tf.float32)
return metrics, loss
Обучите свою модель
Наконец, вы можете обучить модель от начала до конца на выбранном вами наборе данных.
Распределение
Вспомните код настройки вверху, который подключил среду выполнения colab к рабочему TPU с несколькими устройствами TPU. Чтобы распространить на них обучение, вы создадите и скомпилируете свою основную модель Keras в рамках стратегии распространения TPU. (Для получения дополнительной информации см Распределенного обучение с Keras .)
С другой стороны, предварительная обработка выполняется на ЦП рабочего хоста, а не на TPU, поэтому модель Keras для предварительной обработки, а также сопоставленные с ней наборы данных для обучения и проверки построены за пределами области стратегии распространения. Вызов Model.fit()
будет заботиться о распространении переданного в наборе данных в модели реплики.
Оптимизатор
Тонкая настройка следует оптимизатор набор пробуждения от BERT предварительно обучения (как в Classify тексте с Бертом ): Он использует оптимизатор AdamW с линейным распадом условной начальной скорости обучения, приставка с линейной фазой прогрева над первым 10% учебных шагов ( num_warmup_steps
). Согласно статье BERT, начальная скорость обучения меньше для точной настройки (лучше всего 5e-5, 3e-5, 2e-5).
epochs = 3
batch_size = 32
init_lr = 2e-5
print(f'Fine tuning {tfhub_handle_encoder} model')
bert_preprocess_model = make_bert_preprocess_model(sentence_features)
with strategy.scope():
# metric have to be created inside the strategy scope
metrics, loss = get_configuration(tfds_name)
train_dataset, train_data_size = load_dataset_from_tfds(
in_memory_ds, tfds_info, train_split, batch_size, bert_preprocess_model)
steps_per_epoch = train_data_size // batch_size
num_train_steps = steps_per_epoch * epochs
num_warmup_steps = num_train_steps // 10
validation_dataset, validation_data_size = load_dataset_from_tfds(
in_memory_ds, tfds_info, validation_split, batch_size,
bert_preprocess_model)
validation_steps = validation_data_size // batch_size
classifier_model = build_classifier_model(num_classes)
optimizer = optimization.create_optimizer(
init_lr=init_lr,
num_train_steps=num_train_steps,
num_warmup_steps=num_warmup_steps,
optimizer_type='adamw')
classifier_model.compile(optimizer=optimizer, loss=loss, metrics=[metrics])
classifier_model.fit(
x=train_dataset,
validation_data=validation_dataset,
steps_per_epoch=steps_per_epoch,
epochs=epochs,
validation_steps=validation_steps)
Fine tuning https://tfhub.dev/tensorflow/bert_en_uncased_L-12_H-768_A-12/3 model /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/keras/engine/functional.py:585: UserWarning: Input dict contained keys ['idx', 'label'] which did not match any model input. They will be ignored by the model. [n for n in tensors.keys() if n not in ref_input_names]) Epoch 1/3 /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/framework/indexed_slices.py:449: UserWarning: Converting sparse IndexedSlices(IndexedSlices(indices=Tensor("AdamWeightDecay/gradients/StatefulPartitionedCall:1", shape=(None,), dtype=int32), values=Tensor("clip_by_global_norm/clip_by_global_norm/_0:0", dtype=float32), dense_shape=Tensor("AdamWeightDecay/gradients/StatefulPartitionedCall:2", shape=(None,), dtype=int32))) to a dense Tensor of unknown shape. This may consume a large amount of memory. "shape. This may consume a large amount of memory." % value) 267/267 [==============================] - 86s 81ms/step - loss: 0.6092 - MatthewsCorrelationCoefficient: 0.0000e+00 - val_loss: 0.4846 - val_MatthewsCorrelationCoefficient: 0.0000e+00 Epoch 2/3 267/267 [==============================] - 14s 53ms/step - loss: 0.3774 - MatthewsCorrelationCoefficient: 0.0000e+00 - val_loss: 0.5322 - val_MatthewsCorrelationCoefficient: 0.0000e+00 Epoch 3/3 267/267 [==============================] - 14s 53ms/step - loss: 0.2623 - MatthewsCorrelationCoefficient: 0.0000e+00 - val_loss: 0.6469 - val_MatthewsCorrelationCoefficient: 0.0000e+00
Экспорт для вывода
Вы создадите окончательную модель, которая будет иметь часть предварительной обработки и точно настроенный BERT, который мы только что создали.
Во время вывода предварительная обработка должна быть частью модели (потому что больше нет отдельной очереди ввода, как для обучающих данных, которые это делают). Предварительная обработка - это не просто вычисления; у него есть собственные ресурсы (таблица словаря), которые должны быть прикреплены к модели Keras, сохраненной для экспорта. Эта окончательная сборка будет сохранена.
Вы собираетесь сохранить модель на colab , а затем вы можете сохранить его на будущее (View -> Содержание -> Файлы).
main_save_path = './my_models'
bert_type = tfhub_handle_encoder.split('/')[-2]
saved_model_name = f'{tfds_name.replace("/", "_")}_{bert_type}'
saved_model_path = os.path.join(main_save_path, saved_model_name)
preprocess_inputs = bert_preprocess_model.inputs
bert_encoder_inputs = bert_preprocess_model(preprocess_inputs)
bert_outputs = classifier_model(bert_encoder_inputs)
model_for_export = tf.keras.Model(preprocess_inputs, bert_outputs)
print('Saving', saved_model_path)
# Save everything on the Colab host (even the variables from TPU memory)
save_options = tf.saved_model.SaveOptions(experimental_io_device='/job:localhost')
model_for_export.save(saved_model_path, include_optimizer=False,
options=save_options)
Saving ./my_models/glue_cola_bert_en_uncased_L-12_H-768_A-12 WARNING:absl:Found untraced functions such as restored_function_body, restored_function_body, restored_function_body, restored_function_body, restored_function_body while saving (showing 5 of 910). These functions will not be directly callable after loading.
Протестируйте модель
Последний шаг - тестирование результатов вашей экспортированной модели.
Чтобы провести некоторое сравнение, давайте перезагрузим модель и протестируем ее, используя некоторые входные данные из тестовой части набора данных.
with tf.device('/job:localhost'):
reloaded_model = tf.saved_model.load(saved_model_path)
Утилита методы
def prepare(record):
model_inputs = [[record[ft]] for ft in sentence_features]
return model_inputs
def prepare_serving(record):
model_inputs = {ft: record[ft] for ft in sentence_features}
return model_inputs
def print_bert_results(test, bert_result, dataset_name):
bert_result_class = tf.argmax(bert_result, axis=1)[0]
if dataset_name == 'glue/cola':
print('sentence:', test[0].numpy())
if bert_result_class == 1:
print('This sentence is acceptable')
else:
print('This sentence is unacceptable')
elif dataset_name == 'glue/sst2':
print('sentence:', test[0])
if bert_result_class == 1:
print('This sentence has POSITIVE sentiment')
else:
print('This sentence has NEGATIVE sentiment')
elif dataset_name == 'glue/mrpc':
print('sentence1:', test[0])
print('sentence2:', test[1])
if bert_result_class == 1:
print('Are a paraphrase')
else:
print('Are NOT a paraphrase')
elif dataset_name == 'glue/qqp':
print('question1:', test[0])
print('question2:', test[1])
if bert_result_class == 1:
print('Questions are similar')
else:
print('Questions are NOT similar')
elif dataset_name == 'glue/mnli':
print('premise :', test[0])
print('hypothesis:', test[1])
if bert_result_class == 1:
print('This premise is NEUTRAL to the hypothesis')
elif bert_result_class == 2:
print('This premise CONTRADICTS the hypothesis')
else:
print('This premise ENTAILS the hypothesis')
elif dataset_name == 'glue/qnli':
print('question:', test[0])
print('sentence:', test[1])
if bert_result_class == 1:
print('The question is NOT answerable by the sentence')
else:
print('The question is answerable by the sentence')
elif dataset_name == 'glue/rte':
print('sentence1:', test[0])
print('sentence2:', test[1])
if bert_result_class == 1:
print('Sentence1 DOES NOT entails sentence2')
else:
print('Sentence1 entails sentence2')
elif dataset_name == 'glue/wnli':
print('sentence1:', test[0])
print('sentence2:', test[1])
if bert_result_class == 1:
print('Sentence1 DOES NOT entails sentence2')
else:
print('Sentence1 entails sentence2')
print('BERT raw results:', bert_result[0])
print()
Контрольная работа
with tf.device('/job:localhost'):
test_dataset = tf.data.Dataset.from_tensor_slices(in_memory_ds[test_split])
for test_row in test_dataset.shuffle(1000).map(prepare).take(5):
if len(sentence_features) == 1:
result = reloaded_model(test_row[0])
else:
result = reloaded_model(list(test_row))
print_bert_results(test_row, result, tfds_name)
sentence: [b'An old woman languished in the forest.'] This sentence is acceptable BERT raw results: tf.Tensor([-1.7032353 3.3714833], shape=(2,), dtype=float32) sentence: [b"I went to the movies and didn't pick up the shirts."] This sentence is acceptable BERT raw results: tf.Tensor([-0.73970896 1.0806316 ], shape=(2,), dtype=float32) sentence: [b"Every essay that she's written and which I've read is on that pile."] This sentence is acceptable BERT raw results: tf.Tensor([-0.7034159 0.6236454], shape=(2,), dtype=float32) sentence: [b'Either Bill ate the peaches, or Harry.'] This sentence is unacceptable BERT raw results: tf.Tensor([ 0.05972151 -0.08620442], shape=(2,), dtype=float32) sentence: [b'I ran into the baker from whom I bought these bagels.'] This sentence is acceptable BERT raw results: tf.Tensor([-1.6862067 3.285925 ], shape=(2,), dtype=float32)
Если вы хотите использовать модель на сервировка TF , помните , что это будет вызывать SavedModel через один из названных подписей. Обратите внимание, что во вводе есть небольшие отличия. В Python вы можете протестировать их следующим образом:
with tf.device('/job:localhost'):
serving_model = reloaded_model.signatures['serving_default']
for test_row in test_dataset.shuffle(1000).map(prepare_serving).take(5):
result = serving_model(**test_row)
# The 'prediction' key is the classifier's defined model name.
print_bert_results(list(test_row.values()), result['prediction'], tfds_name)
sentence: b'Everyone attended more than two seminars.' This sentence is acceptable BERT raw results: tf.Tensor([-1.5594155 2.862155 ], shape=(2,), dtype=float32) sentence: b'Most columnists claim that a senior White House official has been briefing them.' This sentence is acceptable BERT raw results: tf.Tensor([-1.6298996 3.3155093], shape=(2,), dtype=float32) sentence: b"That my father, he's lived here all his life is well known to those cops." This sentence is acceptable BERT raw results: tf.Tensor([-1.2048947 1.8589772], shape=(2,), dtype=float32) sentence: b'Ourselves like us.' This sentence is acceptable BERT raw results: tf.Tensor([-1.2723312 2.0494034], shape=(2,), dtype=float32) sentence: b'John is clever.' This sentence is acceptable BERT raw results: tf.Tensor([-1.6516167 3.3147635], shape=(2,), dtype=float32)
Ты сделал это! Сохраненную модель можно использовать для обслуживания или простого вывода в процессе с более простым API, меньшим количеством кода и более простым в обслуживании.
Следующие шаги
Теперь, когда вы опробовали одну из базовых моделей BERT, вы можете попробовать другие для достижения большей точности или, возможно, с меньшими версиями моделей.
Вы также можете попробовать другие наборы данных.