《Computer vision》笔记-AlexNet(1)

版权声明:本文为博主原创文章,更多精彩文章请关注公众号【Jeemy110】 https://blog.csdn.net/l7H9JA4/article/details/82761287
作者:石文华
编辑:陈人和


前 言

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 这个尺寸更好一些,这里使用输入数据是2242243的图像进行推导,即长宽都是224的图像,色彩通道是R、G、B三个。
(2)Conv1层:第一个卷积层、使用的卷积核大小为11113,步长为4、Padding为2,最后输出的特征图为555596,其中55=(224-11+4)/2+1(如果求维度不能整除的时候,卷积向下取整,池化向上取整),输出深度为96,因为使用了96个卷积核进行卷积。最后得到特征图维度是555596
(3)MaxPool1层:卷积之后使用最大池化,池化的滑动窗口是3396,步长为2,池化之后输出的特征图的长宽是27,27=(55-3)/2+1,所以池化之后的特征图维度是272796。
(4)Conv2层:使用卷积核大小为5596,步长为1,Padding设置为same,这里为2,因为要确保输出长度为27,所以27=(27-5+2a)/1+1,所以也可知Padding为2。这里使用了256个卷积核进行卷积,所以最后输出的特征图是2727256。
(5)MaxPool2层:滑动窗口大小为3
3256,步长为2,得到的长宽为13,13=(27-3)/2+1,最后得到的特征图大小为1313256。
(6)Conv3层:卷积核大小为3
3256,步长为1,Padding为1,得到特征图的长宽为13,13=(13-3+2)/1+1=13,使用384个卷积核进行卷积。得到输出为1313384。
(7)Conv4层:卷积核大小为3
3384,步长为1,Padding为1,得到特征图的长宽为13,13=(13-3+2)/1+1=13,使用384个卷积核进行卷积。得到输出为1313384。
(8)Conv5层:卷积核大小为3
3384,步长为1,Padding为1,得到特征图的长宽为13,13=(13-3+2)/1+1=13,使用256个卷积核进行卷积。得到输出为1313256。
(9)MaxPool3:滑动窗口大小为3
3256,步长为2,得到的长宽为6,6=(13-3)/2+1,最后得到的特征图大小为66256。
(10)FC6层:第一个全连接层,输入特征维度是6
6256,首先先对输入的特征图进行扁平化处理,将维度变为19216的输入特征图,因为要求输出的数据维度为14096,所以需要一个92164096的矩阵完成输入数据和输出数据的全连接,最后得到输出数据的维度为14096。
(11)FC7层:输入数据维度是1
4096,输出特征要求为14096,所以需要40964096的矩阵完成输入数据和输出数据的全连接,随后得到输出数据的维度是14096。
(12)FC8层:输入数据维度是1
4096,输出特征要求为11000,所以需要40961000的矩阵完成输入数据和输出数据的全连接,随后得到输出数据的维度是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层减少模型的过拟合问题。

代码

