【ローカルLLM】QLoRAの複雑なパラメータを(少しでも)整理する
前回の記事でも触れたとおり、QLoRAによるLlama-2のファインチューニングで試行錯誤している。
「QLoRA」は、LlamaのようなローカルLLMをファインチューンする場合に現在主流となっている手法。通常のLoRAよりもGPUリソースを大幅に節約でき、コストや時間の面でメリットがあるとされる。
パラメータ設定については、Llama-2-7BでQLoRAを行う場合の公式のスクリプトがあり、大部分は以下の設定を流用すればいいはず。
CUDA_VISIBLE_DEVICES=0 python qlora.py \
--model_name_or_path meta-llama/Llama-2-7b-hf \
--use_auth \
--output_dir ./output/llama-2-guanaco-7b \
--logging_steps 10 \
--save_strategy steps \
--data_seed 42 \
--save_steps 500 \
--save_total_limit 40 \
--evaluation_strategy steps \
--eval_dataset_size 1024 \
--max_eval_samples 1000 \
--per_device_eval_batch_size 1 \
--max_new_tokens 32 \
--dataloader_num_workers 1 \
--group_by_length \
--logging_strategy steps \
--remove_unused_columns False \
--do_train \
--do_eval \
--do_mmlu_eval \
--lora_r 64 \
--lora_alpha 16 \
--lora_modules all \
--double_quant \
--quant_type nf4 \
--bf16 \
--bits 4 \
--warmup_ratio 0.03 \
--lr_scheduler_type constant \
--gradient_checkpointing \
--dataset oasst1 \
--source_max_len 16 \
--target_max_len 512 \
--per_device_train_batch_size 1 \
--gradient_accumulation_steps 16 \
--max_steps 1875 \
--eval_steps 187 \
--learning_rate 0.0002 \
--adam_beta2 0.999 \
--max_grad_norm 0.3 \
--lora_dropout 0.1 \
--weight_decay 0.0 \
--seed 0 \
--cache_dir /gscratch/zlab/llama2
とはいえ、LoRA初心者には「分かんないパラメータ、多すぎ…」状態だったので、ひとまず整理してみた。
ハイパーパラメータの簡単な説明
※機械学習において、学習過程を制御するためのパラメータは「ハイパーパラメータ」と呼ぶらしい(「パラメータ」は一般に、学習によって決まるパラメータを指す)。
これらの中で重要と思われる項目について、qlora.pyのヘルプの和訳とともに列挙する。なお*は補足メモ。
基本的な設定
model_name_or_path:default="EleutherAI/pythia-12b"。HuggingFace上のモデルの名称またはパス。
output_dir:default='./output'。ログとチェックポイントを出力するフォルダ。
bf16 / fp16:使用するGPUがbfloat16をサポートしていれば、「--bf16」でトレーニングを高速化できる。*「--bf16」未対応なら「--fp16」を指定する。
ステップ数に関するハイパーパラメータ
logging_steps:default=10。損失(Loss)を記録するステップの頻度。
save_steps:default=250。チェックポイントの保存を行うステップの頻度。
save_total_limit: default=40。最も古いチェックポイントが上書きされるまでに保存するチェックポイントの数。
max_steps: default=10000。最大ステップ数。*最大ステップに到達するまで学習が続く。
トレーニング効率に関するハイパーパラメータ
learning_rate: default=0.0002。学習率(LR)。*機械学習全般における最重要のハイパーパラメータらしい。高い値を設定すると、トレーニングはより速く実行されるが、モデルの先行データが損なわれる可能性も高くなる。学習率を高くすれば、エポックは低くできる(高い学習率 + 低いエポック = 高速だが低品質のトレーニング)。学習率を低くすれば、エポックを高くできる(低い学習率 + 高いエポック = 速度は遅いが質の高いトレーニング)。学習率が低すぎるとトレーニングが進まず、逆に高すぎるとロスが乱高下したりする。
per_device_train_batch_size: default=1。GPU1個あたりのトレーニングバッチサイズ。*バッチサイズが大きいとトレーニングが高速化される。バッチサイズが小さいと遅くなるが、場合によっては汎化が向上し、モデルの品質向上が期待できるかもしれない。
gradient_accumulation_steps: default=16。オプティマイザのステップを実行する前に、累積させる勾配の回数。*per_device_train_batch_size * gradient_accumulation_stepsの積は常に16になる必要がある。例えば、per_device_train_batch_sizeを最大値の16に設定するなら、gradient_accumulation_stepsを1に設定する。
データセットに関するハイパーパラメータ
dataset: default='alpaca'。ファインチューニングに用いるデータセット。自前のデータセットを使う場合は、パスで指定する。
dataset_format: default=None。使用するデータセットの形式。alpaca、chip2、self-instruct、hh-rlhfなど。
source_max_len: default=1024。ソース・シーケンスの最大トークン(defaultの場合、1024を超えるトークンは無視される)。*「ソース」は、データセット中のインストラクション、インプットにあたる部分。ただし、ソース(インプット)には何も入れずに、インストラクションとレスポンスとまとめてターゲット(アウトプット)に突っ込む場合もある。
target_max_len: default=256。ターゲット・シーケンスの最大トークン(defaultの場合、256を超えるトークンは無視される)。*「ターゲット」は、データセット中のレスポンス、アウトプットにあたる部分。target_max_lenを大きくすると、その分トレーニングの際のGPUへの負荷が大きくなるので、できるだけ適切な値を設定する。
データフォーマットについて調べ始めたら長くなりそうなので、このあたりはついては次回以降の記事で詳述。
LoRAハイパーパラメータ
これらのパラメータについては、QLoRAの元論文の4章及びAppendix Aで言及されている。そもそも語彙が理解できないので、Bingによる説明を付してみた。あくまで参考までに掲載する。
lora_r: default=64。Lora Rディメンション。*Bingによる説明:更新行列のランクを表すパラメータです。Rが大きいほど、更新行列は元の重みに近くなりますが、メモリや計算量も増えます。Rが小さいほど、更新行列は元の重みから離れますが、メモリや計算量も減ります。Rは、訓練するタスクやドメインに応じて調整する必要があります。*QLoRA論文での言及:「…すべてのレイヤーでLoRAを使用したところ、LoRAのrは最終的なパフォーマンスとは無関係であることがわかった」
lora_alpha: default=16。Loraアルファ。*Bingによる説明:LoRAのスケーリングに使われるパラメータです。更新行列のノルム(大きさ)を制限することで、LoRAの過学習や不安定さを抑える効果があります。*QLoRA論文での言及:「…LoRAアルファは常に学習率に比例するので、LoRAアルファを固定して学習率を探索する」
lora_dropout: default=0.0。Loraドロップアウト率。*Bingによる説明:LoRAレイヤーのドロップアウト確率のことです。更新行列の一部を無効化することで、LoRAの過学習や不安定さを抑える効果があります。*QLoRA論文での言及:「…0.05のLoRAドロップアウトは、小さなモデル(7B,13B)には有効だが、大きなモデル(33B,65B)には有効ではなかった」
Guanacoのハイパーパラメータ設定例
QLoRAの元論文で登場するLlama-1ファインチューンモデル(Guanaco)で使われたハイパーパラメータ設定は以下のとおり。学習率の2e-4は0.0002、1e-4は0.0001を示す。Sequence lengthは、Target Sequence lengthのみを指すはず(OASST1データセットにSource Sequenceは不要)。
この他のパラメータについては、次のように言及されている。
ロス(Loss)に関する目安
実際にトレーニングを回し始めると、トレーニング・ロスの数値を眺めながら、どこで学習を止めるか判断することになる。目安となる数字は以下の通り。
通常、3~5エポックでトレーニングし、トレーニングロスが ~1.5 になるようにLoRAを行いますが、一般に、トレーニングの期間についての黄金律はないようです。
一般的には、ロスが「1.0」を下回ると以前の記憶を忘れ始めるので、学習を中止する必要があります。場合によっては、「0.5」まで下げたほうがいいこともあります(非常に予測しやすくしたい場合)。
LLMのトレーニングにおける学習曲線については、以下の記事に詳しい。まだちゃんと読めていない。
関連記事
Llama-2のQLoRAを試してみるにあたっては、下記の記事が参考になった。
自前のデータセットを使ったQLoRAについては、以下の英語記事が分かりやすかった。初心者の視点でつまづく箇所が平易に書かれ、機械翻訳でも読みやすい。
学習率とエポック数など、そもそものLoRAの基本的なパラメータの関係性については、以下の記事にわかりやすい。
QLoRAに関する元論文はこちら。
論文の前半がQLoRAの考案に関するテクニカルな説明、中盤が様々なデータセットを用いたQLoRAの実践比較、後半がQLoRAの成果物であるGuanacoという言語モデルの性能評価、という感じの構成になっている。そのため、実際にQLoRAを使うにあたっては中盤の4章・5章+末尾のAppendix A, Bが参考になりそう(読んだので記事に追記)。