日本語

🥳 はじめに

ようこそ!この記事では、いくつかの人気のあるファインチューニング戦略について詳しく説明します:FFT(Full-Fine-Tuning)、SFT(Supervised Fine Tune)、そしてQloraそれぞれの戦略には独自の特徴があり、異なるシナリオやニーズに適用できます。これらの戦略について一緒に探求し、それらがどのように機能するのか、そして実践的なアプリケーションでどのように選択し使用するのかを理解しましょう。始めましょう!

Llama1が導入されて以来、オープンソースモデルのコミュニティは繁栄し始めました。AlpacaVicunaWizardLMから百川、千問、ChatGLMまで、オープンソースは個人や企業により多くのアイデアをもたらし、多様性を加えることができました。Llama2のリリースにより、さらに優れたパフォーマンス(相対的に)とより緩やかなライセンスが、さらなるイノベーションの機会を提供しました(ただし、安全性の制限はやや理解しにくいものです)。

モデルのファインチューニングやLangchainなどのツールの使用は、パーソナライズされたモデルと本番環境のデプロイメントにおいて不可欠なステップとなっています。

事前学習は始まりに過ぎません。モデルを特定のタスクで最適に機能させるためには、ファインチューニングが特に重要になります。これは事前学習済みモデルを対象タスクに特化したデータでさらにトレーニングすることで達成されます。例えば、Llama2はテキスト生成で優れたパフォーマンスを示しますが、特定の質問応答タスクでより良いパフォーマンスを発揮させるためには、ファインチューニングが不可欠です—そのためLlama2のチャットバージョンが存在します(もちろん、破滅的忘却のような問題もパフォーマンスに影響を与えます)。

⚠️ 注意: 私は現在、空き時間に研究を行っており、様々なオンラインチュートリアルやビデオを参照しています(かなりの時間とリソースを費やしましたが、正直なところ結果はそれほど良くありません🫠)。説明の中で間違いを避けようとしていますが、知識の理解や表現にはまだ多くのギャップがあります。もし何か見つけた場合は、コメントまたはメールで指摘してください。ありがとうございます🙏。

⚠️ 注意: ノートパソコンでArcブラウザを使用してこの記事にアクセスしている場合、時的にサイドバーを非表示にすることをお勧めします。そうしないと、画面幅が狭くて不快になる可能性があります。

🤖 背景情報

この記事の定義によると、大規模言語モデル(LLM)は人間の知能を模倣できる人工知能の一種です。これらは統計モデルを使用して膨大な量のデータを分析し、単語やフレーズ間のパターンと関連性を学習します。これにより、学術論文や記事など、特定の著者やジャンルのスタイルに似た新しいコンテンツを生成することができます。

まず、言語モデルはテキストシーケンスにおける次の単語の出現確率を予測するために使用されます。これらのモデルはテキストデータのパターンを学習し、特定のスタイルに適応するようにトレーニングできます。例えば、シェイクスピアや現代のポップカルチャーの言語スタイルを模倣し、それに基づいてテキストを続けることができます。

(全結合ニューラルネットワークは基本的だが強力なニューラルネットワーク構で、分類、回帰、その他の問題によく使用されます。しかし、シーケンスデータ、特に長いシーケンスを扱うには最も効果的ではありません。)

これにより、シーケンスデータ、特にテキストデータを扱うために特別に設計されたTransformerアーキテクチャが登場します。全結合ニューラルネットワークと比較して、Transformerは長距離依存関係と並列計算の処理に明確な利点があります。

簡単な説明
パーティーを主催していて、参加者全員(単語やその他のデータポイント)が情報を集めるために互いに交流したいと想像してください。しかし、このパーティーにはルールがあります:複数の人と同時に話すことはできず、一対一の会話のみが許可されています。これはかなり非効率的ですよね?これが従来のRNN(再帰型ニューラルネットワーク)とLSTM(長短期記憶ネットワーク)の問題です。

そこにTransformerが登場し、「並ぶ必要はありません。好きな人と自由に話してください!」と言います。これにより、情報が全員の間で急速に流れ、各自が全体の状況を包括的に理解できるようになります。これがいわゆる「アテンションメカニズム」で、各データポイントが他のすべてのデータポイントを迅速に考慮できるようになります。

しかしTransformerはそれ以上のことを行います。「マルチヘッド」アテンションを導入します。全員が「通常の言語」だけでなく、同時に「スラング」、「科学用語」、その他の「言語」でコミュニケーションを取れることを想像してください。このように、各人が同じことを複数の角度から理解し、より豊かな情報を集めることができます。

