Grokking(グロッキング)— 過学習のはるか先で突然訪れる汎化を実測する

機械学習を学ぶと、必ずこう教わります。「訓練精度が100%に達してテスト精度が上がらなくなったら、それは過学習。そこで訓練を止めましょう」——早期停止(early stopping)は、実務でも定番中の定番のテクニックです。

ところが2022年、この常識を根底から揺さぶる現象が報告されました。小さなアルゴリズム的課題でニューラルネットを訓練し続けると、訓練精度100%(完全な過学習状態)に到達してから、さらに数十倍のステップ数を経たある日、テスト精度が突然ほぼ0%から100%へ跳ね上がるのです。Power ら(OpenAI, 2022)はこの現象を grokking(グロッキング) と名付けました。grokはSF小説由来の俗語で「深く完全に理解する」という意味。モデルがデータを「丸暗記」した後に、まるで本当の規則を「腹落ち」するかのように振る舞うことから付けられました。

本記事では、この不思議な現象を眺めるだけでなく、手元のPCで実際に再現します。剰余加算というトイ課題で、訓練精度100%到達(step 150)から約60倍のステップを経てテスト精度が急上昇する(step 9,150で90%到達)様子を実測し、weight decayがこの現象の鍵を握ることも実験で確かめます。

grokkingを理解すると、次のような視界が開けます。

  • 「過学習したら終わり」の再考: 早期停止で切り捨てていた領域の先に何があるのかを知ることで、正則化と汎化の関係をより深く理解できます
  • 機械的解釈性への入口: grokkingしたモデルの中身を開けると、驚くほど美しいアルゴリズム(フーリエ回路)が見つかります。「モデルが何を学んだか」を回路レベルで特定する研究の代表例です
  • LLMの創発能力の理解: 訓練を続けるとある時点で能力が急に立ち上がる——大規模言語モデルで観察される「創発」的な振る舞いを考えるうえで、grokkingは最小の実験場になります

本記事の内容

  • grokkingとは何か — 3幕構成の学習曲線
  • 剰余加算というトイ課題の設計
  • PyTorchによる再現実験(訓練100%→長い停滞→突然の汎化)
  • weight decayが握る鍵 — 記憶解と汎化解の綱引き
  • 訓練データ量とgrokking時期の関係
  • なぜ突然汎化するのか — Nandaらのフーリエ回路による機構的説明

まずは、この現象の全体像を1枚の絵で掴みましょう。

grokkingの模式図: 記憶から長い停滞を経て突然の汎化

grokkingの学習曲線は3幕構成です。①訓練精度(青)はあっという間に100%へ——モデルは訓練データを丸暗記します。②その間テスト精度(赤)は当てずっぽうの水準に張り付いたまま、何千ステップも停滞します。③そして突然、テスト精度が立ち上がり100%へ。この「長い停滞の後の急上昇」がgrokkingです。以降、この曲線を実際に自分の手で描くことを目標に進めていきます。

前提知識

この記事を読む前に、以下の記事を読んでおくと理解が深まります。

grokkingとは — 常識に反する学習曲線

私たちが信じてきた学習曲線

教科書的な理解では、訓練を続けたときのテスト誤差はU字を描きます。最初は訓練とともに下がり(学習不足の解消)、ある点を境に上がり始める(過学習の開始)。だから「テスト誤差が上がり始めたら止める」のが早期停止であり、訓練精度100%でテスト精度が低い状態は「回復不能な過学習」として訓練打ち切りのサインとされてきました。

Powerらが見たもの

Power ら(2022, arXiv:2201.02177)は、二項演算の表(たとえば割り算やべき乗の演算表)の一部だけを見せて残りを予測させる課題で、小さなTransformerを普通なら止めるところのはるか先まで訓練し続けました。すると、訓練精度100%到達から10倍、100倍、時には1000倍のステップ数を経て、テスト精度が突然跳ね上がったのです。

重要なのは、この間モデルには何も新しい情報が与えられていないことです。同じ訓練データを、同じ損失関数で、ただ最適化し続けただけ。それなのに、モデルの内部では「丸暗記の解」から「規則を理解した解」への静かな移行が進んでいた——これがgrokkingの核心的な謎です。

Powerらの元実験ではさらに極端なケースも報告されています。ある演算では訓練精度100%到達が数百ステップだったのに対し、テスト精度の立ち上がりは10万ステップ以降——1,000倍近い遅れです。また彼らは、訓練データの割合を減らすとこの遅れが急速に伸びること、weight decayをはじめとする正則化が遅れを大幅に縮めることも系統的に調べており、この2つの観察が後の理論的理解(後述する記憶解と汎化解の綱引き)の土台になりました。

