← 機械学習テキスト 一覧

🎓 レベル:標準 | 重要度:A(必須)

📎 前提:事前学習とスケーリング則 | 関連:表現学習と埋め込み(転移学習)

要点(BLUF)


1. 事前学習からファインチューニングへ:なぜ少データで効くのか

LLM はまず事前学習で、膨大なテキストの次トークン予測から汎用的な言語表現を獲得します。ファインチューニングは、この事前学習済みモデルを初期値として、目的のタスクのデータで追加学習する転移学習です(表現学習と埋め込み)。

少データで効く理由は、最適化の言葉で言えば「良い初期点」にあります。損失 L(θ)\mathcal{L}(\theta) を最小化するとき、ランダム初期化 θrand\theta_{\text{rand}} からではなく、事前学習で得た θpre\theta_{\text{pre}} から探索を始めます。

θ=argminθ  Ltask(θ),θ  の初期値=θpre\theta^* = \arg\min_{\theta} \; \mathcal{L}_{\text{task}}(\theta), \qquad \theta \;\text{の初期値} = \theta_{\text{pre}}

要するに、汎用的な特徴抽出(文法・意味・世界知識)はすでにできあがっていて、タスク固有の「使い方」だけを少しずらせばよいので、必要なデータも更新量も小さくて済む、ということです。これは深層学習の特徴階層が再利用可能だという経験則(表現学習と埋め込み)の、LLM 版です。


2. SFT(教師ありファインチューニング)と指示チューニング

SFT(supervised fine-tuning) は、ラベル付きの「入力 → 望ましい出力」ペアでモデルを微調整する、最も素直なファインチューニングです。損失は事前学習と同じ次トークンの交差エントロピーですが、計算するのは応答部分のトークンだけにします。

入力(プロンプト)を xx、望ましい応答を y=(y1,,yT)y = (y_1, \dots, y_T) とすると、

LSFT(θ)=t=1Tlogpθ ⁣(ytx,y<t)\mathcal{L}_{\text{SFT}}(\theta) = -\sum_{t=1}^{T} \log p_\theta\!\left(y_t \mid x,\, y_{<t}\right)

要するに、「この入力にはこう答えてほしい」という正解列をモデルに教師として与え、その応答を出す確率を上げているだけです。事前学習との違いは、学習データが自由なウェブテキストではなく人手で用意した目的志向のペアである点です。

指示チューニング(instruction tuning)

SFT の特に重要な使い方が指示チューニングです。「要約して」「翻訳して」「コードを書いて」のような多様なタスクを自然言語の指示として与え、その応答ペアを大量に集めてSFT します。

ねらいは個々のタスクを覚えさせることではなく、「指示に従う」というメタな振る舞いそのものを汎化させることです。多様な指示で訓練すると、訓練時に見ていない新しい指示にも従えるようになります。事前学習しただけのモデルは「次に来そうな文」を続けるだけで、指示に従う保証はありません。指示チューニングは、その素のモデルを「対話アシスタント」に変える最初の段階です(人間の選好にさらに合わせるのがアラインメント)。

flowchart LR
  Pre["事前学習済みLLM(次トークン予測のみ)"] --> SFT["SFT:入出力ペアで微調整"]
  SFT --> Inst["指示チューニング(多様な「指示→応答」)"]
  Inst --> Follow["「指示に従う」汎化を獲得"]
  Follow --> Align["さらに人間の選好へ:[[12-04_アラインメント]]"]

3. フルファインチューニングの課題

全パラメータを更新するフルファインチューニングは素直ですが、LLM 規模では二つの大きな問題があります。

(1) 計算・保存コスト:数十億〜数千億のパラメータすべてに勾配と最適化状態(Adam なら勾配・一次/二次モーメントで実質パラメータ数の数倍のメモリ)を持つ必要があり、学習が非常に重くなります。さらにタスクごとに元モデルと同サイズの新モデルが丸ごとできてしまうため、複数タスクに展開すると保存コストが膨らみます。

(2) 破滅的忘却(catastrophic forgetting):新しいタスクのデータだけで全重みを動かすと、事前学習で得ていた汎用能力が上書きされて劣化します。

θpre    タスクデータで全更新    θtask,Ltask ⁣狙い通り    だが    汎用能力 ⁣忘却\theta_{\text{pre}} \;\xrightarrow{\;\text{タスクデータで全更新}\;}\; \theta_{\text{task}}, \qquad \underbrace{\mathcal{L}_{\text{task}}\!\downarrow}_{\text{狙い通り}} \;\; \text{だが} \;\; \underbrace{\text{汎用能力}\!\downarrow}_{\text{忘却}}

要するに、新タスクに最適化するあまり、もとの「何でも屋」としての力を失ってしまう現象です。狭いデータに全パラメータを合わせ込むほど起きやすく、過学習(ニューラルネットの正則化)とも地続きの問題です。緩和の定石は、学習率を小さくする・一部の層を凍結する・更新するパラメータ自体を減らすことです。最後の「更新を減らす」を体系化したのが次の PEFT です。


4. PEFT(parameter-efficient fine-tuning)

PEFT は、事前学習済みの重みの大半を凍結し、ごく一部のパラメータだけを学習・追加してタスクに適応させる手法の総称です。

観点フルファインチューニングPEFT
更新するパラメータ全部ごく一部(数 % 以下)
保存サイズ(タスクごと)元モデル丸ごと小さな差分だけ
破滅的忘却起きやすい起きにくい(元重みを凍結)
学習コスト高い低い

