【前馈神经网络详解与实例】6——正则化方法

我的前馈神经网络系列文章如下,便于读者成体系学习:

【前馈神经网络详解与实例】1——网络结构-CSDN博客

【前馈神经网络详解与实例】2——激活函数-CSDN博客

【前馈神经网络详解与实例】3——初始化方法-CSDN博客

【前馈神经网络详解与实例】4——损失函数-CSDN博客

【前馈神经网络详解与实例】5——参数优化方法-CSDN博客

【前馈神经网络详解与实例】6——正则化方法-CSDN博客

【前馈神经网络详解与实例】7——典型网络介绍-CSDN博客

【前馈神经网络详解与实例】8——实战应用-CSDN博客

6、🔎 正则化方法

在神经网络训练中,过拟合是常见的挑战 。正则化(Regularization) 是一类通过限制模型复杂度、引导模型学习更稳健模式来缓解过拟合的技术。以下是神经网络中常用的正则化方法:

6.1 L1/L2 正则化(权重正则化)

L1 和 L2 正则化是最经典的正则化方法,通过在损失函数中添加权重参数的惩罚项,限制权重的绝对值或平方和,避免模型过度依赖某些特征。

6.1.1 L2 正则化(权重衰减,Weight Decay)

  • 定义:在损失函数中加入权重参数平方和的惩罚项,是实践中最常用的正则化方法。

  • 原理

    • 原始损失函数为 L(\theta)\theta 为模型参数,如权重 W 和偏置 b)

    • L2 正则化后的损失为:L_{\text{reg}}(\theta) = L(\theta) + \lambda \cdot \sum_{w \in \theta} w^2 其中 \lambda 为正则化系数(超参数,需调优),控制惩罚强度。

    • L2 会 “压制” 权重的绝对值,使权重分布更均匀(避免某些权重过大),模型更倾向于学习简单的、泛化性强的模式。

  • PyTorch 实现: PyTorch 中通过优化器的 weight_decay 参数直接支持 L2 正则化(无需手动修改损失函数),默认对所有可学习参数(权重和偏置)生效(通常偏置不正则化,可手动排除)。

     import torch
     import torch.nn as nn
     import torch.optim as optim
     ​
     # 定义简单模型
     class SimpleModel(nn.Module):
         def __init__(self):
             super().__init__()
             self.fc = nn.Linear(10, 2)  # 输入10维,输出2维
         def forward(self, x):
             return self.fc(x)
     ​
     model = SimpleModel()
     criterion = nn.CrossEntropyLoss()  # 分类损失
     ​
     # 优化器设置weight_decay(L2正则化系数)
     optimizer = optim.SGD(model.parameters(), lr=0.01, weight_decay=1e-4)  # λ=1e-4
     ​
     # 训练过程(简化)
     x = torch.randn(32, 10)  # 32个样本,10维特征
     y = torch.randint(0, 2, (32,))  # 标签
     pred = model(x)
     loss = criterion(pred, y)  # 原始损失
     optimizer.zero_grad()
     loss.backward()  # 自动包含L2惩罚的梯度
     optimizer.step()
  • 适用场景:几乎所有神经网络(全连接、卷积、Transformer 等),尤其当模型参数较多、易过拟合时。

6.1.2 L1 正则化

定义:在损失函数中加入权重参数绝对值之和的惩罚项。

  • 原理

    • 正则化后的损失为:L_{\text{reg}}(\theta) = L(\theta) + \lambda \cdot \sum_{w \in \theta} |w|

    • L1 会使部分权重变为 0(稀疏性),相当于自动 “剔除” 不重要的特征,实现特征选择

  • PyTorch 实现: PyTorch 优化器不直接支持 L1 正则化,需手动在损失中添加惩罚项:

     # 定义L1惩罚项(仅对权重,忽略偏置)
     def l1_regularization(model, lambda_l1=1e-4):
         l1_loss = 0.0
         for param in model.parameters():
             if param.dim() > 1:  # 假设权重是2D及以上,偏置是1D
                 l1_loss += torch.norm(param, 1)  # L1范数
         return lambda_l1 * l1_loss
     ​
     # 训练时的总损失
     pred = model(x)
     ce_loss = criterion(pred, y)  # 交叉熵损失
     l1_loss = l1_regularization(model)  # L1惩罚
     total_loss = ce_loss + l1_loss  # 总损失
     ​
     optimizer.zero_grad()
     total_loss.backward()
     optimizer.step()
  • 适用场景:需要特征选择的任务(如高维输入数据),但优化难度高于 L2(L1 损失在 0 点不可导),实际中不如 L2 常用。


