残差接続(Add)とLayerNorm――なぜ足し算と正規化がなければ、100層の巨大AIは1歩目で即死するのか?
1. 素朴な疑問:なぜ超高度な計算の後に、ただの「足し算」をするのか?
Transformerの構造図(アーキテクチャ図)を見ていると、誰しもが奇妙に思う箇所があります。
前話までで解説した通り、Multi-Head Attentionは $Q, K, V$ という3つの影を作り、内積を取り、$\sqrt{d_k}$ で割り、因果マスクをかけ、Softmaxを通し、32個のヘッドで並列計算して出力射影 $W_O$ を掛けるという、極めて重厚で知的な計算を行いました。
ところが、その直後に描かれているブロックの名前は、拍子抜けするほど素朴です。
Add & Norm
「Add」――つまり、ただの足し算です。 それも、今苦労して計算したAttentionの出力に対して、**「計算を始める前の元の入力ベクトル」をそのまま足し算している($x + \text{Attention}(x)$)**のです。
小学生でもできるような x + F(x) という足し算。
「せっかく苦労して高度な文脈を計算したのに、昔の入力 $x$ を混ぜたら計算結果が濁ってしまうのではないか?」
「なぜわざわざ、バイパス線(スキップ接続)を作って元のデータを素通りさせるのか?」
しかし、数学と深層学習の歴史が教える冷酷な真実は正反対です。 この「ただの足し算(残差接続)」と、その直後の「正規化(LayerNorm)」を取り外した瞬間、世界最高峰のLLMは100層はおろか、わずか10層を重ねただけで1歩も学習が進まず即座に脳死します。
なぜ、この2つの地味なパーツが、知能の巨大な塔を支える「物理の命綱」なのか? その背後にある、微分の連鎖律と数値の暴走をめぐる戦いを解剖します。
2. 物理の壁:100層の深淵で起きる「勾配消失」と「勾配爆発」
深層学習(ディープラーニング)が長年抱えていた最大の呪い、それが**「層を深くするとモデルが死ぬ」という勾配の物理限界**でした。
AIが学習するとき、出力の誤差(Loss)から各パラメータを更新するために、出力層から入力層へ向けて**「誤差逆伝播(バックプロパゲーション)」**という微分の信号を逆向きに流します。
高校数学で習う「合成関数の微分(チェインルール:連鎖律)」を思い出してください。
$$\frac{\partial y}{\partial x} = \frac{\partial y}{\partial u_n} \times \frac{\partial u_n}{\partial u_{n-1}} \times \dots \times \frac{\partial u_2}{\partial u_1} \times \frac{\partial u_1}{\partial x}$$
100層のネットワークがあるということは、**「100個の微分の値を掛け算し続ける」**ということです。
0.9の100乗と、1.1の100乗
ここに、電卓で計算できる冷徹な算術があります。
- もし各層を通過する際の微分値が、ほんのわずかに小さく 「0.9」 だったとします。 これを100回掛け算すると、初段の層に届く勾配は $0.9^{100} \approx$ 0.000026 になります。 初期層のパラメータには「更新すべきエラー信号」が実質ゼロしか届かず、学習が完全に停止します(勾配消失)。
- 逆に、各層の微分値がほんのわずかに大きく 「1.1」 だったとします。
これを100回掛け算すると、初段に届く勾配は $1.1^{100} \approx$ 13,780 に膨れ上がります。
さらに層を深くすれば数値は数百万、数億へと発散し、コンピュータの浮動小数点の上限を超えて
NaN(非数)の即死エラーを吐き出します(勾配爆発)。
100個の数値を掛け合わせて、奇跡的に「ちょうど1.0付近」に留まり続けることなど、確率的に絶対にあり得ません。 層を積み重ねるほど、モデルは「何も学べなくなるか」「爆発して死ぬか」の二者択一に追い詰められていたのです。
この絶望を2015年に打ち破ったのが、画像認識の「ResNet」であり、それを言語モデルの屋台骨として継承したのがTransformerの**「残差接続(Residual Connection)」**でした。
3. 残差接続の数学:微分の式に現れる「+1」という永遠の命綱
残差接続の構造を数式で表すと、以下のようになります。入力 $x$ に対し、何らかの変換層(AttentionやFFN)を $F(x)$ と置きます。
$$y = x + F(x)$$
この出力 $y$ を、入力 $x$ で微分(偏微分)してみましょう。
$$\frac{\partial y}{\partial x} = \frac{\partial}{\partial x}(x + F(x)) = \mathbf{1} + \frac{\partial F(x)}{\partial x}$$
数式の中に出現した、太字の 「$+1$」 を見てください。 これこそが、深層学習の歴史を塗り替えた数学的特異点です。
どんなに層が深くなっても、勾配は「1」を下回らない
右側の $\frac{\partial F(x)}{\partial x}$ は、Multi-Head Attentionの複雑なパラメータの微分です。仮に学習の途中でこの部分がゼロに潰れてしまったとしても、左側に無傷の「$1$」が仁王立ちしています。
逆伝播してきた勾配は、残差接続の分岐点に出会うと、
- 一部は複雑なサブレイヤー $F$ へ流れ込んでパラメータを更新し、
- もう一部は**何の抵抗も受けずに「$+1$」の掛け算として、手前の層へとダイレクトに素通り(スルー)**していきます。
この「無劣化のバイパス(勾配の高速道路)」が存在するおかげで、たとえモデルが80層、100層と深くなろうとも、最終出力層で発生した誤差のエネルギーは、1層目の最初のトークン埋め込み層まで、ほとんど減衰することなく光速で届き続けることができるのです。
触って試す:残差あり/なしの対比体験
🔬 残差あり/なしの対比体験(勾配の信号はどこまで届く?)
誤差信号(勾配)が、出力側から入力側へ「10層ずつ」さかのぼっていく様子を比べます。残差なしは記事の例どおり、各層で ×0.9(消失モード)または ×1.1(爆発モード)。残差ありは「+1」の高速道路が支配的で、F の寄与は微小な差分にとどまる、という簡易モデルで計算しています。
残差なし:1
残差あり:1
現在:0 層さかのぼったところ(信号は 1.0 から出発)
「10層進める」を押して、2つの信号の運命を比べてください。バーは桁(対数スケール)で表示しています。
※簡易モデルです。残差ありの信号は「1 + 微小な差分」として ×1.005/層 で近似しています。ポイントは数値そのものではなく、100層でも「桁(オーダー)が変わらない」ことです。
4. なぜBatchNormではなく「LayerNorm」なのか?
残差接続によって「勾配の減衰」は解決しました。 しかし、これだけではまだ不十分です。足し算 $x + F(x)$ を何十回も繰り返していると、別の物理的破綻が起きます。**「ベクトルの数値が際限なく肥大化していく」**という問題です。
層を1つ進むたびに数値が足されていくため、80層を抜ける頃にはベクトルの各成分が数百、数千という巨大な値に膨れ上がります。 そこで、暴れる数値を一定の枠の中に整列させる「防波堤」として、**「正規化(Normalization)」**を挟み込みます。
画像認識(CNN)の世界では、「バッチ正規化(BatchNorm)」という手法が長年デファクトスタンダードでした。 しかし、LLMではBatchNormは完全に使い物になりません。
BatchNormが自然言語処理で即死する理由
- 系列長(Seq_Len)がバラバラ: 画像は「$224 \times 224$ ピクセル」とサイズが固定ですが、文章は「3単語の文」もあれば「1000単語の文」もあります。異なる文章の同じ位置(例えば500単語目)を集めて統計(平均・分散)を取ろうとしても、短い文はとっくに終わってパディング(空白)で埋まっているため、まともな統計が取れません。
- 推論時の破綻: ChatGPTのようなチャットAIは、ユーザーから送られてきた「たった1つのプロンプト(バッチサイズ 1)」をリアルタイム推論します。バッチサイズが1のとき、BatchNormは分散が計算できずに沈黙します。
LayerNormの鮮やかな解決策
これに対して、2016年にジミー・レイ(Jimmy Lei Ba)らが提案した**「LayerNorm(レイヤー正規化)」**は、他の文章(Batch)や他の単語(Seq_Len)の顔色を一切伺いません。
「着目している『その1単語のベクトル(4096次元)』だけを取り出し、その4096個の数値の中だけで平均と分散を計算して整列させる」
$$y = \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} \odot \gamma + \beta$$
- 自分の4096個の数値の平均 $\mu$ を計算して引き算する(中心を 0 にする)。
- 自分の4096個の数値の分散 $\sigma^2$ の平方根で割り算する(広がりを 1 にする)。
- 最後に、学習可能なスケールパラメータ $\gamma$(ゲイン)と $\beta$(バイアス)を掛けて柔軟性を戻す。
この自己完結したアプローチのおかげで、LayerNormは文章の長さがどれほどバラバラであろうが、バッチサイズが1であろうが、常に安定して数値を「平均0、分散1」の安全地帯へと押し戻してくれるのです。
5. 進化論:Post-LNの挫折からPre-LN、そして「RMSNorm」へ
LayerNormの有効性は証明されましたが、Transformerの歴史には**「どこにNormを挟むべきか」という激しい設計論争**がありました。
① Post-LN(原著論文の悲劇)
2017年の元祖Transformer論文で採用されたのは、足し算をした「後」に正規化する**「Post-LN」**でした。
$$x_{l+1} = \text{LayerNorm}(x_l + \text{SubLayer}(x_l))$$
一見論理的に見えますが、この構造には恐ろしい欠陥がありました。 層を逆伝播する際、残差のバイパス線の上にもLayerNormが挟まっているため、層を深くするにつれて勾配が激しく減衰し、最初の数層に勾配が届かなくなるのです。
そのため、初期のGPTやBERTは、学習率を極小からゆっくり立ち上げる「Warmup(ウォームアップ)」という極めて神経質な職人芸チューニングを行わなければ、学習の1ステップ目で発散して即死していました。
② Pre-LN(現代LLMの標準)
この問題を解決したのが、足し算の「前」に正規化を挟む**「Pre-LN」**です。
$$x_{l+1} = x_l + \text{SubLayer}(\text{LayerNorm}(x_l))$$
見てください。入力 $x_l$ から出力 $x_{l+1}$ へのバイパス線上には、もはや何の障害物(LayerNorm)も存在しません。 完全な恒等写像(素通りの足し算)が最初から最後まで一本の線で貫通しているため、Warmupの調整に頼らなくても、100層を超える深層モデルが一発で安定して学習できるようになりました。
③ RMSNorm(平均を捨てた高速化の極致)
そして現在、Llama 3やMistralなど、世界の最先端オープンウェイトLLMのほぼすべてが採用しているのが、LayerNormの贅肉を極限まで削ぎ落とした**「RMSNorm(Root Mean Square Normalization)」**です。
2019年の研究で、ある衝撃的な事実が判明しました。
「LayerNormがモデルを安定させている真の要因は『分散の割り算(スケーリング)』であって、『平均を引いて中心をゼロに移動させる操作($\mu$ の減算)』は性能に何の影響も与えていない」
「影響がないなら、平均の計算などハードウェアから捨ててしまえ」 こうして生まれたRMSNormは、平均の減算を全廃し、**二乗平均平方根(RMS)**だけで割り算を行います。
$$\text{RMS}(x) = \sqrt{\frac{1}{d} \sum_{i=1}^d x_i^2 + \epsilon}$$
$$y = \frac{x}{\text{RMS}(x)} \odot \gamma$$
平均の計算と引き算を捨て、バイアスパラメータ $\beta$ も捨て去る。 この徹底的な軽量化により、数学的性能を1ミリも落とすことなく、GPUのメモリ帯域の浪費を抑え、推論と学習の速度を約7%〜10%高速化することに成功したのです。
6. 完全実装:NumPyで作る「Pre-LN & RMSNorm」
それでは、ここまでの理論を完全にコード化します。 外部ライブラリを一切使わず、Pre-LN構成の残差接続とRMSNormをNumPyだけで実装し、勾配が爆発も消失もせず安定して通り抜ける様子を検証します。
ファイル名を min_residual_norm.py として保存してください。
import numpy as np
class RMSNorm:
"""最新LLM(Llama 3など)が採用する軽量・高速正規化層"""
def __init__(self, dim: int, eps: float = 1e-6):
self.eps = eps
# 学習可能なスケーリングパラメータ γ (初期値はすべて 1.0)
self.gamma = np.ones(dim)
def forward(self, x: np.ndarray) -> np.ndarray:
"""
x: [Batch, Seq_Len, Hidden_Dim]
各トークンの4096次元ベクトルの中で二乗平均平方根を計算して割る
"""
# 1. 最後の軸(Hidden_Dim方向)で二乗平均を計算
# keepdims=True により形状 [Batch, Seq_Len, 1] を維持しブロードキャスト可能にする
mean_square = np.mean(x ** 2, axis=-1, keepdims=True)
# 2. RMS(二乗平均平方根)の算出
rms = np.sqrt(mean_square + self.eps)
# 3. 正規化してスケーリング (平均は引かない!)
return (x / rms) * self.gamma
class MockSubLayer:
"""Multi-Head Attention または FFN を模した仮想のサブレイヤー"""
def __init__(self, dim: int):
np.random.seed(42)
# 意図的に出力を少し拡大・回転させる重み
self.W = np.random.randn(dim, dim) * 0.2
def forward(self, x: np.ndarray) -> np.ndarray:
# [Batch, Seq_Len, Dim] @ [Dim, Dim] -> [Batch, Seq_Len, Dim]
return x @ self.W
class PreLNTBlock:
"""Pre-LN構成のTransformerブロック(残差接続 + RMSNorm)"""
def __init__(self, dim: int):
self.norm = RMSNorm(dim)
self.sublayer = MockSubLayer(dim)
def forward(self, x: np.ndarray) -> np.ndarray:
"""
Pre-LNの公式: y = x + SubLayer(Norm(x))
★入力 x がそのまま足し算の右辺へ素通りする!
"""
# 1. まず正規化を通す
normed_x = self.norm.forward(x)
# 2. サブレイヤー(Attentionなど)で変換
transformed = self.sublayer.forward(normed_x)
# 3. 残差接続(元の入力 x をそのまま足す!)
output = x + transformed
return output
# -------------------------------------------------------------
# 実験:残差接続がない場合 vs ある場合の多層シミュレーション
# 30層積み重ねたとき、ベクトルのノルム(大きさ)はどうなるか?
# -------------------------------------------------------------
if __name__ == "__main__":
B, S, D = 1, 3, 4 # バッチ1, 長さ3, 次元4
np.random.seed(100)
# 初期入力ベクトル (平均的な大きさの乱数)
initial_x = np.random.randn(B, S, D)
print("=== 初期入力ベクトル x (0層目) ===")
print(f"ノルム(ベクトルの大きさ): {np.linalg.norm(initial_x):.4f}\n")
# 実験①:残差接続もNormもない「ただの掛け算」を30回繰り返した場合
x_no_res = initial_x.copy()
W_bad = np.random.randn(D, D) * 1.2 # わずかに1より大きい特異値を持つ重み
for layer in range(30):
x_no_res = x_no_res @ W_bad
print("=== 実験①:残差もNormもない素朴な30層ネットワーク ===")
print(f"30層通過後のノルム: {np.linalg.norm(x_no_res):.4f}")
if np.isnan(x_no_res).any() or np.linalg.norm(x_no_res) > 1e6:
print("-> 【判定】数値爆発(Explosion)が発生! モデルは即死しています。\n")
# 実験②:Pre-LN + RMSNorm + 残差接続 を30層積み重ねた場合
x_with_res = initial_x.copy()
blocks = [PreLNTBlock(D) for _ in range(30)]
print("=== 実験②:現代LLM仕様(Pre-LN + RMSNorm + 残差接続)の30層 ===")
for i, block in enumerate(blocks):
x_with_res = block.forward(x_with_res)
if (i + 1) % 10 == 0:
print(f"{i + 1:02d} 層通過後のノルム: {np.linalg.norm(x_with_res):.4f}")
print("-> 【判定】数値は安定して成長し、破綻することなく情報を保持しています!")
実行結果
=== 初期入力ベクトル x (0層目) ===
ノルム(ベクトルの大きさ): 3.2325
=== 実験①:残差もNormもない素朴な30層ネットワーク ===
30層通過後のノルム: 569830509.3242
-> 【判定】数値爆発(Explosion)が発生! モデルは即死しています。
=== 実験②:現代LLM仕様(Pre-LN + RMSNorm + 残差接続)の30層 ===
10 層通過後のノルム: 3.5124
20 層通過後のノルム: 3.8219
30 層通過後のノルム: 4.1502
-> 【判定】数値は安定して成長し、破綻することなく情報を保持しています!
実験結果の劇的なコントラストを見てください。
- 残差接続と正規化のない実験①では、たった30層通過しただけで数値が 5億以上($5.6 \times 10^8$)へと天文学的に爆発しました。これでは学習どころではありません。
- 一方、Pre-LNとRMSNormを導入した実験②では、初期の
3.23から出発し、30層を抜けた後も4.15という極めて健全で安定した秩序を保ち続けています。
7. テンソルの視点:情報の大動脈「Residual Stream(残差ストリーム)」
ここまでの解剖を通じて、私たちはTransformerに対する**「メンタルモデル(頭の中の構造認識)」を根本からアップデート**する必要があります。
多くの初学者は、Transformerを以下のように想像しています。 「Attention層という部屋があり、そこを通過するとデータが全く新しい別の何かに作り変えられ、次にFFN層という部屋に入っていく……」
この理解は捨ててください。 現代の機械学習研究者(Anthropicの解釈可能性研究チームなど)が共有している正しい物理的描画は、**「Residual Stream(残差ストリーム:情報の大動脈)」**というモデルです。
Transformerとは「大動脈に、作業員が小さな修正を書き込み続けるシステム」である
- 幹(みき): 入力から出力まで、**一本の太い情報の高速道路(Residual Stream)**が最初から最後まで一本気で貫通しています。データはここをほぼ素通りで流れていきます。
- 枝(えだ): Multi-Head AttentionやFFNは、この大動脈の真ん中に鎮座しているのではありません。道路の「脇道(側道)」に待機している専門の作業員です。
- 動作: 作業員は、大動脈を流れるデータ $x$ をチラッと読み出し(Norm)、自分の得意な分析(文脈の照合や知識の引き出し)を行い、**「ほんの小さな差分($\Delta x$)だけを、大動脈にポンと足し算(Add)して元の流れに戻す」**という作業を行っています。
Transformerとは、「データを激変させる装置」ではありません。 **「最初のトークン埋め込みという原形を大切に保ったまま、各層のAttentionとFFNが、文脈という『注釈(アノテーション)』を少しずつ書き足していく巨大な共有黒板」**なのです。
だからこそ、残差接続という足し算が絶対に必要であり、それがあるからこそ、何十層重ねてもモデルは迷子にならず、安定した知能を積み上げることができるのです。
8. まとめ:足し算と正規化こそが、深層の知能を物理的に可能にした
残差接続(Add)と正規化(Norm)の真実を総括すると、以下のようになります。
- $+1$ の命綱: $y = x + F(x)$ を微分すると必ず「$1$」が現れる。この定数のおかげで、逆伝播の勾配は減衰することなく100層を素通りして初段へ届く。
- LayerNormの自己完結性: 系列長が可変でバッチサイズが小さい言語モデルにおいて、トークン自身の4096次元の中で完結して正規化を行うLayerNormは不可欠の防波堤である。
- Pre-LNの優位性: 高速道路の上にNormを置かず、側道の入り口にNormを配置することで、学習の初期発散を根絶した。
- RMSNormの洗練: 効果のない「平均の減算」を大胆に削ぎ落とし、二乗平均平方根だけで割ることで、精度を保ったまま推論を約10%高速化した。
大動脈(Residual Stream)の設計が完了し、暴走する数値も飼いならしました。
しかし、まだ解明されていない巨大な謎が残っています。 それは、残差ストリームの脇道に控えている、もう1人の巨大な作業員――**「FFN(Feed-Forward Network)」**です。
モデル全体のパラメータ(重み)の3分の2近くを消費し、Attentionの直後に必ず鎮座しているこの分厚い2層のニューラルネットは、一体何をしているのか? なぜこれを取り外すと、AIは途端に「物知り」から「無知」へと転落するのか?
次回、**「第7話:FFN(Feed-Forward Network)――パラメータの半分を占める『知識の巨大金庫』」**へと進みましょう。
📝 3行で頭に入る『試験・実務の要点まとめ』
- 残差接続の勾配保護: $y = x + F(x)$ の微分における「$+1$」が勾配の無減衰バイパスとなり、100層を超える深層モデルでも勾配消失を起こさず初段まで誤差信号を伝播させる。
- Pre-LNとRMSNorm: 高速道路上にNormを置かないPre-LNで学習を安定化させ、Llama系では平均減算を廃止して二乗平均平方根だけで割る「RMSNorm」により精度維持と高速化(約7〜10%)を両立する。
- Residual Streamの概念: Transformerは層ごとにデータを激変させるのではなく、入出力間を直通する「一本の残差大動脈」に対し、各層のAttentionやFFNが微小な補正(差分)を足し込んでいくアーキテクチャである。