现代神经网络(VGG),并用VGG16进行实战CIFAR10分类
创始人
2024-05-29 09:33:09
0

专栏:神经网络复现目录


本章介绍的是现代神经网络的结构和复现,包括深度卷积神经网络(AlexNet),VGG,NiN,GoogleNet,残差网络(ResNet),稠密连接网络(DenseNet)。
文章部分文字和代码来自《动手学深度学习》

文章目录

  • 使用块的网络(VGG)
  • VGG块
    • 定义
    • 实现
  • VGG16
    • 模型设计
    • 实现
  • 利用VGG16进行CIFAR10分类
    • 数据集
    • 超参数,优化器,损失函数
    • 训练


使用块的网络(VGG)

VGG是一种深度卷积神经网络,由牛津大学视觉几何组(Visual Geometry Group)在2014年提出。它是由多个卷积层和池化层组成的深度神经网络,具有很强的图像分类能力,特别是在图像识别领域,取得了很好的成果。

VGG的特点在于,它使用相对较小的卷积核(3x3),但是通过叠加多个卷积层和池化层,增加了网络的深度,从而达到更好的图像分类性能。VGG网络包含了多个版本,以卷积层数目为标志,如VGG16和VGG19等,其中VGG16和VGG19是最著名的两个版本。

VGG网络的设计非常简单和规整,容易理解和实现,因此也成为了很多深度学习新手的入门模型。

下图为VGG的六个版本,比较实用的是VGG16和VGG19,本文以VGG16为例子进行讲解
在这里插入图片描述

VGG块

定义

VGG块是VGG网络中的一个基本组成单元,由若干个卷积层和池化层组成,通常用于提取输入图像的特征。每个VGG块都由连续的1或2个卷积层,和一个最大池化层组成。其中,卷积层的卷积核大小都是3x3,而池化层的窗口大小通常是2x2。在每个VGG块中,卷积层的输出通道数都相同,可以通过超参数进行控制。

具体来说,假设一个VGG块由k个卷积层和一个池化层组成,输入为xxx,则该块的输出可以表示为:

VGG(x)=Pool(convk(convk−1(⋯conv1(x)))).\text{VGG}(x) = \text{Pool}(\text{conv}k(\text{conv}{k-1}(\cdots\text{conv}_1(x)))).VGG(x)=Pool(convk(convk−1(⋯conv1​(x)))).

其中,convi(⋅)\text{conv}_i(\cdot)convi​(⋅)表示第iii个卷积层,Pool(⋅)\text{Pool}(\cdot)Pool(⋅)表示池化层。在VGG块中,每个卷积层都会使用ReLU激活函数进行非线性变换,而最大池化层则用于下采样和特征压缩。

在VGG网络中,通常通过叠加多个VGG块来构建网络结构。通过增加VGG块的数量,可以增加网络的深度和宽度,从而提高网络的表达能力和泛化性能。

实现

self.conv1=nn.Sequential(nn.Conv2d(in_channels=3,out_channels=64,kernel_size=3,padding=1,stride=1),nn.ReLU(inplace=True),nn.Conv2d(in_channels=64,out_channels=64,kernel_size=3,padding=1,stride=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2,stride=2),)

inplace=True 表示对于输入的张量进行原地操作,即直接对原始的输入张量进行修改,而不是创建一个新的张量。这样做可以节省内存,但会覆盖原始的输入张量,可能会对后续的计算产生影响。因此,当我们需要保留原始的输入张量时,可以将 inplace 参数设置为 False。

VGG16

模型设计

VGG16是一个卷积神经网络模型,包含13个卷积层、5个池化层和3个全连接层,是由牛津大学计算机视觉组(Visual Geometry Group)在2014年提出的模型,具有较好的图像识别表现。

VGG16模型的架构如下:

输入层:输入图像的大小为224x224x3。

VGG块1

卷积层1:使用64个3x3大小的卷积核进行卷积操作,得到64张大小为224x224的特征图。采用SAME填充,步长为1。然后再通过ReLU非线性激活函数进行激活。

卷积层2:使用64个3x3大小的卷积核进行卷积操作,得到64张大小为224x224的特征图。采用SAME填充,步长为1。然后再通过ReLU非线性激活函数进行激活。

池化层1:使用2x2的最大池化操作,将64张大小为224x224的特征图缩小为64张大小为112x112的特征图。采用SAME填充,步长为2。

VGG块2

卷积层3:使用128个3x3大小的卷积核进行卷积操作,得到128张大小为112x112的特征图。采用SAME填充,步长为1。然后再通过ReLU非线性激活函数进行激活。

卷积层4:使用128个3x3大小的卷积核进行卷积操作,得到128张大小为112x112的特征图。采用SAME填充,步长为1。然后再通过ReLU非线性激活函数进行激活。

池化层2:使用2x2的最大池化操作,将128张大小为112x112的特征图缩小为128张大小为56x56的特征图。采用SAME填充,步长为2。

VGG块3

卷积层5:使用256个3x3大小的卷积核进行卷积操作,得到256张大小为56x56的特征图。采用SAME填充,步长为1。然后再通过ReLU非线性激活函数进行激活。

卷积层6:使用256个3x3大小的卷积核进行卷积操作,得到256张大小为56x56的特征图。采用SAME填充,步长为1。然后再通过ReLU非线性激活函数进行激活。

卷积层7:使用256个3x3大小的卷积核进行卷积操作,得到256张大小为56x56的特征图。采用SAME填充,步长为1。然后再通过ReLU非线性激活函数进行激活。

池化层3:使用2x2的最大池化操作,将256张大小为56x56的特征图缩小为256张大小为28x28的特征图。采用SAME填充,步长为2。

