2.1 一文读懂正则化和指数加权平均

部署运行你感兴趣的模型镜像

这份笔记总结会围绕“核心概念+关键差异+实操代码”展开,将两个知识点拆分成独立模块,方便你快速查阅和对比。

一、L1、L2正则化

正则化是机器学习中防止模型过拟合的核心手段,通过在损失函数中添加参数惩罚项,约束模型权重规模。

1. 正则化的作用
  • 防止过拟合:当模型复杂度过高(如参数过多)时,容易“死记硬背”训练数据的噪声,正则化通过惩罚大权重,降低模型复杂度,提升泛化能力。

  • 稳定模型输出:约束参数范围,避免因输入微小变化导致输出剧烈波动,增强模型鲁棒性。

  • 辅助特征选择:L1正则化可产生稀疏权重,自动筛选关键特征(不重要特征的权重会被压缩至0)。

2. L1与L2正则化的区别

两者核心差异在于惩罚项的数学形式,进而导致对参数的影响、解的特点完全不同,具体对比如下:

对比维度L1正则化(Lasso)L2正则化(Ridge)
惩罚项公式损失函数 + λ×Σw
对参数的影响压缩部分权重至 0,产生稀疏解仅缩小权重值,不产生稀疏解
解的唯一性可能存在多个最优解通常只有唯一最优解
适用场景特征数量多、需筛选关键特征时特征重要性均衡、需稳定权重时
3. 代码示例(基于PyTorch)
import torch
import torch.nn as nn
import torch.optim as optim

# 1. 定义简单模型(以线性回归为例)
model = nn.Linear(in_features=10, out_features=1)

# 2. L1正则化实现(两种方式)
# 方式1:使用L1Loss作为正则项,手动加到总损失中
l1_lambda = 0.01  # 正则化强度(超参数,需调优)
criterion = nn.MSELoss()  # 基础损失(如均方误差)
optimizer = optim.SGD(model.parameters(), lr=0.001)

# 模拟训练过程
x = torch.randn(32, 10)  # 32个样本,每个样本10个特征
y = torch.randn(32, 1)   # 对应标签

optimizer.zero_grad()
y_pred = model(x)
base_loss = criterion(y_pred, y)

# 计算L1正则项(所有参数的绝对值之和)
l1_regularization = torch.tensor(0., requires_grad=True)
for param in model.parameters():
    l1_regularization += torch.norm(param, 1)  # L1范数(绝对值和)

total_loss = base_loss + l1_lambda * l1_regularization
total_loss.backward()
optimizer.step()

# 3. L2正则化实现(PyTorch优化器直接支持,参数weight_decay)
# L2正则化=权重衰减,无需手动计算,直接在optimizer中设置weight_decay
optimizer_l2 = optim.SGD(model.parameters(), lr=0.001, weight_decay=0.01)  # weight_decay即λ

二、指数加权平均(Exponential Weighted Moving Average, EWMA)

指数加权平均是一种对序列数据的平滑处理方法,通过给近期数据更高权重、远期数据更低权重,动态计算平均值,常用于优化器(如Adam)、温度预测等场景。

1. 指数加权平均的含义
  • 核心公式: vt=β⋅vt−1+(1−β)⋅θtv_t = \beta \cdot v_{t-1} + (1-\beta) \cdot \theta_tvt=βvt1+(1β)θt 其中, vtv_tvt 是第t时刻的指数加权平均值, θt\theta_tθt 是第t时刻的原始数据, β\betaβ 是平滑系数(通常取0.9、0.99等)。

  • 权重特点:近期数据的权重为 (1−β)(1-\beta)(1β) ,前一时刻平均值的权重为 β\betaβ ,远期数据的权重会以 βk\beta^kβk 形式指数衰减(k为时间间隔)。

  • 近似窗口:可理解为仅关注最近 11−β\frac{1}{1-\beta}1β1 个数据的平均,例如 β=0.9\beta=0.9β=0.9 时,近似关注前10个数据; β=0.99\beta=0.99β=0.99 时,近似关注前100个数据。

2. 指数加权平均的迭代举例

