Google Colab で、Base model を Instruct model へとチューニングする

May 19, 2024, 2:40 PM
さて、今回は、ベースモデルをインストラクトモデル(指示モデル)にチューニングする方法について学んでいきます。
目的は
https://microai.jp/blog/cfe92497-c2a6-4c44-990a-0954c0a96984
でLlama 3 Youko 8Bをollama用のggufに変換しましたが、それをインストラクトモデルに変換することでしたが、結論、Google Colab の A100 (VRAM:40G)ではメモリ不足で実行できませんでいた。
そのため、今回は、極めて小さなモデルである、cyberagent/open-calm-small をチューニングします。

参考記事

npaka さんの note 
https://note.com/npaka/n/nc7a4c20f98f8
をかなり参考にさせていただきました。私のこのブログよりもわかりやすいかと思いますので、そちらを参考にされる方が早いかもしれません。
私のブログはより素人目線で書いてみます。

出来上がったノート

instruction_tuning.ipynb (12.6 kB) 
こちらです。
ご自身の Google Colab でインポート(アップロード)してお使いください。

全体の流れ

  • モデル・トークナイザー設定・質問設定
  • 必要なライブラリのインストール
  • トークナイザーとモデルの準備
  • チューニング前の状態を確認 (質問に、回答ではなく続きを書いてしまうような文章がでてしまうことを確認する)
  • データセットの読み込み読み込み
  • データセットをinputが空の要素のみ5000個でフィルタリング
  • 終端・パディングトークンの確認
  • プロンプトを作成する関数宣言
  • 学習の実行・モデル保存
  • モデルの準備
  • プロンプトの準備&推論の実行 (質問に、回答している形式になっていることを確認する)
このような流れです。

モデル・トークナイザー設定・質問設定


基本は、初期値のまま進めてください。
question だけ、変えたいときは変えてみてください。

必要なライブラリのインストール

!pip install transformers accelerators
!pip install trl peft datasets
  • transformers
  • accelerators
  • trl
  • peft
  • datasets
を使用するため、インストールしています。

トークナイザーとモデルの準備

from transformers import AutoModelForCausalLM, AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(
modelname
)
model = AutoModelForCausalLM.from_pretrained(
tokenizername,
device_map="auto"
)
トークナイザーとモデルを読み込みます

チューニング前の状態を確認 (質問に、回答ではなく続きを書いてしまうような文章がでてしまうことを確認する)

チューニングする前は、ベースモデルですので、基本的にはユーザーが入力したテキストの続きを書こうとします。
「日本の首都は」と入力された場合は「日本の首都は東京で、人口は◯◯人、世界でも有数の・・・」こんな形です。
ただし、今回使用したモデル、cyberagent/open-calm-small はその名の通り、極めて小さいモデルですので、
### Answer: 正解
### Answer: 日本は、2020年7月に東京オリンピック・パラリンピックが開催される。開催都市には、東京と埼玉が含まれ、オリンピックの閉会式が行われる日でもある。
### Answer: 正解
### Answer: 答え
### Answer: 東京
このように、ある種、意味不明な回答をします。
故に、ここでは、質問に対して、回答形式で返ってこないことだけ確認してください。

データセットの読み込み読み込み

from datasets import load_dataset
dataset = load_dataset("kunishou/databricks-dolly-15k-ja")
https://huggingface.co/datasets/kunishou/databricks-dolly-15k-ja
Hugging Face でkunishou さんが公開してくださっているデータセットを読み込みます。

データセットをinputが空の要素のみ5000個でフィルタリング

train_dataset = dataset["train"].filter(lambda data: data["input"] == "").select(range(5000))
タイトルのままですが、今回のチューニングで使用しやすいデータを5000個読み込みます。

終端・パディングトークンの確認

print(f"eos_token_id: {tokenizer.eos_token_id}")
print(f"eos_token: {tokenizer.eos_token}")
print(f"pad_token: {tokenizer.pad_token}")
print(f"pad_token_id: {tokenizer.pad_token_id}")
終焉トークンと、パッディングトークンを確認します。
パディングトークンが None の場合は、別途パッディングトークンを設定して上げる必要がありますが、今回のモデルはパッディングトークンを含むため不要です。