import torch
import torch.nn as nn
class AlexNet(nn.Module):
    def __init__(self, num_classes=10):
        super(AlexNet, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 96, kernel_size=11, stride=4, padding=0),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.Conv2d(96, 256, kernel_size=5, padding=2, groups=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, groups=2),
            nn.ReLU(inplace=True),
            nn.Conv2d(384, 256, kernel_size=3, padding=1, groups=2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
        )
        self.classifier = nn.Sequential(
            nn.Linear(256 * 6 * 6, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(4096, num_classes),
        )

    def forward(self, x):
        x = self.features(x)
        x = x.view(x.size(0), 256 * 6 * 6)
        x = self.classifier(x)
        return x

alexnet=AlexNet()
print(alexnet)

输出结果:

AlexNet(
  (features): Sequential(
    (0): Conv2d(3, 96, kernel_size=(11, 11), stride=(4, 4))
    (1): ReLU(inplace)
    (2): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
    (3): Conv2d(96, 256, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=2)
    (4): ReLU(inplace)
    (5): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
    (6): Conv2d(256, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (7): ReLU(inplace)
    (8): Conv2d(384, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=2)
    (9): ReLU(inplace)
    (10): Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=2)
    (11): ReLU(inplace)
    (12): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (classifier): Sequential(
    (0): Linear(in_features=9216, out_features=4096, bias=True)
    (1): ReLU(inplace)
    (2): Dropout(p=0.5)
    (3): Linear(in_features=4096, out_features=4096, bias=True)
    (4): ReLU(inplace)
    (5): Dropout(p=0.5)
    (6): Linear(in_features=4096, out_features=10, bias=True)
  )
)

加载数据:

import torch 
from torchvision import datasets,transforms
import os
import matplotlib.pyplot as plt
import time
#transform = transforms.Compose是把一系列图片操作组合起来,比如减去像素均值等。
#DataLoader读入的数据类型是PIL.Image
#这里对图片不做任何处理,仅仅是把PIL.Image转换为torch.FloatTensor,从而可以被pytorch计算
transform = transforms.Compose(
    [
        transforms.Scale([224,224]),
        transforms.ToTensor(),
        #transforms.Normalize(mean=[0.5,0.5,0.5],std=[0.5,0.5,0.5])
    ]
)

#训练集
train_set = datasets.CIFAR10(root='drive/pytorch/Alexnet/', train=True, transform=transform, target_transform=None, download=True)
#测试集
test_set=datasets.CIFAR10(root='drive/pytorch/Alexnet/',train=False,download=True,transform=transform)

trainloader=torch.utils.data.DataLoader(train_set,batch_size=32,shuffle=True,num_workers=0)
testloader=torch.utils.data.DataLoader(test_set,batch_size=32,shuffle=True,num_workers=0)


classes=('plane','car','bird','cat','deer','dog','frog','horse','ship','truck')

(data,label)=train_set[64]
print(classes[label])

查看数据:

X_example,y_example=next(iter(trainloader))
print(X_example.shape)
img=X_example.permute(0, 2, 3, 1)
print(img.shape)
import torchvision
img=torchvision.utils.make_grid(X_example)
img=img.numpy().transpose([1,2,0])

import matplotlib.pyplot as plt

plt.imshow(img)
plt.show()

image.png-197.1kB
训练模型:

import torch.optim as optim          #导入torch.potim模块
import time
from torch.autograd import Variable   # 这一步还没有显式用到variable,但是现在写在这里也没问题,后面会用到
import torch.nn as nn
import torch.nn.functional as F

criterion = nn.CrossEntropyLoss()    #同样是用到了神经网络工具箱 nn 中的交叉熵损失函数
optimizer = optim.Adam(alexnet.classifier.parameters(), lr=0.0001)   #optim模块中的SGD梯度优化方式---随机梯度下降
epoch_n=5

for epoch in range(epoch_n):
  print("Epoch{}/{}".format(epoch,epoch_n-1))
  print("-"*10)
  running_loss = 0.0  #定义一个变量方便我们对loss进行输出
  running_corrects=0
  for i, data in enumerate(trainloader, 1): # 这里我们遇到了第一步中出现的trailoader,代码传入
    inputs, labels = data   # data是从enumerate返回的data,包含数据和标签信息,分别赋值给inputs和labels
    #inputs=inputs.permute(0, 2, 3, 1)

    #print("hahah",len(labels))
    y_pred = alexnet(inputs)                # 把数据输进网络net,这个net()在第二步的代码最后一行我们已经定义了
    _,pred=torch.max(y_pred.data,1)
    optimizer.zero_grad()                # 要把梯度重新归零,因为反向传播过程中梯度会累加上一次循环的梯度

    loss = criterion(y_pred, labels)    # 计算损失值,criterion我们在第三步里面定义了
    loss.backward()                      # loss进行反向传播,下文详解
    optimizer.step()                     # 当执行反向传播之后,把优化器的参数进行更新,以便进行下一轮
    # print statistics                   # 这几行代码不是必须的,为了打印出loss方便我们看而已,不影响训练过程
    running_loss += loss.item()       # 从下面一行代码可以看出它是每循环0-1999共两千次才打印一次
    running_corrects+=torch.sum(pred==labels.data)

    if(i % 2 == 0):    # print every 2000 mini-batches   所以每个2000次之类先用running_loss进行累加
      print("Batch{},Train Loss:{:.4f},Train ACC:{:.4f}".format(i,running_loss/i,100*running_corrects/(32*i)))

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值