PyTorch torch.nn.LayerNorm 函数
torch.nn.LayerNorm 是 PyTorch 中的层归一化模块。
与批归一化不同,层归一化在单个样本的特征维度上进行归一化,不依赖 batch size。
函数定义
torch.nn.LayerNorm(normalized_shape, eps=1e-05, elementwise_affine=True)
参数说明:
normalized_shape(int 或 list): 需要归一化的维度。eps(float): 数值稳定性的epsilon。默认为 1e-5。elementwise_affine(bool): 是否使用可学习的缩放和偏移。默认为 True。
数学原理
层归一化公式:
y = (x - E[x]) / sqrt(Var[x] + eps) * gamma + beta
与批归一化的区别:层归一化在特征的最后一个维度计算均值和方差。
使用示例
示例 1: 基本用法
对特征进行层归一化:
实例
import torch
import torch.nn as nn
# 层归一化:对最后一个维度归一化
ln = nn.LayerNorm(normalized_shape=10)
# 输入:batch=4,特征维度=10
x = torch.randn(4, 10)
# 前向传播
output = ln(x)
print("输入形状:", x.shape)
print("输出形状:", output.shape)
print("n原始输入第一行:", x[0].tolist())
print("归一化后第一行:", output[0].tolist())
import torch.nn as nn
# 层归一化:对最后一个维度归一化
ln = nn.LayerNorm(normalized_shape=10)
# 输入:batch=4,特征维度=10
x = torch.randn(4, 10)
# 前向传播
output = ln(x)
print("输入形状:", x.shape)
print("输出形状:", output.shape)
print("n原始输入第一行:", x[0].tolist())
print("归一化后第一行:", output[0].tolist())
示例 2: 多维输入
处理 3D 或 4D 输入:
实例
import torch
import torch.nn as nn
# 对序列维度归一化:(batch, seq, features)
ln_seq = nn.LayerNorm(normalized_shape=64)
# 3D 输入
x_3d = torch.randn(2, 10, 64)
output_3d = ln_seq(x_3d)
print("3D 输入:", x_3d.shape, "-> 输出:", output_3d.shape)
# 4D 输入 (如图像): (batch, height, width, channels)
# LayerNorm 对最后 channel 维度归一化
ln_channel = nn.LayerNorm(normalized_shape=128)
x_4d = torch.randn(2, 8, 8, 128)
output_4d = ln_channel(x_4d)
print("4D 输入:", x_4d.shape, "-> 输出:", output_4d.shape)
import torch.nn as nn
# 对序列维度归一化:(batch, seq, features)
ln_seq = nn.LayerNorm(normalized_shape=64)
# 3D 输入
x_3d = torch.randn(2, 10, 64)
output_3d = ln_seq(x_3d)
print("3D 输入:", x_3d.shape, "-> 输出:", output_3d.shape)
# 4D 输入 (如图像): (batch, height, width, channels)
# LayerNorm 对最后 channel 维度归一化
ln_channel = nn.LayerNorm(normalized_shape=128)
x_4d = torch.randn(2, 8, 8, 128)
output_4d = ln_channel(x_4d)
print("4D 输入:", x_4d.shape, "-> 输出:", output_4d.shape)
示例 3: 在 Transformer 中使用
典型的 LayerNorm 使用:
实例
import torch
import torch.nn as nn
class TransformerBlock(nn.Module):
def __init__(self, d_model, nhead):
super(TransformerBlock, self).__init__()
self.self_attn = nn.MultiheadAttention(d_model, nhead, batch_first=True)
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.ffn = nn.Sequential(
nn.Linear(d_model, d_model * 4),
nn.GELU(),
nn.Linear(d_model * 4, d_model)
)
def forward(self, x):
# Self-attention with residual
attn_out, _ = self.self_attn(x, x, x)
x = self.norm1(x + attn_out)
# FFN with residual
ffn_out = self.ffn(x)
x = self.norm2(x + ffn_out)
return x
# 测试
block = TransformerBlock(d_model=512, nhead=8)
x = torch.randn(4, 100, 512) # (batch, seq, d_model)
output = block(x)
print("输入形状:", x.shape)
print("输出形状:", output.shape)
import torch.nn as nn
class TransformerBlock(nn.Module):
def __init__(self, d_model, nhead):
super(TransformerBlock, self).__init__()
self.self_attn = nn.MultiheadAttention(d_model, nhead, batch_first=True)
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.ffn = nn.Sequential(
nn.Linear(d_model, d_model * 4),
nn.GELU(),
nn.Linear(d_model * 4, d_model)
)
def forward(self, x):
# Self-attention with residual
attn_out, _ = self.self_attn(x, x, x)
x = self.norm1(x + attn_out)
# FFN with residual
ffn_out = self.ffn(x)
x = self.norm2(x + ffn_out)
return x
# 测试
block = TransformerBlock(d_model=512, nhead=8)
x = torch.randn(4, 100, 512) # (batch, seq, d_model)
output = block(x)
print("输入形状:", x.shape)
print("输出形状:", output.shape)
示例 4: 不使用可学习参数
纯归一化不带缩放偏移:
实例
import torch
import torch.nn as nn
# 不带可学习参数
ln = nn.LayerNorm(16, elementwise_affine=False)
x = torch.randn(4, 16)
output = ln(x)
# 没有 weight 和 bias
print("是否有 weight:", hasattr(ln, 'weight'))
print("是否有 bias:", hasattr(ln, 'bias'))
print("n输出形状:", output.shape)
import torch.nn as nn
# 不带可学习参数
ln = nn.LayerNorm(16, elementwise_affine=False)
x = torch.randn(4, 16)
output = ln(x)
# 没有 weight 和 bias
print("是否有 weight:", hasattr(ln, 'weight'))
print("是否有 bias:", hasattr(ln, 'bias'))
print("n输出形状:", output.shape)
归一化方法对比
| 方法 | 归一化维度 | Batch 依赖 | 适用场景 |
|---|---|---|---|
BatchNorm |
batch 维度 | 是 | CNN、batch 稳定 |
LayerNorm |
特征维度 | 否 | Transformer、RNN |
InstanceNorm |
通道+空间 | 否 | 风格迁移 |
GroupNorm |
通道分组 | 否 | 小 batch 场景 |
常见问题
Q1: LayerNorm 和 BatchNorm 的区别?
LayerNorm 不依赖 batch,适合序列模型和 batch 变化大的场景。
Q2: normalized_shape 如何选择?
通常选择特征维度,如 BERT 中是 768 或 1024。
Q3: 为什么 Transformer 用 LayerNorm?
Transformer 输入序列长度可变,LayerNorm 更稳定。
使用场景
nn.LayerNorm 主要应用场景包括:
- Transformer 架构: BERT、GPT 等
- 循环神经网络: LSTM、GRU
- 变长序列处理: batch 大小不固定
提示:LayerNorm 是 Transformer 的标配,放在残差连接之后(Post-LN)或之前(Pre-LN)。

PyTorch torch.nn 参考手册