つまり、Transformerは優れたパーティープランナーのようなもので、全員が素早く、効率的に、そして包括的にコミュニケーションを取れるようにし、パーティー全体(またはデータ処理タスク)をより成功させるのです!

🫠 ファインチューニングの基本概念

前述したように、ファインチューニングの主な目的は、テキスト分類、感情分析、質問応答などの特定のタスクにおいてモデルをより熟練させることです。ファインチューニング、これらの特定のタスクでモデルのパフォーマンスを最適化することを目指しています。

Screenshot 2023-08-26 at 12.04.45 PM.webp

出典: microsoftのオリジナルコンテンツ

以下はファインチューニングに関する基本的な概念の簡単な説明です:

基本概念 簡単な説明
事前学習モデル すでに「学習」済みで、多くの基礎的なことを知っているモデル
ターゲットタスク モデルに実行させたい特定の「仕事」や「タスク」
転移学習 あるタスクで学んだ知識を別のタスクに適用すること
データセット 特定のタスクのための「練習問題」セット、モデルをそのタスクでより良くするために使用
学習率 モデルに新しいタスクをどれくらい速く「学習」させるかを指示
オプティマイザー モデルがより良く学習するのを助ける「コーチ」
計算リソース 「学習」に必要なコンピューターと時間
評価指標 試験の点数のように、モデルが新しいタスクでどれだけ良く実行できているかを評価する方法
正則化 モデルが「詰め込み学習」を避け、学んだことをより柔軟に適用できるようにする

この記事では3つのファインチューニング方法を紹介します(シンプルなほど良い)(RLHFは現在記事に含まれていません)。

FFT(Full-Fine-Tuning)

FFT、つまりFull-Fine-Tuningは、広く適用されているモデルのファインチューニング方法です。この方法では、モデルの最後の数層だけでなく(通常は分類器層のみをファインチューニングする戦略で行われる)、モデルのすべての層がファインチューニングされます。これは、入力層から出力層まで、モデルのアーキテクチャ全体の重みが更新されることを意味します。

主な特徴

  1. 包括性: モデルのすべての層がファインチューニングされ、通常はより良いモデルパフォーマンスにつながります。

  2. 柔軟性: モデルのすべての部分が学習するため、この方法は一般的に新しいタスクの特徴により適応しやすくなります。

  3. 計算負荷: モデル全体を更新する必要があるため、Full-fine-tuningは一般的により多くの計算リソースと時間を必要とします。

適用シナリオ

  • ターゲットタスクが事前学習タスクと大きく異なる場合、full-fine-tuningは通常より効果的です。
  • 比較的豊富なラベル付きデータ計算リソースがある場合。

SFT(Supervised-Fine-Tune)

SFT、つまりSupervised Fine Tuneは、教師あり学習環境で適用されるモデルのファインチューニング方法です。FFT(Full-Fine-Tuning)とは異なり、SFTは通常モデル全体ではなく、モデルの一部の層のみをファインチューニングします。これにより、タスク固有の特徴により焦点を当てることができ、通常より少ない計算リソースで済みます。

主な特徴

  1. 目標指向: ファインチューニングプロセスは、モデルを特定のタスクに密接に合わせることに焦点を当てています。

  2. 計算効率: モデルの一部の層のみをファインチューニングするため、SFTは一般的にFFTよりも計算効率が良いです。

  3. データ依存: 教師あり学習であるため、ファインチューニングには比較的高品質なラベル付きデータが必要です。

適用シナリオ

  • ターゲットタスクが事前学習済みモデルと密接に関連している場合、より少ない層のファインチューニングで十分です。
  • 計リソースが限られている場合や、より迅速に結果を得たい場合。

(Q)lora(Low-Rank Adaptation)

LoRA(Layer-wise Recurrent Mechanism for Adaptation)は、Transformerなどの大規模な事前学習済みモデルをファインチューニングするための新しい方法です。この方法は、事前学習済みモデルの各層に少数の適応可能なパラメータを追加することで、ファインチューニングのパフォーマンスを向上させます。これらの追加パラメータは層ごとの再帰メカニズムを導入し、ファインチューニングプロセス中にモデルがより効果的に新しいタスクに適応できるようにします。

