知识点卡片:范数 (Norm)
基本信息
| 属性 | 内容 |
|---|---|
| 知识点 | 范数 (L0/L1/L2/Frobenius/谱范数) |
| 掌握程度 | ★★★★★ |
| 学习优先级 | P0 |
| 预估时间 | 6小时 |
| 面试频率 | ★★★★★ |
核心原理
范数是向量/矩阵"长度"的度量,在深度学习中用于:
- 正则化:控制模型复杂度(L1/L2)
- 损失函数:衡量预测与真实值的距离
- 梯度裁剪:防止梯度爆炸
- 模型压缩:衡量参数重要性
范数定义与对比
| 范数 | 公式 | 几何意义 | DL应用 |
|---|---|---|---|
| L0 | 非零元素个数 | 稀疏性度量 | 模型剪枝 |
| L1 | ∑|xᵢ| | 菱形区域 | Lasso正则化/稀疏性 |
| L2 (欧氏距离) | √(∑xᵢ²) | 圆形区域 | Ridge正则化/权重衰减 |
| Frobenius | √(∑ᵢⱼaᵢⱼ²) | 矩阵的L2范数 | 矩阵正则化 |
| 谱范数 | 最大奇异值 | 矩阵的最大放大倍数 | 归一化 |
代码实现
python
import numpy as np
def l0_norm(x):
"""非零元素个数"""
return np.sum(x != 0)
def l1_norm(x):
"""曼哈顿距离"""
return np.sum(np.abs(x))
def l2_norm(x):
"""欧氏距离"""
return np.sqrt(np.sum(x ** 2))
def frobenius_norm(A):
"""矩阵F范数"""
return np.sqrt(np.sum(A ** 2))
def spectral_norm(A):
"""谱范数 = 最大奇异值"""
_, s, _ = np.linalg.svd(A)
return s[0]
def matrix_norm(A, p='fro'):
"""NumPy的矩阵范数"""
return np.linalg.norm(A, p)PyTorch实现
python
import torch
import torch.nn.functional as F
x = torch.randn(3, 4)
# L1范数
l1 = torch.norm(x, p=1) # torch.abs(x).sum()
# L2范数
l2 = torch.norm(x, p=2) # 默认就是L2
# Frobenius范数(矩阵)
A = torch.randn(5, 4)
fro = torch.norm(A, p='fro')
# 谱范数(需要power iteration)
def spectral_norm(A, num_iter=10):
u = torch.randn(A.shape[0], 1)
u = u / torch.norm(u)
for _ in range(num_iter):
v = A @ u
v = v / torch.norm(v)
u = A.T @ v
u = u / torch.norm(u)
return torch.norm(A @ u) / torch.norm(u)深度学习中的应用
1. L2正则化(权重衰减)
python
# 权重衰减在优化器中实现
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3, weight_decay=1e-4)
# 等价于在loss中加入L2项
loss = task_loss + 0.5 * weight_decay * sum(p.pow(2.0).sum() for p in model.parameters())2. 梯度裁剪
python
# 防止梯度爆炸
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
# 梯度裁剪公式
# grads = grads / max(1.0, global_norm / max_norm)3. FGSM对抗攻击
python
# Fast Gradient Sign Method
def fgsm_attack(image, epsilon, gradient):
perturbation = epsilon * torch.sign(gradient)
adv_image = image + perturbation
return torch.clamp(adv_image, 0, 1)面试高频问题
Q1: L1和L2正则化的区别?
| 方面 | L1 (Lasso) | L2 (Ridge) |
|---|---|---|
| 几何形状 | 菱形(顶点处稀疏) | 球形(处处平滑) |
| 解的特点 | 稀疏(产生零解) | 平滑(参数趋近零但不等于零) |
| 计算 | 含绝对值,次梯度 | 闭式解 |
| 特征选择 | 有 | 无 |
| 适用场景 | 稀疏特征 | 所有特征都重要 |
答:
- L1正则化产生稀疏解,可用于特征选择
- L2正则化使参数都趋近于零但不等于零,训练更稳定
- 实际常用Elastic Net(L1+L2组合)
Q2: 为什么梯度裁剪能防止梯度爆炸?
答: 梯度爆炸指梯度范数指数级增长。梯度裁剪将梯度限制在某个阈值内:
python
torch.nn.utils.clip_grad_norm_(parameters, max_norm)
# grad = grad * max_norm / max(global_norm, max_norm)这相当于对损失函数进行了投影,保证训练稳定性。
Q3: 谱范数在归一化中的作用?
答: 谱归一化(Spectral Normalization)限制神经网络的 Lipschitz 常数:
python
# SN使用谱范数归一化每一层
def spectral_normalized(W):
return W / spectral_norm(W)这使得网络更平滑、训练更稳定(SN-GAN的核心)。
数学性质对比
L0范数:不是真正的范数(不满足齐次性)
╭─ 0, x = 0
∥x∥0 ─│
╰─ n, x ≠ 0 (n为非零元素数)
L1范数:∥x∥₁ = |x₁| + |x₂| + ... + |xₙ|
↗ 梯度 = sign(x),含不可导点
L2范数:∥x∥₂ = √(x₁² + x₂² + ... + xₙ²)
↗ 梯度 = 2x,光滑可导
谱范数:∥A∥₂ = max_{∥x∥₂=1} ∥Ax∥₂ = σ₁(最大奇异值)
↗ 矩阵对向量的最大拉伸因子练习题
python
# 1. 验证L1+L2正则化的效果差异
import torch
import torch.nn as nn
model = nn.Linear(10, 5)
# 获取参数
params = list(model.parameters())[0] # weight
# 计算各种范数
l1 = torch.norm(params, p=1)
l2 = torch.norm(params, p=2)
fro = torch.norm(params, p='fro')
print(f"L1: {l1.item():.4f}, L2: {l2.item():.4f}, Fro: {fro.item():.4f}")
# 2. 实现梯度裁剪
def clip_gradients(model, max_norm=1.0):
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm)
# 3. 分析L1为何产生稀疏解
# L1的约束域是菱形,顶点在坐标轴上,优化容易在顶点处停止
# L2的约束域是圆形,顶点处处存在,优化会均匀收缩