勾配降下 入門
現代のあらゆるモデルを訓練しているオプティマイザ。5 つの短いトピックで、1 行の更新規則、 ML で最も調整されるハイパーパラメータ(学習率)、誰もが避けて通れない変種 (ミニバッチ SGD)、新参者を必ず混乱させる語彙(epoch / iteration / step)、 そしてその 4 つから組み上がる訓練ループを扱う。
更新規則
1 行の数式、数十億回繰り返す。
ビー玉が斜面に乗っている様子を思い浮かべる。重力が引っ張る —— 等高線に垂直、最も急な下り方向に。勾配降下とはこのビー玉だ。ビー玉はパラメータベクトル、斜面は損失関数の曲面、「下り」は勾配の反対方向。 小さく 1 歩、いまどこにいるか見直し、また 1 歩。アルゴリズム全体はこれだけ —— 耳にした現代モデルはすべて、このループを回して訓練されている。
1 行の数式に収まる:
θ ← θ − η · ∇L(θ)
4 つの記号、それぞれが具体的な意味を持つ:
θ—— パラメータベクトル。Transformer なら数十億の重み; 教師あり primer の住宅線なら単に(w, b)。L(θ)—— 損失関数。θごとにスカラ 1 つ、小さいほど良い。 損失を直接最適化するのではなく、その勾配の反対方向に進む。∇L(θ)—— 勾配(微積分 primer §4):θと同じ形のベクトル、 最も急な上り方向を指す。マイナス符号がそれを最も急な下りへ反転する。η(イータ)—— 学習率:1 歩の大きさ。§2 の主役。
マイナス符号が仕事の大半を担っている。勾配自体は上りを指す; 私たちが欲しいのは下りだから、その逆へ進む。もし勾配と同じ向きに進めば —— 同じ式の符号をプラスにすれば —— ビー玉は山を駆け上がり、損失は発散し、 訓練は決して収束しない。オプティマイザを手で書くときに最も多いバグがこの マイナス符号の取り違えだ。フレームワークではオプティマイザ内に隠されているが、 各ステップに確かに座っている。
ビー玉の比喩はほぼ正確、ただ 1 点だけ違う:本物のモデルでは斜面が描けない 百万次元空間に住む。上の 1 次元の絵 —— 放物線の損失ボウルとマーカーが下りていく図 —— が最良の直感だ。高次元へ拡張してもアルゴリズムの形は変わらない; 各次元が自分の勾配成分を持ち、ビー玉は全次元同時に進む。
早めに触れておきたい微妙な点:勾配の方向は明確だが、大きさは 損失面の傾きに依存する。急な斜面は長い勾配を、平坦な面は短い勾配を生む。η を掛けた歩幅 η · ‖∇L‖ は、「やることが多い」ときに大きく、 「収束に近い」ときに小さい —— 自動的な適応が規則そのものに織り込まれている。
勾配降下は全域最小を保証しない —— あくまである極小(時には鞍点や平坦) に着く。教師あり primer §3 の凸な住宅 MSE なら極小は 1 つで、勾配降下が必ず見つける。 深層ニューラルネットでは損失面には無数の局所極小があるが、現代の深層学習で 驚くべき経験的事実はその多くがほぼ全域最小と同じくらい良いこと。 だから実用上は勾配降下を回し、たどり着いた極小を受け入れて、 できあがったモデルはたいていうまく動く。
Transformer では:この更新規則は訓練ステップごとに走る。 順伝播が損失を計算し、逆伝播(微積分 primer §3)が数十億のパラメータすべての∇L を同時に出し、オプティマイザが更新を適用する。 この primer の残り 4 節はすべて、この更新 —— と外側のループ —— を 実際に工業規模で走らせるための仕組みについて。
学習率(Learning Rate)
ML で最も影響の大きいつまみ。
θ ← θ − η · ∇L の η が 学習率。 コントロールするのは 1 つだけ:更新ごとにオプティマイザがどれだけ大きく進むか。 地味に聞こえるが、実用上は ML 全体で最もチューニングされるハイパーパラメータだ。 悪い η は、完璧に正しいモデルを台無しにする。
3 つの場面:
- 小さすぎ。ビー玉は極小に向けてじりじりと進む。訓練が永遠にかかり、 GPU 時間を燃やすだけで進歩がない。症状:訓練損失は下がるが、ゆっくりと一定で、 曲線は平坦に折れることがない。
- ちょうど良い。ビー玉は軽快に底まで転がって落ち着く。 訓練損失は最初に急降下し、勾配が縮むと平坦に折れる。 論文の「うまく動いた」訓練曲線はこの形だ。
- 大きすぎ。ビー玉は極小を行き過ぎ、ボウルの反対側に着地し、戻る —— 時には出発点より上まで行く。損失が振動し、最悪
NaNに発散して訓練がクラッシュする。
η を選ぶのはほぼ経験的だ。閉形公式はない —— 妥当な値はモデル構造、 バッチサイズ、パラメータ初期化、損失面の形に依存し、プロジェクトごとに変わる。 ワークフロー:
- まず数桁スイープする。
η = 1e-3が動くなら3e-4と3e-3も試す。 桁を見比べる前に小数 4 桁目で悩むのは無駄。 - 訓練損失曲線を見る。発散するなら
ηを下げる; のんびりした下りなら上げる。最速の初回曲線は「あと一歩で発散」のラインに最も近い曲線。 - LR finder。fast.ai が広めたコツ:小さなミニエポックで
ηを極小から極大へランプアップし、損失が発散する直前のηを選ぶ。 安く、驚くほど効く。
実用では η は一定ではない —— ほぼすべての現代論文が学習率スケジュールを使う:η は訓練ステップの関数だ。 繰り返し現れる 2 つ:
- ウォームアップ。
η = 0から始め、最初の数百〜数千ステップで 目標値へ線形に上げる。なぜか:ランダム初期化直後はパラメータが地雷原を歩く状態で、 早すぎる大きな歩幅が訓練を悪い領域へ叩き込む。ウォームアップは、モデルが 滑らかな盆地を見つけるまでオプティマイザが本格的に動き出すのを待たせる時間だ。 - ディケイ(減衰)。ウォームアップ後、残りの訓練で
ηを 徐々に下げる。よくある形:コサイン(半コサインに沿ってなめらかに低下)、線形(直線で低下)、ステップ(マイルストーンで 10× ずつ下げる)。 目的はどれも同じ:序盤は明らかな作業がある間は大きく進み、終盤は極小近傍での 細かな収束のためにステップを縮める。
典型的な Transformer の訓練曲線は両方を組み合わせる:最初の 2000 ステップで η = 0 から 3e-4 までウォームアップ、その後コサイン減衰で 3e-5 へ。論文は必ずスケジュールを報告する — それが結果を有意に変えるから。
η と相互作用する 2 つの関連パラメータ:
- バッチサイズ。大きいバッチほど勾配推定は正確になる (確率統計 primer §4:分散は
1/nで縮む)。 推定がより正確になれば、より大きな歩幅を安全に取れる。よくある経験則は 「バッチサイズを倍にするとηも(おおむね)倍にできる」 —— ただし超大規模バッチではこの法則は崩れる。 - モメンタム / Adam。速度(モメンタム)を蓄積したり パラメータごとにスケーリング(Adam、RMSProp)するオプティマイザは、 実質的に裸の
η · ∇Lから歩幅を再スケールする。 SGD で「正しい」ηは Adam ではほぼ正しくない —— Adam は十分学習した 座標での実効歩幅がずっと小さいので、ηはより大きくしてよい。
Transformer では:GPT 系列のピーク η は有名どころで 1e-4 〜 6e-4 の範囲、PaLM・Chinchilla 論文も似た値を報告する。 最初の ~0.4% のステップでウォームアップ + コサイン減衰でピークの 0.1× まで、 これが Transformer 文献の事実上の標準スケジュールだ。 ある訓練が不思議とプラトーに陥ったり爆発したりすると、まず誰もが学習率スケジュールを触る。
確率的勾配降下(SGD)
小さなデータの塊から勾配を推定する —— 安く、ノイジーで、現代のあらゆる最適化器が実際にやっていること。
第 1 節は勾配を ∇L(θ) と書いた。ここで L はデータセット全体での損失だ。 数百万・数十億のサンプルで訓練するモデルでは、これは便宜上の嘘でしかない。 毎ステップでデータセット全体の勾配を実際に計算することはできない —— Common Crawl を 1 周するだけで数週間かかる。本物の訓練は「ズル」をする: 毎ステップ、データの小さな塊から勾配を推定する。安く。ノイジーに。普遍的に。
塊の大きさで 3 つの変種に分かれる:
- バッチ勾配降下。訓練集合全体で
∇Lを計算してから 1 歩進む。 「正直」な版。ステップごとに遅く、高く、大規模データでは現実的でない。 - 厳密な意味の確率的勾配降下(SGD)。1 サンプルで
∇Lを計算、 1 歩、繰り返す。ステップ単位では最速。勾配推定はとんでもなくノイジー —— 各サンプルが自分の方向にパラメータを引っ張る —— が、平均すればノイズは打ち消し、 下りには進む。1951 年から存在する概念で、「SGD」の原型。 - ミニバッチ SGD。サンプルの小グループで
∇Lを計算、1 歩、繰り返す。 グループサイズが バッチサイズ:典型的には 32・64・256、 現代の LLM 訓練ではバッチごとに 400 万トークン(数千の系列)。 いいとこ取り —— 2026 年に「SGD」と言えばほぼこれ。
なぜミニバッチが勝つのか? 理由は 2 つ、どちらも理解する価値がある。
計算効率。現代の GPU は、1 バッチの勾配と 1 サンプルの勾配を ほぼ同じ実時間で計算する —— ハードウェアは SIMD 並列で、1 サンプルではシリコンの大半が遊ぶ。 バッチを 1 から 2 に倍増すれば、スループットもほぼ倍増する。256 から 512 に倍増しても 通常は速くなるが、せいぜい 30% 程度 —— GPU が飽和すると、それ以上はステップが 長くなるだけだ。最適点はハードウェア依存。
勾配の品質。1 サンプルからの勾配は、真の(全データ)勾配のノイジーな推定だ —— ランダムな意見のようなもの。n サンプルで平均すると分散は n 倍縮む (確率統計 primer §4 がまた登場)。バッチ 256 はバッチ 1 の SGD と比較して、 各座標のノイズが √256 = 16× 小さい。勾配が滑らかなら、行き過ぎずに 大きく踏み込める。これが追加の計算量を上回ることが多い。
ミニバッチのノイズは純粋なオーバーヘッドではない —— 時に役に立つ。鋭い局所極小は ノイズに不安定だ;ノイジーな勾配降下はそうした点を飛び越え、より平坦な領域に落ち着く —— 平坦な領域は汎化に有利なことが多い。「ある程度のノイズは訓練に良い」と いう小さな文献群もあり、これがフルバッチ勾配降下が安いとしてもそれを使わない理由の一つ。
論文に必ず出てくる実用ノブ:
- 各エポックでシャッフル。シャッフルしないとモデルは毎周回同じ順で 同じミニバッチを見て、「いま何番目のバッチか」を覚える。 訓練前に必ずシャッフルする。
- 勾配累積。論理バッチを 4096 にしたいが GPU には 256 しか乗らない? 256 サンプルで勾配を計算し、それを累積し、16 回繰り返してから1 回だけ更新する。オプティマイザは 4096 の勾配を見るが、ハードウェアは一度に 256 までしか保持しない。
- 線形スケーリング則。バッチサイズを倍にすると、学習率も(おおむね)倍にできる —— 勾配がより正確になり、より大きく踏み込めるから。「臨界バッチサイズ」までは成立し、 それを越えると収益が減る。臨界値はモデルと問題に依存。
Transformer では:現代の LLM は巨大なバッチサイズを使う —— 数百万トークン 単位 —— が、必ず「ミニバッチ + 勾配累積」で実現され、100 万トークンを一度の順伝播・逆伝播で 処理することは決してない。訓練は最初から最後まで本質的にミニバッチで、 過去 70 年で変わったのは「ミニ」の大きさだけだ。論文で「batch size 4M」と読むとき、 それは数千 GPU 上で数十回累積した合計値だ。
エポック · イテレーション · ステップ
「訓練がどれだけ進んだか」を表す 3 つの語 —— 意味は同じではない。
ミニバッチ SGD は訓練を「数え上げ」問題に変える。データセットを塊に切り、各塊が 1 つの更新を生み、更新が積み重なる。その積み重ねを表す語が 3 つあり、論文ですら頻繁に混用される。この短い節の役割は、それらを区別すること。
- ステップ(時に イテレーション) —— 更新規則の 1 回の適用。 順伝播、逆伝播、optimizer.step()。訓練の原子。 PyTorch が「step 12345」、HuggingFace が
global_step=…と表示するとき、 それは 1 回の重み更新。 - イテレーション —— 通常はステップの同義語。 フレームワーク(Keras、初期 TF)では「イテレーション」、ほかでは「ステップ」、 論文では両方が混在する。文脈が違うと言わない限り同義と扱ってよい。
- エポック —— 訓練データセットを 1 周。データセットが 50,000 サンプル、 バッチサイズが 100 なら、1 エポックは
50,000 / 100 = 500ステップ。
1 行の式に収まる:
1 エポックのステップ数 = データセットサイズ / バッチサイズ
同じことに見えるのになぜ 3 つの語があるのか? それぞれ微妙に違う問いに答えるからだ:
- オプティマイザはどれだけ回ったか? ステップを数える —— 更新が適用された回数で、学習率スケジュールの基準もこれ。
- モデルはどれだけのデータを見たか? エポックを数える —— 「訓練集を 7 周見せた」。データカバレッジや過学習リスクを考えるときに使う。
- この訓練は計算コストいくら? ステップ × バッチサイズ × サンプル単価。 またはエポック × データセットサイズ × サンプル単価。答えは同じ、分解の仕方が違う。
もう 1 つ、よく出るが見落としがちな語:
- 総訓練トークン数(または訓練サンプル数) —— 現代 LLM 論文の 見出し数値。GPT-3 はおよそ 3000 億トークン、Chinchilla は 1.4 兆、現代のフロンティアモデルは 10〜15 兆。これは
ステップ × バッチサイズ(トークン換算)—— 大規模訓練では 最もクリーンな「規模」単位だ。「データセット」や「エポック」の境界が曖昧になるから (フロンティア LLM はしばしば 1 エポック未満で訓練し、データセットは再周回ではなく 重複排除と精選で大きさを稼ぐ)。
これらの語につまずきやすい場面:
- 「何エポック?」は有限で再周回するデータセットでのみ意味がある。 Common Crawl の LLM は 1 エポックも完了しない —— データセットが大きすぎて 繰り返せない。「何エポック?」を聞くのは単位が違う、「何トークン?」と聞くべき。
- 「100 ステップ訓練」はバッチサイズなしでは無意味。バッチ 1 の 100 ステップと バッチ 4096 の 100 ステップでは劇的に違う。常に両方を報告する。
- 「損失 vs ステップ」と「損失 vs エポック」のプロット。論文で「損失 vs ステップ」を見たら、それがデータ量で何を意味するかを頭で換算する。 100,000 ステップの滑らかな下降曲線は、200 エポック(小さなデータセット + 何周も) かもしれないし、0.1 エポック(巨大なデータセット + ほぼ毎ステップ新データ) かもしれない —— 汎化に関する物語はまるで違う。
Transformer では:訓練ログは通常 ステップで記録され (学習率スケジュール、チェックポイント間隔の基準)、報告は トークンで行う (「2T トークンで訓練」)。エポックはほとんど出てこない —— フロンティア LLM の データセットが大きすぎ、1 周回るだけで数百万ドルの GPU 時間がかかるからだ。 論文で「300B トークン」と読むときは、それが計算の事実であり、エポックとステップは その周辺の派生記録だ。
訓練ループ
損失を計算、勾配を計算、パラメータを更新 —— 100 万回繰り返す。
この primer のすべての概念は、最終的に 4 行のループに収まり、損失が十分小さくなるか 予算が尽きるまで繰り返される。PyTorch 擬似コード:
for batch in dataloader:
logits = model(batch.inputs) # 順伝播
loss = loss_fn(logits, batch.targets) # スカラ 1 つ
loss.backward() # 逆伝播で .grad を埋める
optimizer.step() # θ ← θ − η · ∇L
optimizer.zero_grad() # .grad をゼロに戻す5 行の Python が、Transformer の訓練アルゴリズム全体だ。読むあらゆる論文、 見るあらゆるモデルカードが、このループを予算が尽きるまで回した結果に過ぎない。 他のすべて —— 分散訓練、混合精度、ZeRO、FlashAttention、勾配チェックポイント —— は、このループをより大きなクラスタでより速く走らせるための工学的インフラだ。
3 つの行ごとの注:
loss.backward()は微積分 primer §3 —— 順伝播中に PyTorch が構築した計算グラフに連鎖律を適用する。各パラメータに対応する∂L/∂θをその.grad属性に書き込む。optimizer.step()は各.gradを読み、 §1 の更新規則(加えてオプティマイザが提供する追加機能:モメンタム、Adam の 座標ごとのスケーリング、重み減衰)を適用し、結果をパラメータテンソルに書き戻す。zero_grad()は、誰もが一度はハマる記録上のディテール。.gradは既定では複数の逆伝播にわたって累積される —— これは仕様で、 §3 の勾配累積を可能にする。だがゼロにし忘れると、次のステップは 「前のバッチ + 今のバッチ」の勾配を使ってしまう。多くのコードは明示的にzero_grad()を呼ぶか、optimizer.zero_grad(set_to_none=True)を使う。
このループが回る様子を見るのが、訓練で一番気持ちいいところだ。 数百万ステップにわたって損失曲線が下がっていく図は、この primer の数学全部の見える対価だ:
ほとんどの訓練曲線に現れる 2 つのフェーズ:
- 初期の急降下。最初の数百ステップで、モデルはランダム初期化の世界から 脱し基本的な構造を学び始める。損失は桁単位で落ちる。log スケールでは ほぼ垂直の下降に見える。
- 長いプラトー。容易な利得が出尽くすと、損失は劇的にゆっくり下がる —— べき乗則型の長い尾。訓練時間の大半はこのプラトーで、最後の僅かな性能を 絞り出すために費やされる。見た目は訓練が止まったようだが、損失は依然下がっている。
実プロジェクトで追加することになる要素:
- 検証評価。数千ステップごとに、ホールドアウトの検証集合 (データ基礎 primer §3)で損失を計算する。検証損失が上がり始めるのに訓練損失が まだ下がっていれば、過学習している(教師あり primer §4) —— 止めるか、 より強く正則化するときだ。
- チェックポイント。N ステップごとにモデル + オプティマイザ状態を ディスクに保存する。クラッシュ、停電、誤ったコード変更 —— チェックポイントが あれば復旧が容易。フロンティア LLM 訓練は数百ステップごとに保存する。
- ログ。損失、学習率、勾配ノルム、スループット (トークン/秒 または サンプル/秒)、GPU 利用率、たまにサンプル出力。 訓練ループは計測がなければ不透明だ;Weights & Biases や TensorBoard が存在するのは 可観測性のため。
- 勾配クリッピング。勾配のノルムをある最大値(よく 1.0)で打ち止めて、 1 つの問題あるミニバッチが数週間の訓練を破壊するのを防ぐ。3 行のコード、 数えきれない訓練を救ってきた。
- 混合精度訓練。順伝播・逆伝播の大半は 16 ビット浮動小数で走り、 オプティマイザの累積器は 32 ビットを保つ。約 2 倍の高速化、2 倍のメモリ削減 —— アンダーフロー回避のために損失スケーリングさえ忘れなければ、ほぼタダ。
Transformer では:上のループはまさに GPT、LLaMA、Claude、Mistral、Gemini —— 現代のすべての LLM の訓練ループだ。違いは規模だけ:数千 GPU が同じループの データ並列コピーを動かし、毎ステップ勾配平均を共有する;系列は単一サンプルではなく 数千トークン;「バッチサイズ」は勾配累積を介して数百万トークン単位。 ループの算数自体は、ラップトップで動かす PyTorch とまったく同じだ。このループを数百万回回すこと、それが現代の AI を成り立たせている全理由だ。