[关闭]
@Team 2018-09-17T15:56:59.000000Z 字数 6131 阅读 1635

《Computer vision》笔记-AlexNet(1)

石文华


AlexNet,是以论文的第一作者 Alex Krizhevsky 的名
字命名的,另外两位合著者是 ilya Sutskever 和 Geoffery Hinton。在2012年的ILSVRC比赛中,作者通过这个模型获得了冠军。如下图是这个卷积神经网络模型的网络架构
image.png-157.6kB
可以看到网络从输入到输出分别是输入层、Conv1层,MaxPool1层、Conv2层,MaxPool2层、Conv3层,Conv4层,Conv5层,MaxPool3层、FC6层、FC7层、FC8层和OutPut层。
(1)输入层:AlexNet 首先用一张 227×227×3 的图片作为输入,实际上原文中使用的图像是 224×224×3,但是如果你尝试去推导一下,你会发现 227×227 这个尺寸更好一些,这里使用输入数据是224*224*3的图像进行推导,即长宽都是224的图像,色彩通道是R、G、B三个。
(2)Conv1层:第一个卷积层、使用的卷积核大小为11*11*3,步长为4、Padding为2,最后输出的特征图为55*55*96,其中55=(224-11+4)/2+1,输出深度为96,是因为使用了96个卷积核进行卷积。最后得到特征图维度是55*55*96
(3)MaxPool1层:卷积之后使用最大池化,池化的滑动窗口是3*3*96,步长为2,池化之后输出的特征图的长宽是27,27=(55-3)/2+1,所以池化之后的特征图维度是27*27*96。
(4)Conv2层:使用卷积核大小为5*5*96,步长为1,Padding设置为same,这里为2,因为要确保输出长度为27,所以27=(27-5+2*a)/1+1,所以也可知Padding为2。这里使用了256个卷积核进行卷积,所以最后输出的特征图是27*27*256。
(5)MaxPool2层:滑动窗口大小为3*3*256,步长为2,得到的长宽为13,13=(27-3)/2+1,最后得到的特征图大小为13*13*256。
(6)Conv3层:卷积核大小为3*3*256,步长为1,Padding为1,得到特征图的长宽为13,13=(13-3+2)/1+1=13,使用384个卷积核进行卷积。得到输出为13*13*384。
(7)Conv4层:卷积核大小为3*3*384,步长为1,Padding为1,得到特征图的长宽为13,13=(13-3+2)/1+1=13,使用384个卷积核进行卷积。得到输出为13*13*384。
(8)Conv5层:卷积核大小为3*3*384,步长为1,Padding为1,得到特征图的长宽为13,13=(13-3+2)/1+1=13,使用256个卷积核进行卷积。得到输出为13*13*256。
(9)MaxPool3:滑动窗口大小为3*3*256,步长为2,得到的长宽为6,6=(13-3)/2+1,最后得到的特征图大小为6*6*256。
(10)FC6层:第一个全连接层,输入特征维度是6*6*256,首先先对输入的特征图进行扁平化处理,将维度变为1*9216的输入特征图,因为要求输出的数据维度为1*4096,所以需要一个9216*4096的矩阵完成输入数据和输出数据的全连接,最后得到输出数据的维度为1*4096。
(11)FC7层:输入数据维度是1*4096,输出特征要求为1*4096,所以需要4096*4096的矩阵完成输入数据和输出数据的全连接,随后得到输出数据的维度是1*4096。
(12)FC8层:输入数据维度是1*4096,输出特征要求为1*1000,所以需要4096*1000的矩阵完成输入数据和输出数据的全连接,随后得到输出数据的维度是1*1000。
(13)OutPut层:输出图像对应的1000个类别的可能性值,将FC7层的输出数据传递到Softma激活函数中,能够得到1000个全新的输出值,这1000个输出值就是模型预测的输入图像对应1000个类别的可能性。
AlexNet 网络结构看起来相对复杂,包含约 6000 万个参数, 这些数字(55×55×96、 27×27×96、
27×27×256……) 都是 Alex Krizhevsky 及其合著者不得不给出的,。
注:AlexNet网络卷积之后的激活函数是relu,每个全连接层后面加上Dropout层减少模型的过拟合问题。

  1. import torch
  2. import torch.nn as nn
  3. class AlexNet(nn.Module):
  4. def __init__(self, num_classes=10):
  5. super(AlexNet, self).__init__()
  6. self.features = nn.Sequential(
  7. nn.Conv2d(3, 96, kernel_size=11, stride=4, padding=0),
  8. nn.ReLU(inplace=True),
  9. nn.MaxPool2d(kernel_size=3, stride=2),
  10. nn.Conv2d(96, 256, kernel_size=5, padding=2, groups=2),
  11. nn.ReLU(inplace=True),
  12. nn.MaxPool2d(kernel_size=3, stride=2),
  13. nn.Conv2d(256, 384, kernel_size=3, padding=1),
  14. nn.ReLU(inplace=True),
  15. nn.Conv2d(384, 384, kernel_size=3, padding=1, groups=2),
  16. nn.ReLU(inplace=True),
  17. nn.Conv2d(384, 256, kernel_size=3, padding=1, groups=2),
  18. nn.ReLU(inplace=True),
  19. nn.MaxPool2d(kernel_size=3, stride=2),
  20. )
  21. self.classifier = nn.Sequential(
  22. nn.Linear(256 * 6 * 6, 4096),
  23. nn.ReLU(inplace=True),
  24. nn.Dropout(),
  25. nn.Linear(4096, 4096),
  26. nn.ReLU(inplace=True),
  27. nn.Dropout(),
  28. nn.Linear(4096, num_classes),
  29. )
  30. def forward(self, x):
  31. x = self.features(x)
  32. x = x.view(x.size(0), 256 * 6 * 6)
  33. x = self.classifier(x)
  34. return x
  35. alexnet=AlexNet()
  36. print(alexnet)

