メインコンテンツへスキップ
友田 陽大
Llama・オープンウェイトLLM
Llama
ファインチューニング
LoRA
生成AI
AWS Bedrock
Python
MLOps

Llama ファインチューニング実践:LoRA/QLoRA で自社データに特化させ本番投入する

オープンウェイトの強みは『重みを自社データで微調整できる』こと。Llama を LoRA/QLoRA でファインチューニングする手順を、まず『本当に必要か(RAG vs FT)』の判断から、データ準備・torchtune/TRL実装・評価ゲート・マージ&デプロイ・ライセンス命名規約まで、本番運用の観点で実コードで解説します。

公開日
読了時間
11分
著者
友田 陽大
シェア

この記事のゴール

Llama を本番投入する全体像で述べたとおり、オープンウェイトを選ぶ最大の理由のひとつが「重みを自社データで微調整(ファインチューニング, FT)できる」ことです。本稿はその FT を、デモではなく本番——再現性・評価・コスト・ライセンスまで——の観点で、実コードで最後まで通します。

読み終えたとき、次の3つができる状態を目指します。

  1. そもそも FT が必要かを判断できる(多くの場合は RAG で足りる、を含めて)。
  2. LoRA/QLoRA で実際に回せる(torchtune と Hugging Face TRL の両経路)。
  3. 評価ゲートを通してから安全にデプロイでき、ライセンスの命名規約まで守れる。

信頼性の開示:私は AWS Bedrock / Vercel AI SDK を土台に生成AIシステムを本番運用しており、ドメイン特化(型番・専門語彙・出力フォーマットの固定)は音声接客の事例でも中心的な課題でした。本稿は「FT は最後の手段」という実務の順序に忠実です。盛った精度向上の数字は出しません。


まず疑う:その課題、本当にFTが要りますか?

FT は強力ですが、最初に手を出すべき道具ではありません。コスト・運用負荷・陳腐化リスクが大きいからです。次の順で検討してください。

手法効くもの効かないものコスト/運用
プロンプト/Few-shot形式の指示、簡単な振る舞い大量の知識、強い様式固定最小
RAG(検索拡張)最新知識・社内文書の参照、出典提示口調・出力様式の根本変更中(pgvector RAG
ファインチューニング振る舞い・出力形式・口調・専門語彙の固定、レイテンシ短縮知識の鮮度(学習時点で凍結)大(データ・学習・評価・再学習)

鉄則

  • 知識を足したい → まず RAG。モデルの中に事実を焼き込むのは陳腐化と幻覚の温床。
  • いつも同じ形式・口調・判断で答えさせたいプロンプトが長くなりすぎた専門語彙の取りこぼしを消したいFT の出番。
  • 実務では RAG + 軽い FT の併用が最も費用対効果が高い(知識は RAG、様式は FT)。

💡 「FT すれば賢くなる」は誤解です。FT が変えるのは主に振る舞いの分布であって、新しい事実の信頼できる記憶ではありません。事実は RAG に持たせるのが本番の定石です。


何を、どう微調整するか(現実的な対象とLoRA/QLoRA)

対象モデル:まず密モデルから

Llama 4 は MoEで総パラメータが巨大(Scout 109B / Maverick 400B)です。これをフルFTするのは相当な分散学習基盤を要し、最初の一歩には向きません。実務の現実的な対象は密(dense)モデル——Llama 3.3 8B / 70B や用途特化の小型版——で、ここに LoRA/QLoRA を当てるのが王道です。

LoRA と QLoRA を一言で

  • LoRA(Low-Rank Adaptation):巨大な重みを凍結し、小さな低ランク行列だけを学習する。更新対象がごく一部なので、省メモリ・高速・成果物(アダプタ)が数十MB
  • QLoRA:ベースモデルを 4bit 量子化して載せ、その上で LoRA を学習する。単一GPUでも 70B 級に手が届くのが利点。精度劣化は実用上小さいことが多い。
手法メモリ速度成果物向く場面
フルFT最大最遅モデル全体大規模・基盤を作り替える
LoRAアダプタ(小)標準。様式・語彙の固定
QLoRA最小アダプタ(小)単一GPUで大きめモデル

データ準備:成否の9割はここ

FT の品質はデータの品質で決まります。モデルやハイパラの差は誤差です。

  • 形式:instruction/chat 形式の JSONL。1行=1サンプル。
  • 品質 > 量:ノイズだらけの10万件より、手で磨いた1,000件。誤りは“正しく学習されてしまう”。
  • 重複排除:near-dup を除く。同じ例の重複は過学習を招く。
  • train/eval 分割:必ず評価用を切り分ける。これを混ぜると「自分の宿題を採点」する状態(リーク)になり、精度を錯覚する。
  • 多様性:本番で来る入力分布をカバーする。エッジケース・断り方(「分かりません」)も学習対象に入れる。
{"messages":[
  {"role":"system","content":"あなたは当社の見積もりアシスタント。数値は推測せず、無い情報は『不明』と返す。"},
  {"role":"user","content":"型番 TX-200 の標準納期は?"},
  {"role":"assistant","content":"TX-200 の標準納期は5営業日です。在庫状況により前後します。"}
]}

⚠️ リークは“静かに”精度を盛る最悪のバグ。評価セットの一部が学習に混ざると、ベンチは上がるのに本番で滑ります。分割は最初に、決定的に(ハッシュで振り分ける等)行ってください。


実装A:torchtune(PyTorchネイティブ・公式)

Meta/PyTorch 公式の torchtune は、「トレーナも抽象も挟まない、素のPyTorch」が思想です。YAML で recipe を設定し、CLI で回します。

pip install torchtune

# 重みを取得(ライセンス同意済みのHFアカウントが必要)
tune download meta-llama/Llama-3.3-70B-Instruct \
  --output-dir ./Llama-3.3-70B-Instruct

# LoRA で単一デバイス学習(recipe と config を指定するだけ)
tune run lora_finetune_single_device \
  --config llama3_3/70B_lora_single_device \
  dataset.source=json \
  dataset.data_files=./data/train.jsonl

torchtune は config に学習率・LoRA rank・エポック・量子化などが宣言的にまとまっており、差分管理(誰がどの設定で回したか)が効きます。これは再現性=本番運用の生命線です。


実装B:Hugging Face TRL + PEFT(QLoRA)

最も普及している経路。TRLSFTTrainerPEFTLoraConfig を渡すだけで QLoRA になります。

# pip install trl peft transformers bitsandbytes datasets
import torch
from datasets import load_dataset
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from peft import LoraConfig
from trl import SFTTrainer, SFTConfig

MODEL_ID = "meta-llama/Llama-3.3-70B-Instruct"  # 密モデルが現実的な対象

# QLoRA:ベースを 4bit(NF4) で載せる=単一GPUでも大きめモデルに届く
bnb = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16,
)
model = AutoModelForCausalLM.from_pretrained(MODEL_ID, quantization_config=bnb, device_map="auto")
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)