では、この現象を再現するにはどんな課題が適しているのでしょうか。次のセクションで実験の舞台を設計します。

実験の舞台 — 剰余加算というトイ課題

なぜ剰余加算なのか

grokkingの再現にはアルゴリズム的な課題——明確な規則が存在し、その規則さえ掴めば全データを完璧に予測できる課題——が適しています。本記事では最も分かりやすい剰余加算を使います。

$$ c = (a + b) \bmod p $$

$a, b \in \{0, 1, \dots, p-1\}$ の2つの数字を入力し、和を $p$ で割った余り $c$ を当てる課題です。本記事では $p = 59$ とします。全組み合わせは $59^2 = 3{,}481$ 通りしかなく、完全な「答えの表」を作れます。

ポイントは、数字をただの記号(トークン)としてモデルに与えることです。モデルは「5」という入力が数の5を意味することを知りません。埋め込みベクトルとして受け取るだけです。つまりモデルにとってこの課題は「3,481マスの表の穴埋め」であり、足し算という規則を自力で発見しない限り、見ていないマスは当てられません。

剰余加算の表と訓練テスト分割

左が答えの表です。$(a+b) \bmod 59$ の値を色で表しており、斜めの縞模様が「足し算」の構造を示しています。右が問題設定で、黒いマス(全体の40%)だけを訓練データとして見せ、白いマス(60%)を当てさせます。丸暗記では黒いマスしか正解できません。白いマスを当てるには、縞模様の規則そのものを掴む必要があります。

この「暗記では解けない・規則なら完璧に解ける」という二択構造が、記憶解と汎化解のドラマを観察するのに最適な舞台になります。それでは、モデルと訓練ループを実装しましょう。

PyTorchで再現する

モデルとデータ

モデルは意図的に小さくシンプルにします。数字の埋め込み層と2層MLPだけです。grokkingはTransformerでなくても再現できます。

import torch
import torch.nn as nn

P = 59  # 剰余の法

class ModAddMLP(nn.Module):
    """埋め込み + 2層MLP で剰余加算を学ぶ小さなモデル"""
    def __init__(self, p=P, d_emb=64, d_hid=256):
        super().__init__()
        self.emb = nn.Embedding(p, d_emb)
        self.net = nn.Sequential(
            nn.Linear(2 * d_emb, d_hid), nn.ReLU(), nn.Linear(d_hid, p)
        )

    def forward(self, xa, xb):
        h = torch.cat([self.emb(xa), self.emb(xb)], dim=-1)
        return self.net(h)

def make_data(p=P, frac=0.4, seed=0):
    """(a+b) mod p の全ペアを作り、割合fracを訓練データに分割"""
    a = torch.arange(p).repeat_interleave(p)
    b = torch.arange(p).repeat(p)
    y = (a + b) % p
    g = torch.Generator().manual_seed(seed)
    perm = torch.randperm(p * p, generator=g)
    n_tr = int(frac * p * p)
    tr, te = perm[:n_tr], perm[n_tr:]
    return (a[tr], b[tr], y[tr]), (a[te], b[te], y[te])

データは全3,481ペアを乱数で40%(訓練1,392ペア)と60%(テスト2,089ペア)に分けるだけです。データが小さいので、ミニバッチを使わず全訓練データを毎ステップ一括で勾配計算します(全バッチ勾配降下)。ミニバッチ由来のノイズが消えるので、これから観察する「停滞→急上昇」がサンプリングの偶然ではなく最適化そのもののダイナミクスであることが明確になります。grokking研究でこの全バッチ設定が好まれるのも同じ理由です。

訓練ループ — weight decayを忘れずに

grokkingの再現で決定的に重要なのが、オプティマイザの設定です。AdamWに大きめのweight decay(本記事では1.0) を入れます。なぜこれが重要かは後のセクションで実験的に確かめますが、まずは入れて訓練します。