输出结果:

  1. AlexNet(
  2. (features): Sequential(
  3. (0): Conv2d(3, 96, kernel_size=(11, 11), stride=(4, 4))
  4. (1): ReLU(inplace)
  5. (2): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
  6. (3): Conv2d(96, 256, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=2)
  7. (4): ReLU(inplace)
  8. (5): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
  9. (6): Conv2d(256, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  10. (7): ReLU(inplace)
  11. (8): Conv2d(384, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=2)
  12. (9): ReLU(inplace)
  13. (10): Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=2)
  14. (11): ReLU(inplace)
  15. (12): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
  16. )
  17. (classifier): Sequential(
  18. (0): Linear(in_features=9216, out_features=4096, bias=True)
  19. (1): ReLU(inplace)
  20. (2): Dropout(p=0.5)
  21. (3): Linear(in_features=4096, out_features=4096, bias=True)
  22. (4): ReLU(inplace)
  23. (5): Dropout(p=0.5)
  24. (6): Linear(in_features=4096, out_features=10, bias=True)
  25. )
  26. )

加载数据:

  1. import torch
  2. from torchvision import datasets,transforms
  3. import os
  4. import matplotlib.pyplot as plt
  5. import time
  6. #transform = transforms.Compose是把一系列图片操作组合起来,比如减去像素均值等。
  7. #DataLoader读入的数据类型是PIL.Image
  8. #这里对图片不做任何处理,仅仅是把PIL.Image转换为torch.FloatTensor,从而可以被pytorch计算
  9. transform = transforms.Compose(
  10. [
  11. transforms.Scale([224,224]),
  12. transforms.ToTensor(),
  13. #transforms.Normalize(mean=[0.5,0.5,0.5],std=[0.5,0.5,0.5])
  14. ]
  15. )
  16. #训练集
  17. train_set = datasets.CIFAR10(root='drive/pytorch/Alexnet/', train=True, transform=transform, target_transform=None, download=True)
  18. #测试集
  19. test_set=datasets.CIFAR10(root='drive/pytorch/Alexnet/',train=False,download=True,transform=transform)
  20. trainloader=torch.utils.data.DataLoader(train_set,batch_size=32,shuffle=True,num_workers=0)
  21. testloader=torch.utils.data.DataLoader(test_set,batch_size=32,shuffle=True,num_workers=0)
  22. classes=('plane','car','bird','cat','deer','dog','frog','horse','ship','truck')
  23. (data,label)=train_set[64]
  24. print(classes[label])

查看数据:

  1. X_example,y_example=next(iter(trainloader))
  2. print(X_example.shape)
  3. img=X_example.permute(0, 2, 3, 1)
  4. print(img.shape)
  5. import torchvision
  6. img=torchvision.utils.make_grid(X_example)
  7. img=img.numpy().transpose([1,2,0])
  8. import matplotlib.pyplot as plt
  9. plt.imshow(img)
  10. plt.show()

image.png-197.1kB
训练模型:

  1. import torch.optim as optim #导入torch.potim模块
  2. import time
  3. from torch.autograd import Variable # 这一步还没有显式用到variable,但是现在写在这里也没问题,后面会用到
  4. import torch.nn as nn
  5. import torch.nn.functional as F
  6. criterion = nn.CrossEntropyLoss() #同样是用到了神经网络工具箱 nn 中的交叉熵损失函数
  7. optimizer = optim.Adam(alexnet.classifier.parameters(), lr=0.0001) #optim模块中的SGD梯度优化方式---随机梯度下降
  8. epoch_n=5
  9. for epoch in range(epoch_n):
  10. print("Epoch{}/{}".format(epoch,epoch_n-1))
  11. print("-"*10)
  12. running_loss = 0.0 #定义一个变量方便我们对loss进行输出
  13. running_corrects=0
  14. for i, data in enumerate(trainloader, 1): # 这里我们遇到了第一步中出现的trailoader,代码传入
  15. inputs, labels = data # data是从enumerate返回的data,包含数据和标签信息,分别赋值给inputs和labels
  16. #inputs=inputs.permute(0, 2, 3, 1)
  17. #print("hahah",len(labels))
  18. y_pred = alexnet(inputs) # 把数据输进网络net,这个net()在第二步的代码最后一行我们已经定义了
  19. _,pred=torch.max(y_pred.data,1)
  20. optimizer.zero_grad() # 要把梯度重新归零,因为反向传播过程中梯度会累加上一次循环的梯度
  21. loss = criterion(y_pred, labels) # 计算损失值,criterion我们在第三步里面定义了
  22. loss.backward() # loss进行反向传播,下文详解
  23. optimizer.step() # 当执行反向传播之后,把优化器的参数进行更新,以便进行下一轮
  24. # print statistics # 这几行代码不是必须的,为了打印出loss方便我们看而已,不影响训练过程
  25. running_loss += loss.item() # 从下面一行代码可以看出它是每循环0-1999共两千次才打印一次
  26. running_corrects+=torch.sum(pred==labels.data)
  27. if(i % 2 == 0): # print every 2000 mini-batches 所以每个2000次之类先用running_loss进行累加
  28. print("Batch{},Train Loss:{:.4f},Train ACC:{:.4f}".format(i,running_loss/i,100*running_corrects/(32*i)))

参考文献:
Andrew Ng 《Deep Learning》
唐进民 《深度学习之PyTorch实战计算机视觉》

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注