Skip to content

知识点卡片:范数 (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的约束域是圆形,顶点处处存在,优化会均匀收缩