def train(frac=0.4, wd=1.0, steps=15000, seed=0):
    """全バッチAdamWで訓練し、精度・重みノルムの履歴を返す"""
    torch.manual_seed(seed)
    (xa_tr, xb_tr, y_tr), (xa_te, xb_te, y_te) = make_data(frac=frac, seed=seed)
    model = ModAddMLP()
    opt = torch.optim.AdamW(model.parameters(), lr=1e-3,
                            weight_decay=wd, betas=(0.9, 0.98))
    lossf = nn.CrossEntropyLoss()
    hist = {k: [] for k in ["step", "tr_acc", "te_acc", "wnorm"]}
    for step in range(1, steps + 1):
        model.train()
        opt.zero_grad()
        loss = lossf(model(xa_tr, xb_tr), y_tr)
        loss.backward()
        opt.step()
        if step % 50 == 0 or step == 1:
            model.eval()
            with torch.no_grad():
                tr_acc = (model(xa_tr, xb_tr).argmax(-1) == y_tr).float().mean()
                te_acc = (model(xa_te, xb_te).argmax(-1) == y_te).float().mean()
                wnorm = sum((prm**2).sum() for prm in model.parameters()).sqrt()
                hist["step"].append(step)
                hist["tr_acc"].append(tr_acc.item())
                hist["te_acc"].append(te_acc.item())
                hist["wnorm"].append(wnorm.item())
    return hist, model

hist, model = train(frac=0.4, wd=1.0, steps=15000, seed=0)

def first_step(hist, key, th):
    for s, v in zip(hist["step"], hist[key]):
        if v >= th:
            return s
    return None

print("訓練100%到達:", first_step(hist, "tr_acc", 0.999))
print("テスト50%到達:", first_step(hist, "te_acc", 0.5))
print("テスト90%到達:", first_step(hist, "te_acc", 0.9))
print("最終テスト精度:", hist["te_acc"][-1])

このコードはCPUでも1〜2分で完走します。出力は次のとおりです(seed=0で再現可能)。

訓練100%到達: 150
テスト50%到達: 7300
テスト90%到達: 9150
最終テスト精度: 1.0

数字を見てください。訓練精度はわずか150ステップで100% に到達します。丸暗記は一瞬です。ところがテスト精度が50%を超えるのはstep 7,300、90%を超えるのはstep 9,150——記憶の完了から約60倍のステップ数が経ってからです。そして最終的にテスト精度は100%に達します。見せていない2,089マスを全問正解するのですから、モデルは足し算の規則そのものを獲得したことになります。

実測したgrokking曲線

この履歴を対数軸で描いたのが次の図です。

実測したgrokking曲線

冒頭の模式図とそっくりの曲線が、実測で得られました。青(訓練精度)はstep 150で天井に張り付き、赤(テスト精度)は数千ステップにわたり当てずっぽうの水準($1/59 \approx 1.7\%$)を這った後、step 4,000あたりから立ち上がり、9,000過ぎに90%を突破します。「何も新しい情報を与えていないのに、遅れて突然汎化する」というgrokkingの定義どおりの振る舞いです。

損失で見ても同じ構造が確認できます。

訓練損失とテスト損失の推移

訓練損失(青)は早々にほぼ0へ落ちます。一方テスト損失(赤)は一度上昇します——これは教科書どおりの「過学習」の徴候で、普通ならここで訓練を止めるところです。しかしそのまま続けると、テスト損失は峠を越えて下がり始め、最終的に訓練損失と同水準まで落ちます。早期停止していたら、この後半の物語は永遠に見られなかったわけです。

では、この遅れた汎化を駆動しているものは何なのでしょうか。次のセクションで犯人を特定します。

鍵はweight decay — 記憶解と汎化解の綱引き

weight decayを切ると何が起きるか

同じ設定でweight decayだけを0にして訓練してみます。

hist_wd0, model_wd0 = train(frac=0.4, wd=0.0, steps=15000, seed=0)
print("訓練100%到達:", first_step(hist_wd0, "tr_acc", 0.999))
print("最終テスト精度:", round(hist_wd0["te_acc"][-1], 4))

出力は次のとおりです。

訓練100%到達: 150
最終テスト精度: 0.0005

訓練精度100%への到達はweight decayありと同じstep 150。ところが15,000ステップ訓練し続けてもテスト精度は0.05%——当てずっぽう(1.7%)にすら届かない完全な記憶マシンのままです。

weight decayの有無によるgrokkingの比較

両者の曲線を重ねると違いは一目瞭然です。weight decay = 1.0(赤実線)はstep 9,000過ぎに急上昇するのに対し、weight decay = 0(グレー)は最後まで底を這ったまま。grokkingはweight decayという正則化が駆動していることが、この対照実験からはっきり読み取れます。

なぜ正則化が「遅れた汎化」を生むのか

