当前位置: 首页 > article >正文

深度学习中的正则化技术

在深度学习中,正则化是一种防止模型过拟合的重要手段。过拟合是指模型在训练数据上表现良好,但在未见数据上表现不佳的现象。正则化通过引入额外的约束或信息来限制模型的复杂性,从而提高模型的泛化能力。本文将介绍几种常见的正则化技术,包括 L1 正则化、L2 正则化、Dropout 和 Batch Normalization,并提供在 PyTorch 中的实现方法。

1. 正则化技术

1.1 L1 正则化

原理

L1 正则化(Lasso 正则化)通过在损失函数中添加权重绝对值的和来实现。其主要特点是能够导致一些权重变为零,从而实现特征选择。

公式

L1 正则化的损失函数公式如下:

L = Loss + λ ∑ j = 1 n ∣ w j ∣ L = \text{Loss} + \lambda \sum_{j=1}^{n} |w_j| L=Loss+λj=1nwj

其中:

  • L L L 是总损失。
  • Loss \text{Loss} Loss 是原始损失(如均方误差)。
  • λ \lambda λ 是正则化强度(超参数)。
  • w j w_j wj 是模型的权重。
在 PyTorch 中的实现

在 PyTorch 中,L1 正则化通常需要在损失函数中手动添加 L1 范数。可以通过遍历模型的参数,计算绝对值和并将其添加到损失中。


1.2 L2 正则化

原理

L2 正则化(Ridge 正则化)通过在损失函数中添加权重平方和来实现。它的主要作用是将权重收缩到更小的值,从而减小模型的复杂性。

公式

L2 正则化的损失函数公式如下:

L = Loss + λ ∑ j = 1 n w j 2 L = \text{Loss} + \lambda \sum_{j=1}^{n} w_j^2 L=Loss+λj=1nwj2

其中:

  • L L L 是总损失。
  • Loss \text{Loss} Loss 是原始损失。
  • λ \lambda λ 是正则化强度(超参数)。
  • w j w_j wj 是模型的权重。
在 PyTorch 中的实现

在 PyTorch 中,L2 正则化可以通过在优化器中设置 w e i g h t _ d e c a y weight\_decay weight_decay 参数来实现。例如,使用 SGD 优化器时,可以直接在优化器的初始化中添加 w e i g h t _ d e c a y weight\_decay weight_decay


1.3 Dropout

原理

Dropout 是一种随机丢弃神经元的技术。在训练过程中,随机选择一部分神经元(及其连接)不参与前向传播和反向传播。其主要目的是防止神经网络对特定神经元的过度依赖,从而提高模型的泛化能力。

在 PyTorch 中的实现

在 PyTorch 中,可以通过在模型中添加 n n . D r o p o u t nn.Dropout nn.Dropout 层来实现 Dropout。您可以指定丢弃的概率(例如,0.5 表示有 50% 的概率丢弃神经元)。


1.4 Batch Normalization

原理

Batch Normalization 是一种加速训练并提高模型稳定性的技术。它通过对每一层的输入进行标准化,使其具有零均值和单位方差,从而减少内部协变量偏移。Batch Normalization 通常可以提高模型的收敛速度并增强泛化能力。

在 PyTorch 中的实现

在 PyTorch 中,可以通过在模型中添加 n n . B a t c h N o r m 1 d nn.BatchNorm1d nn.BatchNorm1d n n . B a t c h N o r m 2 d nn.BatchNorm2d nn.BatchNorm2d 层来实现 Batch Normalization,具体取决于输入的维度(1D 或 2D)。


2. 实验代码与分析

下面是使用 MNIST 手写数字数据集的代码示例,比较了不带正则化的 CNN 模型与带有 L2 正则化、Dropout 和 Batch Normalization 的 CNN 模型。

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision.transforms as transforms
from torchvision import datasets
from torch.utils.data import DataLoader

# 检查设备
device = torch.device("mps" if torch.backends.mps.is_available() else "cpu")
print(f"Using device: {device}")

# 数据准备
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))  # 归一化
])

# 下载 MNIST 数据集
train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
test_dataset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)