VGG块4

卷积层8-10:使用512个3x3大小的卷积核进行卷积操作,得到512张大小为28x28的特征图。采用SAME填充,步长为1。然后再通过ReLU非线性激活函数进行激活。

池化层4:使用2x2的最大池化操作,将512张大小为28x28的特征图缩小为512张大小为14x14的特征图。采用SAME填充,步长为2。

VGG块5

卷积层11-13:使用512个3x3大小的卷积核进行卷积操作,得到512张大小为14x14的特征图。采用SAME填充,步长为1。然后再通过ReLU非线性激活函数进行激活。

池化层5:使用2x2的最大池化操作,将512张大小为14x14的特征图缩小为512张大小为7x7的特征图。采用SAME填充,步长为2。

全连接层

3个全连接层,第1、2个都有4096个输出通道,第3个全连接层则有1000个输出通道。

实现

class VGG16(nn.Module):def __init__(self):super(VGG16,self).__init__()self.conv1=nn.Sequential(nn.Conv2d(in_channels=3,out_channels=64,kernel_size=3,padding=1,stride=1),nn.ReLU(inplace=True),nn.Conv2d(in_channels=64,out_channels=64,kernel_size=3,padding=1,stride=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2,stride=2),)self.conv2=nn.Sequential(nn.Conv2d(in_channels=64,out_channels=128,kernel_size=3,padding=1,stride=1),nn.ReLU(inplace=True),nn.Conv2d(in_channels=128,out_channels=128,kernel_size=3,padding=1,stride=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2,stride=2),)self.conv3=nn.Sequential(nn.Conv2d(in_channels=128,out_channels=256,kernel_size=3,padding=1,stride=1),nn.ReLU(inplace=True),nn.Conv2d(in_channels=256,out_channels=256,kernel_size=3,padding=1,stride=1),nn.ReLU(inplace=True),nn.Conv2d(in_channels=256,out_channels=256,kernel_size=3,padding=1,stride=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2,stride=2),)self.conv4=nn.Sequential(nn.Conv2d(in_channels=256,out_channels=512,kernel_size=3,padding=1,stride=1),nn.ReLU(inplace=True),nn.Conv2d(in_channels=512,out_channels=512,kernel_size=3,padding=1,stride=1),nn.ReLU(inplace=True),nn.Conv2d(in_channels=512,out_channels=512,kernel_size=3,padding=1,stride=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2,stride=2),)self.conv5=nn.Sequential(nn.Conv2d(in_channels=512,out_channels=512,kernel_size=3,padding=1,stride=1),nn.ReLU(inplace=True),nn.Conv2d(in_channels=512,out_channels=512,kernel_size=3,padding=1,stride=1),nn.ReLU(inplace=True),nn.Conv2d(in_channels=512,out_channels=512,kernel_size=3,padding=1,stride=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2,stride=2),)self.feature=nn.Sequential(self.conv1,self.conv2,self.conv3,self.conv4,self.conv5,)self.flatten=nn.Flatten()self.fc=nn.Sequential(nn.Linear(512*7*7,4096),nn.ReLU(inplace=True),nn.Dropout(0.4),nn.Linear(4096,4096),nn.ReLU(inplace=True),nn.Dropout(0.4),nn.Linear(4096,1000),#nn.Softmax(10))def forward(self,x):x=self.feature(x)# x=self.flatten(x)x = x.view(x.size(0), -1)x=self.fc(x)return x

查看结构

vgg = VGG16()
print(vgg)
x=torch.rand(1,3,224,224)
y=vgg(x)
print(y.shape)

利用VGG16进行CIFAR10分类

import torch.nn as nn
import torch
import torchvisionif(torch.cuda.is_available()):device = torch.device("cuda")print("使用GPU训练中:{}".format(torch.cuda.get_device_name()))
else:device = torch.device("cpu")print("使用CPU训练")

数据集

# transform的创建(compose方法)
from torchvision import transforms
def get_dataloader_workers():  #@save"""使用4个进程来读取数据"""return 4def load_data_cifar10(batch_size, resize=None):  #@savetrans = [transforms.ToTensor()]if resize:trans.insert(0, transforms.Resize(resize))trans = transforms.Compose(trans)mnist_train = torchvision.datasets.CIFAR10(root="../data", train=True, transform=trans, download=True)mnist_test = torchvision.datasets.CIFAR10(root="../data", train=False, transform=trans, download=True)return (torch.utils.data.DataLoader(mnist_train, batch_size, shuffle=True,num_workers=get_dataloader_workers()),torch.utils.data.DataLoader(mnist_test, batch_size, shuffle=False,num_workers=get_dataloader_workers()))
batch_size=4
train_iter, test_iter = load_data_cifar10(batch_size,resize=224)

超参数,优化器,损失函数

from torch import optim
net=VGG16()
lr=0.001
optimizer=optim.SGD(net.parameters(),lr=lr,momentum=0.9)
loss=nn.CrossEntropyLoss()
epochs=10

训练

def train(net,train_iter,test_iter,num_epochs, lr, device):def init_weights(m):if type(m) == nn.Linear or type(m) == nn.Conv2d:nn.init.xavier_uniform_(m.weight)net.apply(init_weights)print('training on', device)net.to(device)for epoch in range(num_epochs):net.train()train_step = 0for i, (X, y) in enumerate(train_iter):optimizer.zero_grad()X, y = X.to(device), y.to(device)y_hat = net(X)l=loss(y_hat,y)l.backward()optimizer.step()train_step+=1if(train_step%50==0):#每训练一百组输出一次损失print("第{}轮的第{}次训练的loss:{}".format((epoch+1),train_step,l.item()))

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...