AI・データ●●●●○

ファインチューニング

Fine-Tuning ・ ふぁいんちゅーにんぐ

学習済みモデルに追加データで再訓練を施し、特定の口調・形式・領域へ適応させる手法。

✦ 30秒で試す — 航海元の重みは1つも動かさずに、モデルの癖を変える訓練する数は、元の層の数のどれくらい?予想してみる

概要

ファインチューニングは、すでに学習を終えたモデルに対して、目的に特化した追加データで再訓練を施し、特定の口調・出力形式・専門領域へ適応させる手法です。汎用のLLMを「自社サポートの応対スタイルで答えるモデル」「医療文書の分類に特化したモデル」のように仕立て直す、いわばモデルの仕上げ調整(fine tune = 微調整)にあたります。

土台になるのは、膨大なデータで一般的な言語能力を獲得済みの「事前学習済みモデル」です。そこに数百〜数万件程度の目的特化データを追加で学習させることで、ゼロから作るのとは比べものにならない小さなコストで専用モデルが得られます。今日よく使われるのは、モデル本体の重みには手を付けず、小さな追加部品だけを訓練する LoRA のような軽量な方式です。プロンプトエンジニアリングやRAGと並ぶ、LLMを実務に適応させる主要な選択肢のひとつです。

なぜ生まれたか

ニューラルネットワークをゼロから訓練するには、膨大なデータと計算資源が必要です。現代のLLMの事前学習には数兆トークン規模のテキストと、数千台のGPUを数か月動かす計算が投じられており、これを個々の企業やタスクごとに繰り返すのは非現実的です。一方で、汎用モデルをそのまま使うと、専門用語の扱い・出力形式・応対の流儀が目的に合わない、という問題が残ります。

そこで機械学習の世界で育ったのが「転移学習」という考え方です。大規模データで獲得された汎用的な能力は別のタスクにもそのまま活きる — だから高価な事前学習は一度だけ行い、各タスクへの適応は軽い追加学習で済ませればよい、という分業です。画像認識では ImageNet で学習したモデルを流用するのが2010年代半ばには定石になり、言語でも2018年の ULMFiT や BERT が「事前学習してからファインチューニング」という型を確立しました。ChatGPT のような対話モデル自体も、事前学習済みモデルに「指示と模範応答」のデータでファインチューニング(instruction tuning)を施し、さらにRLHFで好みに合わせて作られています。

ところがモデルが数十億〜数千億パラメータへ巨大化すると、今度はファインチューニングそのものが重くなりました。全部の重みを更新すると、重みと同じ大きさの勾配と、その2倍ほどのオプティマイザの状態(Adam なら2つの移動平均)をメモリに持つ必要があり、タスクごとにモデル全体のコピーも残ります。この重さを解くために、2019年のアダプタ(Houlsby ら)、2021年の LoRA(Hu ら、Microsoft)と、「少しのパラメータだけを足して訓練する」手法が生まれました。

詳細

全パラメータ更新と PEFT — どこまで書き換えるか

最も素朴な方法は、モデルの全パラメータを追加データで更新する「フルファインチューニング」です。適応の自由度は最大ですが、Transformerベースの大規模モデルでは数十億個の重みすべてに勾配とオプティマイザの状態が要り、訓練にも保存にも巨大なGPU資源を要します。タスクごとにモデルの完全なコピーを持つことになるのも重い負担です。

この重さを解決したのが、PEFT(Parameter-Efficient Fine-Tuning、パラメータ効率的ファインチューニング)と総称される軽量手法群で、代表格が LoRA(Low-Rank Adaptation)です。LoRA は元の重みを凍結したまま、各層に小さな追加パラメータ(全体の1%未満)だけを差し込んで訓練します。性能はフルファインチューニングに迫りつつ、必要な GPU メモリは大幅に減り、タスクごとの成果物も数十 MB 程度のアダプタファイルだけで済みます。

