arXiv preprint. Computes the mean and variance over the hidden units of one layer for a single training case, then applies a learned gain and bias.
Layer Normalization & RMSNorm
Normalizing each token's vector across its features: LayerNorm subtracts the mean and divides by the standard deviation; RMSNorm only divides by the root mean square.
Intuition
The idea in plain words, before the symbols.
LayerNorm and RMSNorm normalize the features within one token's vector. We compare mean-centering and root-mean-square scaling on a single vector, then follow a separate residual block through a loss and update. The figure checks how the two normalizations change the vector and how their placement changes the block's gradients. You will need means, variances, and the chain rule.
Activation scale and the derivatives of the intervening operations both affect gradient flow. Normalization controls specified activation statistics. That can help optimization, but normalized activations alone do not guarantee stable training.
Transformers almost always use LayerNorm (or RMSNorm) instead of BatchNorm because:
- sequence models often have small or variable batch sizes,
- we want behavior that does not depend on other examples in the batch,
- decoding/inference should behave the same as training.
RMSNorm is a simplification introduced by Zhang and Sennrich (2019): it drops the mean-centering step and normalizes by the root mean square.
To connect normalization to training, follow one residual block through a loss and update. That block is a separate worked example with fixed numbers; the single-vector comparison stays available too.
Study prompts for this section: Intuition
Each button copies a prompt about this section to your clipboard, for an AI assistant you already use. Nothing is sent by this site.
Mathematics
Definitions, assumptions and the derivation.
For a vector of activations (for one token / one example), LayerNorm (Ba et al., 2016) is:
RMSNorm removes mean-centering and uses:
Here is a numerical stabilizer placed inside the square root. The equation follows the PyTorch RMSNorm formulation; the example, the code and the figure all use . The statistics reduce over the features of one vector, while act elementwise; RMSNorm has no term in the convention used here.
Two practical consequences:
- Normalization makes the layer output less sensitive to the overall scale of .
- Normalizing before the branch (pre-norm) or after the residual addition (post-norm) changes the gradient path. The optional block below isolates that one change in a small example.
The two also differ in what they remove. LayerNorm subtracts the vector's own mean, so it removes a shift shared by every feature; RMSNorm does not. Take , and, so the numbers are exact, . On both return , because the mean is already zero. Now add to both features: . Its mean is , so the centred vector is still , its variance is still , and . RMSNorm keeps the shift: the mean square is , so . Agreeing on one input does not make two operations the same. With these values change by less than . The practice section works this example step by step.
One block, through one update
The optional investigation below uses a new, fixed example. Rows of are two tokens; columns are three features. Each token passes through the same two-unit hidden layer. The matrices and return the branch to the input shape so it can be added to . Biases and broadcast across rows. The nonlinearity is componentwise tanh. Let be the feature-axis LayerNorm above, with learned and . For a fixed target matrix , define
All 23 scalars in update simultaneously from their original gradients. and do not update. Changing changes the step, not the original gradient. The loss divides the sum of six squared errors by twelve, so its output derivative is .
To follow the MLP backward, write and , both of shape . For a received branch gradient , the chain rule gives , , , , and . The matrix gradient has the same shape as its parameter; bias gradients sum both rows.
For one normalization group, let and . If the gradient received at the affine normalization output is , first set . The input derivative is . This expression uses the stabilized ; do not replace with an unstabilized standard deviation. The learned gain and bias derivatives sum and across tokens, respectively.
For pre placement, and : the direct residual path bypasses normalization. For post placement, first compute for , then and . Here denotes applying the normalization input derivative just defined; it is not an inverse forward operation. The identity contribution in the pre form does not guarantee a well-conditioned whole Jacobian.
The axis-error contrast computes each feature's mean/variance across the two tokens, while retaining feature-wise gain/bias. At fixed parameters and before any update, replacing token 1 must leave token 0's output unchanged for either correct position-wise form. The wrong-axis calculation can violate that property. Recomputing an SGD update on the changed data is a different test: both rows share parameters, so it can change token 0 even with correct axes.
Xiong et al., Table 1 and section 3.3 study normalization placement in Transformers under stated initialization assumptions. Their Pre-LN architecture also includes a final normalization before prediction. The tanh sublayer with squared error used here leaves out attention, depth, that final normalization and their random-initialization model. Its one-step loss changes do not reproduce their analysis or show that warmup is unnecessary.
Study prompts for this section: Mathematics
Each button copies a prompt about this section to your clipboard, for an AI assistant you already use. Nothing is sent by this site.
Code
The same calculation as runnable code, in the notation of the derivation.
import numpy as np
rs = np.random.RandomState(0)
x = rs.randn(8) * 2.0 + 3.0 # nonzero mean on purpose
eps = 1e-5
gamma = np.ones_like(x)
beta = np.zeros_like(x)
def layernorm(x, gamma, beta, eps):
mu = float(x.mean())
var = ((x - mu) ** 2).mean()
sigma_eps = np.sqrt(var + eps)
normalized = (x - mu) / sigma_eps
output = gamma * normalized + beta
return {
"mean": mu,
"variance": float(var),
"sigma_eps": float(sigma_eps),
"normalized": normalized,
"output": output,
}
def rmsnorm(x, gamma, eps):
mean_square = (x ** 2).mean()
rms_eps = np.sqrt(mean_square + eps)
inverse_rms = 1.0 / rms_eps
normalized = x * inverse_rms
output = gamma * normalized
return {
"mean_square": float(mean_square),
"rms_eps": float(rms_eps),
"inverse_rms": float(inverse_rms),
"normalized": normalized,
"output": output,
}
ln = layernorm(x, gamma, beta, eps)
rn = rmsnorm(x, gamma, eps)
cos = float(
(ln["output"] @ rn["output"])
/ (np.linalg.norm(ln["output"]) * np.linalg.norm(rn["output"]))
)
assert x.shape == gamma.shape == beta.shape == (8,)
assert ln["normalized"].shape == rn["normalized"].shape == x.shape
assert np.isclose(rn["rms_eps"] ** 2, rn["mean_square"] + eps)
print("mean(x), std(x):", round(float(x.mean()), 3), round(float(x.std()), 3))
print("mean_square, rms_eps:", round(rn["mean_square"], 3), round(rn["rms_eps"], 3))
print("cos(LN, RMS):", round(cos, 3))
print("LN mean/std:", round(float(ln["output"].mean()), 3), round(float(ln["output"].std()), 3))
print(
"RMS mean/rms:",
round(float(rn["output"].mean()), 3),
round(float(np.sqrt((rn["output"] ** 2).mean())), 3),
)
The residual block in Python
This second program uses only Python's standard library. It computes the analytic reverse pass and one simultaneous SGD step from the fixed arrays, without training a model or calling a service.
theta is flattened in W1 row order, b1, W2 row order, b2, gamma, beta order.
Its gradients agree with independent central-difference estimates up to floating-point rounding, not bit for bit.
from math import sqrt, tanh, isfinite
X = [[1., -1., .5], [.2, .8, -.6]]
TARGET = [[.3, -.4, .2], [-.2, .5, -.1]]
THETA = [.5, -.3, .2, .4, -.4, .1, .1, -.2,
.3, -.5, .2, -.2, .1, .4, .05, -.05, .1,
1., .8, 1.2, 0., .1, -.1]
EPS = 1e-5
def grid(n, m, fn=lambda t, d: 0.):
return [[fn(t, d) for d in range(m)] for t in range(n)]
def average(values):
return sum(values) / len(values)
def norm(x, gamma, beta, wrong_axis=False):
groups = ([[(t, d) for t in range(2)] for d in range(3)]
if wrong_axis else [[(t, d) for d in range(3)] for t in range(2)])
u, means, variances, scales = grid(2, 3), [], [], []
for group in groups:
mu = average([x[t][d] for t, d in group])
var = average([(x[t][d] - mu)**2 for t, d in group])
s = sqrt(var + EPS)
means.append(mu); variances.append(var); scales.append(s)
for t, d in group:
u[t][d] = (x[t][d] - mu) / s
return dict(input=x, mean=means, variance=variances, scale=scales,
standardized=u, output=grid(2, 3, lambda t, d: gamma[d]*u[t][d]+beta[d]),
axis="tokens" if wrong_axis else "features")
def norm_back(trace, upstream, gamma):
groups = ([[(t, d) for t in range(2)] for d in range(3)]
if trace["axis"] == "tokens" else [[(t, d) for d in range(3)] for t in range(2)])
dx, u = grid(2, 3), trace["standardized"]
for group, s in zip(groups, trace["scale"]):
p = [upstream[t][d]*gamma[d] for t, d in group]
correlation = average([q*u[t][d] for q, (t, d) in zip(p, group)])
for q, (t, d) in zip(p, group):
dx[t][d] = (q-average(p)-u[t][d]*correlation)/s
dg = [sum(upstream[t][d]*u[t][d] for t in range(2)) for d in range(3)]
db = [sum(upstream[t][d] for t in range(2)) for d in range(3)]
return dx, dg, db
def forward(theta, x, target, mode):
w1 = [theta[i:i+2] for i in range(0, 6, 2)]
b1, w2 = theta[6:8], [theta[i:i+3] for i in (8, 11)]
b2, gamma, beta = theta[14:17], theta[17:20], theta[20:23]
n = None if mode == "post" else norm(x, gamma, beta, mode == "wrong-axis")
u = x if n is None else n["output"]
a = grid(2, 2, lambda t, h: sum(u[t][d]*w1[d][h] for d in range(3))+b1[h])
h = [[tanh(v) for v in row] for row in a]
f = grid(2, 3, lambda t, d: sum(h[t][j]*w2[j][d] for j in range(2))+b2[d])
r = grid(2, 3, lambda t, d: x[t][d]+f[t][d])
if n is None:
n = norm(r, gamma, beta)
y = n["output"] if mode == "post" else r
loss = sum((y[t][d]-target[t][d])**2 for t in range(2) for d in range(3))/12
return dict(branchInput=u, preactivation=a, hidden=h, branch=f, residual=r,
normalization=n, output=y, loss=loss)
def inspect(mode="pre", rate=.1, theta=THETA, x=X, target=TARGET):
def vector(v, length):
return isinstance(v, (list, tuple)) and len(v) == length and all(
type(a) in (float, int) and isfinite(a) and abs(a) <= 4 for a in v)
if mode not in ("pre", "post", "wrong-axis") or rate not in (.1, 10):
raise ValueError("Choose a declared placement and SGD rate (.1 or 10)")
if not vector(theta, 23) or not all(isinstance(a, (list, tuple)) and len(a) == 2
and all(vector(row, 3) for row in a) for a in (x, target)):
raise ValueError("Expected 23 parameters and two 3-feature rows, finite and in [-4, 4]")
before = forward(theta, x, target, mode)
u, h, n = before["branchInput"], before["hidden"], before["normalization"]
w1 = [theta[i:i+2] for i in range(0, 6, 2)]
w2, gamma = [theta[i:i+3] for i in (8, 11)], theta[17:20]
gy = grid(2, 3, lambda t, d: (before["output"][t][d]-target[t][d])/6)
post = norm_back(n, gy, gamma) if mode == "post" else None
direct = gy if post is None else post[0]
gw2 = grid(2, 3, lambda j, d: sum(h[t][j]*direct[t][d] for t in range(2)))
gb2 = [sum(direct[t][d] for t in range(2)) for d in range(3)]
ga = grid(2, 2, lambda t, j: sum(direct[t][d]*w2[j][d] for d in range(3))*(1-h[t][j]**2))
gw1 = grid(3, 2, lambda d, j: sum(u[t][d]*ga[t][j] for t in range(2)))
gb1 = [sum(ga[t][j] for t in range(2)) for j in range(2)]
gu = grid(2, 3, lambda t, d: sum(ga[t][j]*w1[d][j] for j in range(2)))
gn = norm_back(n, gu, gamma) if post is None else post
through = gn[0] if post is None else gu
gradients = [v for row in gw1 for v in row]+gb1+[v for row in gw2 for v in row]+gb2+gn[1]+gn[2]
before["gradients"] = dict(parameters=gradients,
input=grid(2, 3, lambda t, d: direct[t][d]+through[t][d]), direct=direct,
throughBranch=through, output=gy, activation=ga, branchInput=gu)
updated = [v-rate*g for v, g in zip(theta, gradients)]
return dict(placement=mode, rate=rate, before=before, parameters=updated,
after=forward(updated, x, target, mode))
if __name__ == "__main__":
for mode in ("pre", "post", "wrong-axis"):
r = inspect(mode)
print(mode, "loss", r["before"]["loss"], "->", r["after"]["loss"])
print("W1[0,0]", THETA[0], "gradient", r["before"]["gradients"]["parameters"][0],
"updated", r["parameters"][0])
Study prompts for this section: Code
Each button copies a prompt about this section to your clipboard, for an AI assistant you already use. Nothing is sent by this site.
Demo
Change an input, predict the result, and see which quantities respond.
Explore Layer Normalization & RMSNorm
Observation guide
Optional and ungraded. Opening a guide saves nothing.
Choose what to inspect in Layer Normalization & RMSNorm, then open its guide.
Use the demo to see:
- how centering (LayerNorm) vs non-centering (RMSNorm) changes the direction of a vector,
- how , , and produce the normalized vector using the same stabilizer as the code,
- how learned let the network keep normalization while still representing useful scales,
- how normalization placement changes a residual block's forward computation and gradients (this alone does not guarantee stable training).
Study prompts for this section: Demo
Each button copies a prompt about this section to your clipboard, for an AI assistant you already use. Nothing is sent by this site.
Shift every feature
Compare LayerNorm and RMSNorm on one vector, then add the same number to both features and predict again.
Concept: Layer Normalization & RMSNorm
What is the smallest example of Layer Normalization & RMSNorm you can work through by hand, and what does it show?
DetailsAttention & Transformers
Reference id
concept:attention-transformers/layer-normalizationAfter the first pass
Go deeper
Optional material for a second reading. Sources are always shown; the other panels open from their headings or from these links, and closing one keeps what you wrote or revealed.What to look for in each sectionChoose a section and what you expect to see in it, then read short advice.
Section by section
Choose what to look for in each section
Normalizing each token's vector across its features: LayerNorm subtracts the mean and divides by the standard deviation; RMSNorm only divides by the root mean square.