# 学習するのは低ランクのアダプタだけ。注意機構の射影行列を対象にするのが定番。
lora = LoraConfig(
    r=16, lora_alpha=32, lora_dropout=0.05,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
    task_type="CAUSAL_LM",
)

dataset = load_dataset("json", data_files={"train": "data/train.jsonl"})["train"]

trainer = SFTTrainer(
    model=model,
    train_dataset=dataset,
    peft_config=lora,
    args=SFTConfig(
        output_dir="out/llama-domain-lora",
        num_train_epochs=2,                 # 入れすぎは過学習。1〜3で様子を見る
        per_device_train_batch_size=1,
        gradient_accumulation_steps=8,      # 実効バッチを稼ぐ
        learning_rate=2e-4,
        bf16=True,
        logging_steps=10,
        save_strategy="epoch",
    ),
)
trainer.train()
trainer.save_model("out/llama-domain-lora")  # 成果物はアダプタ(小さい)

ポイントは 学習するのがアダプタだけなこと。ベース 70B は凍結・4bit のまま動くので、必要VRAMが現実的な水準に収まります。


実装C:マネージド(運用を AWS に寄せる)

学習基盤を持ちたくないなら AWS にマネージドで寄せます

  • Bedrock のマネージドFT:本稿執筆時点で Llama 2 / Llama 3.2(Vision 含む)等が対象。学習データを S3 に置き、コンソール/APIでジョブを回すとカスタムモデルが払い出される。GPU 運用ゼロ。
  • SageMaker + Bedrock Custom Model Import:torchtune/TRL で作った重み(Llama 2/3/3.1/3.2 系アーキ)を Bedrock に取り込み、既存の Converse API でそのまま叩く。

📌 正確性のための注記:マネージドFTの対応モデル・リージョンは更新されます。最新は Bedrock のモデルカスタマイズ対応表 を必ず確認してください。「やりたいモデルがマネージドFTの対象か」を先に確かめるのが事故防止になります。


評価ゲート:これ無しに本番へ出さない

FT で最も危険なのは「なんとなく良くなった気がする」で出すことです。ホールドアウトでFT前後を機械比較し、回帰を検出してから初めてデプロイします。

# evaluate.py — ベース vs FT後 を同じ評価セットで比較し、合否を判定する
import json, statistics
from typing import Callable

