基于pytorch实现AlexNet模型
前言
最近在看经典的卷积网络架构,打算自己尝试复现一下,在此系列文章中,会参考很多文章,有些已经忘记了出处,所以就不贴链接了,希望大家理解。
完整的代码在最后。
本系列必须的基础
python基础知识、CNN原理知识、pytorch基础知识
本系列的目的
一是帮助自己巩固知识点;
二是自己实现一次,可以发现很多之前的不足;
三是希望可以给大家一个参考。
目录结构
1. 说明:
之前写了篇文章,主要是为了梳理如何使用pytorch从头到尾实现LeNet5这个模型。这个模型非常简单,但是与大部分模型一样,实现起来流程都差不多,无非就是多了些东西或者数据不同。
而现在开始要实现经典的图像分类算法,这些算法本来都是基于ImageNet这个比赛而来的,所以涉及的数据集都很大,比如AlexNet在2012年出现,使用了双GPU的方法,也训练了3天。当然,到现在,肯定不需要这么久的时间了,因为GPU算力得到很大的提升。但是,对于我来说,还是要花不少时间,所以后面的文章,会首先给出模型的实现方法,具体的训练会到最后(指本系列差不多写完了),看有没有机会嫖到老师的服务器来跑,如果实在不行,就只有自己慢慢跑,但是最后还是会补充上去的。
ps:后面这段说明不会加上了
2. AlexNet模型介绍:
AlexNet在现在看来也不过如此,但是在当时却是轰动一时的存在,主要的原因是它终结了由人手工提取特征的时代,改为了由神经网络自动完成。
而,AlexNet的模型在原论文中为双GPU模型,这是受限于当时GPU太low的原因,现在实现都是单GPU了(指AlexNet),所以这里放的也是单GPU的AlexNet架构:
3. AlexNet模型构建:
代码参考于pytorch官方实现的版本
首先,导入需要的模块:
# 导入模块
import torch
from torch import nn
其次,把pytorch实现模型的基本结构写出来:
# 创建AlexNet模型
class My_AlexNet(nn.Module):
def __int__(self):
super(My_AlexNet, self).__int__()
# 准备定义模型
# 前向算法
def forward(self,x):
pass
然后,我们先来定义前面的特征提取层,即卷积–池化—卷积–池化…的层:
# 特征提取
self.features = nn.Sequential(
# 输入通道数为3,因为图片为彩色,三通道
# 而输出96、卷积核为11*11,步长为4,是由AlexNet模型决定的,后面的都同理
# conv1
nn.Conv2d(in_channels=3,out_channels=96,kernel_size=11,stride=4),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3,stride=2),
# conv2
nn.Conv2d(in_channels=96,out_channels=256,kernel_size=5,padding=2),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3,stride=2),
# conv3
nn.Conv2d(in_channels=256,out_channels=384,padding=1,kernel_size=3),
nn.ReLU(),
# conv4
nn.Conv2d(in_channels=384,out_channels=384,kernel_size=3,padding=1),
nn.ReLU(),
# conv5
nn.Conv2d(in_channels=384,out_channels=256,kernel_size=3,padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3,stride=2)
)
然后,我们来实现全连接的部分:
# 全连接层
self.classifier = nn.Sequential(
# 全连接的第一层,输入肯定是卷积输出的拉平值,即6*6*256
# 输出是由AlexNet决定的,为4096
nn.Linear(in_features=6*6*256,out_features=4096),
nn.ReLU(),
nn.Dropout(p=0.5),
nn.Linear(4096,4096),
nn.ReLU(),
# 最后一层,输出1000个类别,也是我们所说的softmax层
nn.Linear(4096,1000)
)
最后,我们定义我们的前向算法:
# 前向算法
def forward(self,x):
x = self.features(x)
# 不要忘记在卷积--全连接的过程中,需要将数据拉平,之所以从1开始拉平,是因为我们
# 批量训练,传入的x为[batch(每批的个数),x(长),x(宽),x(通道数)],因此拉平需要从第1(索引,相当于2)开始拉平
# 变为[batch,x*x*x]
x = torch.flatten(x,1)
result = self.classifier(x)
return result
4. 总结:
AlexNet构建起来很简单,只需要把握住输入、输出通道数和不要忘记卷积到全连接的时候把数据拉平即可。
另外,虽然我这里没有使用数据集来训练它,但是大家可以拓展。因为ImageNet的数据集是开源的,可以在网上下载到。另外,如果不会下载,可以使用上一篇文章中提及的MNIST数据集,不过对于一些地方需要稍微修改,这就看大家的了(后面有机会我也会尝试一下分享出来)。
完整代码
# author: baiCai
# 导入模块
import torch
from torch import nn
from torchvision.models import AlexNet
# 创建AlexNet模型
class My_AlexNet(nn.Module):
def __int__(self):
super(My_AlexNet, self).__int__()
# 特征提取
self.features = nn.Sequential(
# 输入通道数为3,因为图片为彩色,三通道
# 而输出96、卷积核为11*11,步长为4,是由AlexNet模型决定的,后面的都同理
nn.Conv2d(in_channels=3,out_channels=96,kernel_size=11,stride=4),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3,stride=2),
nn.Conv2d(in_channels=96,out_channels=256,kernel_size=5,padding=2),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3,stride=2),
nn.Conv2d(in_channels=256,out_channels=384,padding=1,kernel_size=3),
nn.ReLU(),
nn.Conv2d(in_channels=384,out_channels=384,kernel_size=3,padding=1),
nn.ReLU(),
nn.Conv2d(in_channels=384,out_channels=256,kernel_size=3,padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3,stride=2)
)
# 全连接层
self.classifier = nn.Sequential(
# 全连接的第一层,输入肯定是卷积输出的拉平值,即6*6*256
# 输出是由AlexNet决定的,为4096
nn.Linear(in_features=6*6*256,out_features=4096),
nn.ReLU(),
# AlexNet采取了DropOut进行正则,防止过拟合
nn.Dropout(p=0.5),
nn.Linear(4096,4096),
nn.ReLU(),
# 最后一层,输出1000个类别,也是我们所说的softmax层
nn.Linear(4096,1000)
)
# 前向算法
def forward(self,x):
x = self.features(x)
# 不要忘记在卷积--全连接的过程中,需要将数据拉平,之所以从1开始拉平,是因为我们
# 批量训练,传入的x为[batch(每批的个数),x(长),x(宽),x(通道数)],因此拉平需要从第1(索引,相当于2)开始拉平
# 变为[batch,x*x*x]
x = torch.flatten(x,1)
result = self.classifier(x)
return result