查看原文
其他

《Computer vision》笔记-GoodLeNet(3)

石文华 机器学习算法工程师 2021-12-31

   作者: 石文华          

编辑: 龚   赛          

 

前  言

GoodLeNet在2014年举办的ILSVRC中获得了分类任务第一名,与同年在分类任务中获得亚军的VGGNet模型相比,它的深度更深,达到22层。该网络引入Inception模块,Inception的目的是设计一种具有优良局部拓扑结构的网络,即对输入图像并行地执行多个卷积运算或池化操作,并将所有输出结果拼接为一个非常深的特征图。因为 1*1、3*3 或 5*5 等不同的卷积运算与池化操作可以获得输入图像的不同信息,并行处理这些运算并结合所有结果将获得更好的图像表征。


01

Inception单元结构

最初开始设计的Inception 模块(Native Inception)。它使用 3 个不同大小的滤波器(1x1、3x3、5x5)对输入执行卷积操作,此外它还会执行最大池化。最后将所有子层的输出合并起来,作为输出的特征图。

假设输入是28*28*192的特征图
(1)使用64个1*1卷积核,输出结果会是28*28*64; 
(2)使用128个3*3的卷积核,为了使最后不同卷积核得到的特征图合并时维度匹配,padding为same,使得输出维度还是28*28,那么得到的特征图维度是28*28*128. 
(3)使用32个5*5的卷积核,padding为same,输出特征图为28*28*32. 
(4)使用maxpool,在最大池化之前,设置padding为same。步长为1,然后再进行最大池化,使得输出特征图维度为28*28*192,192个通道数太大,为了避免最后输出时,池化层占据大多数的通道。使用32个1*1的卷积压缩通道数,最后得到的特征图维度是28*28*32。将上述输出的特征图叠加在一起,那么最后得到特度特征图大小为28*28*(64+128+32+32),如下图所示:

上述的结构存在一个非常大的问题,就是计算成本特别的大,还是以28*28*192的输入特征图为例子,重点来看5*5的过滤器,由于输出特征图有192个通道,所以一个过滤器的参数为5*5*192。由于期望得到的输出特征图通道为32,长宽为28,所以需要计算28*28*32次。最后乘法运算的总次数为每个输出值所需要执行的乘法运算次数 (5×5×192)乘以输出值个数(28×28×32),把这些数相乘结果等于 1.2 亿(120422400) 。运算成本是非常高的。解决这个问题的方法就是先使用1*1卷积,压缩通道数,比如像将输入特征图的通道数压缩为16,然后在这个压缩之后的特征图上使用32个5*5的卷积核进行卷积。

计算量为(1*1*192*28*28*16)+(5*5*16*28*28*32)=2408448+10035200,约等于1204万,相比之前的1.2亿下降到了原来的十分之一。 
因此,Native Inception结构使用1*1的卷积之后变为(Inception V1):

利用实现降维的 Inception 模块可以构建 GoogLeNet(Inception v1),其架构如下图所示:

可以发现,网络中间有两个分支,它们是全连接层再加上softmax层,确保了即便是隐藏单元和中间层也参与了特征计算,也能预测图片的分类。它在Inception 网络中,起到一种调整的效果,并且能防止网络发生过拟合。假设这两个分支的损失值分别是aux_loss_1 ,aux_loss_2,论文中将它们的权重值设置为0.3,从而得到训练时的总损失计算:training.total_loss = real_loss + 0.3 * aux_loss_1 + 0.3 * aux_loss_2。


02

Inception V2 

将 5×5 的卷积分解为两个 3×3 的卷积运算以提升计算速度。因为一个 5×5 的卷积在计算成本上是一个 3×3 卷积的 2.78 倍。所以叠加两个 3×3 卷积实际上在性能上会有所提升,将 n*n 的卷积核尺寸分解为 1×n 和 n×1 两个卷积。例如,一个 3×3 的卷积等价于首先执行一个 1×3 的卷积再执行一个 3×1 的卷积。他们还发现这种方法在成本上要比单个 3×3 的卷积降低 33%。如下图所示:


03

Inception v3 

V3整合了前面v2 中提到的所有升级,还使用了RMSProp 优化器、Factorized 7x7 卷积、辅助分类器使用了 BatchNorm;标签平滑(添加到损失公式的一种正则化项,旨在阻止网络对某一类别过分自信,即阻止过拟合) 。

注:Inception v4和Inception -resnet可以阅读论文:https://arxiv.org/pdf/1602.07261.pdf 

代码:

1)加载数据

import torchfrom torchvision import datasets,transformsimport osimport matplotlib.pyplot as pltimport 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/inception/', train=True, transform=transform, target_transform=None, download=True)# 测试集test_set=datasets.CIFAR10(root='drive/pytorch/inception/',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])

直接使用Pytorch的models里面预训练好的模型,进行迁移学习,首先先下载模型,然后冻结所有的层,仅对后面全连接层参数进行调整以及后面的AuxLogits和Mixed_7c两个模块的参数更新策略设置为parma.requires_grad=True,允许更新参数,调整之后再进行迁移学习,代码如下:

from torchvision import models inceptionv3=models.inception_v3(pretrained=True)import torchimport torch.nn as nnfor parma in inceptionv3.parameters():    parma.requires_grad = Falseinceptionv3.fc=nn.Linear(in_features=2048, out_features=10, bias=True) inceptionv3.AuxLogits.fc=nn.Linear(in_features=768, out_features=10, bias=True)for parma in inceptionv3.AuxLogits.parameters():    parma.requires_grad=Truefor parma in inceptionv3.Mixed_7c.parameters():    parma.requires_grad=True

2)训练模型

import torch.optim as optim          #导入torch.potim模块import timefrom torch.autograd import Variable   # 这一步还没有显式用到variable,但是现在写在这里也没问题,后面会用到import torch.nn as nnimport torch.nn.functional as F optimizer=torch.optim.Adam(inceptionv3.parameters(),lr=0.0001) epoch_n=5for 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 = inceptionv3(inputs)                # 把数据输进网络net,这个net()在第二步的代码最后一行我们已经定义了    _,pred=torch.max(y_pred.data,1)    optimizer.zero_grad()                # 要把梯度重新归零,因为反向传播过程中梯度会累加上一次循环的梯度    loss = cost(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)))

参考文献: 
http://baijiahao.baidu.com/s?id=1601882944953788623&wfr=spider&for=pc 
Andrew Ng 《Deep Learning》 
https://blog.csdn.net/u014114990/article/details/52583912




 

END








往期回顾之作者石文华

【1】《Computer vision》笔记-VGGNet(2)

【2】《Computer vision》笔记-AlexNet(1)

【3】 干货|(DL~3)deep learning中一些层的介绍

【4】 干货|(DL~2)一看就懂的卷积神经网络

【5】 基础|认识机器学习中的逻辑回归、决策树、神经网络算法

【6】 (Keras/监督学习)15分钟搞定最新深度学习车牌OCR









机器学习算法工程师


                            一个用心的公众号

长按,识别,加关注

进群,学习,得帮助

你的关注,我们的热度,

我们一定给你学习最大的帮助





: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存