メインコンテンツまでスキップ

Qwen2-0.5BのLoRAファインチューニング

このノートブックでは、効率的な手法を使用して Qwen2-0.5B 大規模言語モデルを効率的に微調整する方法を示します。 以下の方法を学習します:

  • LoRA (低ランク適応) を適用して、モデルの品質を維持しながらトレーニング可能な論点を最大 99% 削減します
  • 最適化された Triton カーネルを使用したメモリ効率の高いトレーニングには Liger カーネルを 使用します。
  • TRL ( Transformer強化学習) を活用して教師付きファインチューニングを実現
  • ガバナンスとデプロイメントのために、微調整されたモデルを Unity Catalog に登録する

重要な概念:

  • LoRA : 基本モデルとトレーニングする小さなアダプター層をフリーズし、メモリ要件とトレーニング時間を大幅に削減する技術
  • Liger Kernels : 融合演算によりメモリ使用量を最大 80% 削減する GPU 最適化カーネル
  • 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 インタープリターを再起動します。

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 の追跡に必要なライブラリをインポートします。

Python
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 ステップごとにメトリクスを記録します。
Python
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_projk_projv_projo_proj
  • MLP : gate_projup_projdown_proj
Python
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カーネルの最適化

メモリとパフォーマンスの最適化

Liger カーネルは、次の機能を通じてメモリとパフォーマンスを大幅に向上させます。

  • 融合線形演算 :損失のある線形層を組み合わせる
  • 最適化されたカーネル : RMSNorm、RoPE、SwiGLU、CrossEntropy の最適化
  • メモリ削減 : 融合操作で最大80%のメモリ節約
  • シングル GPU フォーカス : A10 シングル GPU トレーニング用に最適化

詳細については、 「Efficient Triton Kernels」の論文を参照してください。

データセットの読み込みと準備

次のセルはトレーニング データセットをロードし、ファインチューニングの準備をします。

  • データセット : trl-lib/Capybara - 指示に従うために最適化された高品質の会話データ
  • トレーニングする/検証分割 : テスト セットが存在しない場合は 90/10 分割を作成します
  • データ検証 : 会話型ファインチューニングの適切なフォーマットを保証します。
Python
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 に設定します
Python
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 (低ランク適応) を適用します。

  • 設定 : ランク=8、アルファ=32、ドロップアウト=0.1でLoRAを設定します
  • ターゲットモジュール : アテンション層とMLP層にアダプターを適用します
  • 問題効率 : トレーニング可能な問題を元のモデルの ~1% に削減します
  • メモリ節約 : 勾配メモリの要件を大幅に削減
  • フォールバック : LoRA 設定が失敗した場合、自動的にフルファインチューニングにフォールバックします。
Python
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) :メモリ使用量が少なく、計算が高速
  • 勾配累積 : 安定したトレーニングのためにより大きなバッチサイズをシミュレートします
  • チェックポイント : 100 ステップごとに 2 つのチェックポイントの制限付きでモデルを保存します。

トレーニング ループは 25 ステップごとに進行状況を記録し、100 ステップごとに評価します。

Python
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}
  • 再利用性 : アダプタは推論用の基本モデルとともにロードできます
Python
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に微調整されたモデルを登録します。

モデル登録ワークフロー

  1. トレーニング済みモデルのロード : ベースモデルをロードし、LoRA アダプターを適用します。
  2. マージアダプタ : デプロイメント用にLoRAの重みをベースモデルと組み合わせる
  3. ログ記録の準備 : モデルとトークナイザーを使用してトランスフォーマーのモデル辞書を作成する
  4. Unity Catalogに登録する : MLflowにログを記録し、 Unity Catalogに登録する
  5. メタデータを追加 : タスクタイプ、モデルファミリ、サイズ情報が含まれます

Unity Catalog登録のメリット

  • ガバナンス : アクセス制御とリネージ追跡を備えた一元的なモデルレジストリ
  • バージョン管理 : モデルのライフサイクルの自動バージョン管理
  • デプロイメント : モデルサービングエンドポイントへの簡単なデプロイメント
  • 発見可能性 : モデルはUnity Catalogで検索可能で、ドキュメント化されています
Python
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に登録されました。 次に、次の操作を実行できます。

サンプルノートブック

Qwen2-0.5BのLoRAファインチューニング

ノートブックを新しいタブで開く