6.2 Dropout

Dropout 是 Hinton 团队提出的针对神经网络的专用正则化方法,通过随机丢弃部分神经元,强制模型学习更鲁棒的特征(不依赖特定神经元)。

  • 原理

    • 训练阶段:对某一层的神经元,以概率 p(通常 0.5)随机将其输出设为 0(“丢弃”),其余神经元输出乘以 1/(1-p)(保持期望不变)。 例如:若某层有 4 个神经元,输出为 ([a, b, c, d]),Dropout 概率 (p=0.5),可能随机丢弃第 2 和第 4 个神经元,输出变为 ([2a, 0, 2c, 0])(乘以 (1/(1-0.5)=2))。

    • 验证阶段:不丢弃神经元,所有神经元正常输出(无需缩放,因训练时已通过缩放保持期望)。

      直观来说,Dropout 使模型在训练时 “随机瘦身”,避免对特定神经元的依赖,相当于同时训练多个子模型,最终集成它们的效果。

  • PyTorch 实现

通过 nn.Dropout 层实现,注意训练和验证时的模式切换(model.train()model.eval()):

 class DropoutModel(nn.Module):
     def __init__(self):
         super().__init__()
         self.fc1 = nn.Linear(10, 100)
         self.dropout = nn.Dropout(p=0.5)  # 丢弃概率50%
         self.fc2 = nn.Linear(100, 2)
     
     def forward(self, x):
         x = torch.relu(self.fc1(x))
         x = self.dropout(x)  # 训练时生效,推理时关闭
         x = self.fc2(x)
         return x
 ​
 model = DropoutModel()
 criterion = nn.CrossEntropyLoss()
 optimizer = optim.Adam(model.parameters(), lr=0.001)
 ​
 # 训练模式(开启Dropout)
 model.train()
 x_train = torch.randn(32, 10)
 y_train = torch.randint(0, 2, (32,))
 pred = model(x_train)
 loss = criterion(pred, y_train)
 loss.backward()
 optimizer.step()
 ​
 # 推理模式(关闭Dropout)
 model.eval()
 with torch.no_grad():  # 关闭梯度计算
     x_test = torch.randn(10, 10)
     pred_test = model(x_test)  # 无丢弃
  • 适用场景

    • 全连接层(效果显著)、卷积层(可使用,但需较小的丢弃概率,如 0.1-0.3)。

    • 不建议用于循环神经网络(RNN),可改用专门的 nn.Dropout2d(空间维度丢弃)或 nn.AlphaDropout(保持均值和方差,适合自归一化网络)。


6.3 早停(Early Stopping)

早停是一种 “朴素” 但高效的正则化方法,通过监控验证集性能,在模型开始过拟合前停止训练,避免模型过度学习训练数据的噪声。

  • 原理

    • 训练过程中,模型在训练集上的损失会持续下降,但验证集损失会先下降后上升(过拟合的标志)。

    • 早停的核心是:当验证集损失连续若干个 epoch(如 5-10 次)不再下降时,停止训练,并保存此时的模型参数(验证集性能最优的状态)。

  • PyTorch 实现

需手动记录验证集损失,判断是否停止:

 model = SimpleModel()
 criterion = nn.CrossEntropyLoss()
 optimizer = optim.Adam(model.parameters(), lr=0.001)
 ​
 # 早停参数
 patience = 5  # 最多容忍5个epoch无改进
 best_val_loss = float('inf')
 counter = 0  # 记录无改进的epoch数
 ​
 # 假设已划分训练集和验证集
 for epoch in range(100):
     # 训练
     model.train()
     train_pred = model(train_x)
     train_loss = criterion(train_pred, train_y)
     optimizer.zero_grad()
     train_loss.backward()
     optimizer.step()
     
     # 验证
     model.eval()
     with torch.no_grad():
         val_pred = model(val_x)
         val_loss = criterion(val_pred, val_y)
     
     # 早停判断
     if val_loss < best_val_loss:
         best_val_loss = val_loss
         best_model = model.state_dict()  # 保存最优模型
         counter = 0  # 重置计数器
     else:
         counter += 1
         if counter >= patience:
             print(f"早停于第{epoch}轮")
             break
 ​
 # 加载最优模型
 model.load_state_dict(best_model)
  • 适用场景

所有神经网络训练,尤其当训练数据有限、模型复杂度高时(如深层 CNN、Transformer)。需注意:验证集的划分需合理(与训练集独立同分布),否则可能导致早停失效。