直感的なストーリーはこうです。まず前提として、今回のモデル(隠れ層256ユニット、パラメータ数約5万)は訓練データ1,392件に対して十分に大きく、丸暗記する容量が余裕であります。ニューラルネットは一般に、個々の訓練点の近傍だけで正しい出力を返す「補間的な」解を勾配降下ですばやく見つけられます。1点覚えるのに専用のユニットの組を割り当てるようなイメージで、部品同士の調整がほとんど要らないため、最適化としては下り坂を転がるだけの簡単な仕事です。一方、足し算の規則を実装する解は、埋め込み・中間層・出力層の全部品が整合して初めて機能する「大域的な」構造で、偶然に組み上がることはまずありません。この非対称性ゆえに、勾配降下は必ず記憶解に先に到達します。

そのうえで、この課題の損失地形には、訓練データを完璧に説明する解が(少なくとも)2種類あることになります。

  1. 記憶解: 訓練データの1,392マスをそれぞれ個別に暗記する。作るのは簡単(勾配降下がすぐ見つける)だが、パラメータをたくさん使うため重みのノルムが大きい。もちろんテストは解けない
  2. 汎化解: 足し算の規則そのものを実装する。見つけるのは難しいが、規則は簡潔なので重みのノルムが小さい。テストも完璧に解ける

weight decayは重みノルムにペナルティを課します。AdamWの更新式を見ると、通常の勾配ステップとは別に、毎ステップ重みを一定率で縮める項が入っています。

$$ \bm{w} \leftarrow \bm{w} – \eta \, \hat{\bm{g}} – \eta \lambda \bm{w} $$

ここで $\eta$ は学習率、$\hat{\bm{g}}$ はAdamの適応的勾配、$\lambda$ がweight decay係数です。第3項 $-\eta\lambda\bm{w}$ は「訓練損失に関係なく、常に重みを原点方向へ引く力」として働きます。訓練誤差がほぼ0になった停滞期には第2項の勾配が小さくなるため、この縮小力が相対的に主役になり、訓練誤差0を保てる範囲でノルムの小さい解へとモデルを押し流していくわけです。

つまり総損失で見ると、記憶解は「訓練誤差0だがノルム罰が重い」、汎化解は「訓練誤差0でノルム罰も軽い」——汎化解のほうが総損失が低いのです。勾配降下はまず見つけやすい記憶解に落ち、その後weight decayの圧力を受けながら、訓練誤差0を保ったまま損失地形の谷底を這ってより低い汎化解へゆっくり移動します。この「谷底の移動」が長い停滞期間の正体で、汎化解の流域に入った瞬間にテスト精度が雪崩を打って上がる、というわけです。本記事で $\lambda = 1.0$ という(普段の感覚では大きすぎる)値を使ったのは、この移動を15,000ステップという手頃な時間内に完了させるためです。

記憶解と汎化解の損失地形の模式図

このストーリーが正しければ、訓練中の重みノルムは「増えてから減る」 はずです。実測してみましょう。

重みノルムの推移と汎化の対応

まさにその通りの動きが観測されました。重みノルム(実線)は記憶解の形成とともに膨らみピーク69.4に達し、その後weight decayに押されて単調に減少して53.8へ。そしてノルムの下り坂の途中でテスト精度(破線)が立ち上がる——「ノルムの小さい解=汎化解への移動」がgrokkingの実体であることを、数値が裏付けています。ちなみにweight decay=0のモデルの最終ノルムは210.0で、汎化したモデルの4倍近くに膨れ上がったままでした。

記憶解と汎化解の綱引きという見方が得られたところで、もう一つの重要な変数——訓練データの量——を動かしてみましょう。

訓練データ量とgrokkingの時期

Powerらの論文で報告されたもう一つの特徴が、訓練データの割合が小さいほどgrokkingが遅くなる(そして一定以下では起きなくなる)ことです。割合を30%・40%・50%・60%と変えて実測しました。

for frac, steps in [(0.3, 50000), (0.5, 15000), (0.6, 15000)]:
    h, _ = train(frac=frac, wd=1.0, steps=steps, seed=0)
    print(f"frac={frac}: テスト90%到達 =",
          first_step(h, "te_acc", 0.9),
          " 最終テスト精度 =", round(h["te_acc"][-1], 3))

出力は次のとおりです(40%は先ほどの実験の値)。

frac=0.3: テスト90%到達 = None  最終テスト精度 = 0.506
frac=0.5: テスト90%到達 = 4150  最終テスト精度 = 1.0
frac=0.6: テスト90%到達 = 2000  最終テスト精度 = 1.0