フルファインチューニングLoRA層 1 — 全重みを更新層 2 — 全重みを更新層 3 — 全重みを更新すべての重みに勾配とオプティマイザ状態が必要成果物はモデル全体のコピー層 1 — 凍結層 2 — 凍結層 3 — 凍結訓練するのは小さなアダプタのみ、全体の1%未満成果物は小さなアダプタファイルだけ訓練で更新される凍結されたまま
フルファインチューニングと LoRA の比較 — LoRA は元の重みを凍結し、小さなアダプタだけを訓練する

LoRA の「低ランク」とは何か

LoRA の中身は1行の式で書けます。ある層の重み行列を W(d×k)とすると、ファインチューニングで欲しいのは更新 ΔW を足した W + ΔW です。LoRA はこの ΔW を、細長い2本の行列の積 BA で置き換えます。B は d×r、A は r×k で、r は d や k よりずっと小さな数(4〜64 程度)です。W は凍結し、訓練するのは B と A だけです。入力 x に対する出力は h = Wx + BAx となり、元の経路の横に「k 次元を r 次元に縮めてから d 次元に戻す」細い脇道が1本増えた形になります。

入力 xk 次元W(d×k)事前学習の重み凍結して動かさないA(r×k)k 次元 → r 次元B(d×r)r 次元 → d 次元+出力 hWx + BAxd = k = 4096、r = 8 ならW: 約1,678万個(凍結)A と B: 65,536個(訓練する)B は 0 で初期化するので、学習の開始時は元のモデルと同じ
LoRA の脇道。凍結した W の横に、k 次元を r 次元へ縮めて d 次元へ戻す細い経路を足し、出力で足し合わせる

なぜこれで足りるのでしょうか。積 BA の1つ1つの成分は、B のある行と A のある列の掛け算の和です。r = 1 なら、BA は「B の列ベクトル × A の行ベクトル」という縞模様1枚にしかなりません。r を増やすと縞を r 枚まで重ねられるようになり、表せる模様が増えます。ランクとは、この「重ねられる縞の枚数」のことです。LoRA の論文は、ファインチューニングで実際に必要な更新 ΔW は、行列の大きさの割にごく少ない枚数の縞で近似できる(固有のランクが低い)と観察し、それなら最初から少ない枚数に絞って訓練すればよい、と考えました。訓練するパラメータは d×k から d×r+r×k に減り、d = k = 4096、r = 8 の層なら約1,678万個が65,536個(0.4%)になります。

下の部品では、8×12 の小さな W で確かめられます。B と A のマスを動かして縞ができる仕組みを見てから、目標の模様へ勾配降下で近づけてみてください。「十字」はランク1では写しきれず、「でたらめ」はランク4でも写しきれません。

⚡ 体験: 細長い2本の行列で、大きな W を動かす
A(1×12)B(8×1)W(8×12・凍結)+ BA目標の更新(縞・ランク1)いまの BA目標との一致度0%
ランク r
目標の更新
訓練するパラメータ d×r+r×k20全部を更新 d×k96比21%実物の層(4096×4096)なら0.05%

左の細長い B のマスを1つ上下にドラッグしてください。W は凍結されたままで、更新は B×A の積だけです。

マスの色: 金=正、青=負、濃さ=大きさ。中央は W(凍結、薄い地模様)に BA を足した更新後の重み。本物の層は d=k=4096 ほどで、r=8 なら訓練するのは 65,536 個、全体(約1,678万個)の0.4%です。

実装上の細部にも意味があります。B を 0、A を小さな乱数で初期化するので、学習の開始時点では BA = 0 で、モデルの出力は元とまったく同じです。更新の大きさは α/r という係数で調整し、r を変えても学習率を調整し直さなくて済むようにします。推論時は W + BA を一度計算して元の行列に書き戻せば(マージ)、追加の計算はゼロになります。逆にマージせずにおけば、1つの土台モデルに用途別のアダプタを差し替えて使えます。どの行列に差し込むかも選べ、原論文は注意機構の Q と V の射影だけでも十分な効果を示しましたが、近年はすべての線形層に入れる設定もよく使われます。

QLoRA — 量子化と組み合わせる