6.4 数据增强(Data Augmentation)

数据增强是从数据层面缓解过拟合的方法,通过对训练数据进行随机变换(如旋转、裁剪、加噪等),生成 “新样本”,扩大训练集规模,迫使模型学习更通用的特征。

  • 原理

    • 变换后的样本保留原始数据的核心特征(如猫的图像旋转后仍是猫),但细节不同(如角度、位置)。

    • 模型在多样化的样本上训练,能减少对特定细节(如训练集中猫的位置)的依赖,提高泛化能力。

  • PyTorch 实现

通过 torchvision.transforms 实现(以图像为例):

 from torchvision import transforms
 from torch.utils.data import Dataset, DataLoader
 ​
 # 定义数据增强变换(仅用于训练集)
 train_transform = transforms.Compose([
     transforms.RandomResizedCrop(224),  # 随机裁剪并缩放至224x224
     transforms.RandomHorizontalFlip(p=0.5),  # 50%概率水平翻转
     transforms.RandomRotation(15),  # 随机旋转±15度
     transforms.ColorJitter(brightness=0.2),  # 随机调整亮度
     transforms.ToTensor(),  # 转为Tensor
 ])
 ​
 # 验证集不增强(保持原始分布)
 val_transform = transforms.Compose([
     transforms.Resize(256),
     transforms.CenterCrop(224),
     transforms.ToTensor(),
 ])
 ​
 # 自定义数据集(假设已实现)
 train_dataset = CustomDataset(data_dir, transform=train_transform)
 val_dataset = CustomDataset(data_dir, transform=val_transform)
 ​
 train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
 val_loader = DataLoader(val_dataset, batch_size=32)
  • 适用场景

    • 图像任务(最常用):通过裁剪、翻转、色彩变换等增强。

    • 文本任务:通过同义词替换、随机插入 / 删除单词、回译等增强。

    • 语音任务:通过加噪、语速调整、音调变换等增强。 数据增强的关键是变换需保留标签信息(如猫的图像旋转后标签仍是 “猫”)。


6.5 批量归一化(Batch Normalization, BN)

BN 主要用于加速神经网络训练(缓解梯度消失 / 爆炸),但同时具有一定正则化效果,可辅助缓解过拟合。

  • 原理

    • 训练时,对每一层的输入按批次标准化(减去均值、除以标准差),并引入可学习的缩放和平移参数。

    • 正则化效果来源:批次内的随机噪声(不同批次的均值 / 标准差不同)会给模型带来微小扰动,类似 Dropout 的 “随机性”,迫使模型更稳健。

  • PyTorch 实现

class BNModel(nn.Module):
     def __init__(self):
         super().__init__()
         self.fc1 = nn.Linear(10, 100)
         self.bn = nn.BatchNorm1d(100)  # 对100维特征做BN
         self.fc2 = nn.Linear(100, 2)
     
     def forward(self, x):
         x = self.fc1(x)
         x = self.bn(x)  # 应用BN
         x = torch.relu(x)
         x = self.fc2(x)
         return x
  • 适用场景

几乎所有深度神经网络(CNN、全连接网络等),尤其深层模型。注意:BN 的正则化效果较弱,通常需与 Dropout、早停等配合使用。


6.6 其他正则化方法

  • 标签平滑(Label Smoothing): 软化分类任务的 one-hot 标签(如将标签 “1” 改为 “0.9”,其他类别改为 “0.1/(C-1)”,C 为类别数),避免模型对预测过于自信,减少过拟合。 PyTorch 实现:nn.CrossEntropyLoss(label_smoothing=0.1)(PyTorch 1.10 + 支持)。

  • 模型集成(Ensemble): 训练多个不同的模型(如不同初始化、不同架构),通过投票或平均输出得到最终结果。集成方法能显著提高泛化能力,但计算成本高。 示例:训练 3 个不同的 CNN,推理时取预测概率的平均值。

  • 权重剪枝(Weight Pruning): 移除神经网络中绝对值较小的权重(认为其对模型贡献小),简化模型结构,减少过拟合。PyTorch 可通过 torch.nn.utils.prune 模块实现。

总结

正则化方法的核心是 “限制模型复杂度” 或 “增加数据多样性”,实际应用中通常组合多种方法(如 L2 正则化 + Dropout + 早停 + 数据增强)以达到最佳效果。选择时需结合任务类型(分类 / 回归)、数据规模(小数据更依赖数据增强和早停)、模型结构(深层模型需更多正则化)等因素综合考虑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值