【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%左右,有明显下降。分析原因:加入预处理可以使输入的数据处在一个更好的分布更有利于网络的训练,使得优化算法更容易找到最优解方向,收敛更快。

相关文章
|
24天前
|
机器学习/深度学习 PyTorch 算法框架/工具
PyTorch 中的动态计算图:实现灵活的神经网络架构
【8月更文第27天】PyTorch 是一款流行的深度学习框架,它以其灵活性和易用性而闻名。与 TensorFlow 等其他框架相比,PyTorch 最大的特点之一是支持动态计算图。这意味着开发者可以在运行时定义网络结构,这为构建复杂的模型提供了极大的便利。本文将深入探讨 PyTorch 中动态计算图的工作原理,并通过一些示例代码展示如何利用这一特性来构建灵活的神经网络架构。
47 1
|
1月前
|
机器学习/深度学习 人工智能 PyTorch
【深度学习】使用PyTorch构建神经网络:深度学习实战指南
PyTorch是一个开源的Python机器学习库,特别专注于深度学习领域。它由Facebook的AI研究团队开发并维护,因其灵活的架构、动态计算图以及在科研和工业界的广泛支持而受到青睐。PyTorch提供了强大的GPU加速能力,使得在处理大规模数据集和复杂模型时效率极高。
160 59
|
8天前
|
缓存 监控 网络协议
移动端常见白屏问题优化之网络优化篇
本文将要分享的是得物技术团队针对移动端最常见的图片加载导致的端侧白屏问题,而进行的的移动网络方向的技术优化实践,希望能带给你启发。
15 1
移动端常见白屏问题优化之网络优化篇
|
22天前
|
安全 网络安全 网络虚拟化
优化大型企业网络架构:从核心到边缘的全面升级
大型企业在业务运作中涉及多种数据传输,涵盖办公应用、CRM/ERP系统、数据中心、云环境、物联网及安全合规等多个方面。其复杂的业务生态和全球布局要求网络架构具备高效、安全和可靠的特性。网络设计需全面考虑核心层、汇聚层和接入层的功能与冗余,同时实现内外部的有效连接,包括广域网连接、远程访问策略、云计算集成及多层次安全防护,以构建高效且可扩展的网络生态系统。
优化大型企业网络架构:从核心到边缘的全面升级
|
7天前
|
机器学习/深度学习
小土堆-pytorch-神经网络-损失函数与反向传播_笔记
在使用损失函数时,关键在于匹配输入和输出形状。例如,在L1Loss中,输入形状中的N代表批量大小。以下是具体示例:对于相同形状的输入和目标张量,L1Loss默认计算差值并求平均;此外,均方误差(MSE)也是常用损失函数。实战中,损失函数用于计算模型输出与真实标签间的差距,并通过反向传播更新模型参数。
|
15天前
|
算法
基于GA遗传优化的离散交通网络双层规划模型设计matlab仿真
该程序基于GA遗传优化设计了离散交通网络的双层规划模型,以路段收费情况的优化为核心,并通过一氧化碳排放量评估环境影响。在MATLAB2022a版本中进行了验证,显示了系统总出行时间和区域排放最小化的过程。上层模型采用多目标优化策略,下层则确保总阻抗最小,实现整体最优解。
|
20天前
|
机器学习/深度学习 安全 算法
利用机器学习优化网络安全防御策略
【8月更文挑战第30天】在信息技术迅猛发展的今天,网络安全问题日益突显,传统的安全防御手段逐渐显得力不从心。本文提出一种基于机器学习的网络安全防御策略优化方法。首先,通过分析现有网络攻击模式和特征,构建适用于网络安全的机器学习模型;然后,利用该模型对网络流量进行实时监控和异常检测,从而有效识别潜在的安全威胁;最后,根据检测结果自动调整防御策略,以提升整体网络的安全性能。本研究的创新点在于将机器学习技术与网络安全防御相结合,实现了智能化、自动化的安全防御体系。
|
2天前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于PSO粒子群优化的GroupCNN分组卷积网络时间序列预测算法matlab仿真
本项目展示了一种结合粒子群优化(PSO)与分组卷积神经网络(GroupCNN)的时间序列预测算法。该算法通过PSO寻找最优网络结构和超参数,提高预测准确性与效率。软件基于MATLAB 2022a,提供完整代码及详细中文注释,并附带操作步骤视频。分组卷积有效降低了计算成本,而PSO则智能调整网络参数。此方法特别适用于金融市场预测和天气预报等场景。
|
24天前
|
机器学习/深度学习 数据采集 PyTorch
构建高效 PyTorch 模型:内存管理和优化技巧
【8月更文第27天】PyTorch 是一个强大的深度学习框架,被广泛用于构建复杂的神经网络模型。然而,在处理大规模数据集或使用高性能 GPU 进行训练时,有效的内存管理对于提升模型训练效率至关重要。本文将探讨如何在 PyTorch 中有效地管理内存,并提供一些优化技巧及代码示例。
38 1
|
28天前
|
监控 算法 网络协议
在Linux中,如何进行网络资源的优化?
在Linux中,如何进行网络资源的优化?