AlexNet是2012年ImageNet比赛的冠军model,以第一作者alex命名;(关于ImageNet:超过1400万的图像URL被ImageNet手动注释,以指示图片中的对象;在至少一百万个图像中,提供了边界框,ImageNet包含2万多个类别,ImageNet挑战使用了一个“修剪”的1000个非重叠类的列表【参考百度百科】)
AlexNet用于解决图像分类问题;
它证明了CNN在复杂模型下的有效性,使用GPU实现使得训练在可接受的时间内得到结果;
AlexNet模型结构图:
输入: 256 * 256的3通道(RGB)彩色图片;
使用随机位置采点的方法做数据增强,增强了图像的泛化能力;
AlexNet的创新点 / 特点:
- 卷积部分采用分组的方法(因当时GPU显卡还不够强大)分成上下两块进行计算;
分通道学习降低了卷积核学习维度(卷积核维度越高,学习难度越高); - AlexNet有一个特殊的计算层 —— LRN层(局部响应归一化),对输出结果做平滑处理(在某一层得到多个通道响应图后,对响应图的某一位置和相邻通道值做归一化处理);(后来在VGG中发现局部归一化处理并没有作用)
- AlexNet最后一个全连接层是上一个全连接层进行ReLU及dropout后,再进行全连接的结果;
- 使用softmax作为输出层的激活函数;
- 最后输出融合label和softmax loss;
注释:
dropout: 前向传播时,让某个神经元的激活值以一定的概率p停止工作(后层神经元只与前一层的部分神经元进行连接),通过阻止特征检测器的共同作用来提高神经网络的性能,防止过拟合;
AlexNet模型代码(pytorch):
模型部分:
import numpy as np
import torch
import torch.nn.functional as F
from torch.utils.data import Dataset, DataLoader
from torch import nn
from PIL import Image
from torch.autograd import Variable
from torchvision import transforms
# AlexNet模型
class AlexNet(nn.Module):
def __init__(self):
super(AlexNet, self).__init__()
self.layer1 = nn.Sequential(
nn.Conv2d(3, 96, 11, 4),
nn.ReLU(),
nn.MaxPool2d(3, 2)
)
self.layer2 = nn.Sequential(
nn.Conv2d(96, 256, 5, padding=2, groups=2),
nn.ReLU(),
nn.MaxPool2d(3, 2)
)
self.layer3 = nn.Sequential(
nn.Conv2d(256, 384, 3, padding=1),
nn.ReLU()
)
self.layer4 = nn.Sequential(
nn.Conv2d(384, 256, 3, padding=1),
nn.ReLU(),
)
self.layer5 = nn.Sequential(
nn.Conv2d(384, 256, 3, padding=1),
nn.ReLU(),
nn.MaxPool2d(3, 2)
)
self.layer6 = nn.Sequential(
nn.Linear(256 * 6 * 6, 4096),
nn.ReLU(),
nn.Dropout()
)
self.layer7 = nn.Sequential(
nn.Linear(4096, 4096),
nn.ReLU(),
nn.Dropout()
)
self.layer8 = nn.Linear(4096, 1000)
def forward(self, x):
x = self.layer5(self.layer4(self.layer3(self.layer2(self.layer1(x)))))
x = x.view(x.size(0), -1)
x = self.layere8(self.layer7(self.layer6(x)))
output = F.softmax(x, dim=1)
return output
超参数:
# 定义超参数
LR = 0.001
EPOCH = 20
BATCH_SIZE = 50
LOAD_DOWN = True
数据加载部分:
图片路径与标签信息已保存在txt文件中(路径与标签用空格分隔);
加载自己的数据集详解【点击此处】
# 数据预处理
def pre_loader(path):
im = Image.open(path).convert('RGB')
im = np.asarray(im.resize((227, 227)))
return im
class MyDataset(Dataset):
def __init__(self, txt, transform=None, target_transform=None, loader=pre_loader):
f = open(txt, 'r')
self.folder = txt.split('/')[-1].split('.')[0]
img = []
for line in f.readlines():
img_name = line.split()[0]
label = line.split()[1]
img.append((img_name, int(label)))
self.img = img
self.transform = transform
self.target_transform = target_transform
self.loader = loader
def __getitem__(self, index):
img_name, label = self.img[index]
img = self.loader('./data/' + self.folder + '/' + img_name)
if self.transform is not None:
img = self.transform(img)
return img, label
def __len__(self):
return len(self.img)
训练 & 测试部分:
# 模型加载
alexnet = AlexNet().cuda()
optimizer = torch.optim.Adam(alexnet.parameters(), lr=LR)
loss_func = nn.CrossEntropyLoss()
for epoch in range(EPOCH):
# 训练
for x, y in train_loader:
x, y = Variable(x).cuda(), Variable(y).cuda()
pred_out = alexnet(x)
loss = loss_func(pred_out, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 测试
alexnet.eval()
for b_x, b_y in test_loader:
b_x = Variable(b_x, volatile=True).cuda()
b_y = Variable(b_y, volatile=True).cuda()
output = torch.max(alexnet(b_x), 1)[1]
loss = loss_func(output, b_y)
accuracy = sum(output == b_y) / b_y.size
print('loss:', loss.data.numpy(), '| accuracy:', accuracy)
保存模型参数:
torch.save(alexnet.state_dict(), 'alexnet_parameters.pkl')
保存模型:
torch.save(alexnet, 'alexnet.pkl')
加载模型参数:
须先搭建一个相同的模型,再加载参数:
model.load_state_dict(torch.load('alexnet_parameters.pkl'))
加载模型:
model = torch.load('alexnet.pkl')