TRL documentation

後悔しないLoRA

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

後悔しないLoRA

Thinking Machines Labのチームによる最近の研究(Schulman et al., 2025)は、適切に設定された場合、LoRAはフルファインチューニングと同等のパフォーマンスを発揮できることを示しており、その際に必要な計算量は約67%に抑えられます。これらの知見は、TRLのユーザーにとって非常に魅力的です。なぜなら、実装が容易であり、より少ない予算でモデルのパフォーマンスを向上させることができるからです。

このガイドでは、TRLでブログ記事の結果を再現するための簡単な手順を説明します。

このガイドに従う前にブログ記事を読むことをお勧めします。または、最適な結果を得るために、両方のリソースを並行して参照してください。

完全なファインチューニングに対するLoRAの利点

まず、フルファインチューニングに対するLoRAの利点を思い出しましょう。

LoRAはベースモデルの上にアダプタ層を追加しますが、このアダプタ層はベースモデル自体よりもはるかに少ないパラメータ数で構成されています。この設計により、GPUメモリ要件が削減され、より効率的なトレーニングが可能になります。ブログに記載されているように、このアプローチは当初、パフォーマンスのトレードオフを伴うと考えられていましたが、慎重な設定を行うことでこのトレードオフを克服し、フルファインチューニングと同等のパフォーマンスを実現できます。

TRLの例

ブログ記事の主要な調査結果に基づいて、TRLスクリプトでLoRAアダプタを実装して学習しましょう。その後、TRLの結果を踏まえて、各調査結果を再検討します。

教師ありファインチューニング(SFT)

このブログ記事では、Hub上のさまざまなモデルとデータセットに対してSFTを実行しており、これはTRLで再現できます。

モデルデータセット
Llama-3.2-1B-Instructallenai/tulu-3-sft-mixture
Llama-3.2-1B-Instructopen-thoughts/OpenThoughts-114k
Llama-3.1-8B-Instructallenai/tulu-3-sft-mixture
Llama-3.1-8B-Instructopen-thoughts/OpenThoughts-114k
python
ジョブ
ローカル

これらの知見をTRL Python APIに次のように統合できます。


from datasets import load_dataset
from peft import LoraConfig
from trl import SFTTrainer, SFTConfig

dataset = load_dataset("open-thoughts/OpenThoughts-114k", split="train")

peft_config = LoraConfig(r=256, lora_alpha=16, target_modules="all-linear")

training_args = SFTConfig(
    learning_rate=2e-4,
    per_device_train_batch_size=1,
    gradient_accumulation_steps=4,
    num_train_epochs=1,
    report_to=["trackio"],
)

trainer = SFTTrainer(
    model="Qwen/Qwen2.5-3B-Instruct",
    train_dataset=dataset,
    peft_config=peft_config,
    args=training_args,
)

trainer.train()

トレーニングが開始されると、Trackioで進捗を監視できます。URLはログに記録されます。

強化学習(GRPO)

このブログ記事では、Hub上のさまざまなモデルとデータセットに対してGRPOを実行しており、TRLでも結果を再現できます。

モデルデータセット
Llama-3.1-8B-BaseGSM8k
Llama-3.1-8B-BaseDeepMath-103K
Qwen3-8b-baseDeepMath-103K

強化学習では、ブログではPython関数として再現可能な数学推論タスクを使用しています。

python
ジョブ
ローカル

これらの推奨事項は、TRL Python API を使用して次のように実装できます。


from datasets import load_dataset
from peft import LoraConfig
from trl import GRPOConfig, GRPOTrainer
from trl.rewards import reasoning_accuracy_reward

dataset = load_dataset("HuggingFaceH4/OpenR1-Math-220k-default-verified", split="train")

peft_config = LoraConfig(
    r=1,
    lora_alpha=32,
    target_modules="all-linear"
)

training_args = GRPOConfig(
    learning_rate=5e-5,
    per_device_train_batch_size=1,
    gradient_accumulation_steps=4,
    num_train_epochs=1,
    num_generations=8,
    generation_batch_size=8,
    report_to=["trackio"],
)

trainer = GRPOTrainer(
    model="Qwen/Qwen3-0.6B",
    reward_funcs=reasoning_accuracy_reward,
    args=training_args,
    train_dataset=dataset,
    peft_config=peft_config,
)

trainer.train()

このスニペットは、例を簡潔に保つため、上記で定義された報酬関数を省略しています。

GRPOによる強化学習スクリプトは、TRLのカスタムスクリプトとして実装されており、上記の報酬関数を使用しています。grpo.py - LoRAによる強化学習のベストプラクティスで確認できます。

LoRAの最適化における主な調査結果

著者らは、ランクを上げてもこの制限を補うことはできないため、LoRAをアテンション層に限定するのではなく、すべての重み行列に適用することを推奨しています。TRLでは、--lora_target_modules all-linear を使用して、すべての重み行列にLoRAを適用するように設定できます。

