[PYTHON] [TPU] [Transformatoren] Machen Sie BERT mit explosiver Geschwindigkeit

Ich konnte in dem Wettbewerb, an dem ich teilgenommen habe, sehr einfach ein BERT-Modell mit TPU + Transformers bauen, also werde ich es teilen.

Wie auch immer, wir werden die Geschwindigkeit priorisieren und BERT erstellen, was ein aktueller NLP-Trend ist.

BERT Es ist ein von Google entwickeltes Allzweck-Sprachmodell. Dieses Mal verwenden wir ein zeitsparendes Rezept mit Distil BERT, einem leichteren und schnelleren Destillationsmodell als BERT. Das Pretrain-Modell verwendet japanisches Modell, veröffentlicht vom Bandai Namco Research Institute.

TPU TPU (Tensor Processing Unit) ist ein von Google entwickelter Prozessor, der sich auf Berechnungen zum maschinellen Lernen spezialisiert hat. Durch Ersetzen der arithmetischen Schaltung von 32 Bit auf 8 oder 16 Bit oder durch Übergeben von Werten zwischen arithmetischen Schaltungen ohne Lese- und Schreibspeicher scheint die Matrixarithmetik schneller als Allzweckprozessoren ausgeführt werden zu können. Vor kurzem gab es TPUs für Edge, die mit GCP verwendet und in Raspberry pi installiert werden können.

Dieses Mal werden wir TPU in Google Colab verwenden, um die Lernzeit zu explodieren.

Transformers Dies ist ein Deep Learning-Framework von Hugging Face, das sich auf Transformer-Modelle spezialisiert hat. Sie können die Tokenizer- und Pretrain-Modelle, die zum Erstellen von Transformer-Modellen erforderlich sind, problemlos aus den auf Hugging Face's HP veröffentlichten Modellen laden. (Natürlich können Sie auch auf das lokal gespeicherte Modell verweisen.) Zu Beginn der Entwicklung war es nur mit Pytorch kompatibel, jetzt ist es auch mit Tensorflow kompatibel. Dieses Mal werden wir ein Modell für Tensorflow (Keras) laden und erstellen, um die Einfachheit von I / F und die Benutzerfreundlichkeit von TPU zu berücksichtigen. (Wenn ich TPU mit Pytorch verwende, verwende ich Tensorflow, das relativ einfach zu verwenden ist, da es schwierig ist, XLA zu verwenden und Mehrfachverarbeitung zu schreiben.)

Bauen

Dieses Mal ist es solide, aber wir werden einen Klassifikator für mehrere Klassen mit dem Livedoor-Korpus erstellen, den jeder liebt.

Vorbereitung

Ändern Sie die Laufzeit von Notebooks Runtime-> Change Runtime Type in TPU. (Standard ist Keine)

tpu.png

Da Transfomere nicht in der Colab-Umgebung enthalten sind, werde ich sie mit pip fallen lassen. Da der diesmal verwendete Tokenizer Mecab verwendet, installieren Sie ihn ebenfalls.

!pip install transformers
!apt install aptitude
!aptitude install mecab libmecab-dev mecab-ipadic-utf8 git make curl xz-utils file -y
!pip install mecab-python3==0.7
from google.colab import drive
drive.mount('/gdrive')
%cd "/gdrive/My Drive/workspace/python/bakusoku"

Datenvorverarbeitung

Dieses Mal werde ich AutoTokenizer verwenden. Wenn Sie ein Pretrain-Modell angeben, wird der für dieses Modell geeignete Tokenizer automatisch geladen. (In diesem Fall laden wir eine Instanz von BertJapaneseTokenizer.) Sie können die Anweisung mit der Tokenize-Methode tokenisieren. Dieser Tokenizer ist in Wortstückeinheiten unterteilt. (Es gibt andere Teilungsmethoden wie Satzstücke.)

from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("cl-tohoku/bert-base-japanese-whole-word-masking")

print(tokenizer.tokenize('Machen Sie BERT mit explosiver Geschwindigkeit'))
# ['LOL', '##Schnell', 'damit', 'BE', '##R', '##T', 'Zu', 'erstellen']

Da der Satz zum Lernen in eine Folge von Wort-IDs konvertiert werden muss, wird er mit der folgenden Methode konvertiert.

import numpy as np