以“每日温度”数据为例,假设 β=0.9\beta=0.9β=0.9 ,原始温度序列为 [25, 26, 24, 27],逐步计算迭代过程:

  1. 第1天(t=1):无历史平均值,初始 v0=0v_0=0v0=0 ,则 v1=0.9×0+0.1×25=2.5v_1 = 0.9 \times 0 + 0.1 \times 25 = 2.5v1=0.9×0+0.1×25=2.5 (初始值偏差大,实际中常做“偏差修正”)。

  2. 第2天(t=2): v2=0.9×v1+0.1×26=0.9×2.5+2.6=4.85v_2 = 0.9 \times v_1 + 0.1 \times 26 = 0.9 \times 2.5 + 2.6 = 4.85v2=0.9×v1+0.1×26=0.9×2.5+2.6=4.85

  3. 第3天(t=3): v3=0.9×v2+0.1×24=0.9×4.85+2.4=6.765v_3 = 0.9 \times v_2 + 0.1 \times 24 = 0.9 \times 4.85 + 2.4 = 6.765v3=0.9×v2+0.1×24=0.9×4.85+2.4=6.765

  4. 第4天(t=4): v4=0.9×v3+0.1×27=0.9×6.765+2.7=8.7885v_4 = 0.9 \times v_3 + 0.1 \times 27 = 0.9 \times 6.765 + 2.7 = 8.7885v4=0.9×v3+0.1×27=0.9×6.765+2.7=8.7885

  • 偏差修正:初始阶段(t较小时),用 vt/(1−βt)v_t / (1-\beta^t)vt/(1βt) 修正,例如 t=1 时修正为 2.5/(1−0.91)=252.5/(1-0.9^1)=252.5/(10.91)=25 ,避免初始值带来的偏差。
3. 代码示例(手动实现+PyTorch EMA)
import torch
import numpy as np

# 1. 手动实现指数加权平均(带偏差修正)
def exponential_weighted_average(data, beta):
    v_list = []  # 存储每个时刻的平均值
    v_prev = 0   # 初始平均值v0=0
    for t in range(len(data)):
        theta_t = data[t]
        # 计算当前平均值vt
        v_t = beta * v_prev + (1 - beta) * theta_t
        # 偏差修正(仅前几轮需要,t从0开始计数)
        v_t_corrected = v_t / (1 - beta ** (t + 1))
        v_list.append(v_t_corrected)
        v_prev = v_t
    return v_list

# 测试:用温度数据
temperatures = [25, 26, 24, 27, 28, 25]
beta = 0.9
ewma_result = exponential_weighted_average(temperatures, beta)
print("修正后的指数加权平均值:", np.round(ewma_result, 2))  # 输出:[25.  , 25.11, 24.9, 25.41, 26.07, 25.76]

# 2. PyTorch中模型参数的EMA(常用于模型保存与推理)
class EMA:
    def __init__(self, model, decay=0.999):
        self.model = model
        self.decay = decay
        # 初始化EMA权重(与原模型参数结构一致)
        self.ema_weights = {name: param.clone().detach() for name, param in model.named_parameters()}
    
    def update(self):
        # 迭代更新EMA权重
        for name, param in self.model.named_parameters():
            if param.requires_grad:
                self.ema_weights[name] = self.decay * self.ema_weights[name] + (1 - self.decay) * param.data
    
    def apply_shadow(self):
        # 将EMA权重赋给原模型(用于推理)
        self.origin_weights = {name: param.clone() for name, param in self.model.named_parameters()}
        for name, param in self.model.named_parameters():
            param.data = self.ema_weights[name]
    
    def restore(self):
        # 恢复原模型权重(用于继续训练)
        for name, param in self.model.named_parameters():
            param.data = self.origin_weights[name]

# 测试EMA类
model = nn.Linear(10, 1)
ema = EMA(model, decay=0.999)
# 模拟训练:每轮训练后更新EMA
for epoch in range(10):
    # (省略模型训练步骤)
    ema.update()
# 推理时使用EMA权重
ema.apply_shadow()
# 推理结束后恢复原权重
ema.restore()

您可能感兴趣的与本文相关的镜像

PyTorch 2.8

PyTorch 2.8

PyTorch
Cuda

PyTorch 是一个开源的 Python 机器学习库,基于 Torch 库,底层由 C++ 实现,应用于人工智能领域,如计算机视觉和自然语言处理

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Peter_Monster

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值