train_loader = DataLoader(dataset=train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(dataset=test_dataset, batch_size=64, shuffle=False)

# 定义不带正则化的 CNN 模型
class SimpleCNNNoReg(nn.Module):
    def __init__(self):
        super(SimpleCNNNoReg, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3, padding=1)  # 输入通道数为1,输出通道数为32
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
        self.fc1 = nn.Linear(64 * 7 * 7, 128)  # 7x7 是经过卷积和池化后的特征图大小
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        x = torch.relu(self.conv1(x))
        x = nn.MaxPool2d(kernel_size=2)(x)  # 最大池化
        x = torch.relu(self.conv2(x))
        x = nn.MaxPool2d(kernel_size=2)(x)  # 最大池化
        x = x.view(-1, 64 * 7 * 7)  # 展平
        x = torch.relu(self.fc1(x))
        x = self.fc2(x)
        return x

# 定义带 L2 正则化、Dropout 和 Batch Normalization 的 CNN 模型
class SimpleCNNWithReg(nn.Module):
    def __init__(self):
        super(SimpleCNNWithReg, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3, padding=1)
        self.bn1 = nn.BatchNorm2d(32)  # Batch Normalization
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
        self.bn2 = nn.BatchNorm2d(64)  # Batch Normalization
        self.fc1 = nn.Linear(64 * 7 * 7, 128)
        self.dropout = nn.Dropout(0.5)  # Dropout
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        x = torch.relu(self.bn1(self.conv1(x)))  # Batch Normalization
        x = nn.MaxPool2d(kernel_size=2)(x)  # 最大池化
        x = torch.relu(self.bn2(self.conv2(x)))  # Batch Normalization
        x = nn.MaxPool2d(kernel_size=2)(x)  # 最大池化
        x = x.view(-1, 64 * 7 * 7)  # 展平
        x = torch.relu(self.fc1(x))
        x = self.dropout(x)  # Dropout
        x = self.fc2(x)
        return x

# 训练和评估函数
def train(model, train_loader, criterion, optimizer, epochs=10):
    model.train()
    for epoch in range(epochs):
        running_loss = 0.0
        for images, labels in train_loader:
            images, labels = images.to(device), labels.to(device)  # 移动到设备
            optimizer.zero_grad()
            outputs = model(images)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
            running_loss += loss.item()

        # 计算平均损失
        avg_loss = running_loss / len(train_loader)
        print(f'Epoch [{epoch + 1}/{epochs}], Loss: {avg_loss:.4f}')

def evaluate(model, test_loader):
    model.eval()
    correct = 0
    total = 0
    with torch.no_grad():
        for images, labels in test_loader:
            images, labels = images.to(device), labels.to(device)  # 移动到设备
            outputs = model(images)
            _, predicted = torch.max(outputs.data, 1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()
    return correct / total

# 不带正则化的模型
model_no_reg = SimpleCNNNoReg().to(device)  # 移动模型到设备
criterion = nn.CrossEntropyLoss()
optimizer_no_reg = optim.SGD(model_no_reg.parameters(), lr=0.01)

# 训练不带正则化的模型
print("Training model without regularization...")
train(model_no_reg, train_loader, criterion, optimizer_no_reg, epochs=10)
accuracy_no_reg = evaluate(model_no_reg, test_loader)

# 带 L2 正则化、Dropout 和 Batch Normalization 的模型
model_with_reg = SimpleCNNWithReg().to(device)  # 移动模型到设备
optimizer_with_reg = optim.SGD(model_with_reg.parameters(), lr=0.01, weight_decay=0.01)  # L2 正则化

# 训练带正则化的模型
print("\nTraining model with L2 regularization, Dropout, and Batch Normalization...")
train(model_with_reg, train_loader, criterion, optimizer_with_reg, epochs=10)
accuracy_with_reg = evaluate(model_with_reg, test_loader)

# 输出结果
print(f"\nAccuracy without regularization: {accuracy_no_reg:.4f}")
print(f"Accuracy with L2 regularization, Dropout, and Batch Normalization: {accuracy_with_reg:.4f}")
Accuracy without regularization: 0.9850
Accuracy with L2 regularization, Dropout, and Batch Normalization: 0.9857
  • 不带正则化的 CNN:包含两个卷积层和两个全连接层,适合于处理 MNIST 这样的图像数据。
  • 带正则化的 CNN:在卷积层后添加了 Batch Normalization 和 Dropout,帮助模型提高泛化能力和稳定性。

在这个实验中,通过比较不带正则化的模型与带有 L2 正则化、Dropout 和 Batch Normalization 的模型,我们能够观察到正则化技术对模型泛化能力的影响。正则化可以有效地减少过拟合,提高模型在未见数据上的准确性。

  • L2 正则化:通过惩罚较大的权重,帮助模型保持简单,从而提高泛化能力。
  • Dropout:通过随机丢弃神经元,减少模型对特定特征的依赖,增强模型的鲁棒性。
  • Batch Normalization:通过标准化层的输入,加速训练并提高模型稳定性。

http://www.kler.cn/a/405174.html

相关文章:

  • 『 Linux 』文件与网络套接字的内部关系
  • Docker3:docker基础1
  • 好用的js组件库
  • nginx 配置lua执行shell脚本
  • 原生微信小程序在顶部胶囊左侧水平设置自定义导航兼容各种手机模型
  • 【软件测试】自动化常用函数
  • C++中的组合模式
  • 「Mac玩转仓颉内测版23」基础篇3 - 深入理解整数类型
  • Ubuntu24.04解决向日葵安装libgconf-2-4依赖问题
  • 鸿蒙学习高效开发与测试-ArkUI 框架(2)
  • MySQL 视图使用详解
  • [C#] 关于数组的详细解释以及使用注意点
  • 【QT常用技术讲解】QSettings把中文输入到配置文件
  • Nuxt.js 应用中的 webpack:configResolved事件钩子
  • 二叉树遍历相关算法题|后序遍历非递归|下到上左到右层次遍历|先序遍历非递归(C)
  • QT简单设计 网格布局 QT5.12.3环境 C++实现
  • 【pytorch-04】:线性回归案例(手动构建)
  • mongoDB回顾笔记(一)
  • springboot嗨玩旅游网站
  • 11.21 深度学习-tensor常见操作
  • Project指针pointer 作业
  • 【日常经验】Mysql中的某个存储过程中如果有查数据,存数据和删除数据,会自动在一个事务中吗
  • AWTK VSCode 实时预览插件端口冲突的解决办法
  • ubuntu 之 安装mysql8
  • 如何用redis+lua来实现高并发限流,超时数据进行等待
  • 基于Java Springboot北京医疗企业固定资产管理系统