def run_eval(generate: Callable[[str], str], eval_path: str) -> float:
    """各サンプルを採点し平均スコアを返す。採点は完全一致/数値一致/LLM-judge等、用途で選ぶ。"""
    scores = []
    with open(eval_path) as f:
        for line in f:
            ex = json.loads(line)
            out = generate(ex["input"])
            scores.append(score(out, ex["expected"]))  # 0.0〜1.0
    return statistics.mean(scores)

base = run_eval(generate_base, "data/eval.jsonl")
tuned = run_eval(generate_tuned, "data/eval.jsonl")

# 改善が閾値未満、または既存能力の回帰があれば“不合格”としてデプロイを止める。
assert tuned >= base + 0.03, f"改善不足: base={base:.3f} tuned={tuned:.3f}"
print(f"PASS base={base:.3f} -> tuned={tuned:.3f}")

評価は用途に合わせた採点関数が肝です。構造化出力なら完全一致/スキーマ準拠率、要約なら LLM-judge、分類なら F1。「本番で何が正解か」を数値化できて初めて、FT は工学になります。


デプロイとライセンス(命名規約に注意)

  1. アダプタをマージ:LoRA アダプタをベースに統合し、単一の重みにする(推論を軽くするため)。
  2. サーブvLLM で自前サーブするか、Bedrock Custom Model Import で Converse から叩く。
  3. コストを見積もる:自前運用は推論コストの設計で損益分岐を出してから。

⚖️ ライセンス必読Llama Community License では、Llama を使って作った派生モデルを配布・提供する場合、モデル名の先頭に「Llama」を付けることが求められます(例:Llama-YourCompany-Support-8B)。さらに Built with Llama 表示が必要です。社内利用のみなら配布には当たりませんが、外部提供する瞬間に命名・表示義務が発生します。詳細はピラー記事のライセンス章を参照してください。


よくある落とし穴

  • 破滅的忘却(catastrophic forgetting):特化に振りすぎて、元の汎用能力が落ちる。汎用タスクも評価セットに混ぜて回帰を監視する。
  • 過学習:エポック過多・データ過少で、評価が悪化する。早期に eval を見て止める。
  • データリーク:評価が学習に混入。分割を最初に決定的に
  • 小さすぎるデータ:数十件で様式は変わらない。数百〜数千の良質例を狙う。
  • RAGで足りたのにFTした:知識追加は RAG が基本。FTで事実を焼くと陳腐化する。

よくある質問(FAQ)

Q. RAG とファインチューニング、どちらを先にやるべき? A. RAG が先です。知識・鮮度は RAG、振る舞い・様式は FT。多くの案件は RAG+プロンプトで要件を満たし、足りない様式固定だけ軽い LoRA を足す、が費用対効果の最適点です。

Q. どれくらいのデータが必要? A. 様式・口調の固定なら数百〜数千の良質サンプルが目安。量より質。手で磨いた少数が、雑多な大量に勝ちます。

Q. Llama 4(MoE)も微調整できる? A. 技術的には可能ですが、巨大MoEのFTは分散基盤が要り最初の一歩には不向き。まず Llama 3.3 8B/70B などの密モデル+LoRA/QLoRA から始めるのが現実的です。

Q. GPUが無くてもできる? A. できます。Bedrock のマネージドFT(対象モデルは要確認)なら GPU 運用ゼロ。検証だけなら小型モデルを Colab/単一GPUの QLoRA で回せます。

Q. 成果物(アダプタ)はどれくらいの大きさ? A. LoRA アダプタは数十MB級。ベースとは別に配布・差し替えでき、複数ドメイン用のアダプタを使い分ける運用も可能です。


まとめ

ファインチューニングは「賢くする魔法」ではなく、「振る舞いを設計どおりに固定する工学」です。だからこそ、RAGで足りないかを先に疑いデータ品質に投資し評価ゲートを通しライセンス命名を守る——この規律が、デモと本番を分けます。

ドメイン特化した Llama を、RAG との役割分担・評価ハーネス・コスト設計・ライセンス対応まで含めて本番に載せたいなら、実績をご覧のうえご相談ください。一人 × 生成AIで、PoC から本番運用まで一気通貫で設計します。

出典・公式リソース

※ 対応モデル・リージョン・ライセンスは更新されます。実装前に必ず一次情報を確認してください。

友田

友田 陽大

経済産業大臣賞 受賞プロダクト開発者。TypeScript + Python + AWS で、SaaS・業界DX・ 実用レベルの生成AI(RAG)を、要件定義からインフラ・運用まで一人で完遂します。

この記事で解説した技術の適用事例

生成AI音声チャットボット

ケーススタディを見る