def encode_texts(texts, tokenizer, maxlen=512):
    enc_di = tokenizer.batch_encode_plus(
        texts, 
        return_attention_masks=False, 
        return_token_type_ids=False,
        pad_to_max_length=True,
        max_length=maxlen
    )
    return np.array(enc_di['input_ids'])
x_train = encode_texts(train_df['text'].values, tokenizer)
x_valid = encode_texts(valid_df['text'].values, tokenizer)
x_test = encode_texts(test_df['text'].values, tokenizer)
print(x_train)
# [[    2   281   306 ...  2478     9     3]
#  [    2  1519     7 ...    15    16     3]
#  [    2 11634  3217 ...  2478     7     3]
#  ...
#  [    2  6093 16562 ...     0     0     0]
#  [    2   885  2149 ...     0     0     0]
#  [    2  5563  2037 ...     0     0     0]]

Das richtige Antwortetikett ist ebenfalls One-Hot-codiert.

from tensorflow.keras.utils import to_categorical
y_train = to_categorical(train_df['label'].values)
y_valid = to_categorical(valid_df['label'].values)
print(y_train)
# [[1. 0. 0. ... 0. 0. 0.]
#  [1. 0. 0. ... 0. 0. 0.]
#  [1. 0. 0. ... 0. 0. 0.]
#  ...
#  [0. 0. 0. ... 0. 0. 1.]
#  [0. 0. 0. ... 0. 0. 1.]
#  [0. 0. 0. ... 0. 0. 1.]]

Vorbereitung zur Verwendung von TPU

Im Gegensatz zur GPU-Laufzeit, die nur durch Umschalten verwendet werden kann, muss für die TPU-Laufzeit der folgende Code geschrieben werden. Es ist fast ein magisches Level, aber es ist schneller, die Stapelgröße entsprechend der Anzahl der TPU-Kerne zu ändern.

import tensorflow as tf

try:
    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()
    print('Running on TPU ', tpu.master())
except ValueError:
    tpu = None

if tpu:
    tf.config.experimental_connect_to_cluster(tpu)
    tf.tpu.experimental.initialize_tpu_system(tpu)
    strategy = tf.distribute.experimental.TPUStrategy(tpu)
else:
    strategy = tf.distribute.get_strategy()

num_replicas =  strategy.num_replicas_in_sync
print("REPLICAS: ", num_replicas)
# REPLICAS:  8
BATCH_SIZE = 16 * num_replicas # 128

Modellbau

Dieses Mal werden wir einen Klassifikator für mehrere Klassen erstellen, der Distil BERT als Encoder verwendet. Von der Ausgabe des Codierers ist diejenige, die dem ersten Token entspricht (ein spezielles Token, das den Satzanfang [CLS] angibt), mit dem HEAD verbunden (Ausgabeschicht von Softmax). Ich denke, es ist auch möglich, nach Global Pooling den gesamten Ausgang des Encoders zu verbinden.

from tensorflow.keras.layers import Dense, Input
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.models import Model

def build_model(transformer, num_cls=1, max_len=512):
    input_word_ids = Input(shape=(max_len,), dtype=tf.int32, name="input_word_ids")
    sequence_output = transformer(input_word_ids)[0]
    cls_token = sequence_output[:, 0, :]
    out = Dense(num_cls, activation='softmax')(cls_token)
    
    model = Model(inputs=input_word_ids, outputs=out)
    model.compile(Adam(lr=2e-4), loss='categorical_crossentropy', metrics=['accuracy']) # lr = 5e-5 * 4
    
    return model

Laden Sie das auf dem Hugging Face HP veröffentlichte Pretrain-Modell und erstellen Sie das obige Modell. Wie der Tokenizer verwendet er TFAutoModel, um das Pretrain-Modell auf die TPU zu laden. (In diesem Fall laden wir eine Instanz von TFDistilBertModel.)

from transformers import TFAutoModel
with strategy.scope():
    transformer_layer = (TFAutoModel.from_pretrained('bandainamco-mirai/distilbert-base-japanese', from_pt=True))
    model = build_model(transformer_layer, num_cls=9, max_len=512)
model.summary()
# Model: "model_1"
# _________________________________________________________________
# Layer (type)                 Output Shape              Param #   
# =================================================================
# input_word_ids (InputLayer)  [(None, 512)]             0         
# _________________________________________________________________
# tf_distil_bert_model_1 (TFDi ((None, 512, 768), ((None 67497984  
# _________________________________________________________________
# tf_op_layer_strided_slice_1  [(None, 768)]             0         
# _________________________________________________________________
# dense_1 (Dense)              (None, 9)                 6921      
# =================================================================
# Total params: 67,504,905
# Trainable params: 67,504,905
# Non-trainable params: 0
# _________________________________________________________________

