simons blog

Backprob through Layernorm

Equation for Layernorm:

yi=xi−miv+ϵwi=xi′wi

m=1N∑i=1Nxi, v=1N∑i=1N(x−m)2, xi′=xi−mv+ϵ. As a computational graph: Screenshot 2025-07-13 at 14

∂yiL given.

∂xi′L=∂yiL·wi

Sum over all paths from x′ to v.

∂vL=∑j∂xj′L·∂vxj′∂vxj′=(xj−m)∂v(v+ϵ)−1/2=−12(xj−m)(v+ϵ)−3/2

Plugging in:

∂vL=−12(v+ϵ)3/2∑j∂yjL·wj·(xj−m)

m has incoming paths from both x′ and v. Over the paths from x′ we need to sum and sum these with the path from v.

∂mL=∂vL·∂mv+∑j∂xj′L·∂mxj′∂mv=1N∂m∑j(xj−m)2=−2N∑j(xj−m)=−2N(∑jxj−N·1N∑jxj)=0.∂mxj′=∂mx−mv+ϵ=−1v+ϵ

Plugging in:

∂mL=−1(v+ϵ)1/2∑j∂yjL·wj

Final backprop: Incoming from m, v and x′.

∂xiL=∂mL·∂xim+∂vL·∂xiv+∂xi′L·∂xixi′

Calculate the terms separately.

First term:

∂xim=∂xi1N∑jxj=1N∂mL·∂xim=−1(v+ϵ)1/21N∑j∂yjL·wj

Second term:

∂xiv=1N∂xi∑j(xj−m)2=2N(xi−m)∂vL·∂xiv=−1(v+ϵ)3/21N(xi−m)∑j∂yjL·wj·(xj−m)

We can simplify this using definition of x′.

∂vL·∂xiv=−1(v+ϵ)1/21Nxi′∑j∂yjL·wj·xj′

Last term

∂xixi′=∂xixi−mv+ϵ=1v+ϵ∂xi′L·∂xixi′=∂yiL·wi·1(v+ϵ)1/2

To summarise we have the three terms:

∂mL·∂xim=−1(v+ϵ)1/21N∑j∂yjL·wj∂vL·∂xiv=−1(v+ϵ)1/21Nxi′∑j∂yjL·wj·xj′∂xi′L·∂xixi′=∂yiL·wi·1(v+ϵ)1/2

Now sum these up to obtain final result:

∂xiL=1(v+ϵ)1/2[∂yiL·wi−1N∑j∂yjL·wj−xi′·1N∑j∂yjL·wj·xj′]

This is the formula given here.

    @staticmethod
    def backward(dout, cache):
        x, w, mean, rstd = cache
        # recompute the norm (save memory at the cost of compute)
        norm = (x - mean) * rstd
        # gradients for weights, bias
        db = dout.sum((0, 1))
        dw = (dout * norm).sum((0, 1))
        # gradients for input
        dnorm = dout * w
        dx = dnorm - dnorm.mean(-1, keepdim=True) - norm * (dnorm * norm).mean(-1, keepdim=True)
        dx *= rstd
        return dx, dw, db