搭建VGG神经网络(基于pytorch)

前言

之前的几篇博客分享了关于搭建简单全连接神经网络的内容如何搭建神经网络--基于pytorch搭建全连接神经网络-CSDN博客 对于简单的数据集,全连接网络可以获得较好的结果,例如MNIST数据集;但是当数据集比较复杂的时候,全连接网络就不能够获得好的效果

今天我们就来介绍一个典型的深度神经网络VGG,可以比较好地处理较为复杂数据集的任务


VGG神经网络

VGG(Visual Geometry Group)网络是由牛津大学计算机视觉组VGG团队提出的一种深度卷积神经网络。它在2014年的ImageNet竞赛中取得了出色的成绩。

VGG网络的主要创新之处在于:通过重复小型卷积核(3x3)的卷积操作并增加网络深度,以提高模型的表达能力。VGG网络的设计简洁,整个网络都是由卷积层和全连接层两种结构组成。 主要有两种版本,即VGG16和VGG19。

  • VGG16: 该版本包含13个卷积层、3个全连接层和5个最大池化层。卷积层和全连接层都配有ReLU激活函数。
  • VGG19: 与VGG16相比,VGG19在表现上更优。它的结构基本一样,只是增加了3个卷积层,故卷积层总数为16个。

VGG网络的优点是模型结构简单清晰,完全采用3x3小型滤波器和2x2最大池化层,整个模型非常规整。但缺点则是模型参数量过大,密集连接层(即全连接层)占据了参数总量的大部分,导致需要消耗大量计算资源和存储空间。

训练数据集介绍

这里使用之前介绍过的CIFAR10数据集,相比于MNIST数据集,CIFAR数据集更加复杂,分类的种类更多,同时也是三通道的彩色图片,比较适合来体现深度网络的性能

关于CIFAR10数据集的介绍CIFAR-10数据集详解与可视化-CSDN博客

VGG神经网络搭建代码

cfg = {'VGG16':[64,64,'m',128,128,'m',256,256,256,'m',512,512,512,'m',512,512,512,'m'],
       'VGG19':[64,64,'m',128,128,'m',256,256,256,256,'m',512,512,512,512,'m',512,512,512,512,'m']
       }

class VGG(nn.Module):
    def __init__(self, cfg_name):
        super(VGG,self).__init__()
        self.features = self._make_layers(cfg[cfg_name])
        self.out = nn.Sequential(nn.Linear(512,10),nn.Softmax(dim=1)) # 如果是多分类就用softmax

    def forward(self,x):
        x = self.features(x)
        # print(x.shape)
        x = x.view(x.size(0),-1)
        x = self.out(x)
        return x
    
    def _make_layers(self,cfg_name):
        in_channels = 3
        layers = []
        for layer in cfg_name:
            if layer == "m":
                layers+=[nn.MaxPool2d(kernel_size=2,stride=2)]
            else:
                layers+=[nn.Conv2d(in_channels=in_channels,out_channels=layer,kernel_size=3,padding=1),
                               nn.BatchNorm2d(layer),
                               nn.ReLU(inplace=True)
                               ]
                in_channels = layer
        layers.append(nn.AvgPool2d(kernel_size=1,stride=1))
        return nn.Sequential(*layers)

在模型的搭建中,我们事先定义一个字典cfg对应不同种类的VGG网络,网络名称做主键对应的值为一个列表数据,表示各卷积层的参数或者池化层,‘m’表示进行窗口为2\times2,步长为2的最大池化,其他数字表示对应的卷积层的in_channels参数,卷积后对应进行归一化和进行激活函数输出,最后再用一个窗口1\times1、步长为1的平均池化层整合各个通道的数据

完成这些处理后再把数据输入全连接层进行分类输出

使用数据集进行模型训练

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import transforms, utils
from torch.utils.data import DataLoader
from torchvision.datasets import CIFAR10

import matplotlib.pyplot as plt


class_str = "airplane|automobile|bird|cat|deer|dog|frog|horse|ship|truck"
classes = class_str.split("|")