Start with the picture, metaphor, or geometric mechanism.
Choose what you expect to see in this section of Layer Normalization & RMSNorm.
Questions to ask of the pictureChoose a part of the picture and what you expect, then read short advice.
Looking at the picture
Questions to ask of the picture
Normalizing each token's vector across its features: LayerNorm subtracts the mean and divides by the standard deviation; RMSNorm only divides by the root mean square.
Which part of the picture should you look at first?
Pick the part of the picture you expect to explain Layer Normalization & RMSNorm.
Sources
References for this page
A reference shows where an idea comes from; it does not vouch for every step on this page.NeurIPS 2019. Defines RMSNorm, which rescales by the root mean square and drops LayerNorm's mean-centering.
ICML 2020. Table 1 distinguishes pre- and post-norm placement and the final Pre-LN normalization; Section 3.3 analyzes initialization under simplifying assumptions. The tanh example on this page is not that analysis.
For normalized_shape=3, statistics reduce the last feature dimension with population variance, inside-root epsilon and per-feature affine parameters. Documentation evidence only; no PyTorch or GPU execution claimed.
What each claim rests on2 claims, each with its sources, where it appears on this page, and its caveats.
Claims and sources
Normalizing each token's vector across its features: LayerNorm subtracts the mean and divides by the standard deviation; RMSNorm only divides by the root mean square.
The checks were made by this site, not by an independent reviewer.
Ba et al. compute LayerNorm statistics over all hidden units in one layer for a single training case and apply learned gain/bias after normalization. Zhang and Sennrich review LN's mean/std form, define RMSN...
Checks only the normalization arithmetic and this page's examples. The token/example wording maps papers' per-case/per-layer statistics to the page's transformer frame; this does not verify norm placement, L...
Checked Ba Sec.3/RNN equations and Zhang/Sennrich Secs.3-4. Ba supports per-case/layer statistics over one activation vector with shared mu,sigma and learned gain/bias. Zhang/Sennrich review LN as mean/std scaling, define RMSNorm as a_i/RMS(a)*g_i, and state it removes the mean statistic. The mathematics, code and figure on this page show centering versus RMS-only scaling on small vectors; use in Transformers was not part of this check.
Xiong Table 1 grounds the placement distinction; the configured PyTorch formulation grounds the reduction and epsilon convention. The 23-parameter tanh block, squared-error objective, analytic derivatives an...
A fixed feed-forward sublayer, not a full Transformer or Xiong reproduction. The axis probe freezes original parameters; shared updates can otherwise couple tokens. No measured learning outcome, convergence/...
The paper and the documentation were checked separately from this page's fixed-array example. The Python shown on the page agrees with independent forward-mode derivatives and with 1,218 central-difference estimates across seven example inputs and three placements.
Explain it without the pageWrite your own explanation before asking for feedback. Your draft and any hints stay while this page is open.
Practice · Layer Normalization & RMSNorm
Try the idea in your own words
Normalizing each token's vector across its features: LayerNorm subtracts the mean and divides by the standard deviation; RMSNorm only divides by the root mean square.
Concept · Selected for practice
Layer Normalization & RMSNorm
What it rests on: Sources: Layer Normalization; Root Mean Square Layer Normalization; On Layer Normalization in the Transformer Architecture
Context and links
Attention & Transformers
Explain the mechanism
For Layer Normalization & RMSNorm: What is the smallest example of Layer Normalization & RMSNorm you can work through by hand, and what does it show? Explain your answer, including what changes, why, and which assumption matters.
A rough first thought is enough. Your draft stays when you change tasks.
Your draft stays on this page and is cleared when you leave or reload.
A little help · Explain
Open one hint at a time. These are suggestions, not your answer or a grade.
0 of 3 hints shown for this question.
Clearing your answer keeps this help record. Outside help is your own report; this page cannot check it.
Where am I stuck? (optional)
Take your draft to a feedback conversation
No AI feedback runs here. You can copy a prompt to use elsewhere; nothing is sent automatically. Review the text before sharing, and leave out private information.
Write an attempt before copying a feedback prompt.
A draft, or an AI reply to it, is not a test of what you have learned. To check that, try a different case later without help.
Ask about this pagePick one item on this page and copy a prompt about it into an AI assistant you already use. Notes you write here stay in this browser.
assert x.shape == gamma.shape == beta.shape == (8,)Your question
Choose what your question is about
Pick the idea, equation, source, code, claim, misconception or demo state you want to ask about. The prompt you copy includes it, so the answer can stay on that item.Open the draft below to save one note and next action in this browser.
Layer Normalization & RMSNorm
What is the smallest example of Layer Normalization & RMSNorm you can work through by hand, and what does it show?
Fixed prompts generated from this item. They are not comments from people or independent reviews.
The 4 cited sources must support this exact item, not just the surrounding topic.
Connect the definition to one equation, piece of code or demo before widening the discussion.
Change one input, then check that the same relationship holds in the mathematics, the code and the demo.
You can state the mechanism in your own words
Local action draftNo local draft saved yetOpen when you are ready to write one next action
This draft stays in this browser and is attached to this item only.
- What the 4 cited sources say about this exact item
- The definition, its prerequisites, and a contrasting concept
- The equation or code that makes the concept concrete
- One demo state that shows what stays the same as the inputs change
- You can state the mechanism in your own words
- You can name the prerequisite that would clear up the confusion
- You can predict how the result changes when one input changes
Reference id
concept/concept-notebook/attention-transformers/layer-normalization
concept:attention-transformers/layer-normalization