主な特徴

  1. パラメータ効率: LoRAは少数のパラメータのみを追加し、計算の複雑さとストレージ要件を大幅に削減します。

  2. 強力な適応性: 各層に再帰メカニズムを追加することで、LoRAはモデルがより良く新しいタスクに適応できるようにします。

  3. 良好な互換性: LoRAは通常、既存の事前学習済みモデルとシームレスに統合でき、再トレーニングを必要としません

適用シナリオ

  • 限られた計算リソースとストレージリソースでファインチューニングを行う必要がある場合。
  • 事前学習済みモデルの元の構造に影響を与えることなく、ファインチューニングタスクのパフォーマンスを向上させたい場合。

パラメータ効率の良いファインチューニング(PEFT)方法により、より少ない計算リソースとストレージリソースで、既に学習済みの大規模言語モデル(PLM)を特定のタスクに合わせて調整することができます。通常、これらの大規模モデルの調整は時間がかかりコストがかかりますが、PEFTはパラメータの小さなサブセットのみを調整することで、プロセスをより便利で経済的にします。LoRAはPEFTの中の1つの方法です。

QLoRA(Quantized Low-Rank Adapters)には、量子化を表す「Q」が含まれています。量子化は、浮動小数点数を低ビット整数に変換することで、モデルのサイズとメモリ使用量を削減する技術です。例えば、4ビット量子化は浮動小数点数を0から15の範囲の整数にマッピングします。簡単に言えば、これは消費者向けGPUでも扱えることを意味しますが、私が今まで達成した結果はあまり良くありません。

出力活性化の向上は、重み行列AとBで構成される低ランクアダプター(右)から得られ、元の(凍結された)事前学習済みの重み(左)と比較されます。

出典: huggingfaceのオリジナルコンテンツ

詳細については、https://huggingface.co/blog/4bit-transformers-bitsandbytes を参照してください。

💬 ファインチューニング方法の詳細な説明

このセクションでは、Meta’s Llama2をベースにしたVicuna 7b 1.5バージョンモデルをFull-Fine-TuningSFT(Supervised-Fine-Tune)、**QLoRA(Quantized Low-Rank Adapters)**を使用してファインチューニングする詳細な説明を提供します。Google Colab(Pro)でファインチューニングが難しいFull-Fine-Tuningを除き、他の方法はColabでファインチューニングできます。もちろん、SFT方法については、クラウドサービスプロバイダーの方がコスト効率が良い傾向にあるため、推奨されます。内容の大部分はオンラインチュートリアルと公式ドキュメントを参照しています。オリジナルの記事は参考文献セクションに表示されます。改めて感謝いたします。

1. Full-Fine-Tuning

ここでは公式のファインチューニング方法を使用します。

  1. リポジトリのクローン
1
2
git clone https://github.com/lm-sys/FastChat.git
cd FastChat
  1. 必要なパッケージのインストール
1
2
3
pip3 install --upgrade pip  # PEP 660サポートを有効化
pip3 install -e ".[model_worker,webui]"
pip3 install -e ".[train]"

⚠️ 注意: Flash-Attentionをインストールする必要がありますが、これはpip3 install -e “.[train]”でカバーされているはずです。Ninjaもインストールされ、ビルドプロセスが高速化されます。Ninjaがないと、複数のCPUコアを使用しないため、コンパイルに時間がかかる可能性があります(2時間)。Ninjaを使用すると、64コアマシンでのコンパイルはわずか3-5分で済みます(64コアマシンがある場合)。

FlashAttention-2は現在以下をサポートしています:

  • Ampere、Ada、またはHopper GPU(例:A100、RTX 3090、RTX 4090、H100)。
  • データ型fp16とbf16(bf16はAmpere、Ada、またはHopper GPU必要)。
  • 256までのすべてのヘッドディメンション。ヘッドディメンションが192を超える場合、逆伝播にはA100/A800またはH100/H800 GPUが必要です。

Screenshot 2023-08-15 at 00.20.56.webp

  1. データセットを準備してトレーニングを開始
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
torchrun --nproc_per_node=4 --master_port=20001 fastchat/train/train_mem.py \
--model_name_or_path lmsys/vicuna-7b-v1.5-16k \
--data_path [your dataset path] \
--bf16 False \
--output_dir output_vicuna \
--num_train_epochs 3 \
--per_device_train_batch_size 4 \
--per_device_eval_batch_size 4 \
--gradient_accumulation_steps 4 \
--evaluation_strategy "no" \
--save_strategy "steps" \
--save_steps 1200 \
--save_total_limit 10 \
--learning_rate 2e-5 \
--weight_decay 0. \
--warmup_ratio 0.03 \
--lr_scheduler_type "cosine" \
--logging_steps 1 \
--fsdp "full_shard auto_wrap" \
--fsdp_transformer_layer_cls_to_wrap 'LlamaDecoderLayer' \
--tf32 True \
--model_max_length 1024 \
--gradient_checkpointing True \
--lazy_preprocess True