cfg = {'VGG16':[64,64,'m',128,128,'m',256,256,256,'m',512,512,512,'m',512,512,512,'m'],
       'VGG19':[64,64,'m',128,128,'m',256,256,256,256,'m',512,512,512,512,'m',512,512,512,512,'m']
       }

# 创建多进程时防止报错
if __name__=='__main__':

    my_trans = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
    
    # 这里的路径改为本地CIFAR10数据集保存得到路径
    train_dataset = CIFAR10('D:/deep_learning/12_16/data/', train=True, transform=my_trans, download=False)
    test_dataset = CIFAR10('D:/deep_learning/12_16/data/', train=False, transform=my_trans, download=False)

    train_boarder = DataLoader(train_dataset, batch_size=10, num_workers=5, shuffle=True)
    test_boarder = DataLoader(test_dataset, batch_size=10, num_workers=5)

    
    class VGG(nn.Module):
        def __init__(self, cfg_name):
            super(VGG,self).__init__()
            self.features = self._make_layers(cfg[cfg_name])
            self.out = nn.Sequential(nn.Linear(512,10),nn.Softmax(dim=1)) # 如果是多分类就用softmax

        def forward(self,x):
            x = self.features(x)
            # print(x.shape)
            x = x.view(x.size(0),-1)
            x = self.out(x)
            return x

        def _make_layers(self,cfg_name):
            in_channels = 3
            layers = []
            for layer in cfg_name:
                if layer == "m":
                    layers+=[nn.MaxPool2d(kernel_size=2,stride=2)]
                else:
                    layers+=[nn.Conv2d(in_channels=in_channels,out_channels=layer,kernel_size=3,padding=1),
                                   nn.BatchNorm2d(layer),
                                   nn.ReLU(inplace=True)
                                   ]
                    in_channels = layer
            layers.append(nn.AvgPool2d(kernel_size=1,stride=1))
            return nn.Sequential(*layers)


    # 模型送入GPU
    device = torch.device('cuda:0' if torch.cuda.is_available() else "cpu")
    print(device)
    model = VGG("VGG16")
    model.to(device)

    # 定义损失函数和优化器
    optimizer = optim.Adam(model.parameters(), lr=0.001)
    loss_funcation = nn.CrossEntropyLoss()

    # 模型训练 可以自己调整
    epoch_num = 25
    
    for epoch in range(epoch_num):
        train_loss = 0
        train_acc = 0
        model.train()
        for imgs, labels in train_boarder:
            imgs = imgs.to(device)
            labels = labels.to(device)

            out = model(imgs)
            loss = loss_funcation(out, labels)
            loss.backward()
            optimizer.step()
            
            optimizer.zero_grad()

            train_loss += loss.item()

            _,pred = out.max(1)
            correct_num = (pred == labels).sum().item()
            train_acc += correct_num/imgs.size(0)

        train_acc_all = train_acc/len(train_boarder)
        train_loss_all = train_loss/len(train_boarder)

        model.eval()
        test_loss = 0
        test_acc = 0
        for imgs, labels in test_boarder:
            imgs = imgs.to(device)
            labels = labels.to(device)

            out = model(imgs)
            loss = loss_funcation(out, labels)
            test_loss += loss.item()

            _,pred = out.max(1)
            correct_num = (pred == labels).sum().item()
            test_acc += correct_num/imgs.size(0)

        test_acc_all = test_acc/len(test_boarder)
        test_loss_all = test_loss/len(test_boarder)

        print('epoch:{}, Train Loss:{:.4f}, Train Acc:{:.4f}, Test Loss:{:.4f}, Test Acc:{:.4f}'.format(epoch, train_loss_all, \
        train_acc_all, test_loss_all, test_acc_all))

训练中使用的是VGG16版本的模型

注意代码中的数据集路径需要改为本地CIFAR10保存的路径;由于VGG是深层神经网络,训练的时间会比较长,迭代次数epoch_num设置为25,具体运行的时候大家可以把迭代次数设置得更大以获得更好的训练结果

欢迎大家讨论交流~


猜你喜欢

转载自blog.csdn.net/weixin_57506268/article/details/135219982