CV系列卷积神经网络典型应用—AlexNet
前言
AlexNet是一个卷积神经网络(CNN),由Alex Krizhevsky、Ilya Sutskever和Geoffrey Hinton在2012年的ImageNet比赛中获胜,成为深度学习历史上的一个里程碑。 AlexNet的成功打破了以前在图像识别任务中使用传统机器学习算法的记录,使得深度学习开始受到广泛关注。
AlexNet在当时使用了非常大的数据集,即ImageNet数据集,包括1000个类别、120万张高分辨率的图像。 在ImageNet比赛中,AlexNet模型在分类任务中获得了15.3%的误差率,远高于第二名的26.2%。 这表明了深度学习方法在计算机视觉领域的强大表现,并推动了深度学习技术在各个领域的广泛应用。
论文链接:
ImageNet Classification with Deep Convolutional Neural Networks
一、AlexNet简介
AlexNet模型由8个层次组成,其中5个卷积层和3个全连接层。 模型使用ReLU激活函数以及Dropout技术来减少过拟合,还使用了局部响应归一化(LRN)技术来增强模型的鲁棒性。
AlexNet作为深度学习的里程碑,具有以下几个优点:
-
较高的分类准确率:AlexNet模型在ImageNet数据集上取得了显著的成果,将误差率从以前的最佳结果26.2%降低到15.3%。
-
激活函数和Dropout技术:AlexNet引入了ReLU激活函数和Dropout技术来减少过拟合,这些技术后来成为深度学习中常用的技术。
-
局部响应归一化:AlexNet使用局部响应归一化(LRN)技术来增强模型的鲁棒性,这个技术被后来的模型放弃了,但对于AlexNet的成功起到了一定作用。
-
大规模数据集的使用:AlexNet使用了非常大的数据集,即ImageNet数据集,包括1000个类别、120万张高分辨率的图像。 这让AlexNet能够学习到更丰富的特征,并提高了模型的准确率。
二、AlexNet结构
它是一个卷积神经网络(Convolutional Neural Network, CNN),由5个卷积层(相邻的卷积层和池化层可以看作一层)和3个全连接层构成,总共有60 million个参数。
以下第1、2层可以看作一层,第3、4层可以看作一层,第7、8层可以看作一层
以下是AlexNet的具体结构:
第1层:卷积层(Convolutional Layer)。输入为224x224x3的图像,使用96个11x11x3的卷积核,步长为4,不使用padding。输出为55x55x96的特征图。
第2层:池化层(Pooling Layer)。使用3x3的max pooling,步长为2。输出为27x27x96的特征图。
第3层:卷积层(Convolutional Layer)。使用256个5x5x48的卷积核,步长为1,使用padding。输出为27x27x256的特征图。
第4层:池化层(Pooling Layer)。使用3x3的max pooling,步长为2。输出为13x13x256的特征图。
第5层:卷积层(Convolutional Layer)。使用384个3x3x256的卷积核,步长为1,使用padding。输出为13x13x384的特征图。
第6层:卷积层(Convolutional Layer)。使用384个3x3x192的卷积核,步长为1,使用padding。输出为13x13x384的特征图。
第7层:卷积层(Convolutional Layer)。使用256个3x3x192的卷积核,步长为1,使用padding。输出为13x13x256的特征图。
第8层:池化层(Pooling Layer)。使用3x3的max pooling,步长为2。输出为6x6x256的特征图。
第9层:全连接层(Fully Connected Layer)。4096个神经元。
第10层:全连接层(Fully Connected Layer)。4096个神经元。
第11层:全连接层(Fully Connected Layer)。1000个神经元,对应ImageNet数据集中的1000个类别。
需要注意:AlexNet使用两块GPU,单GPU无法训练太大的额数据集,因此使用两个并行GPU
三、AlexNet代码
以pytorch自带手写数据集为例
1.引入库
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
2.加载数据集
# 加载数据集并预处理
transform = transforms.Compose(
[transforms.Resize(256),
transforms.CenterCrop(227),
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))])
trainset = torchvision.datasets.MNIST(root='./data', train=True,
download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=32,
shuffle=True, num_workers=2)
testset = torchvision.datasets.MNIST(root='./data', train=False,
download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=32,
shuffle=False, num_workers=2)
2.定义AlexNet模型
# 定义 AlexNet 模型
class AlexNet(nn.Module):
def __init__(self, num_classes=10):
super(AlexNet, self).__init__()
self.features = nn.Sequential(
# 手写数据集是灰度图,只有一个通道,故nn.Conv2d的第一个参数为1
# 96是过滤器个数,也是卷积核输出特征图个数,也是下一层卷积的输入通道数,以下卷积层类似
nn.Conv2d(1, 96, kernel_size=11, stride=4, padding=2),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.Conv2d(96, 256, kernel_size=5, padding=2),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.Conv2d(256, 384, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(384, 384, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(384, 256, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
)
self.avgpool = nn.AdaptiveAvgPool2d((6, 6))
self.classifier = nn.Sequential(
nn.Dropout(),
nn.Linear(256 * 6 * 6, 4096),
nn.ReLU(inplace=True),
nn.Dropout(),
nn.Linear(4096, 4096),
nn.ReLU(inplace=True),
nn.Linear(4096, num_classes),
)
def forward(self, x):
x = self.features(x)
x = self.avgpool(x)
x = torch.flatten(x, 1)
x = self.classifier(x)
return x
3、实例化模型,定义优化器和损失函数
# 定义设备
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
net = AlexNet()
net.to(device)
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters(), lr=0.001)
3、训练模型
num_epochs = 10
for epoch in range(num_epochs):
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
inputs, labels = data
inputs, labels = inputs.to(device), labels.to(device)
# 梯度清零
optimizer.zero_grad()
# 前向传播、计算损失、反向传播和优化
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
# 统计损失
running_loss += loss.item()
if i % 2000 == 1999: # 每 2000 批次打印一次
print('[%d, %5d] loss: %.3f' %(epoch + 1, i + 1, running_loss / 2000))
running_loss = 0.0
print('Finished Training')
3、测试模型
correct = 0
total = 0
with torch.no_grad():
for data in testloader:
images, labels = data
images, labels = images.to(device), labels.to(device)
outputs = net(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct / total))