上記の方法は分散トレーニングを使用するため、2、4、または8台のA100(40GまたはRAM 80G)ど、複数のGPUが必要になる場合があります。上記は単なる例です。具体的な状況に応じて修正してください。


以下は様々なパラメータの説明です:

  • --model_name_or_path: 使用する事前学習済みモデルのパス
  • --data_path: トレーニングデータのパス
  • --bf16: bfloat16を使用するかどうか
  • --output_dir: モデルの出力ディレクトリ
  • --num_train_epochs: トレーニングのエポック数
  • --per_device_train_batch_size: デバイスごとのトレーニングバッチサイズ
  • --gradient_accumulation_steps: 勾配蓄積ステップ数
  • --learning_rate: 学習率
  • --weight_decay: 重み減衰
  • --warmup_ratio: ウォームアップの比率
  • --lr_scheduler_type: 学習率スケジューラーの種類
  • --model_max_length: 最大シーケンス長
  • --gradient_checkpointing: 勾配チェックポイントを使用するかどうか

Screenshot 2023-08-15 at 20.47.37.webp

⚠️ 注意: トレーニング前に、トレーニング状況を監視したい場合は、Wandbを使用できます。トークンが必要になります。

⚠️ 注意: データセットはVicunaのフォーマットに従う必要がります。以下は公式の例フォーマットです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[
{
"id": "identity_0",
"conversations": [
{
"from": "human",
"value": "あなたは誰ですか?"
},
{
"from": "gpt",
"value": "私はVicunaです。Large Model Systems Organization(LMSYS)の研究者によってトレーニングされた言語モデルです。"
},
{
"from": "human",
"value": "何ができますか?"
}
]
}
]

2. SFT(Supervised Fine-Tuning)

ここでは、TRLを使用してSFTを実装します。TRLは、Hugging Faceが開発したTransformerモデルの強化学習のためのライブラリです。

  1. 必要なパッケージのインストール
1
2
pip install -q -U trl transformers accelerate git+https://github.com/huggingface/peft.git
pip install -q datasets bitsandbytes einops wandb
  1. データセットの準備とトレーニングの開始
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import os
import torch
from datasets import load_dataset
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
TrainingArguments,
pipeline,
logging,
)
from peft import LoraConfig, PeftModel
from trl import SFTTrainer

# モデルの設定
model_name = "lmsys/vicuna-7b-v1.5-16k"

# データセットの読み込み
data = load_dataset("json", data_files="your_dataset.json")

# トークナイザーの設定
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"

# モデルの設定
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.float16,
device_map="auto",
)

# トレーニング引数の設定
training_arguments = TrainingArguments(
output_dir="./results",
num_train_epochs=3,
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
optim="paged_adamw_32bit",
save_steps=100,
logging_steps=10,
learning_rate=2e-4,
weight_decay=0.001,
fp16=True,
bf16=False,
max_grad_norm=0.3,
max_steps=-1,
warmup_ratio=0.03,
group_by_length=True,
lr_scheduler_type="constant",
)

# トレーナーの設定
trainer = SFTTrainer(
model=model,
train_dataset=data["train"],
tokenizer=tokenizer,
args=training_arguments,
max_seq_length=None,
dataset_text_field="text",
)

# トレーニングの開始
trainer.train()

# モデルの保存
trainer.model.save_pretrained("sft_vicuna_model")

⚠️ 注意: 上記のコードは単なる例です。実際の状況に応じて修正してください。


以下は様々なパラメータの説明です:

  • model_name: 使用する事前学習済みモデルの名前
  • data_files: トレーニングデータのパス
  • output_dir: モデルの出力ディレクトリ
  • num_train_epochs: トレーニングのエポック数
  • per_device_train_batch_size: デバイスごとのトレーニングバッチサイズ
  • gradient_accumulation_steps: 勾配蓄積ステップ数
  • learning_rate: 学習率
  • weight_decay: 重み減衰
  • warmup_ratio: ウォームアップの比率
  • lr_scheduler_type: 学習率スケジューラーの種類
  • max_seq_length: 最大シーケンス長