TRLとSmolLM3モデルを使用して、ブログ記事の結果を再現することができました。上記の報酬関数と設定を用いて、Math 220k データセットでモデルを500ステップ訓練しました。下の図に示すように、LoRAモデルの平均訓練報酬の曲線は、フルファインチューニングの曲線と一致しています。

train reward

そして最も重要なのは、下の図に示すように、LoRAモデルはフルファインチューニングモデルよりもはるかに少ないメモリで済む点です。

memory usage

上記のモデルを学習するために使用したパラメータは以下の通りです

パラメータLoRAフルFT
--model_name_or_pathHuggingFaceTB/SmolLM3-3BHuggingFaceTB/SmolLM3-3B
--dataset_nameHuggingFaceH4/OpenR1-Math-220k-default-verifiedHuggingFaceH4/OpenR1-Math-220k-default-verified
--learning_rate1.0e-51.0e-6
--max_completion_length40964096
--lora_r1-
--lora_alpha32-
--lora_dropout0.0-
--lora_target_modulesall-linear-

ブログ記事の主要な発見と、それらをどのように再現したのかを分解して見ていきましょう。

1. LoRA はすべての重み行列に適用した場合に、より良いパフォーマンスを発揮します

著者らは、ランクを高くしてもこの制限を補うことはできないため、LoRAをアテンション層に限定するのではなく、すべての重み行列に適用することを推奨しています。

all layers

Attentionのみを対象にしたLoRAは、パラメータ数を合わせるためにより高いランクを使用しても、性能が劣ることがあります。TRLでは、--lora_target_modules all-linear を使用して、すべての重み行列にLoRAを適用するように設定できます。Pythonでは、次のように実行できます。

from peft import LoraConfig  

peft_config = LoraConfig(target_modules="all-linear")  

2. アダプターは、データセットから学習するために十分な容量を必要とします

ブログ記事では、データセットから学習するために十分なLoRAランクを使用することを推奨しています。ランクは、LoRAアダプター内の学習可能なパラメータの数を決定します。したがって、「LoRAの容量を超えるデータセットでは、LoRAはFullFTよりも性能が劣ります」。

learning rate

TRLスクリプトでは、--lora_r を使用してランクを設定し、トレーニング対象のタスクとデータセットに応じて調整できます。ブログ記事では、タスクとデータセットのサイズに基づいて、以下のランクが推奨されています。

強化学習のタスクは通常、より低い容量で済むため、より小さいLoRAランクを使用できます。これは、ポリシーグラデーションアルゴリズムがエピソードあたり約1ビットの情報を抽出するだけで済むため、パラメータ容量の要求が最小限だからです。

ブログ記事では、LoRAのフルファインチューニングと同等の性能を発揮するための理想的なデータセットサイズを「Post-training scale」と定義しています。これを用いて、SFTおよびRLのLoRAの推奨ランクを以下のように決定できます。

タスクタイプデータセットサイズ推奨ランク
SFTポストトレーニングのスケール256
強化学習任意のサイズ1-32

3. “FullFTと高ランクLoRAは類似の学習曲線を示す”

直感に反して、このブログ記事ではフルファインチューニングよりも高い学習率の使用を推奨しています。上記の表では、LoRAに1.0e-5、フルファインチューニングに1.0e-6を使用しました。TRLスクリプトでは、 --learning_rate で学習率を設定できます。LoRAにおける 1r \frac{1}{r} のスケーリングにより、最適な学習率はランクにほぼ依存しなくなります。

learning rate

4. 「一部のシナリオでは、LoRAはフルファインチューニングよりも大きなバッチサイズに対して許容度が低い場合があります。」

ブログ記事では、著者らがLoRAは大きなバッチサイズにあまり耐性がないことを発見したため、実効バッチサイズが32未満になるよう設定することを推奨しています。この問題は、LoRAのランクを大きくしても緩和できませんでした。TRLのスクリプトでは、--per_device_train_batch_sizeと--gradient_accumulation_stepsを使用してバッチサイズを設定できます。

learning rate

要点

TRLを使用すると、FullFTの重い計算コストを伴うことなく、コアなインサイト(すべての重み行列を対象とすること、適切なランクの選択、バッチサイズと学習率の管理)を適用しながら、フルファインチューニングのパフォーマンスに匹敵するLoRAアダプターを効率的に実装できます。

引用

@article{schulman2025lora,  
    title        = {{LoRA Without Regret}},  
    author       = {John Schulman and Thinking Machines Lab},  
    year         = 2025,  
    journal      = {Thinking Machines Lab: Connectionism},  
    doi          = {10.64434/tml.20250929},  
    note         = {https://thinkingmachines.ai/blog/lora/}  
}  
Update on GitHub