プロンプトを作成する関数宣言

def formatting_prompts_func(example):
output_texts = []
for i in range(len(example['instruction'])):
text = f"### Question: {example['instruction'][i]}\n ### Answer: {example['output'][i]}{tokenizer.eos_token}"
output_texts.append(text)
return output_texts
先程確認した終焉トークンを用いたプロンプト作成用の関数を宣言しておきます。

学習の実行・モデル保存

from trl import SFTTrainer

# 学習の実行
trainer = SFTTrainer(
model=model,
tokenizer=tokenizer,
train_dataset=train_dataset,
max_seq_length=512,
formatting_func=formatting_prompts_func,
)
trainer.train()

# モデルの保存
trainer.save_model("output")
SFTTrainer を使用して、学習を実行し、モデルとしてoutputフォルダに出力します。

モデルの準備

tuned_model = AutoModelForCausalLM.from_pretrained(
"./output",
device_map="auto"
)
上記で出力したチューニングした新しいモデルを読み込みます。

プロンプトの準備&推論の実行 (質問に、回答している形式になっていることを確認する)

import torch

# プロンプトの準備
prompt = f"### User: {question}\n ### Answer:"

# 推論の実行
for i in range(5):
inputs = tokenizer(prompt, return_tensors="pt").to(tuned_model.device)
with torch.no_grad():
tokens = tuned_model.generate(
**inputs,
max_new_tokens=64,
do_sample=True,
temperature=0.7,
top_p=0.9,
repetition_penalty=1.05,
pad_token_id=tokenizer.pad_token_id,
)
output = tokenizer.decode(tokens[0], skip_special_tokens=True)
print(output)
print("----")
チューニングした新しいモデルで同じ質問をします。

出力結果

### User: 日本の首都は
### Answer: シンガポール
----
### User: 日本の首都は
### Answer: ニューヨーク、ロサンゼルス、サンフランシスコ、シアトル
----
### User: 日本の首都は
### Answer: 茨城県
----
### User: 日本の首都は
### Answer: オーストラリア
----
### User: 日本の首都は
### Answer: シンガポール、タイ、オランダ、ドイツ、スイス、スペイン、イギリス
----
このように表示され、以前に行ったときとは違い、回答をしようとしていることがわかります。
これで Instruct model の完成です🍺

用語の説明

Google Colab

Googleが提供するクラウドベースのJupyterノートブック環境です。ユーザーはブラウザ上でインタラクティブにPythonコードを記述し、実行することができます。特に機械学習やデータサイエンスのプロジェクトに適しており、無料でGPUやTPUを利用できる点が大きな特徴です。

トークナイザー (Tokenizer)

自然言語処理 (NLP) の分野において、テキストデータを小さな単位に分割するプロセスやそのためのツールを指します。これらの小さな単位は「トークン」と呼ばれ、通常は単語、文、またはサブワードの形を取ります。

EOS Token (End of Sequence Token)

自然言語処理 (NLP) や機械翻訳、テキスト生成モデルなどにおいて、テキストシーケンスの終わりを示すために使用される特別なトークンです。EOSトークンは、モデルに対して入力や生成されたテキストの終わりを明確に伝える役割を果たします。

PAD Token (Padding Token)

自然言語処理 (NLP) において、バッチ処理や固定長のシーケンスを扱う際にシーケンスの長さを揃えるために使用される特別なトークンです。PADトークンは、短いシーケンスを他のシーケンスと同じ長さに揃えるために挿入されるもので、通常はモデルが無視するように設計されています。

SFTTrainer (Supervised Fine-Tuning Trainer)

教師あり学習 (Supervised Learning) の手法を用いて、大規模言語モデル (LLM) の微調整 (Fine-Tuning) を行うためのツールやフレームワークを指します。このプロセスでは、既存の事前学習されたモデルを特定のタスクやドメインに適応させるために、ラベル付きデータを使用してモデルを再トレーニングします。
HuggingFace Model (Llama 3 Youko 8B) を GGUF に変換して、ollama で実行する
Jetson Orin Nano 16G に pyenv, pipenv をインストールする