Screenshot 2023-08-15 at 20.47.37.webp

⚠️ 注意: トレーニング前に、トレーニング状況を監視したい場合は、Wandbを使用できます。トークンが必要になります。

3. QLoRA(Quantized Low-Rank Adaptation)

ここでは、PEFTを使用してQLoRAを実装します。PEFTは、Hugging Faceが開発したパラメータ効率の良いファインチューニングのためのライブラリです。

  1. 必要なパッケージのインストール
1
2
pip install -q -U trl transformers accelerate git+https://github.com/huggingface/peft.git
pip install -q datasets bitsandbytes einops wandb
  1. データセットの準備とトレーニングの開始
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import os
import torch
from datasets import load_dataset
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
TrainingArguments,
pipeline,
logging,
)
from peft import LoraConfig, PeftModel
from trl import SFTTrainer

# モデルの設定
model_name = "lmsys/vicuna-7b-v1.5-16k"

# データセットの読み込み
data = load_dataset("json", data_files="your_dataset.json")

# トークナイザーの設定
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"

# BitsAndBytesの設定
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_use_double_quant=False,
)

# モデルの設定
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config,
device_map="auto",
trust_remote_code=True,
)
model.config.use_cache = False

# LoRAの設定
peft_config = LoraConfig(
lora_alpha=16,
lora_dropout=0.1,
r=64,
bias="none",
task_type="CAUSAL_LM",
)

# トレーニング引数の設定
training_arguments = TrainingArguments(
output_dir="./results",
num_train_epochs=3,
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
optim="paged_adamw_32bit",
save_steps=100,
logging_steps=10,
learning_rate=2e-4,
weight_decay=0.001,
fp16=True,
bf16=False,
max_grad_norm=0.3,
max_steps=-1,
warmup_ratio=0.03,
group_by_length=True,
lr_scheduler_type="constant",
)

# トレーナーの設定
trainer = SFTTrainer(
model=model,
train_dataset=data["train"],
peft_config=peft_config,
tokenizer=tokenizer,
args=training_arguments,
max_seq_length=None,
dataset_text_field="text",
)

# トレーニングの開始
trainer.train()

# モデルの保存
trainer.model.save_pretrained("qlora_vicuna_model")

⚠️ 注意: 上記のコードは単なる例です。実際の状況に応じて修正してください。


以下は様々なパラメータの説明です:

  • model_name: 使用する事前学習済みモデルの名前
  • data_files: トレーニングデータのパス
  • output_dir: モデルの出力ディレクトリ
  • num_train_epochs: トレーニングのエポック数
  • per_device_train_batch_size: デバイスごとのトレーニングバッチサイズ
  • gradient_accumulation_steps: 勾配蓄積ステップ数
  • learning_rate: 学習率
  • weight_decay: 重み減衰
  • warmup_ratio: ウォームアップの比率
  • lr_scheduler_type: 学習率スケジューラーの種類
  • max_seq_length: 最大シーケンス長
  • lora_alpha: LoRAのアルファパラメータ
  • lora_dropout: LoRAのドロップアウト率
  • r: LoRAのランク

Screenshot 2023-08-15 at 20.47.37.webp

⚠️ 注意: トレーニング前に、トレーニング状況を監視したい場合は、Wandbを使用できます。トークンが必要になります。

🎯 まとめ

この記事では、3つの主要なファインチューニング方法について説明しました:

  1. FFT(Full-Fine-Tuning)

    • モデル全体をファインチューニング
    • 最も包括的だが、計算リソースを多く必要とする
    • 大規模なデータセットと十分な計算リソースがある場合に適している
  2. SFT(Supervised Fine-Tuning)

    • モデルの一部の層のみをファインチューニング
    • 計算効率が良い
    • 特定のタスクに焦点を当てたい場合に適している
  3. QLoRA(Quantized Low-Rank Adaptation)

    • パラメータ効率の良いファインチューニング
    • 限られたリソースでも実行可能
    • 消費者向けGPUでも使用可能

各方法には独自の利点と制限があり、具体的な状況に応じて適切な方法を選択する必要があります。

📚 参考文献

  1. FastChat
  2. TRL
  3. PEFT
  4. QLoRA Paper
  5. LoRA Paper
  6. Fine-tuning
  7. Parameter-Efficient Fine-Tuning