訓練データ割合によるgrokking時期の変化

きれいな傾向が出ています。60%ならstep 2,000、50%なら4,150、40%なら9,150と、データが減るほどgrokkingは指数的に遅れていきます。30%では5万ステップかけてもテスト精度は50.6%止まりで、90%には届きませんでした(それでも上昇途中ではあり、さらに続ければ汎化する可能性があります)。

この傾向も先ほどの綱引きの絵で理解できます。データが少ないほど「暗記」は簡単になり(覚えるマスが少ない)、記憶解の魅力が相対的に増します。一方、規則を特定する手がかりは減るので汎化解へ辿り着く道は険しくなる。データ量は記憶と汎化の綱引きのバランスを直接動かすパラメータなのです。

ここまでで「いつ・どんな条件で」grokkingが起きるかを実測してきました。最後に残る最大の疑問——モデルは一体何を学んだのか——に踏み込みます。

なぜ突然汎化するのか — フーリエ回路という答え

モデルの中身を開ける

Nanda ら(ICLR 2023, arXiv:2301.05217)は、grokkingした剰余加算モデルをリバースエンジニアリングし、驚くべき事実を発見しました。モデルは足し算を、数字を波として埋め込み、三角関数の加法定理で計算する「フーリエ回路」 として実装していたのです。

回路の仕組みはこうです。モデルはまず各数字 $a$ を、いくつかの周波数 $\omega_k = 2\pi k / p$ の波

$$ \cos(\omega_k a), \quad \sin(\omega_k a) $$

として埋め込みます。数直線ではなく円周上の位置として数を表すわけです。すると2数の和は、加法定理

$$ \cos(\omega_k a)\cos(\omega_k b) – \sin(\omega_k a)\sin(\omega_k b) = \cos\bigl(\omega_k (a + b)\bigr) $$

により、埋め込み同士の積と和だけで計算できます。円周上で角度 $\omega_k a$ と $\omega_k b$ を足す操作は、$p$ を法とする剰余を自動的に処理します(1周回ったら元に戻るので)。

最後の答えの読み出しも見事です。答え候補 $c$ のロジットを、複数の周波数について

$$ \text{logit}(c) \propto \sum_{k} \cos\bigl(\omega_k (a + b – c)\bigr) $$

と作ります。$c = (a+b) \bmod p$ のときはすべての $k$ で $\cos$ の中身が $2\pi$ の整数倍になり、全周波数が $+1$ で揃って足し合わさります。一方それ以外の $c$ では各項の位相がバラバラになり、足し合わせで打ち消し合います。複数の波を重ねるほど「正解だけが鋭く立つ」——フーリエ級数がデルタ関数的なピークを作るのと同じ原理です。モデルが複数の周波数を併用するのは、この打ち消しを効かせて正解と不正解のマージンを広げるためだと解釈できます。

Nandaらのフーリエ回路の概念図

「剰余の足し算は円周上の回転」という数学的に自然な構造を、モデルが勾配降下だけで自力発見していた——機械的解釈性の分野で最も鮮やかな成果の一つです。

私たちのモデルでも確認する

このフーリエ構造は、私たちの小さなMLPでも確認できます。学習後の埋め込み行列を数字方向にフーリエ変換し、スペクトルを見てみます。

import numpy as np

def embedding_spectrum(model):
    """埋め込み行列を数字方向にFFTし、周波数ごとの振幅合計を返す"""
    W = model.emb.weight.detach().numpy()  # (p, d_emb)
    spec = np.abs(np.fft.rfft(W, axis=0))  # (p//2+1, d_emb)
    return spec.sum(axis=1)

spec_grok = embedding_spectrum(model)      # grokking後 (wd=1.0)
spec_wd0 = embedding_spectrum(model_wd0)   # 記憶のみ (wd=0)

top6 = np.argsort(spec_grok[1:])[-6:] + 1  # 直流成分を除く上位6周波数
share = spec_grok[top6].sum() / spec_grok[1:].sum()
print("grokking後の上位6周波数:", sorted(top6.tolist()),
      f" 上位6の占有率: {share:.3f}")

出力は次のとおりです。

grokking後の上位6周波数: [3, 5, 6, 7, 21, 25]  上位6の占有率: 0.421

学習後の埋め込みのフーリエスペクトル実測

