深度卷积神经网络AlexNet
重要的计算例题:通道数为3,宽高均为224的输入,经过一层输出通道数为96,卷积核大小为11,步长为4,无padding的卷积层后,得到的feature map的宽高为:
(原始宽高 - kernel_size)/步长下取整 + 1
即 (224-11)/4下取整 +1 = 54
在特征提取方面,主要存在两种主流认知:
- 机器学习的特征提取:手工定义的特征提取函数
- 神经网络的特征提取:通过学习得到数据的多级表征,并逐级表⽰越来越抽象的概念或模式。
AlexNet
深度卷积神经网络AlexNet首次证明了学习到的特征可以超越⼿⼯设计的特征,从而⼀举打破计算机视觉研究的前状。
AlexNet(右)和LetNet的区别:
AlexNet主要的区别:
- 输出维度大,提取的特征多
- 用的最大池化,可以提取最重要的特征
- 卷积核更大
- 用的是ReLU函数作为激活函数,因为sigmoid函数在正饱和区和负饱和区导数都接近0,因此容易出现梯度消失的问题,而且ReLU函数导数是1,收敛快
- 用Dropout(丢弃法)来控制全连接层的模型复杂度。即让全连接层某些隐藏单元停止工作
AlexNet主要结构如图所示:包含了一共五个卷积层,三个最大池化层,和三个全连接层构成。第一个卷积层用的1111的卷积核,输出通道为96,步长为4。后面的层结构如图
输入宽和高:224
经过第一个卷积层图像大小的变化:(224-11)/4+1 = 54 (这里的除法下取整)
经过第一个池化层:(54-3)/2+1 = 26
经过第二个卷积层:(4+26-5)/1+1 = 26 (加4是因为两个维度各pad了2个单位)
经过第二个池化层:(26-3)/2+1 = 12
经过第三个卷积层:(2+12-3)/1+1 = 12
经过第四个卷积层:(2+12-3)/1+1 = 12
经过第五个卷积层:(2+12-3)/1+1 = 12
经过最后一个池化层:(12-3)/2+1 = 5
所以最后输出的图像为55的feature map
AlexNet的代码实现
import time
import torch
from torch import nn, optim
import torchvision
import numpy as np
import sys
sys.path.append("/home/kesci/input/")
import d2lzh1981 as d2l
import os
import torch.nn.functional as F
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
class AlexNet(nn.Module):
def __init__(self):
super(AlexNet, self).__init__()
self.conv = nn.Sequential(
nn.Conv2d(1, 96, 11, 4), # in_channels, out_channels, kernel_size, stride, padding
nn.ReLU(),
nn.MaxPool2d(3, 2), # kernel_size, stride
# 减小卷积窗口,使用填充为2来使得输入与输出的高和宽一致,且增大输出通道数
nn.Conv2d(96, 256, 5, 1, 2),
nn.ReLU(),
nn.MaxPool2d(3, 2),
# 连续3个卷积层,且使用更小的卷积窗口。除了最后的卷积层外,进一步增大了输出通道数。
# 前两个卷积层后不使用池化层来减小输入的高和宽
nn.Conv2d(256, 384, 3, 1, 1),
nn.ReLU(),
nn.Conv2d(384, 384, 3, 1, 1),
nn.ReLU(),
nn.Conv2d(384, 256, 3, 1, 1),
nn.ReLU(),
nn.MaxPool2d(3, 2)
)
# 这里全连接层的输出个数比LeNet中的大数倍。使用丢弃层来缓解过拟合
self.fc = nn.Sequential(
nn.Linear(256*5*5, 4096),
nn.ReLU(),
nn.Dropout(0.5),
#由于使用CPU镜像,精简网络,若为GPU镜像可添加该层
#nn.Linear(4096, 4096),
#nn.ReLU(),
#nn.Dropout(0.5),
# 输出层。由于这里使用Fashion-MNIST,所以用类别数为10,而非论文中的1000
nn.Linear(4096, 10),
)
def forward(self, img):
feature = self.conv(img)
output