LoRA で訓練するパラメータは減っても、凍結した W そのものはメモリに載せる必要があります。2023年の QLoRA(Dettmers ら)は、凍結した W を4ビットに量子化して載せ、その上で LoRA のアダプタだけを16ビットで訓練する組み合わせです。正規分布に近い重みに合わせて目盛りを配った NF4 という4ビット形式と、量子化の係数自体をさらに量子化する二重量子化などの工夫で、650億パラメータのモデルを48GB の GPU 1枚でファインチューニングできることを示しました。家庭用や単体の GPU で LLM をカスタマイズする流れは、ここから一気に広がりました。

何を学ばせるか — データがすべて

ファインチューニングの成否は、手法よりも訓練データの質で決まります。LLMの場合、典型的なデータは「入力(指示や質問)と理想の出力」のペアで、数百〜数万件を人手で整備します。ここで重要なのは、ファインチューニングが得意なのは「振る舞いの型」を教えることであって、「事実知識」を確実に覚えさせることではない、という点です。出力形式・口調・タスクの手順は少量のデータでよく定着しますが、個別の事実を注入しようとすると、覚え漏れや既存知識との混線が起きやすく、事実が変わるたびに再訓練が必要になります。知識を足したいなら、検索してコンテキストウィンドウに入れる RAG のほうが向いています。

手段の選び方は、軽い順に「プロンプトエンジニアリング → RAG → ファインチューニング」と試すのが定石です。プロンプトの指示と例示で直らない振る舞いの癖 — 特殊な出力形式の厳守、ブランド固有の文体、プロンプトに書ききれない暗黙の作法 — を焼き込むのがファインチューニングの出番です。使い分けの詳しい比較は RAG の記事に譲ります。

落とし穴 — 破滅的忘却と評価

代表的な落とし穴が「破滅的忘却(catastrophic forgetting)」です。特定タスクのデータに寄せて訓練しすぎると、モデルが事前学習で得た汎用能力を失い、ターゲット以外の入力への応答が壊れることがあります。学習率を抑える、汎用データを混ぜる、LoRA のように元の重みを凍結する、といった対策が採られます(LoRA でも忘却はゼロにはなりません)。少数のデータへの過学習で応答が不自然に画一化する問題もあるため、学習に使わなかった評価用データでターゲットの性能と汎用能力の両方を測ることが欠かせません。安全のために施された調整が、無害に見える少量のデータでのファインチューニングで弱まることがある点も知られています。

最後にコストの見積もりです。訓練データの整備と評価には人手がかかり、土台のモデルが新しい版に変わるたびにファインチューニングはやり直しになります。基盤モデルの進化が速い領域では「プロンプトと RAG で粘るほうが結果的に安い」ケースも多い、という点は意思決定のときに押さえておきたいところです。

試問

8×12 の小さな重みの表 W は凍結されていて、細長い B(8×r)と A(r×12)の積 BA だけが更新として足されます。ランク r(B と A の幅)を 1〜4 から選び、「学習させる」を押すと、B と A が目標の模様に近づくよう自動で訓練されます。目標は、横の帯と縦の帯が交わる「十字」です。

✦ 命題挑戦中

訓練するパラメータを W の半分以下に抑えたまま、目標の「十字」を写しきれ

  • 目標「十字」との一致度が 97% 以上
  • 訓練するパラメータが W 全体(96 個)の半分以下
⚡ 体験: 十字を、訓練するパラメータを抑えて写す
A(1×12)B(8×1)W(8×12・凍結)+ BA目標の更新(十字)いまの BA目標との一致度0%
ランク r
訓練するパラメータ d×r+r×k20全部を更新 d×k96比21%実物の層(4096×4096)なら0.05%

左の細長い B のマスを1つ上下にドラッグしてください。W は凍結されたままで、更新は B×A の積だけです。

マスの色: 金=正、青=負、濃さ=大きさ。中央は W(凍結、薄い地模様)に BA を足した更新後の重み。本物の層は d=k=4096 ほどで、r=8 なら訓練するのは 65,536 個、全体(約1,678万個)の0.4%です。