fine-tuning Lassen Sie uns das Modell trainieren, das wir zuvor gemacht haben. Im folgenden Beispiel schließen 5.500 Fälle - 4 Epochen das Lernen in etwa 70 Sekunden ab.

AUTO = tf.data.experimental.AUTOTUNE

train_dataset = (
    tf.data.Dataset
    .from_tensor_slices((x_train, y_train))
    .repeat()
    .shuffle(2048)
    .batch(BATCH_SIZE)
    .prefetch(AUTO)
)

valid_dataset = (
    tf.data.Dataset
    .from_tensor_slices((x_valid, y_valid))
    .batch(BATCH_SIZE)
    .cache()
    .prefetch(AUTO)
)

test_dataset = (
    tf.data.Dataset
    .from_tensor_slices(x_test)
    .batch(BATCH_SIZE)
)

n_steps = x_train.shape[0] // BATCH_SIZE
train_history = model.fit(
    train_dataset,
    steps_per_epoch=n_steps,
    validation_data=valid_dataset,
    epochs=4
)
# Epoch 1/4
# 43/43 [==============================] - 31s 715ms/step - accuracy: 0.2473 - loss: 2.0548 - val_accuracy: 0.3355 - val_loss: 1.9584
# Epoch 2/4
# 43/43 [==============================] - 13s 308ms/step - accuracy: 0.6726 - loss: 1.4064 - val_accuracy: 0.6612 - val_loss: 1.1878
# Epoch 3/4
# 43/43 [==============================] - 13s 309ms/step - accuracy: 0.8803 - loss: 0.7522 - val_accuracy: 0.7877 - val_loss: 0.8257
# Epoch 4/4
# 43/43 [==============================] - 13s 309ms/step - accuracy: 0.9304 - loss: 0.4401 - val_accuracy: 0.8181 - val_loss: 0.6747

Auswertung

Die Genauigkeit beträgt 81% ... Das Ergebnis ist Bimyo. Ich denke, dass sich die Genauigkeit verbessern wird, wenn Sie etwas mehr Datenbereinigung und die Modellstruktur nach Encoder entwickeln.

from sklearn.metrics import classification_report

test_df['predict'] = model.predict(test_dataset, verbose=1).argmax(axis=1)
print(classification_report(test_df['label'], test_df['predict'], target_names=target_names))
# 12/12 [==============================] - 11s 890ms/step
#                 precision    recall  f1-score   support
# 
# dokujo-tsushin       0.73      0.95      0.83       174
#   it-life-hack       0.66      0.91      0.76       174
#  kaden-channel       0.79      0.47      0.59       173
# livedoor-homme       0.91      0.31      0.47       102
#    movie-enter       0.81      0.96      0.88       174
#         peachy       0.81      0.71      0.76       169
#           smax       0.91      0.97      0.94       174
#   sports-watch       0.88      1.00      0.94       180
#     topic-news       0.91      0.75      0.83       154
# 
#       accuracy                           0.81      1474
#      macro avg       0.83      0.78      0.78      1474
#   weighted avg       0.82      0.81      0.79      1474

Recommended Posts

[TPU] [Transformatoren] Machen Sie BERT mit explosiver Geschwindigkeit
Erstellen Sie einen Regenbenachrichtigungs-Bot für Hangouts Chat mit explosiver Geschwindigkeit
Python-Vorlage, die eine Protokollanalyse mit explosiver Geschwindigkeit durchführt
Erstellen Sie maschinelle Lernprojekte mit explosiver Geschwindigkeit mithilfe von Vorlagen
Implementieren Sie die API mit explosiver Geschwindigkeit mithilfe des Django REST Framework
Berechnen Sie den Gaußschen Kernel auch mit Python mit explosiver Geschwindigkeit
Versuchen Sie, Sudoku mit explosiver Geschwindigkeit mit Numpy zu lösen
Erstellen Sie mit hug einen Web-API-Server mit explosiver Geschwindigkeit
Versuchen Sie eine multivariate Korrelationsanalyse mit grafischem Lasso bei explosiver Geschwindigkeit