一、AlexNet概述
AlexNet由Hinton和他的学生Alex Krizhevsky设计,模型名字来源于论文第一作者的姓名Alex。该模型以很大的优势获得了2012年ISLVRC竞赛的冠军网络,分类准确率由传统的 70%+提升到 80%+,自那年之后,深度学习开始迅速发展。
ImageNet是一个在2009年创建的图像数据集,从2010年开始到2017年举办了七届的ImageNet 挑战赛——ImageNet Large Scale Visual Recognition ChallengeI (LSVRC),在这个挑战赛上诞生了AlexNet、ZFNet、OverFeat、VGG、Inception、ResNet、WideResNet、FractalNet、DenseNet、ResNeXt、DPN、SENet 等经典模型。
AlexNet现在的参考意义实际不大,毕竟当时的GPU发展不足以支撑深层CNN模型。原始的AlexNet需要多GPU运行,原文貌似分在两个GPU上运行,不过现在可以合在一个GPU上运行。
二、网络模型图
原文模型图
网络很简单,5层卷积+3层全连接层,下采样使用最大池化(原文采用3×3步幅为2的卷积)。
第一个卷积层过滤224×224×3(实测227×227更好)输入图像,96个大小为11×11×3的核,步幅为4像素(这是相邻的接受野中心之间的距离。第二个卷积层将第一个卷积层的输出(响应归一化和池化)作为输入,并使用256个大小为5 × 5 × 48的核对其进行过滤。
第三层、第四层和第五层卷积层相互连接,没有任何中间池化层或归一化层。第三个卷积层有384个大小为3 × 3 × 256的核,这些核连接到第二个卷积层的输出(归一化,池化)。第四个卷积层有384个大小为3 × 3 × 192的核,第五个卷积层有256个大小为3 × 3 × 192的核。完全连接的层每层有4096个神经元。
单GPU模型框架
将数据图片的大小resize到227×227的大小,然后按下面公式进行计算即可。
Pytorch网络结构
import torch
from torch import nn
class AlexNet(nn.Module):
def __init__(self, num_classes=1000):
super(AlexNet, self).__init__()
self.net = nn.Sequential(
# 为了和论文的图像输入尺寸保持一致以及下一层的55对应,这里对图像进行了padding
nn.Conv2d(in_channels=3, out_channels=96, kernel_size=11, stride=4, padding=2),
nn.ReLU(),
nn.LocalResponseNorm(size=5, alpha=10e-4, beta=0.75, k=2),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.Conv2d(in_channels=96, out_channels=256, kernel_size=5, padding=2),
nn.ReLU(),
nn.LocalResponseNorm(size=5, alpha=10e-4, beta=0.75, k=2),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.Conv2d(in_channels=256, out_channels=384, kernel_size=3, padding=1),
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),
nn.Flatten(),
nn.Dropout(p=0.5),
nn.Linear(in_features=256 * 6 * 6, out_features=4096),
nn.ReLU(),
nn.Dropout(p=0.5),
nn.Linear(in_features=4096, out_features=4096),
nn.ReLU(),
nn.Linear(in_features=4096, out_features=num_classes)
)
self.init_weights()
def init_weights(self):
for layer in self.net:
# 先一致初始化
if isinstance(layer, nn.Conv2d):
nn.init.kaiming_normal_(layer.weight, mode='fan_out', nonlinearity='relu')
# nn.init.normal_(layer.weight, mean=0, std=0.01) # 论文权重初始化策略
nn.init.constant_(layer.bias, 0)
elif isinstance(layer, nn.Linear):
nn.init.normal_(layer.weight, mean=0, std=0.01)
nn.init.constant_(layer.bias, 1)
# 单独对论文网络中的2、4、5卷积层的偏置进行初始化
nn.init.constant_(self.net[4].bias, 1)
nn.init.constant_(self.net[10].bias, 1)
nn.init.constant_(self.net[12].bias, 1)
def forward(self, x):
return self.net(x)
def test_output_shape(self):
test_img = torch.rand(size=(1, 3, 227, 227), dtype=torch.float32)
for layer in self.net:
test_img = layer(test_img)
print(layer.__class__.__name__, 'output shape: \t', test_img.shape)
# alexnet = AlexNet()
# alexnet.test_output_shape()