左がgrokkingしたモデルの埋め込みスペクトルです。少数の周波数(3, 5, 6, 7, 21, 25)に振幅が集中し、この6本だけで全体の42%を占めます。まさに「特定の周波数の波で数を表す」フーリエ回路の痕跡です。右は記憶のみのモデル(wd=0)で、巨大な直流成分(周波数0)以外は全周波数にのっぺりと散らばっており、上位6周波数の占有率は24%にとどまります。汎化したモデルとしていないモデルは、中身の構造からして別物であることが、スペクトル1枚で見て取れます。

grokkingの「突然」の理由も、この回路観から腑に落ちます。フーリエ回路は部品(各周波数の埋め込み・積を取る結合・出力の位相照合)が揃って初めて機能します。停滞期の間、weight decayに導かれて部品は水面下で徐々に組み上がっており、回路として繋がった瞬間にテスト精度が一気に跳ねる——Nandaらは進行度を測る指標を設計してこの「水面下の進行」を実際に可視化し、grokkingが見かけほど「突然」ではないことも示しています。

grokkingが教えてくれること

最後に、この現象が既存の概念とどう繋がるかを整理します。

早期停止との関係: grokkingは「テスト誤差が上がり始めたら止めろ」という規則の反例です。ただし実務への教訓は「常に長く訓練しろ」ではありません。grokkingが観察されているのは主に規則が存在する小さなアルゴリズム的課題であり、ノイズの多い実データで同じことが起きる保証はないからです。教訓はむしろ「正則化が効いた状態での訓練の継続は、記憶から汎化への構造的な移行を起こしうる」という汎化理解の更新にあります。

二重降下との関係: テスト誤差が一度悪化してから再び改善する現象としては「二重降下(double descent)」も知られています。二重降下は主にモデルサイズや訓練時間に対する誤差曲線の非単調性を指し、grokkingはその極端な時間方向の現れと見ることもできます。どちらも「過学習の先にもう一段ある」ことを示す点で地続きの現象です。

創発との関係: 大規模言語モデルでは、規模や訓練量がある閾値を超えると特定の能力が急に立ち上がる「創発」が話題になります。grokkingは、この種の急激な能力獲得を数千パラメータのモデルと1枚のGPUすらいらない実験で観察できる、いわば創発のミニチュア模型です。能力の急上昇の裏で回路が徐々に組み上がっているという知見は、大きなモデルの理解にも示唆を与えます。

研究の現在地: grokkingの説明はweight decayによるノルム縮小だけでは完結しない、という指摘もあります。weight decayなしでも極端に長い訓練で汎化が起きるケース、Adamの適応学習率と損失スパイクの相互作用(slingshot機構)がgrokkingと同期するという報告、表現学習の効率という観点からの理論化など、複数の要因が絡む現象として現在も活発に研究されています。本記事の実験は「weight decayが支配的な駆動力になる典型設定」を切り出したものと理解してください。ハイパーパラメータ(特に $\lambda$・学習率・データ割合)を変えると停滞の長さや急峻さは大きく変わります。seed=0・本文の設定で数値まで再現できることは確認済みです。

まとめ

本記事では、grokking——過学習のはるか先で突然訪れる汎化——を実測しました。

  • 現象: 剰余加算 $(a+b) \bmod 59$ の表の40%で訓練すると、訓練精度100%到達(step 150)から約60倍のステップを経て、テスト精度が急上昇した(step 9,150で90%、最終100%)
  • 鍵はweight decay: weight decay = 0では15,000ステップ後もテスト精度0.05%のまま。正則化が「ノルムの大きい記憶解」から「ノルムの小さい汎化解」への移行を駆動する。実測でも重みノルムはピーク69.4→53.8へ減少し、その下り坂でテスト精度が立ち上がった
  • データ量との関係: 訓練割合60%→50%→40%でgrokking時期は2,000→4,150→9,150ステップと指数的に遅れ、30%では5万ステップでも汎化途中だった
  • 機構的説明: grokkingしたモデルは数字を波として埋め込み、三角関数の加法定理で足し算する「フーリエ回路」を実装していた。実測でも埋め込みスペクトルが少数の周波数(占有率42%)に集中し、記憶のみのモデル(24%)と明確に異なった

「訓練データを丸暗記したモデルの中で、規則を理解した回路が静かに組み上がっていく」——grokkingは、ニューラルネットの学習が私たちの素朴な直感よりずっと豊かなダイナミクスを持つことを教えてくれます。

次のステップとして、以下の記事も参考にしてください。