Qwen2-0.5BのLoRAファインチューニング
このノートブックでは、効率的な手法を使用して Qwen2-0.5B 大規模言語モデルを効率的に微調整する方法を示します。 あなたは以下のことを学びます:
- LoRA (低ランク適応) を適用して、モデルの品質を維持しながらトレーニング可能な論点を最大 99% 削減します
- 最適化されたTritonカーネルを使用して、メモリ効率の良いトレーニングを行うには、 Ligerカーネルを 使用してください。
- TRL(Transformer Reinforcement Learning) を活用して、教師ありファインチューニングを行う
- ガバナンスとデプロイメントのための微調整されたモデルをUnity Catalogに登録する
主要概念:
- LoRA : 基本モデルとトレーニングする小さなアダプター層をフリーズし、メモリ要件とトレーニング時間を大幅に削減する技術
- Liger Kernels :GPUに最適化されたカーネルで、融合演算によりメモリ使用量を最大80%削減します。
- TRL :強化学習と教師ありファインチューニングによる言語モデルのトレーニング用ライブラリ
LoRAとフルファインチューニングの決定マトリックス
LoRA (Low-Rank Adaptation)は、ベースモデルをフリーズし、小さなアダプター層のみをトレーニングすることで、トレーニング可能な懸念を最大 99% 削減します。 これにより、トレーニングが高速化され、メモリ効率も向上します。
シナリオ | 推奨事項 | 理由: |
|---|---|---|
GPUメモリが制限されている | ロラ | わずか 1% のトレーニングにより、より大きなモデルをメモリに適合させる |
タスク固有の適応 | ロラ | 複数のタスクに対して同じ基本モデル上の異なるアダプタをスワップする |
主要なモデル動作の変更 | フルファインチューニング | モデルの動作に対する根本的な変更をすべて更新します |
本番運用展開 | ロラ | ファイルサイズが小さくなり(MB単位対GB単位)、読み込み速度が速くなり、バージョン管理が容易になる。 |
ライガーカーネルの効能
Ligerカーネルは、複数の処理ステップを単一のカーネルに統合することでメモリ転送を削減し、効率を向上させる、GPUに最適化された演算です。この技術論文では、大幅な性能向上を示す詳細なベンチマークデータが掲載されている。
- 融合演算 :演算(例:線形演算+損失演算)を組み合わせることで、メモリオーバーヘッドを最大80%削減します。
- Tritonカーネル :トランスフォーマー演算(RMSNorm、RoPE、SwiGLU、CrossEntropy)に最適化されたカスタムGPUカーネル
- メモリ効率 :GPUメモリに収まらないような大きなバッチサイズやモデルの処理を可能にする
- シングル GPU の最適化 : A10/A100 シングル GPU トレーニング シナリオに特に効果的
このノートブックはTRL ライブラリを使用してトレーニング構成を簡素化し、これらの最適化を自動的に適用します。
サーバレスGPUコンピュートに接続する
サーバレス GPU コンピュートに接続するには、ノートブックの [接続 ] ドロップダウン メニューをクリックし、 [サーバレス GPU] を選択します。
詳細については、 GPU コンピュートのドキュメントを参照してください。
必要なライブラリをインストールします
次のセルでは、ファインチューニングに必要なPythonパッケージをインストールします。
コアトレーニングライブラリ:
- trl==0.18.1 :教師ありファインチューニングとRLHFのためのTransformer強化学習ライブラリ
- peft : LoRA 実装を提供する、欠点-Efficient ファインチューニング ライブラリ
- liger-kernel : トランスフォーマーの効率的なトレーニングのためのメモリ最適化された GPU カーネル
サポートライブラリ:
- hf_transfer : Rustベースの転送を使用してHugging Face Hubからのダウンロードを高速化
%restart_pythonコマンドは、新しくインストールされたパッケージが正しくロードされるように、Python インタープリタを再起動します。
%pip install --upgrade peft==0.17.1
%pip install --upgrade hf_transfer==0.1.9
%pip install --upgrade transformers==4.56.1
%pip install trl==0.18.1
%pip install liger-kernel
%restart_python
ライブラリをインポートする
次のセルでは、モデルのトレーニング、データセットの処理、およびMLflowの追跡に必要なライブラリをインポートします。
from datasets import load_dataset
from transformers import AutoConfig, AutoModelForCausalLM, AutoTokenizer
from peft import LoraConfig, TaskType, get_peft_model
from trl import (
SFTConfig,
SFTTrainer,
setup_chat_format
)
import json
import os
import mlflow
設定構成
Unity Catalogの連携
次のセルでは、微調整したモデルの保存場所と登録場所を設定します。
- カタログとスキーマ : Unity Catalog名前空間内でモデルを整理します (確実:
main.default) - モデル名 :ガバナンスとデプロイメントのためにUnity Catalogに登録されたモデル名
- Volume : トレーニング中にモデルのチェックポイントを保存するためのUnity Catalogボリューム
これらのウィジェットを使用すると、コードを編集することなく保存場所をカスタマイズできます。このモデルは、アクセスとバージョン管理を容易にするため、 {catalog}.{schema}.{model_name}として登録されます。
ハイパーパラメータのトレーニング
このセルでは、主要なトレーニングの問題も定義します。
- モデルとデータセット : Qwen2-0.5B (Capybara 会話データセット付き)
- バッチサイズ(8) :トレーニングステップごとにGPUあたりで処理するサンプル数
- グラジエント累積 (4) : 有効バッチ サイズ 32 の場合、4 バッチにわたるグラジエントを累積します。
- 学習率 (1e-4) : 控えめな率、LoRA トレーニング用に自動的に 10 倍に調整されます。
- エポック(1) :データセットを1回通過させて過学習を防ぐ
- ロギングとチェックポイント : 100 ステップごとに進行状況を保存し、25 ステップごとにメトリクスを記録します
dbutils.widgets.text("uc_catalog", "main")
dbutils.widgets.text("uc_schema", "default")
dbutils.widgets.text("uc_model_name", "qwen2_liger_lora_assistant")
dbutils.widgets.text("uc_volume", "checkpoints")
UC_CATALOG = dbutils.widgets.get("uc_catalog")
UC_SCHEMA = dbutils.widgets.get("uc_schema")
UC_MODEL_NAME = dbutils.widgets.get("uc_model_name")
UC_VOLUME = dbutils.widgets.get("uc_volume")
print(f"UC_CATALOG: {UC_CATALOG}")
print(f"UC_SCHEMA: {UC_SCHEMA}")
print(f"UC_MODEL_NAME: {UC_MODEL_NAME}")
print(f"UC_VOLUME: {UC_VOLUME}")
# MLflow and Unity Catalog configuration
# Model selection - Choose based on your compute constraints
MODEL_NAME = "Qwen/Qwen2-0.5B"
DATASET_NAME = "trl-lib/Capybara"
OUTPUT_DIR = f"/Volumes/{UC_CATALOG}/{UC_SCHEMA}/{UC_VOLUME}/{UC_MODEL_NAME}"
# Training hyperparameters
BATCH_SIZE = 8
GRADIENT_ACCUMULATION_STEPS = 4
LEARNING_RATE = 1e-4
NUM_EPOCHS = 1
EVAL_STEPS = 100
LOGGING_STEPS = 25
SAVE_STEPS = 100
LoRA設定
次のセルは、モデルの微調整方法を制御する LoRA (Low-Rank Adaptation) を構成します。 LoRA は、ベース モデルの重みを固定し、小さなアダプター マトリックスのみをトレーニングすることで、メモリ要件を大幅に削減します。
争点選択
- ランク (r=8) : パフォーマンスとデメリットのバランスが取れています。
- アルファ(32) :スケーリング係数。通常はランクの2~4倍。
- ドロップアウト(0.1) :過学習を防ぐための正則化
Qwen2のターゲットモジュール
この例では、すべての主要な変換レイヤーを対象としています。
- 注意 :
q_proj、k_proj、v_proj、o_proj - MLP :
gate_proj、up_proj、down_proj
LORA_R = 8
LORA_ALPHA = 32
LORA_DROPOUT = 0.1
LORA_TARGET_MODULES = [
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"
]
ライガーカーネルの最適化
メモリとパフォーマンスの最適化
Liger Kernelsは、以下の方法でメモリとパフォーマンスを大幅に向上させます。
- 融合線形演算 :損失を伴う線形層を組み合わせる
- 最適化されたカーネル :RMSNorm、RoPE、SwiGLU、CrossEntropyの最適化
- メモリ削減 :融合演算で最大80%のメモリ削減を実現
- シングル GPU フォーカス : A10 シングル GPU トレーニング用に最適化
詳細については、 「効率的なTritonカーネル」の論文を参照してください。
データセットをロードして準備する
次のセルはトレーニング データセットをロードし、ファインチューニングの準備をします。
- データセット : trl-lib/Capybara - 指示に従うことに最適化された高品質の会話データ
- トレーニングする/検証分割 : テスト セットが存在しない場合は 90/10 分割を作成します
- データ検証 : 会話型ファインチューニングの適切なフォーマットを保証します。
dataset = load_dataset(DATASET_NAME)
print(f"✓ Dataset loaded: {dataset}")
if "test" not in dataset:
print("Creating validation split from training data...")
dataset = dataset["train"].train_test_split(test_size=0.1, seed=42)
print("✓ Data split: 90% train, 10% validation")
モデルとトークナイザーを初期化する
次のセルはベースモデルとトークナイザーをロードし、会話用に構成します。
- モデル読み込み中 :Hugging FaceからQwen2-0.5Bをダウンロード
- トークナイザー設定 :適切なパディングを備えた高速トークナイザーを設定します
- チャットフォーマット :構造化された会話にChatMLフォーマットを適用します
- 一回の設定 : 適切なシーケンス処理のためにパディングを EOS に設定します
model = AutoModelForCausalLM.from_pretrained(
MODEL_NAME,
trust_remote_code=True,
)
tokenizer = AutoTokenizer.from_pretrained(
MODEL_NAME,
trust_remote_code=True,
use_fast=True
)
# Chat template formatting for conversational fine-tuning
if tokenizer.chat_template is None:
print("Adding chat template for proper conversation formatting...")
model, tokenizer = setup_chat_format(model, tokenizer, format="chatml")
print("✓ ChatML format applied for structured conversations")
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
print("✓ Padding token set to EOS token")
print("✓ Model and tokenizer loaded successfully")
LoRAアダプターを適用する
次のセルでは、LoRA(低ランク適応)をモデルに適用します。
- 設定 :LoRAをランク=8、アルファ=32、ドロップアウト=0.1で設定します
- 対象モジュール :アテンション層とMLP層にアダプターを適用します
- 問題効率 : トレーニング可能な問題を元のモデルの ~1% に削減します
- メモリ節約 :グラデーションメモリの必要量を大幅に削減します
- フォールバック :LoRA設定が失敗した場合、自動的にフルファインチューニングにフォールバックします。
peft_config = None
try:
print("Configuring LoRA for parameter-efficient fine-tuning...")
peft_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
inference_mode=False,
r=LORA_R,
lora_alpha=LORA_ALPHA,
lora_dropout=LORA_DROPOUT,
target_modules=LORA_TARGET_MODULES,
bias="none",
use_rslora=False,
modules_to_save=None,
)
print(f"LoRA configuration: rank={LORA_R}, alpha={LORA_ALPHA}, dropout={LORA_DROPOUT}")
print(f"Target modules: {', '.join(LORA_TARGET_MODULES)}")
original_params = model.num_parameters()
model = get_peft_model(model, peft_config)
trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
total_params = sum(p.numel() for p in model.parameters())
efficiency_ratio = 100 * trainable_params / total_params
print(f"✓ LoRA applied successfully:")
print(f" • Original parameters: {original_params:,}")
print(f" • Trainable parameters: {trainable_params:,}")
print(f" • Training efficiency: {efficiency_ratio:.2f}% of parameters")
print(f" • Memory savings: ~{100-efficiency_ratio:.1f}% reduction in gradient memory")
except Exception as e:
print(f"✗ LoRA configuration failed: {e}")
print("Falling back to full fine-tuning...")
USE_LORA = False
peft_config = None
モデルをトレーニングする
次のセルは、トレーニングプロセスを設定および実行します。
トレーニング構成
- 学習率調整 :LoRAの学習率を10倍高く設定します( LoRA論文で推奨されているとおり)。
- バッチ構成 : デバイスごとに 8 サンプル、4 つのグラジエント蓄積ステップ (有効バッチ サイズ: 32)
- 最適化 : ウォームアップステップ、重み減衰、評価損失に基づく最適なモデルの選択
- ロギング : エクスペリメント追跡のためにメトリクスをMLflowにレポートします。
主要な最適化が有効になりました
- Liger Kernels :GPU演算の融合によりメモリ使用量を最大80%削減
- 混合精度(FP16) :メモリ使用量を抑えつつ、より高速な計算が可能
- 勾配蓄積 :安定したトレーニングのために、より大きなバッチサイズをシミュレートします。
- チェックポイント : 2 チェックポイントの制限付きで 100 ステップごとにモデルを保存します
トレーニング ループは 25 ステップごとに進行状況を記録し、100 ステップごとに評価します。
with mlflow.start_run(run_name=f"{MODEL_NAME}_fine-tuning", log_system_metrics=True):
try:
# Learning rate adjustment for LoRA
adjusted_lr = LEARNING_RATE * 10
print(f"Learning rate: {adjusted_lr}")
training_args_dict = {
"output_dir": OUTPUT_DIR,
"per_device_train_batch_size": BATCH_SIZE,
"per_device_eval_batch_size": BATCH_SIZE,
"gradient_accumulation_steps": GRADIENT_ACCUMULATION_STEPS,
"learning_rate": adjusted_lr,
"num_train_epochs": NUM_EPOCHS,
"eval_steps": EVAL_STEPS,
"logging_steps": LOGGING_STEPS,
"save_steps": SAVE_STEPS,
"save_total_limit": 2,
"report_to": "mlflow", # Log to MLflow
"warmup_steps": 50,
"weight_decay": 0.01,
"metric_for_best_model": "eval_loss",
"greater_is_better": False,
"dataloader_pin_memory": False,
"remove_unused_columns": False,
"use_liger_kernel": True, # Enable Liger kernel optimizations
"fp16": True, # Mixed precision training
}
print("✓ Liger kernel optimizations enabled")
training_args = SFTConfig(**training_args_dict)
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=dataset["train"],
eval_dataset=dataset["test"],
processing_class=tokenizer,
peft_config=peft_config,
)
print("\n" + "="*50)
print("STARTING TRAINING")
print("="*50)
print("🚀 Training with Liger kernels for memory-efficient single GPU training")
print("🎯 Using LoRA for parameter-efficient fine-tuning")
trainer.train()
print("\n✓ Training completed successfully!")
except Exception as e:
print(f"✗ Training failed: {e}")
raise
モデルアーティファクトを保存する
次のセルでは、学習済みモデルとトークナイザーをUnity Catalogボリュームに保存します。
- LoRAアダプタ :学習済みのアダプタの重みのみを保存します(フルモデルよりもはるかに小さいサイズ)。
- トークナイザー :推論用のトークナイザー設定を保存します
- 保存場所 :保存先
/Volumes/{catalog}/{schema}/{volume}/{model_name} - 再利用性 :アダプターには推論用の基本モデルをロードできます。
try:
print("\nSaving trained model...")
print("Saving LoRA adapter weights...")
trainer.save_model(training_args.output_dir)
print("✓ LoRA adapters saved - use with base model for inference")
tokenizer.save_pretrained(training_args.output_dir)
print("✓ Tokenizer saved with model")
print(f"\n🎉 All artifacts saved to: {training_args.output_dir}")
except Exception as e:
print(f"✗ Model saving failed: {e}")
raise
Unity Catalogに登録するモデル
次のセルでは、ガバナンスとデプロイメントのためにUnity Catalogに微調整されたモデルを登録します。
モデル登録ワークフロー
- 学習済みモデルの読み込み :ベースモデルを読み込み、LoRAアダプタを適用します。
- アダプターのマージ :LoRAの重みを基本モデルと組み合わせ、展開します。
- ログ記録の準備 :モデルとトークナイザーを使用してトランスフォーマーモデル辞書を作成します
- Unity Catalogに登録する : MLflowにログを記録し、 Unity Catalogに登録する
- メタデータの追加 :タスクの種類、モデルファミリー、サイズ情報が含まれます
Unity Catalog登録のメリット
- ガバナンス : アクセス制御とリネージ追跡を備えた一元的なモデルレジストリ
- バージョン管理 :モデルライフサイクルの自動バージョン管理
- 導入 : モデルサービングエンドポイントへの簡単な導入
- 発見しやすさ :モデルはUnity Catalogで検索可能で、ドキュメント化されています。
mlflow_run_id = mlflow.last_active_run().info.run_id
print("\nRegistering model with MLflow and Unity Catalog...")
with mlflow.start_run(run_id = mlflow_run_id):
try:
# Load the trained model for registration
print("Loading LoRA model for registration...")
# For LoRA models, we need both base model and adapter
base_model = AutoModelForCausalLM.from_pretrained(
MODEL_NAME,
trust_remote_code=True
)
# Load tokenizer
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
from peft import PeftModel
peft_model = PeftModel.from_pretrained(base_model, training_args.output_dir)
model_type = "LoRA"
size_params = "0.5b_lora"
# Merge LoRA into base and drop PEFT wrappers
merged_model = peft_model.merge_and_unload()
# Prepare transformers model dictionary
transformers_model = {
"model": merged_model,
"tokenizer": tokenizer
}
# Create Unity Catalog model name
full_model_name = f"{UC_CATALOG}.{UC_SCHEMA}.{UC_MODEL_NAME}"
print(f"Registering model as: {full_model_name}")
# Start MLflow run and log model
task = "llm/v1/chat"
model_info = mlflow.transformers.log_model(
transformers_model=transformers_model,
task=task,
registered_model_name=full_model_name,
metadata={
"task": task,
"pretrained_model_name": MODEL_NAME,
"databricks_model_family": "QwenForCausalLM",
"databricks_model_size_parameters": size_params,
},
repo_type="local", # Fix: specify repo_type for local path
)
print(f"✓ Model successfully registered in Unity Catalog: {full_model_name}")
print(f"✓ MLflow model URI: {model_info.model_uri}")
# Print deployment information
print(f"\n📦 Model Registration Complete!")
print(f"Unity Catalog Path: {full_model_name}")
print(f"Model Type: {model_type}")
print(f"Optimization: Liger Kernels + LoRA")
except Exception as e:
print(f"✗ Model registration failed: {e}")
print("Model is still saved locally and can be registered manually")
print(f"Local model path: {training_args.output_dir}")
次のステップ
お客様のQwen2-0.5BモデルはLoRAによるファインチューニングが正常に完了し、 Unity Catalogに登録されました。 次に、次のことができます。
- モデルのデプロイ :モデルサービングを使用してモデルを提供する
- 分散トレーニングの詳細については 、マルチGPUおよびマルチノード分散トレーニングをご覧ください。
- サーバレス GPU の使用を最適化する :サーバレス GPU コンピュートのベスト プラクティス
- 問題のトラブルシューティング :サーバレス GPU コンピュートの問題のトラブルシューティング