【Pytorch(六)】网络优化练习

简介: 【Pytorch(六)】网络优化练习

0. 概述

其中,Dropout 与权重衰减 (Weight Decay) 两种方法已经在以后实验中(过拟合专题)练习,本次实验我们将练习其他一些重要的网络优化方法。


具体包括:


(1) 小批量梯度下降(这部分将讨论 batch size 与学习率的设置问题)


(2) 学习率衰减 (Learning Rate Decay)


(3) 批量归一化 (Batch Normalization)


(4) 数据预处理


1. PyTorch 库导入及数据集介绍

import torch
import torchvision
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
print(torch.manual_seed(1))
<torch._C.Generator object at 0x000001C4DFC45B50>

关于数据集:


本次实验我们将用到一个新的图片数据集:CIFAR-10。该数据集共有 60000 张 RGB 彩色图像,其中 50000 张用于训练,10000 张用于测试。图片共分为 10 个类别,每类各有 6000 张图片,每张图片包含 32*32 个像素点。


数据集样例和 10 个类别如下所示:

image.png



CIFAR-10 的官方说明及下载地址:http://www.cs.toronto.edu/~kriz/cifar.html

 相较于之前用过的 MNIST 和 Fashion-MNIST 来说,CIFAR-10 的分类难度显著增加。


2. 对照组结果

# 训练集
batch_size_small = 10  # 小批次:每次处理 10 张图片
train_set = torchvision.datasets.CIFAR10('./dataset_cifar10', train=True, download=True,
                                       transform=torchvision.transforms.Compose([
                                           torchvision.transforms.ToTensor(),
                                           torchvision.transforms.Normalize(
                                               (0.4914,0.4822,0.4465), (0.2023,0.1994,0.2010)
                                           )
                                       ])
)
# 测试集
test_set = torchvision.datasets.CIFAR10('./dataset_cifar10', train=False, download=True,
                                      transform=torchvision.transforms.Compose([
                                          torchvision.transforms.ToTensor(),
                                          torchvision.transforms.Normalize(
                                              (0.4914,0.4822,0.4465), (0.2023,0.1994,0.2010)
                                          )
                                      ]))
train_loader_small = torch.utils.data.DataLoader(train_set, batch_size=batch_size_small, shuffle=True)
test_loader_small = torch.utils.data.DataLoader(test_set, batch_size=batch_size_small, shuffle=True)
Files already downloaded and verified
Files already downloaded and verified

设计一个普通的卷积神经网络,其中包含三个卷积层和两个全连接层。


class CNN5_SmallBatch(nn.Module):
    def __init__(self):
        super(CNN5_SmallBatch, self).__init__()
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=32, padding=1, kernel_size=3)
        self.conv2 = nn.Conv2d(in_channels=32, out_channels=32, padding=1, kernel_size=3)
        self.conv3 = nn.Conv2d(in_channels=32, out_channels=32, padding=1, kernel_size=3)
        self.fc1 = nn.Linear(in_features=32*4*4, out_features=64)
        self.out = nn.Linear(in_features=64, out_features=10)
    def forward(self, t):        
        t = self.conv1(t)
        t = F.relu(t)  
        t = F.max_pool2d(t, kernel_size=2, stride=2)  
        t = self.conv2(t)
        t = F.relu(t)
        t = F.max_pool2d(t, kernel_size=2, stride=2)     
        t = self.conv3(t)
        t = F.relu(t)
        t = F.max_pool2d(t, kernel_size=2, stride=2)
        t = t.reshape(batch_size_small, 32*4*4)  # dim0: batch size = 10
        t = self.fc1(t)
        t = F.relu(t)
        t = self.out(t)
        return t
