NLPスーパーパワーを活用する:ステップバイステップのハグフェイスファインチューニングチュートリアル
「NLPスーパーパワーを活用する方法:ステップバイステップのハグフェイスファインチューニングチュートリアル」
はじめに
Natural Language Processing(NLP)モデルの調整は、モデルのハイパーパラメータやアーキテクチャを変更し、通常はデータセットを調整して、特定のタスクでモデルのパフォーマンスを向上させることを意味します。学習率、モデルのレイヤー数、埋め込みのサイズ、およびさまざまな他のパラメータを調整することで、これを実現することができます。ファインチューニングは、モデルとタスクについての堅実な理解を要する時間のかかる手続きです。この記事では、Hugging Faceモデルのファインチューニング方法について説明します。
学習目標
- Transformerとセルフアテンションを含むT5モデルの構造を理解する。
- モデルのパフォーマンスを向上させるためのハイパーパラメータの最適化方法を学ぶ。
- トークン化やフォーマットなどのテキストデータの準備方法をマスターする。
- 事前学習済みモデルを特定のタスクに適応させる方法を知る。
- モデルのトレーニングのためのクリーニング、分割、およびデータセットの作成方法を学ぶ。
- 損失や精度などのメトリクスを使用してモデルのトレーニングと評価の経験を積む。
- ファインチューニングされたモデルを使用した応答や回答の生成の実世界の応用を探索する。
本記事は、Data Science Blogathonの一部として公開されました。
Hugging Faceモデルについて
Hugging Faceは、自然言語処理(NLP)モデルのトレーニングと展開のためのプラットフォームを提供する企業です。このプラットフォームは、言語翻訳、テキスト生成、質問応答など、さまざまなNLPタスクに適したモデルライブラリを提供しています。これらのモデルは、大規模なデータセットでトレーニングされ、幅広い自然言語処理(NLP)活動で優れたパフォーマンスを発揮するように設計されています。
Hugging Faceプラットフォームには、特定のデータセットで事前学習済みモデルをファインチューニングするためのツールも含まれており、アルゴリズムを特定のドメインや言語に適応させるのに役立ちます。プラットフォームには、アプリケーションで事前学習済みモデルをアクセスおよび利用するためのAPIや、ベスポークモデルを構築してクラウドにデリバリーするためのツールもあります。
NLPタスクにおけるHugging Faceライブラリの使用には、次のようなさまざまな利点があります:
- 多様なモデルの選択肢: Hugging Faceライブラリを通じて、言語翻訳、質問応答、テキスト分類などのタスクでトレーニングされたさまざまな事前学習済みNLPモデルが利用できるため、要件に適したモデルを簡単に選択することができます。
- プラットフォーム間の互換性: Hugging Faceライブラリは、TensorFlow、PyTorch、Kerasなどの標準的なディープラーニングシステムと互換性があり、既存のワークフローに簡単に統合することができます。
- 簡単なファインチューニング: Hugging Faceライブラリには、事前学習済みモデルをデータセットにファインチューニングするためのツールが含まれているため、モデルをゼロからトレーニングする手間と時間を節約することができます。
- 活発なコミュニティ: Hugging Faceライブラリには、広大で活発なユーザーコミュニティが存在し、サポートや助けを得ることができるだけでなく、ライブラリの成長に貢献することもできます。
- 充実したドキュメンテーション: Hugging Faceライブラリには、詳細なドキュメンテーションが含まれており、効率的に使用する方法を学ぶのが容易です。
必要なライブラリのインポート
必要なライブラリをインポートすることは、特定のプログラミングとデータ分析活動のためのツールキットを構築することに似ています。これらのライブラリは、しばしば事前に書かれたコードのコレクションであり、開発を迅速に進めるのに役立つさまざまな機能とツールを提供します。開発者やデータサイエンティストは、適切なライブラリをインポートすることで新しい機能にアクセスし、生産性を向上させ、既存のソリューションを活用することができます。
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
import torch
from transformers import T5Tokenizer
from transformers import T5ForConditionalGeneration, AdamW
import pytorch_lightning as pl
from pytorch_lightning.callbacks import ModelCheckpoint
pl.seed_everything(100)
import warnings
warnings.filterwarnings("ignore")
データセットのインポート
データセットのインポートは、データ駆動型プロジェクトの重要な初期ステップです。
df = pd.read_csv("/kaggle/input/queestion-answer-dataset-qa/train.csv")
df.columns
df = df[['context','question', 'text']]
print("Number of records: ", df.shape[0])
問題の定義
「文脈と質問に基づいて応答を生成できるモデルを作成する」という問題の定義です。
例:
文脈 = 「クラスタリングによって、類似したケースをグループ化することができます。たとえば、類似の患者を見つけたり、銀行業界での顧客セグメンテーションに使用したりすることができます。また、アソシエーション技術は、頻繁に共起するアイテムやイベントを見つけるために使用されます。たとえば、特定の顧客が通常一緒に購入する食料品のアイテムです。異常検出は、異常や普通ではないケースを発見するために使用されます。たとえば、クレジットカードの不正検出です。」
質問 = 「異常検出の例は何ですか?」
回答 = ????????????????????????????????
df["context"] = df["context"].str.lower()
df["question"] = df["question"].str.lower()
df["text"] = df["text"].str.lower()
df.head()
パラメータの初期化
- input length: トレーニング中、モデルに入力される単一の例の入力トークン(単語や文字など)の数を入力の長さと呼びます。例えば、文の中で次の単語を予測する言語モデルをトレーニングしている場合、入力の長さはフレーズの単語の数になります。
- Output length: トレーニング中、モデルは一度のサンプルで特定の数の出力トークン(単語や文字など)を生成することが期待されます。出力の長さはモデルが文内で予測する単語の数に対応します。
- Training batch size: トレーニング中、モデルはいくつかのサンプルを一度に処理します。トレーニングバッチサイズを32に設定すると、モデルは32のインスタンス(たとえば32のフレーズ)を同時に処理し、モデルの重みを更新します。
- Validating batch size: トレーニングバッチサイズと同様、このパラメータはモデルが検証フェーズで処理するインスタンスの数を示します。言い換えれば、モデルが保持しているデータのボリュームを示します。
- Epochs: エポックは完全なトレーニングデータセットの単一のループです。つまり、トレーニングデータセットが1000個のインスタンスを含み、トレーニングバッチサイズが32である場合、1つのエポックには32のトレーニングステップが必要です。モデルを10エポックトレーニングすると、1万のインスタンス(10 * 1000 = 10,000)が処理されます。
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
INPUT_MAX_LEN = 512 # 入力の長さ
OUT_MAX_LEN = 128 # 出力の長さ
TRAIN_BATCH_SIZE = 8 # トレーニングバッチサイズ
VALID_BATCH_SIZE = 2 # 検証バッチサイズ
EPOCHS = 5 # イテレーションの数
T5 Transformer
T5モデルは、シーケンシャルな入力データを効果的に処理するために設計されたTransformerアーキテクチャに基づいています。エンコーダーとデコーダーからなり、互いに接続された「レイヤー」のシーケンスを含んでいます。
エンコーダーとデコーダーレイヤーには、さまざまな「注意」メカニズムと「フィードフォワード」ネットワークが含まれています。注意メカニズムは、モデルが入力シーケンスのさまざまなセクションに別のタイミングで焦点を当てることを可能にします。同時に、フィードフォワードネットワークは、一連の重みとバイアスを使用して入力データを変更します。
T5モデルはまた、「自己注意」を採用しており、入力シーケンスの各要素が他のすべての要素に注意を払うことができます。これにより、モデルは入力データの単語やフレーズ間の関連性を認識することができます。これは、多くの自然言語処理のアプリケーションにとって重要です。
エンコーダーとデコーダーに加えて、T5モデルには「言語モデルヘッド」も含まれており、前の単語に基づいてシーケンスの次の単語を予測します。これは、翻訳やテキスト生成のジョブには必須であり、モデルが連続した自然な出力を提供する必要があります。
T5モデルは、シーケンシャルな入力の高効率かつ正確な処理のために設計された大規模かつ洗練されたニューラルネットワークを表しています。さまざまなテキストデータセットで広範にトレーニングを受け、幅広い自然言語処理タスクを能力を持って実行することができます。
T5Tokenizer
T5Tokenizerは、テキストをトークンのリストに変換するために使用されます。各トークンは単語や句読点を表します。トークナイザは、入力テキストに一意のトークンを挿入し、テキストの開始と終了を示し、異なるフレーズを区別します。
T5Tokenizerは、文字レベルと単語レベルのトークニゼーションの組み合わせと、SentencePieceトークナイザに類似したサブワードレベルのトークニゼーション戦略を採用しています。トレーニングデータの各文字または文字のシーケンスの出現頻度に基づいて入力テキストをサブワードに分割します。これにより、トレーニングデータには存在しないがテストデータに出現する語彙外(OOV)の用語に対して、トークナイザが対処できるようになります。
T5Tokenizerはさらに、文の開始と終了を示すための一意のトークンをテキストに挿入し、文を区切ります。たとえば、フレーズの開始と終了を示すために s > と / s > のトークンを追加し、パディングを示すために pad > というトークンを追加します。
MODEL_NAME = "t5-base"tokenizer = T5Tokenizer.from_pretrained(MODEL_NAME, model_max_length= INPUT_MAX_LEN)
print("eos_token: {} and id: {}".format(tokenizer.eos_token, tokenizer.eos_token_id)) # 終端のトークン(eos_token)print("unk_token: {} and id: {}".format(tokenizer.unk_token, tokenizer.eos_token_id)) # 未知のトークン(unk_token)print("pad_token: {} and id: {}".format(tokenizer.pad_token, tokenizer.eos_token_id)) # パディングのトークン(pad_token)
データセットの準備
PyTorchでの取り扱いをする際には、通常、データをモデルで使用するためにデータセットクラスを使用して準備します。データセットクラスは、データをディスクからロードし、トークナイズや数値化などの必要な準備手順を実行する責任を持ちます。また、インデックスによってデータセットから単一のアイテムを取得するためにgetitem関数を実装する必要があります。
initメソッドはデータセットにテキストリスト、ラベルリスト、およびトークナイザを追加します。len関数はデータセット内のサンプル数を返します。getitem関数はインデックスによってデータセットから単一のアイテムを返します。インデックスidxを受け取り、トークナイズされた入力とラベルを出力します。
また、パディングや切り捨てなど、さまざまな前処理ステップを含めることも一般的です。また、ラベルをテンソルに変換することもできます。
class T5Dataset: def __init__(self, context, question, target): self.context = context self.question = question self.target = target self.tokenizer = tokenizer self.input_max_len = INPUT_MAX_LEN self.out_max_len = OUT_MAX_LEN def __len__(self): return len(self.context) def __getitem__(self, item): context = str(self.context[item]) context = " ".join(context.split()) question = str(self.question[item]) question = " ".join(question.split()) target = str(self.target[item]) target = " ".join(target.split()) inputs_encoding = self.tokenizer( context, question, add_special_tokens=True, max_length=self.input_max_len, padding = 'max_length', truncation='only_first', return_attention_mask=True, return_tensors="pt" ) output_encoding = self.tokenizer( target, None, add_special_tokens=True, max_length=self.out_max_len, padding = 'max_length', truncation= True, return_attention_mask=True, return_tensors="pt" ) inputs_ids = inputs_encoding["input_ids"].flatten() attention_mask = inputs_encoding["attention_mask"].flatten() labels = output_encoding["input_ids"] labels[labels == 0] = -100 # T5ドキュメンテーションに従って labels = labels.flatten() out = { "context": context, "question": question, "answer": target, "inputs_ids": inputs_ids, "attention_mask": attention_mask, "targets": labels } return out
DataLoader
DataLoaderクラスは、データを並列にロードし、バッチ処理することで、メモリに格納することができないほど大規模なデータセットと作業することが可能です。DataLoaderクラスは、データをロードするためのデータセットクラスと組み合わせることで使用します。
DataLoaderは、データセットを繰り返し処理し、モデルに対してトレーニングや評価のためのデータバッチを返します。DataLoaderクラスでは、バッチサイズ、ワーカースレッドの数、各エポック前にデータをシャッフルするかどうかなど、データのロードと前処理を制御するためのさまざまなパラメータが提供されています。
class T5DatasetModule(pl.LightningDataModule):
def __init__(self, df_train, df_valid):
super().__init__()
self.df_train = df_train
self.df_valid = df_valid
self.tokenizer = tokenizer
self.input_max_len = INPUT_MAX_LEN
self.out_max_len = OUT_MAX_LEN
def setup(self, stage=None):
self.train_dataset = T5Dataset(
context=self.df_train.context.values,
question=self.df_train.question.values,
target=self.df_train.text.values
)
self.valid_dataset = T5Dataset(
context=self.df_valid.context.values,
question=self.df_valid.question.values,
target=self.df_valid.text.values
)
def train_dataloader(self):
return torch.utils.data.DataLoader(
self.train_dataset,
batch_size=TRAIN_BATCH_SIZE,
shuffle=True,
num_workers=4
)
def val_dataloader(self):
return torch.utils.data.DataLoader(
self.valid_dataset,
batch_size=VALID_BATCH_SIZE,
num_workers=1
)
モデルの構築
PyTorchでトランスフォーマーモデルを作成する際には、通常、torch.nn.Moduleから派生した新しいクラスを作成することから始めます。このクラスは、モデルのアーキテクチャを定義します。これには、レイヤーやフォワード関数などが含まれます。init関数では、モデルのアーキテクチャを定義し、モデルの異なるレベルをインスタンス化し、クラス属性として割り当てることが一般的です。
forwardメソッドは、データをモデルを通して順方向に渡すための担当です。このメソッドは、入力データを受け取り、モデルのレイヤーを適用して出力を作成します。forwardメソッドは、入力をレイヤーのシーケンスを通して渡し、結果を返すなど、モデルのロジックを実装する必要があります。
init関数では、埋め込みレイヤー、トランスフォーマーレイヤー、完全に接続されたレイヤーを作成し、これらをクラス属性として割り当てます。forwardメソッドは、入力データxを受け取り、指定されたステージを通じて処理し、結果を返します。トランスフォーマーモデルをトレーニングする際には、トレーニングプロセスは通常、トレーニングとバリデーションの2つのステージで行われます。
training_stepメソッドは、単一のトレーニングステップを実行する理論を指定します。一般的には、以下のものが含まれます:
- モデルを通した順方向パス
- 損失の計算
- 勾配の計算
- モデルのパラメータの更新
val_stepメソッドは、バリデーションセットでモデルを評価するために使用されます。通常は、以下のものが含まれます:
- モデルを通した順方向パス
- 評価メトリクスの計算
class T5Model(pl.LightningModule):
def __init__(self):
super().__init__()
self.model = T5ForConditionalGeneration.from_pretrained(MODEL_NAME, return_dict=True)
def forward(self, input_ids, attention_mask, labels=None):
output = self.model(
input_ids=input_ids,
attention_mask=attention_mask,
labels=labels
)
return output.loss, output.logits
def training_step(self, batch, batch_idx):
input_ids = batch["inputs_ids"]
attention_mask = batch["attention_mask"]
labels = batch["targets"]
loss, outputs = self(input_ids, attention_mask, labels)
self.log("train_loss", loss, prog_bar=True, logger=True)
return loss
def validation_step(self, batch, batch_idx):
input_ids = batch["inputs_ids"]
attention_mask = batch["attention_mask"]
labels = batch["targets"]
loss, outputs = self(input_ids, attention_mask, labels)
self.log("val_loss", loss, prog_bar=True, logger=True)
return loss
def configure_optimizers(self):
return AdamW(self.parameters(), lr=0.0001)
モデルのトレーニング
データセットをバッチごとに繰り返し処理し、入力をモデルに送り、計算された勾配と最適化基準セットに基づいてモデルのパラメータを変更することは、トランスフォーマーモデルをトレーニングする際の一般的な手順です。
def run():
df_train, df_valid = train_test_split(
df[0:10000], test_size=0.2, random_state=101
)
df_train = df_train.fillna("none")
df_valid = df_valid.fillna("none")
df_train['context'] = df_train['context'].apply(lambda x: " ".join(x.split()))
df_valid['context'] = df_valid['context'].apply(lambda x: " ".join(x.split()))
df_train['text'] = df_train['text'].apply(lambda x: " ".join(x.split()))
df_valid['text'] = df_valid['text'].apply(lambda x: " ".join(x.split()))
df_train['question'] = df_train['question'].apply(lambda x: " ".join(x.split()))
df_valid['question'] = df_valid['question'].apply(lambda x: " ".join(x.split()))
df_train = df_train.reset_index(drop=True)
df_valid = df_valid.reset_index(drop=True)
dataModule = T5DatasetModule(df_train, df_valid)
dataModule.setup()
device = DEVICE
models = T5Model()
models.to(device)
checkpoint_callback = ModelCheckpoint(
dirpath="/kaggle/working",
filename="best_checkpoint",
save_top_k=2,
verbose=True,
monitor="val_loss",
mode="min"
)
trainer = pl.Trainer(
callbacks=checkpoint_callback,
max_epochs=EPOCHS,
gpus=1,
accelerator="gpu"
)
trainer.fit(models, dataModule)
run()
モデル予測
T5のようなファインチューニングされたNLPモデルを使用して、新しい入力で予測するには、次の手順に従うことができます:
- 新しい入力の前処理:新しい入力テキストをトークン化して前処理し、トレーニングデータに適用した前処理と一致するようにします。モデルが期待する正しい形式であることを確認します。
- 推論のためのファインチューニングされたモデルの使用:以前にトレーニングしたまたはチェックポイントから読み込んだT5のファインチューニングされたモデルをロードします。
- 予測の生成:前処理された新しい入力をモデルに渡して予測します。T5の場合、generateメソッドを使用して応答を生成できます。
train_model = T5Model.load_from_checkpoint("/kaggle/working/best_checkpoint-v1.ckpt")train_model.freeze()def generate_question(context, question): inputs_encoding = tokenizer( context, question, add_special_tokens=True, max_length= INPUT_MAX_LEN, padding = 'max_length', truncation='only_first', return_attention_mask=True, return_tensors="pt" ) generate_ids = train_model.model.generate( input_ids = inputs_encoding["input_ids"], attention_mask = inputs_encoding["attention_mask"], max_length = INPUT_MAX_LEN, num_beams = 4, num_return_sequences = 1, no_repeat_ngram_size=2, early_stopping=True, ) preds = [ tokenizer.decode(gen_id, skip_special_tokens=True, clean_up_tokenization_spaces=True) for gen_id in generate_ids ] return "".join(preds)
予測
新しい入力を使用して、ファインチューニングされたT5モデルによる予測を生成しましょう:
context = “似たようなケースのクラスタリング、たとえば、類似した患者を見つけたり、銀行業界の顧客セグメンテーションに使用したりする。頻繁に共起するアイテムやイベントを見つけるために連想技術を使用する、たとえば、特定の顧客が一緒に購入することが多い食料品のアイテム。異常検出を使用して、異常で通常と異なるケースを発見する、たとえば、クレジットカードの不正検出。”
que = “異常検出の例は何ですか?”
print(generate_question(context, que))
context = "ターゲットがカテゴリ的な場合には分類が、ターゲット変数が連続的な場合には回帰が使用される。分類と回帰は、教師あり機械学習アルゴリズムのカテゴリに属する。"que = "いつ分類が使用されますか?"print(generate_question(context, que))
結論
この記事では、質問応答のタスクに対して自然言語処理(NLP)モデルであるT5モデルをファインチューニングするための旅に乗り出しました。このプロセスを通じて、NLPモデルの開発と展開のさまざまな側面について取り上げました。
主なポイント:
- エンコーダーデコーダー構造と自己注意機構の基盤となる能力を探究しました。
- ハイパーパラメータのチューニングは、モデルのパフォーマンスを最適化するための重要なスキルです。
- 学習率、バッチサイズ、モデルサイズの実験を行うことで、効果的にモデルをファインチューニングしました。
- トークン化、パディング、生のテキストデータをモデルの入力形式に適した形に変換することに熟達しました。
- 事前学習済みの重みのロード、モデルレイヤーの修正、特定のタスクに適応させるためのファインチューニングに深入りしました。
- データのクリーニングと構造化方法を学び、トレーニングセットと検証セットに分割しました。
- 入力コンテキストと質問に基づいて応答や回答を生成する方法を示し、実世界での有用性を紹介しました。
よくある質問
この記事に表示されるメディアはAnalytics Vidhyaが所有しておらず、著者の裁量で使用されています。
We will continue to update VoAGI; if you have any questions or suggestions, please contact us!
Was this article helpful?
93 out of 132 found this helpful
Related articles