ファインチューニングに対する誤解から始めたい
Gemma 4 のような公開重みモデルが手に入ったとき、多くの人が最初に期待するのはフルファインチューニングです。一方で、実際にやってみると「個人の予算と計算資源では無理」という壁にぶつかります。27B のモデルを素直に全パラメータ更新するとなると、クラウド GPU を数百時間動かすような計算コストがかかり、研究者でも躊躇する領域です。
しかしここで諦めてしまうのはもったいない話で、LoRA と QLoRA を使えば、同じモデルを個人予算で「自分用に仕上げる」ことは十分にできます。私自身、小規模な要約ワークフローの精度を上げる目的で、Gemma 4 9B と 27B の両方に対して LoRA / QLoRA の学習を回してきました。この記事はその経験をベースに、「公開チュートリアルには載らない実務的な落とし穴」を中心にまとめたものです。
ベンチマークの話はしません。公開重みのモデルに対して、自分のデータで学習を回し、その結果を実際のワークフローに組み込むまでの、手触りのある部分を書きます。
LoRA / QLoRA とは(改めて整理しておく
概要部分は手短に。LoRA(Low-Rank Adaptation)は、元のモデルの重みを凍結したまま、各層に小さな「差分」を追加で学習する手法です。全パラメータを更新するフルファインチューニングと違い、学習するパラメータ数がモデル全体の 0.1〜1% 程度に収まるため、メモリ使用量も計算コストも劇的に下がります。
QLoRA はその拡張で、元のモデル重みを 4bit 量子化した状態で保持しつつ、LoRA のアダプタだけを通常精度で学習します。これによって、さらにメモリを節約でき、個人の GPU でも 70B クラスまで視野に入ってきます。Gemma 4 のような 9B / 27B なら、消費者向け GPU でも十分に回せます。
個人的な感覚として、LoRA と QLoRA のどちらを選ぶかの判断は次のような目安で決めています。
- 24GB 以上の GPU(RTX 4090 や L4 など)が使えるなら、9B まではプレーン LoRA で十分
- 27B を扱う場合、QLoRA にしないと 24GB でも厳しい
- 推論時に量子化を使う前提なら、学習時も QLoRA に揃えたほうが挙動が合いやすい
データ準備が結局いちばん効く
ファインチューニングで成果が出るかどうかは、8 割がデータ準備で決まります。「公開されているレシピの通りに学習を回したのに精度が上がらない」という相談を受けたとき、9 割以上はデータ側の問題です。
学習データの粒度を決める
最初に決めるべきは、1 件のサンプルの粒度です。Gemma 4 のような指示応答型モデルのファインチューニングなら、1 件 = 1 つの入力 + 1 つの出力、というペアが基本形になります。このとき、入力が極端に長かったり、出力が複雑な構造物だったりすると、学習が不安定になります。
個人的には、1 サンプルあたりトークン数 1,500 以内、出力部分は 600 トークン以内に収まるように分割するのが、最初の試行として扱いやすいです。これより長くなると、学習時に勾配のばらつきが増えて、収束しづらくなります。
データの「一貫性」がモデルの態度を決める
Gemma 4 を自分用に仕上げるとき、最も大事なのは「ファインチューニングで何を学ばせたいか」をデータ全体で一貫させることです。要約タスクならば、毎回「何文字で」「どんな観点を拾って」要約するかをデータ内で揃える必要があります。ここがブレると、モデルは中途半端な平均を学んでしまい、元の Gemma 4 より使い勝手が悪くなることもあります。
私が学んだ重要な教訓は、「少数でも一貫したデータのほうが、大量だが不一致のあるデータより強い」です。2,000 件の一貫したデータは、10,000 件のばらばらなデータより確実に良い結果を出します。
合成データを使うときの注意
時間がない場合、Gemini 2.5 Pro や Claude を使って学習データを合成することも選択肢に入ります。これ自体は悪くないのですが、合成データだけで学習したモデルは「教師モデルの癖」を色濃く受け継ぎます。それが悪いわけではないのですが、後から挙動を制御しにくくなるというデメリットがあります。
私がやっているのは、自分で手作業で作った 300 件の「正解例」を核にして、そこから合成データを 1,500 件ほど増やす、というハイブリッド方式です。核となる正解例が方針を決める土台になり、合成データは量を補う役割に徹してくれます。
学習設定の実用的な勘所
学習のハイパーパラメータは、公開されているレシピをベースに、自分のデータに合わせて調整していくことになります。ここでは、私が何度か失敗して学んだ、意識しておきたいポイントを書いておきます。
LoRA の rank (r) をむやみに上げない
LoRA のランク r は、学習する差分の表現力を決めます。数値が大きいほど表現力は上がりますが、その分過学習もしやすくなります。ネット上のサンプルコードで r=64 のような大きな値を見かけますが、2,000 件程度のデータで学習するなら r=8 または r=16 から始めるのがおすすめです。
私の経験則では、データ量が 10,000 件を超えるまでは r=16 で十分です。rank を上げると学習効率は上がりますが、一般化性能が落ちやすくなるので、評価結果を見ながら調整します。
学習率とバッチサイズの目安
学習率 2e-4、効果バッチサイズ 16〜32 あたりが、LoRA の一般的な安全圏です。QLoRA だと 4bit 量子化の影響で勾配が少し不安定になるので、学習率を 1e-4 まで下げると安定することが多いです。
エポック数は、最初は 3 エポックで止めて挙動を見るのが安全です。データが少ない場合に過学習を避けるため、early stopping の代わりに「バリデーション損失が悪化し始めたら止める」という単純なルールで十分機能します。
target_modules をどう選ぶか
LoRA を適用する層(target_modules)は、Gemma 系なら q_proj, k_proj, v_proj, o_proj をまず押さえます。余裕があれば gate_proj, up_proj, down_proj まで含めて FFN 層にも効かせると、小規模データで効きが良くなる傾向があります。
# Hugging Face PEFT のおおまかな設定例
from peft import LoraConfig
lora_config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=[
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj",
],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM",
)この設定はあくまで出発点です。自分のデータと目的に合わせて、r と target_modules は実験で微調整していきます。
学習が終わったあとの評価をサボらない
ファインチューニングが完走すると、「動いた!」という満足感があります。ただ、本当に役立つモデルになったかどうかは、ここからの評価で決まります。
学習データに含まれない入力で試す
最も基本的なチェックですが、見落としがちです。学習時に使ったサンプルを入れて出力を見るのは「丸暗記できたか」の確認にしかなりません。学習データには含まれない入力を数十件用意して、期待する挙動が再現するかを確認します。
元の Gemma 4 との一対比較
自分用ファインチューニングをしたモデルと、元の Gemma 4 に、同じプロンプトを入れて出力を並べて比較します。これをやると、「思っていた方向に動いていない」ことに気付く場合があります。例えば、要約の長さは学習データ通りになったが、肝心の内容の選び方は元モデルより悪くなっている、といったケースです。
比較の際は、自分が評価者として盲検にするのが理想です。どちらが新モデルか見えない状態で、純粋に出力の好ましさで判定すると、思い込みでの過大評価を避けられます。
失敗パターンを分類する
出力の中で気に入らなかったものを集めて、失敗パターンを分類しておきます。「長すぎる出力」「指示を無視する出力」「内容が薄い出力」など、カテゴリごとに分けておくと、次の学習でデータをどう補強すればいいかが見えてきます。
ファインチューニングは一回で完成しません。「今回の失敗パターン」を次のデータ改善に反映させる、という往復を何周かすることで、少しずつ仕上がっていくものです。
Antigravity ワークフローに組み込む
ファインチューニング済みの Gemma 4 アダプタができたら、Antigravity の日常ワークフローに組み込んで使い始めます。ここでの設計が、最終的に便利な道具になるか、ただの学習記録になるかを分けます。
アダプタだけをデプロイする
LoRA / QLoRA の利点の一つは、元のモデル本体とアダプタを分離してデプロイできる点です。本体の 27B モデルは共通で持っておき、用途別のアダプタ(要約用・分類用・翻訳用など)をいくつか切り替えて使う運用が現実的です。
推論サーバー側で、呼び出し時に「どのアダプタを使うか」を指定できるようにしておくと、Antigravity 上からもタスクに応じて使い分けられます。私は vLLM の LoRA サポートを使ってこの構成を組んでいます。
Antigravity エージェントから呼ぶ
Antigravity のエージェントから自分のファインチューニング済みモデルを呼ぶ場合、OpenAI 互換の API エンドポイントとして公開するのが最も整合性が取れます。vLLM はこの互換 API を標準で提供するので、Antigravity の設定側で「カスタムエンドポイント」として登録すればそのまま使えます。
エージェントワークフローの中で、「要約は自家製モデル、画像解釈は Gemini、コード生成は Claude」のように多モデルを混ぜると、用途ごとに最適なものを選べるようになります。ファインチューニング済みモデルは、汎用モデルには真似できない「自分の文体・自分の分類軸」を提供する役割で使うと映えます。
アダプタのバージョン管理
アダプタは学習のたびに微妙に別物になります。自分のワークフローにデプロイする前に、どの学習データ・どの設定で作ったアダプタかをタグ付けして管理しておくと、あとで問題が起きたときに切り戻せます。
私は GitHub の Release 機能を使って、アダプタファイルとその時の学習設定 YAML をセットで保存しています。派手な仕組みではありませんが、これだけで「あの時のモデルに戻したい」が確実に実行できるようになります。
どこから始めるか — 最小の検証サイクル
最後に、個人開発者が今日から始める場合の最小サイクルを書いておきます。
最初の 1 週間は、データ作りだけに集中します。自分が「Gemma 4 にこう答えてほしい」というサンプルを、手で 200 件ほど作ります。合成データはまだ作りません。この 200 件が、あとのすべての学習の土台になります。
次の 1 週間で、この 200 件だけを使って、9B モデルに対して LoRA を一度回してみます。学習設定は記事中に挙げたデフォルト(r=16, 学習率 2e-4, 3 エポック)から始めます。学習自体は、クラウド GPU で 1〜2 時間あれば終わります。
学習が終わったら、評価を丁寧にやります。学習データに含まれない入力を 30 件用意して、元 Gemma 4 と比較します。ここで「方向性は合っている」と確信できたら、次は合成データでサンプル数を増やします。確信が持てない場合は、データを作り直すほうが、学習設定をいじるより確実に改善につながります。
このサイクルを 3 回ほど回すと、自分のワークフローで実際に使える Gemma 4 アダプタができあがっています。モデルを「使う」側から「仕立てる」側に回ると、AI ツールとの関わり方が一段深くなります。Antigravity のような実行環境があると、その仕立て上げたモデルを日常に馴染ませやすくなります。次の学習サイクルに踏み出すきっかけになれば幸いです。