Pytorch 第七回:卷积神经网络——VGG模型

发布于:2025-03-03 ⋅ 阅读:(36) ⋅ 点赞:(0)

Pytorch 第七回:卷积神经网络——VGG模型

本次开启深度学习第七回,基于Pytorch的VGG卷积神经网络模型。在上回当中,大致讲解了AlexNet卷积神经网络的思路。但AlexNet卷积神经网络需要一层层去搭建,并没有给大家提供一个通用性的模板,因此这次给大家分享一个具有通用模板的经典卷积神经网络模型——VGG卷积神经网络模型。
本次学习,借助的平台是PyCharm 2024.1.3,python版本3.11 numpy版本是1.26.4,pytorch版本2.0.0+cu118


VGG神经网络模型

VGG神经网络模型作为经典的卷积网络模型,与AlexNet模型一样,VGG模型也在ImageNet大赛中取得过不错的战绩。与AlexNet模型相似的是,VGG模型也是采取卷积层与池化层进行叠加,最后全连接层进行收尾的方式进行搭建。不同的是,VGG采用的卷积核更小,都是3*3的卷积核;搭建的卷积层数更多,神经元数更多。AlexNe模型中,其有5个卷积层,3个全连接层,共8层;VGG模型主要有VGG-16~19等多个版本,其中VGG-11有8层卷积和3层全连接层,共11层。除此之外,在代码上,VGG采用VGG块,形式上如搭积木一样设计卷积层和池化层。这样就给大家提供了一个通用的代码搭建方式。

闲言少叙,直接上代码展示,先展示引用:

import numpy as np
import torch
from torch import nn
from torch.autograd import Variable
from torchvision.datasets import CIFAR10
import time
from torch.utils.data import DataLoader

一、数据准备

如第五回一样,准备CIFAR10数据集。(具体解释可以查看上一回)

def data_tf(x):
    x = np.array(x, dtype='float32') / 255
    x = (x - 0.5) / 0.5  #
    x = x.transpose((2, 0, 1))  #
    x = torch.from_numpy(x)
    return x
train_set = CIFAR10('./data', train=True, transform=data_tf)
train_data = DataLoader(train_set, batch_size=64, shuffle=True)   

二、模型准备

1.VGG 块定义

在定义VGG模型前,需要先定义VGG块。其作用为:输入卷积的层数、通道数,输出搭建好的卷积层和池化层。具体如下:

def vgg_stack(num_conv2d, channels):
    net_vgg = []
    for num, channel in zip(num_conv2d, channels):
        in_channel = channel[0]
        out_channel = channel[1]
        net_conv2d = [nn.Conv2d(in_channel, out_channel, kernel_size=3, padding=1),
                      nn.ReLU(True)]  # 定义第一层卷积
        for i in range(num - 1):  # 定义后续层卷积
            net_conv2d.append(nn.Conv2d(out_channel, out_channel, kernel_size=3, padding=1))
            net_conv2d.append(nn.ReLU(True))
        net_conv2d.append(nn.MaxPool2d(2, 2))  # 定义池化层
        net_vgg.append(nn.Sequential(*net_conv2d))
    return nn.Sequential(*net_vgg)

其中:nn.Conv2d用于定义卷积层,nn.ReLU(True)为激活函数(用于连接神经元,第四回已经解释),nn.MaxPool2d用于定义池化层。
展示一下如何应用:生成五个卷积块,共有七层,前三块分别有一个卷积层,后两块有两个卷积层(没有完全按照标准来,只是做了个大概)。如下所示:

Net_Vgg = vgg_stack((1, 1, 1, 2, 2),
                    ((3, 100), (100, 256), (256, 512), (512, 1024), (1024, 1024)))

VGG块输出展示:

Net_Vgg: Sequential(
  (0): Sequential(
    (0): Conv2d(3, 100, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU(inplace=True)
    (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (1): Sequential(
    (0): Conv2d(100, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU(inplace=True)
    (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (2): Sequential(
    (0): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU(inplace=True)
    (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (3): Sequential(
    (0): Conv2d(512, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU(inplace=True)
    (2): Conv2d(1024, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (3): ReLU(inplace=True)
    (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (4): Sequential(
    (0): Conv2d(1024, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU(inplace=True)
    (2): Conv2d(1024, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (3): ReLU(inplace=True)
    (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
)

2.VGG 模型定义

模型定义分为两部分:一个是模型的初始化函数,一个是前向传播函数。初始化函数包括两部分:一个部分由卷积层和池化层组成,用于特征提取;一个是全连接层,用于特征连接与分类。具体如下:

class vgg(nn.Module):
    def __init__(self):
        super(vgg, self).__init__()
        self.feature = Net_Vgg
        self.connect = nn.Sequential(
            nn.Linear(1024, 512),
            nn.ReLU(True),
            nn.Dropout(0.3),
            nn.Linear(512, 100),
            nn.ReLU(True),
            nn.Dropout(0.3),
            nn.Linear(100, 10)
        )

    def forward(self, x):
        x = self.feature(x)
        # 数据展开
        x = x.view(x.shape[0], -1)
        x = self.connect(x)
        return x

注:
nn.Dropout用于在训练过程中随机丢弃(置零)神经网络中的一部分神经元,从而避免过拟合,提高模型泛化能力。

3.损失函数和优化器定义

定义交叉熵损失函数,SGD优化器(用于计算梯度下降函数)。

optimizer = torch.optim.SGD(classify_VGGNet.parameters(), lr=1e-1)
Loss_f = nn.CrossEntropyLoss()

三、模型训练

1、实例化模型

前面我们已经定义好了模型,但是在使用时,我们需要进行实例化。具体如下:

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print("device=", device)
classify_VGGNet = vgg().to(device)

其中,由于需要使用GPU参与训练,因此需要检测是否存在GPU,并将数据转化为GPU类型(上回中提到)。

2、迭代训练

进行20次迭代训练,具体如下:

time1 = time.time()
for k in range(20):
    train_loss = 0
    train_acc = 0
    classify_VGGNet.train()  # 将模型设为测试模式
    for x_data, y_data in train_data:
        x_data = x_data.to(device)
        y_data = y_data.to(device)
        # 前向传播
        y_predict = classify_VGGNet(x_data)
        loss_train = Loss_f(y_predict, y_data).to(device)
        # 反向传播
        optimizer.zero_grad()  # 梯度清零
        loss_train.backward()  # 计算梯度
        optimizer.step()  # 使用优化器更新参数
        # 记录误差
        train_loss += loss_train
        # 计算分类的准确率
        _, pred = y_predict.max(1)
        train_correct = (pred == y_data).sum().item() / x_data.shape[0]
        train_acc += train_correct

    time_consume = time.time() - time1
    print('epoch:{},TrainLoss:{:.6f},TrainAcc:{:.6f},consume time:{:.3f}s'.format(k,
                                                                                  train_loss / len(train_data),
                                                                                  train_acc / len(train_data),
                                                                                  time_consume))
torch.save(classify_VGGNet.state_dict(), 'classify_VGGNet_params.pth')

3、输出展示

epoch:0,TrainLoss:2.303084,TrainAcc:0.099345,consume time:211.026s
epoch:4,TrainLoss:1.769737,TrainAcc:0.303868,consume time:1055.522s
epoch:8,TrainLoss:0.927300,TrainAcc:0.678129,consume time:1901.646s
epoch:12,TrainLoss:0.373853,TrainAcc:0.875160,consume time:2748.123s
epoch:16,TrainLoss:0.129802,TrainAcc:0.959159,consume time:3594.814s
epoch:19,TrainLoss:0.062160,TrainAcc:0.980659,consume time:4231.123s

对比上回训练的结果,可以看出VGG模型比Alexnet模型训练精度提高了很多,但是花费的训练时间更多(层数多了,神经元多了,自然训练时间多了)。
注:
训练思路展示完成,测试思路(代码)与第五回下半部分一样,有需要可以去查看。

总结

1、数据准备:准备CIFAR10数据集
2、模型准备:准备AGG块,AGG模型,交叉熵损失函数和优化器
3、数据训练:实例化训练模型,并进行20次数据训练。