network = CNN5_SmallBatch()
print(network.cuda())
1
2
CNN5_SmallBatch(
  (conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (conv2): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (conv3): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (fc1): Linear(in_features=512, out_features=64, bias=True)
  (out): Linear(in_features=64, out_features=10, bias=True)
)

训练前准备


loss_func = nn.CrossEntropyLoss()  # 损失函数
optimizer = optim.SGD(network.parameters(), lr=0.1)  # 优化器(学习率 lr 等于 0.1)
def get_num_correct(preds, labels):  # get the number of correct times
    return preds.argmax(dim=1).eq(labels).sum().item()

开始训练


total_epochs = 10  # 训练 10 个周期
for epoch in range(total_epochs):
    total_loss = 0
    total_train_correct = 0
    for batch in train_loader_small:         
        images, labels = batch
        images = images.cuda()
        labels = labels.cuda()
        preds = network(images)
        loss = loss_func(preds, labels)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
        total_train_correct += get_num_correct(preds, labels)
    print("epoch:", epoch, 
          "correct times:", total_train_correct,
          f"training accuracy:", "%.3f" %(total_train_correct/len(train_set)*100), "%", 
          "total_loss:", "%.3f" %total_loss)
torch.save(network.cpu(), "cnn5.pt")  # 保存模型
epoch: 0 correct times: 20931 training accuracy: 41.862 % total_loss: 8056.230
epoch: 1 correct times: 24131 training accuracy: 48.262 % total_loss: 7359.204
epoch: 2 correct times: 24193 training accuracy: 48.386 % total_loss: 7401.946
epoch: 3 correct times: 24470 training accuracy: 48.940 % total_loss: 7411.769
epoch: 4 correct times: 24225 training accuracy: 48.450 % total_loss: 7540.996
epoch: 5 correct times: 23992 training accuracy: 47.984 % total_loss: 7580.270
epoch: 6 correct times: 24355 training accuracy: 48.710 % total_loss: 7503.453
epoch: 7 correct times: 24148 training accuracy: 48.296 % total_loss: 7539.350
epoch: 8 correct times: 23923 training accuracy: 47.846 % total_loss: 7676.186
epoch: 9 correct times: 23948 training accuracy: 47.896 % total_loss: 7615.532

查看测试结果


network = CNN5_SmallBatch()  # 加载模型
network = torch.load("cnn5.pt")
total_test_correct = 0
total_loss = 0
for batch in test_loader_small:
    images, labels = batch
    images = images
    labels = labels
    preds = network(images)
    loss = loss_func(preds, labels)
    total_loss += loss
    total_test_correct += get_num_correct(preds, labels)
print("correct times:", total_test_correct, 
      f"test accuracy:", "%.3f" %(total_test_correct/len(test_set)*100), "%",
      "total_loss:", "%.3f" %total_loss)
correct times: 4475 test accuracy: 44.750 % total_loss: 1604.812

3. 小批量梯度下降:batch size 与学习率 (lr) 设置

在理论课中,我们已经学习了什么是小批量梯度下降,下面我们来对如下结论予以验证:


批量越大,随机梯度的方差越小,引入的噪声也越小,训练也越稳定,因此可以设置较大的学习率;

批量较小时,需要设置较小的学习率,否则模型会不收敛。

(1) 为了验证结论,我们将 batch size 从原先的 10 增加到 100,维持学习率 0.1 不变。观察此时训练和测试结果并讨论。


训练结果,测试结果如图1,图2所示。


image.png


图 1训练结果(batch size=100,lr=0.1)

image.png



图 2 测试结果(batch size=100,lr=0.1)


与对照组对比发现:网络测试准确率从42%左右提高到了71%左右,有了较大提升。原因在于:保持相同的学习率保证了优化算法每次迈出的步子大小相同;增大batch size优化算法可以获得更多的损失信息,这样它可以朝着更加正确的方向(全局或局部最小值)迈步子。有了相同大小的步子而方向更加准确,因此在有限的训练周期内会获得更好的训练效果,测试效果自然更好。因此大的batch size,对应大的学习率。


4. 学习率衰减策略(Learning Rate Decay)

一般来说,我们希望在训练初期学习率大一些,使得网络收敛迅速,在训练后期学习率小一些,使得网络能够更好的收敛到最优解。


下面我们来做如下测试:保持 batch size 为 10,每个周期结束后,使得学习率衰减为原先的 0.8 倍。观察此时训练和测试结果并讨论。


训练结果如图3所示,测试结果如图4所示。


image.png


图3 训练结果(学习率衰减)


image.png


图4 测试结果(学习率衰减)


与对照组对比发现:网络测试准确率从42%左右提高到了71%左右,有了较大提升。原因在于:在学习初期通常处于离最小值较远的地方,因此采用较大的学习率迈出较大的步子加快训练速度。但是随着训练的进行,已经很靠近最小值了,这时要学习率小一些,使得网络能够更好的收敛到最优解。


除了手动减少学习率,PyTorch 也为我们提供了多种学习率衰减策略,感兴趣的同学可以阅读官网上的说明 “How to adjust learning rate” (https://pytorch.org/docs/stable/optim.html) 。


5. 批量归一化 (Batch Normalization)

批量归一化方法目前已经被广泛的应用在神经网络中,它有很多显著的优点,例如能够有效提高网络泛化能力、可以选择比较大的初始学习率、能够提高网络收敛性等。


感兴趣的同学可参考文献:《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》


下面我们维持 batch size (10) 和学习率 (0.1) 不变,重新定义并训练一个包含 batch normalization layer (nn.BatchNorm2d) 的卷积神经网络。请同学们观察训练和测试结果并讨论。


# ------------- data loader (batch size = 10) -------------
# 使用 train_loader_small 和 test_loader_small 
# -------------  network (包含批量归一化处理) -------------
class CNN5_BatchNorm(nn.Module):
    def __init__(self):
        super(CNN5_BatchNorm, self).__init__()
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=32, padding=1, kernel_size=3)
        self.bn1 = nn.BatchNorm2d(32)  # 批量归一化层 (32:输入通道数)
        self.conv2 = nn.Conv2d(in_channels=32, out_channels=32, padding=1, kernel_size=3)
        self.bn2 = nn.BatchNorm2d(32)  # 批量归一化层 (32:输入通道数)
        self.conv3 = nn.Conv2d(in_channels=32, out_channels=32, padding=1, kernel_size=3)
        self.bn3 = nn.BatchNorm2d(32)  # 批量归一化层 (32:输入通道数)
        self.fc1 = nn.Linear(in_features=32*4*4, out_features=64)
        self.out = nn.Linear(in_features=64, out_features=10)
    def forward(self, t):
        t = self.conv1(t)  # conv1
        t = self.bn1(t)  # batch normalization
        t = F.relu(t)
        t = F.max_pool2d(t, kernel_size=2, stride=2)          
        t = self.conv2(t)  # conv2
        t = self.bn2(t)  # batch normalization
        t = F.relu(t)
        t = F.max_pool2d(t, kernel_size=2, stride=2)             
        t = self.conv3(t)  # conv3
        t = self.bn3(t)  # batch normalization
        t = F.relu(t)
        t = F.max_pool2d(t, kernel_size=2, stride=2)
        t = t.reshape(batch_size_small, 32*4*4)
        t = self.fc1(t)  # fc1
        t = F.relu(t)
        t = self.out(t)  # output layer
        return t
network = CNN5_BatchNorm()
network.cuda()
# ------------- 训练 -------------
optimizer = optim.SGD(network.parameters(), lr=0.1)  # 学习率 lr 设置为 0.1
for epoch in range(total_epochs):
    total_loss = 0
    total_train_correct = 0
    for batch in train_loader_small:         
        images, labels = batch
        images = images.cuda()
        labels = labels.cuda()
        preds = network(images)
        loss = loss_func(preds, labels)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()       
        total_loss += loss.item()
        total_train_correct += get_num_correct(preds, labels)
    print("epoch:", epoch, 
          "correct times:", total_train_correct,
          f"training accuracy:", "%.3f" %(total_train_correct/len(train_set)*100), "%", 
          "total_loss:", "%.3f" %total_loss)
torch.save(network.cpu(), "cnn5.pt")  # 保存模型

训练结果如图5所示,测试结果如图6所示。


image.png


图5 训练结果(批量归一化)


image.png


图6 测试结果(批量归一化)


与对照组对比发现:网络测试准确率从42%左右提高到了73%左右,有了较大提升。原因在于:在深层神经网络中,中间层的输入是上一层神经网络的输出。因此,之前的层的神经网络参数的变化会导致当前层输入的分布发生较大的差异。在使用随机梯度下降法来训练神经网络时,每次参数更新都会导致网络中每层的输入分布发生变化。越是深层的神经网络,其输入的分布会改变的越明显。从机器学习角度来看,如果某层的输入分布发生了变化,那么其参数需要重新学习,这种现象称为内部协变量偏移。为了解决内部协变量偏移问题,就要使得每一层神经网络输入的分布在训练过程中要保持一致。最简单的方法是对每一层神经网络都进行归一化操作,使其分布保持稳定。批量归一化可以使得每一层神经网络输入的分布在训练过程中要保持一致,因此可以有效提高网络性能。


6. 数据预处理

在之前的实验中,我们在将数据集传递给神经网络前,每次都对数据进行了标准化处理 (data normalization)。下面我们取消标准化和 shuffle 设置,将 batch size 和学习率分别设为 100 和 0.1,请和 3-(1) 对比,观察数据预处理是否对结果有所影响。


# ------------- data loader (batch size = 100,取消标准化处理) -------------
train_set_noTransform = torchvision.datasets.CIFAR10('./dataset_cifar10', train=True, download=True, 
                                                     transform=torchvision.transforms.Compose([
                                                         torchvision.transforms.ToTensor(),                                                         
                                                     ]))
test_set_noTransform = torchvision.datasets.CIFAR10('./dataset_cifar10', train=False, download=True,
                                                    transform=torchvision.transforms.Compose([
                                                        torchvision.transforms.ToTensor(),
                                                    ]))

训练结果如图7所示,测试结果如图8所示。


image.png


图7 训练结果(batch size=100,lr=0.1,无预处理)


image.png


图8 测试结果(batch size=100,lr=0.1,无预处理)


与“batch size=100,lr=0.1,有预处理”的组别对比发现:网络测试准确率从71%左右降低到了65%左右,有明显下降。分析原因:加入预处理可以使输入的数据处在一个更好的分布更有利于网络的训练,使得优化算法更容易找到最优解方向,收敛更快。

相关文章
|
14天前
|
机器学习/深度学习 数据可视化 算法
PyTorch生态系统中的连续深度学习:使用Torchdyn实现连续时间神经网络
神经常微分方程(Neural ODEs)是深度学习领域的创新模型,将神经网络的离散变换扩展为连续时间动力系统。本文基于Torchdyn库介绍Neural ODE的实现与训练方法,涵盖数据集构建、模型构建、基于PyTorch Lightning的训练及实验结果可视化等内容。Torchdyn支持多种数值求解算法和高级特性,适用于生成模型、时间序列分析等领域。
157 77
PyTorch生态系统中的连续深度学习:使用Torchdyn实现连续时间神经网络
|
2月前
|
负载均衡 网络协议 网络性能优化
动态IP代理技术详解及网络性能优化
动态IP代理技术通过灵活更换IP地址,广泛应用于数据采集、网络安全测试等领域。本文详细解析其工作原理,涵盖HTTP、SOCKS代理及代理池的实现方法,并提供代码示例。同时探讨配置动态代理IP后如何通过智能调度、负载均衡、优化协议选择等方式提升网络性能,确保高效稳定的网络访问。
283 2
|
20天前
|
机器学习/深度学习 搜索推荐 PyTorch
基于昇腾用PyTorch实现传统CTR模型WideDeep网络
本文介绍了如何在昇腾平台上使用PyTorch实现经典的WideDeep网络模型,以处理推荐系统中的点击率(CTR)预测问题。
186 66
|
5天前
|
机器学习/深度学习 存储 算法
近端策略优化(PPO)算法的理论基础与PyTorch代码详解
近端策略优化(PPO)是深度强化学习中高效的策略优化方法,广泛应用于大语言模型的RLHF训练。PPO通过引入策略更新约束机制,平衡了更新幅度,提升了训练稳定性。其核心思想是在优势演员-评论家方法的基础上,采用裁剪和非裁剪项组成的替代目标函数,限制策略比率在[1-ϵ, 1+ϵ]区间内,防止过大的策略更新。本文详细探讨了PPO的基本原理、损失函数设计及PyTorch实现流程,提供了完整的代码示例。
107 10
近端策略优化(PPO)算法的理论基础与PyTorch代码详解
|
8天前
|
机器学习/深度学习 计算机视觉
RT-DETR改进策略【Neck】| ECCV-2024 RCM 矩形自校准模块 优化颈部网络
RT-DETR改进策略【Neck】| ECCV-2024 RCM 矩形自校准模块 优化颈部网络
34 10
RT-DETR改进策略【Neck】| ECCV-2024 RCM 矩形自校准模块 优化颈部网络
|
2月前
|
机器学习/深度学习 算法
基于改进遗传优化的BP神经网络金融序列预测算法matlab仿真
本项目基于改进遗传优化的BP神经网络进行金融序列预测,使用MATLAB2022A实现。通过对比BP神经网络、遗传优化BP神经网络及改进遗传优化BP神经网络,展示了三者的误差和预测曲线差异。核心程序结合遗传算法(GA)与BP神经网络,利用GA优化BP网络的初始权重和阈值,提高预测精度。GA通过选择、交叉、变异操作迭代优化,防止局部收敛,增强模型对金融市场复杂性和不确定性的适应能力。
207 80
|
3天前
|
传感器 算法 物联网
基于粒子群算法的网络最优节点部署优化matlab仿真
本项目基于粒子群优化(PSO)算法,实现WSN网络节点的最优部署,以最大化节点覆盖范围。使用MATLAB2022A进行开发与测试,展示了优化后的节点分布及其覆盖范围。核心代码通过定义目标函数和约束条件,利用PSO算法迭代搜索最佳节点位置,并绘制优化结果图。PSO算法灵感源于鸟群觅食行为,适用于连续和离散空间的优化问题,在通信网络、物联网等领域有广泛应用。该算法通过模拟粒子群体智慧,高效逼近最优解,提升网络性能。
|
3天前
|
机器学习/深度学习 数据采集 算法
基于GWO灰狼优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真
本项目基于MATLAB2022a,展示了时间序列预测算法的运行效果(无水印)。核心程序包含详细中文注释和操作视频。算法采用CNN-GRU-SAM网络,结合灰狼优化(GWO),通过卷积层提取局部特征、GRU处理长期依赖、自注意力机制捕捉全局特征,最终实现复杂非线性时间序列的高效预测。
|
1月前
|
机器学习/深度学习 数据采集 算法
基于GA遗传优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真
本项目基于MATLAB2022a实现时间序列预测,采用CNN-GRU-SAM网络结构。卷积层提取局部特征,GRU层处理长期依赖,自注意力机制捕捉全局特征。完整代码含中文注释和操作视频,运行效果无水印展示。算法通过数据归一化、种群初始化、适应度计算、个体更新等步骤优化网络参数,最终输出预测结果。适用于金融市场、气象预报等领域。
基于GA遗传优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真
|
2月前
|
机器学习/深度学习 人工智能 PyTorch
使用PyTorch实现GPT-2直接偏好优化训练:DPO方法改进及其与监督微调的效果对比
本文将系统阐述DPO的工作原理、实现机制,以及其与传统RLHF和SFT方法的本质区别。
103 22
使用PyTorch实现GPT-2直接偏好优化训练:DPO方法改进及其与监督微调的效果对比