PEFT にはいくつか系統があります。追加型(アダプタ:層の間に小さな学習可能モジュールを挿入)プロンプト型(入力側に学習可能なベクトルを足す)、そして重み更新を低ランクで近似する LoRA です。元の重みを凍結するので、事前学習の知識が保たれ忘却が起きにくいのが共通の利点です。


5. LoRA:重み更新を低ランク分解する(中心)

LoRA(Low-Rank Adaptation) は PEFT の中でも現在もっとも広く使われる手法です。アイデアは一行で言えば、「重みの更新分 ΔW\Delta W を、低ランクの積 BABA で近似する」です。

着想:更新は低い「内在ランク」を持つ

LoRA の出発点は、事前学習済みモデルの適応に必要な重みの変化 ΔW\Delta W は、本質的に低ランクであるという仮説です(Hu ら 2021)。巨大なパラメータ空間でも、解は低い内在次元(intrinsic dimension)に乗るという観察にもとづきます。

要するにΔW\Delta W をフルランクで自由に学ぶ必要はなく、わずかな方向(低ランク)だけ動かせばタスク適応には十分だろう、という賭けです。

定式化

事前学習済みの重み行列を W0Rd×kW_0 \in \mathbb{R}^{d \times k} とします。フルファインチューニングはこれを W0+ΔWW_0 + \Delta W に更新しますが、LoRA は ΔW\Delta W二つの小さな行列の積に制約します。

W=W0+ΔW=W0+BA,BRd×r,    ARr×k,    rmin(d,k)W = W_0 + \Delta W = W_0 + BA, \qquad B \in \mathbb{R}^{d \times r}, \;\; A \in \mathbb{R}^{r \times k}, \;\; r \ll \min(d, k)

学習中、W0W_0 は凍結して勾配を流さず、低ランクの AABB だけを更新します。入力 xx に対する順伝播は次のようになります。

h=W0x+ΔWx=W0x+BAxh = W_0\,x + \Delta W\,x = W_0\,x + B A\,x

実装上は安定化のため、AA をガウス分布で、BBゼロで初期化します。すると学習開始時は BA=0BA = 0、つまり W=W0W = W_0 となり、ちょうど事前学習済みモデルそのものから微調整が始まるので破綻しません。さらにスケーリング係数 α\alpha を使い、更新の大きさを αr\frac{\alpha}{r} で調整するのが一般的です。

h=W0x+αrBAxh = W_0\,x + \frac{\alpha}{r}\,B A\,x
flowchart LR
  X["入力 x"] --> W0["W0(凍結・更新しない)"]
  X --> A["A(r×k・学習する)"]
  A --> B["B(d×r・学習する、初期値ゼロ)"]
  W0 --> ADD["足し合わせ:h = W0 x + B A x"]
  B --> ADD
  ADD --> H["出力 h"]

なぜコストが桁違いに下がるのか

全更新では ΔW\Delta W の自由度は d×kd \times k 個です。LoRA はそれを AAr×kr \times kBBd×rd \times r、合わせて r(d+k)r(d + k) 個に減らします。

dkフル更新    r(d+k)LoRA,rd,k\underbrace{d\,k}_{\text{フル更新}} \;\longrightarrow\; \underbrace{r(d + k)}_{\text{LoRA}}, \qquad r \ll d, k

たとえば d=k=4096d = k = 4096r=8r = 8 なら、dk1.7×107dk \approx 1.7 \times 10^7 に対し r(d+k)6.6×104r(d+k) \approx 6.6 \times 10^4学習する数が約 250 分の 1 になります。

要するに、勾配と最適化状態を持つべきパラメータが激減するので、必要メモリと計算がまとめて小さくなります。保存も同様で、タスクごとに丸ごとモデルを複製せず、小さな A,BA, B(数 MB 程度)だけを差分として残せばよくなります。1 個の凍結した事前学習モデルに、タスクごとの LoRA を付け替える運用ができます。

推論時はマージできる

LoRA のもう一つの利点は、推論時に追加コストがゼロにできることです。学習が終われば BAB A を一度だけ計算して元の重みに足し込み、

W=W0+BAW' = W_0 + B A

という単一の行列 WW'マージできます。こうすると推論経路は普通の線形層と同じで、アダプタを別計算する遅延が生じません。差分のまま付け替えたいときはマージせず分離しておく、という使い分けも可能です。


⚠️ 要最新確認:派生手法とどれを使うか

LoRA を起点に多くの派生が出ており、ここは移り変わりが速いので最新確認が必要です(2026年6月時点)。


まとめ

ファインチューニングは、事前学習の汎用表現を下流に転用する転移学習です。SFT と指示チューニングで「指示に従う」モデルを作り、フルファインチューニングの重さと破滅的忘却を、重み更新を低ランク分解する LoRA を中心とした PEFT で回避します。LoRA の本質は「ΔW=BA\Delta W = BA と低ランク近似し、W0W_0 を凍結して A,BA, B だけ学ぶ」ことに尽き、これが学習・保存コストを桁違いに下げ、推論時にはマージで追加コストをゼロにできます。人間の選好にさらに合わせるアラインメントへ続きます。


対応するシミュレーション

simulations/lora_low_rank.py:ファインチューニングでの重みの変化 ΔW\Delta W を、低ランクの積 ΔWBA\Delta W\approx BA(細い2枚)で近似します。ランク rr を少し上げるだけで近似誤差が急に下がること、必要パラメータ数 2dr2dr がフルの d2d^2 よりずっと少ないこと(例:15.6%のパラメータで更新の9割を再現)を可視化します。重みの変化が実質的に低ランクなので LoRA が成り立ち、1つの基盤モデルに複数のLoRAを差し替えられます。

低ランク近似ΔW=BAで省パラメータ

関連ノート