本篇文章采用百度paddlepaddle深度学习框架,并在百度Ai Studio平台上运行。

本篇文章基于PaddlePaddle2.0-构建卷积网络GoogLeNet,不了解2.0API的读者可以参考深度学习(paddle2.0 API)_无意2121的博客-CSDN博客

目录

1 GoogLeNet的介绍

1.1 GoogLeNet的简介

1.2 GoogLeNet 原始论文

1.2.1 论文标题的来源

1.2.2 GoogLeNet 提出的原因

2 GoogLeNet 创新点

2.1 inception(原生模块)的结构

​2.2 inception(原生模块)的优势

2.3 inception(具有降维功能)的结构

2.4 1*1卷积核的作用

2.5 GAP

2.6 两个辅助分类器

3 GoogLeNet的定义

3.1 GoogLeNet的总体架构

3.2 GoogLeNet的变种

3.3 GoogLeNet的完整代码定义

4 构建GoogLeNet做CIFAR图像识别


1 GoogLeNet的介绍

1.1 GoogLeNet的简介

GoogLeNet模型是由谷歌(Google)团队开发出来的卷积神经网络,它是2014年ImageNet挑战赛的冠军模型。相比于AlexNet模型,GoogLeNet模型的网络结构更深,共包括87层。尽管模型结构变得更复杂,但参数量更少了。GoogLeNet模型的参数量为5941552个,仅为AlexNet模型参数量的1/10。这主要归功于GoogLeNet创新性地采用了Inception模块。感兴趣的读者可以阅读原始顶会顶刊http://arxiv.org/abs/1409.4842。

1.2 GoogLeNet 原始论文

1.2.1 论文标题的来源

有趣的是原始论文的标题《Going deeper with convolutions》来自这个表情包

1.2.2 GoogLeNet 提出的原因

从 LeNet 开始,卷积神经网络通常有一个标准范式(结构) - 堆叠卷积层(后跟归一化和最大池化),然后跟一个或多个全连接层,这种模式及其优化后的模式确实在图像分类中取得较好的结果。

但为了获得更好的神经网络性能,这时候我们就需要扩大网络规模(增加网络层数及其宽度),但是更大的规模意味着更多的参数,容易出现过拟合,尤其是在训练集中标记示例的数量有限的情况下。增加网络规模的另一个缺点是计算资源的使用急剧增加

为了解决这两个问题,他们将原本密集连接的神经网络转向稀疏连接的神经网络。Aroar基于模仿生物系统的神经网络模型研究结论提出,一个基于稀疏结构的深度、宽度神经网络经过数据信息的输入后,末端神经节点中反映该数据信息特征的节点将总是处于激活状态。假如要识别一只猫,有些神经元是识别猫眼睛,有些是识别猫鼻子、猫尾巴等,如果图像真的是一只猫,这些特征会一起激活。虽然严格的数学证明需要很强的条件,但事实上这个陈述与赫布理论类似。这表明稀疏连接的神经网络具有一定科学性,但是,计算机软硬件对非均匀稀疏数据的计算效率很差

现在的问题是有没有一种方法,既能保持网络结构的稀疏性,又能利用密集矩阵的高计算性能。大量的文献表明可以将稀疏矩阵聚类为较为密集的子矩阵来提高计算性能,据此论文提出了名为inception的结构来实现此目的。

2 GoogLeNet 创新点

2.1 inception(原生模块)的结构

通过赫布理论与多尺度处理,论文提出了一种多通路 (inception) 的设计方案,即在网络同一层将不同尺寸的卷积核并联放置

(1) 将不同尺寸的卷积核放在同一层,意味着有不同大小的感受野,可以提取到不同特征,最后拼接特征,相当于对不同特征进行融合。

(2)之所以卷积核大小采用1、3、5,主要是为了输出维度一致。设定卷积核移动步长stride=1之后,只要分别设定padding=0、1、2,那么卷积之后便可以得到相同尺寸的特征,然后这些特征就可以直接聚合在一起了。

(3)论文表明pooling在实验中是有效的,所以Inception里面也有。
(4)网络越到后面,特征越抽象,而且每个特征所涉及的感受野也更大了,因此随着层数的增加,3x3和5x5卷积的比例也要增加。

2.2 inception(原生模块)的优势

多个尺寸上进行卷积再聚合的优势

  • 直观感觉上在多个尺度上同时进行卷积,能提取到不同尺度的特征。特征更为丰富也意味着最后分类判断时更加准确。
  • 利用稀疏矩阵分解成密集矩阵计算的原理可以加快收敛速度。用稀疏的分散的网络,对它们进行汇总,就可以取代一些庞大臃肿的网络。稀疏矩阵的分解示意图如下

这个原理在inception中就是在特征维度上进行分解

传统的卷积层的输入数据只与一种尺度(例如3*3)的卷积核进行卷积,输出固定维度(例如192个特征)的数据。而这192个特征是平均分布在3*3的尺度范围上的,这可以理解为输出了一个稀疏均匀分布的特征集。而在inception模块中在多个尺寸的卷积核下提取特征,输出的192个特征不是均匀分布的,而是相关性强的特征聚合在一起。比如3*3的96个特征聚合在一起,5*5的96个特征聚合在一起,这也可以理解为多个密集分布的子集合。由于相关性强的特征聚合在一起,同时相关性弱的特征就被弱化,因此冗余的数据比较少,也就是数据的有效性非常强,这能够加快收敛速度。

换句话说,即神经元同时激活的情况下,将联合评判做出结论!意味着神经元传递信息可能不是简单的复制逐层传递,而是并行的同时传递,这也反映着inception更逼近真实生物系统的神经网络。

2.3 inception(具有降维功能)的结构

简单的多通路拼接会造成通道数迅速增长,导致计算量和复杂度增高。在3*3与5*5的卷积核之前,先经过1*1的卷积核,这样的设置能够把通道数减少。在3*3的池化层之后,用1*1卷积核降维。

因此,我们可以看到具有降维功能的inception的最大创新之处是加入了1*1的卷积核。最终GooLeNet 用的inception 是改进后的具有降维功能的inception。代码如下

class Inception(paddle.nn.Layer):def __init__(self, in_channels, c1, c2, c3, c4):'''c1:第一条支路1x1卷积的输出通道数,数据类型是整数c2:第二条支路卷积的输出通道数,数据类型是tuple或list,  其中c2[0]是1x1卷积的输出通道数,c2[1]是3x3c3: 第三条支路卷积的输出通道数,数据类型是tuple或list,  其中c3[0]是1x1卷积的输出通道数,c3[1]是3x3c4:第四条支路1x1卷积的输出通道数,数据类型是整数'''super(Inception, self).__init__()#路线1,卷积核1x1self.route1x1_1 = paddle.nn.Conv2D(in_channels, c1, kernel_size=1)#路线2,卷积层1x1、卷积层3x3self.route1x1_2 = paddle.nn.Conv2D(in_channels, c2[0], kernel_size=1)self.route3x3_2 = paddle.nn.Conv2D(c2[0], c2[1], kernel_size=3, padding=1)#路线3,卷积层1x1、卷积层5x5self.route1x1_3 = paddle.nn.Conv2D(in_channels, c3[0], kernel_size=1)self.route5x5_3 = paddle.nn.Conv2D(c3[0], c3[1], kernel_size=5, padding=2)#路线4,池化层3x3、卷积层1x1self.route3x3_4 = paddle.nn.MaxPool2D(kernel_size=3, stride=1, padding=1)self.route1x1_4 = paddle.nn.Conv2D(in_channels, c4, kernel_size=1)def forward(self, x):route1 = F.relu(self.route1x1_1(x))route2 = F.relu(self.route3x3_2(F.relu(self.route1x1_2(x))))route3 = F.relu(self.route5x5_3(F.relu(self.route1x1_3(x))))route4 = F.relu(self.route1x1_4(self.route3x3_4(x)))out = [route1, route2, route3, route4]return paddle.concat(out, axis=1)  #在通道维度(axis=1)上进行连接def BasicConv2d(in_channels, out_channels, kernel, stride=1, padding=0):layer = paddle.nn.Sequential(paddle.nn.Conv2D(in_channels, out_channels, kernel, stride, padding), paddle.nn.BatchNorm2D(out_channels, epsilon=1e-3),paddle.nn.ReLU())return layer

2.4 1*1卷积核的作用

(1)1*1的卷积核相当于对所有特征进行一次相同权重的全连接的计算

(2)减少通道数,而不改变输出的宽度与高度,起到降维的作用,减少计算复杂度

(3)只要最后输出的特征数不变,中间的降维类似于压缩的效果,并不影响最终训练的结果

第一种没有1*1卷积核的参数量=256*3*3*256=589824

第二种有1*1卷积核的参数量=256*1*1*32+32*3*3*256=81920

可见大大减少参数量

2.5 GAP

无论是 AlexNet 还是 VGG,最后的卷积层和全连接层相连,参数量是巨大的(占网络参数量的 70-90% 左右)。GoogLeNet 采用了全局平均池化 Global Average Pooling 代替全连接

2.6 两个辅助分类器

通过添加连接到这些中间层的辅助分类器,作用是尽快学到可分类的特征,相当于是起到了一个正则化的作用,防止梯度消失。这些分类器采用较小卷积网络的形式,放置在Inception (原生模块) 和 Inception (具有降维功能)模块的输出之上。

3 GoogLeNet的定义

3.1 GoogLeNet的总体架构

拥有上述9个inception

局部响应归一化(Local Response Normalization,LRN)技术是首次在 AlexNet 模型中提出这个概念

3.2 GoogLeNet的变种

本篇文章主要讲解inception v1,改进的版本这里不再赘述

3.3 GoogLeNet的完整代码定义

#构建模型
class Inception(paddle.nn.Layer):def __init__(self, in_channels, c1, c2, c3, c4):'''c1:第一条支路1x1卷积的输出通道数,数据类型是整数c2:第二条支路卷积的输出通道数,数据类型是tuple或list,  其中c2[0]是1x1卷积的输出通道数,c2[1]是3x3c3: 第三条支路卷积的输出通道数,数据类型是tuple或list,  其中c3[0]是1x1卷积的输出通道数,c3[1]是3x3c4:第四条支路1x1卷积的输出通道数,数据类型是整数'''super(Inception, self).__init__()#路线1,卷积核1x1self.route1x1_1 = paddle.nn.Conv2D(in_channels, c1, kernel_size=1)#路线2,卷积层1x1、卷积层3x3self.route1x1_2 = paddle.nn.Conv2D(in_channels, c2[0], kernel_size=1)self.route3x3_2 = paddle.nn.Conv2D(c2[0], c2[1], kernel_size=3, padding=1)#路线3,卷积层1x1、卷积层5x5self.route1x1_3 = paddle.nn.Conv2D(in_channels, c3[0], kernel_size=1)self.route5x5_3 = paddle.nn.Conv2D(c3[0], c3[1], kernel_size=5, padding=2)#路线4,池化层3x3、卷积层1x1self.route3x3_4 = paddle.nn.MaxPool2D(kernel_size=3, stride=1, padding=1)self.route1x1_4 = paddle.nn.Conv2D(in_channels, c4, kernel_size=1)def forward(self, x):route1 = F.relu(self.route1x1_1(x))route2 = F.relu(self.route3x3_2(F.relu(self.route1x1_2(x))))route3 = F.relu(self.route5x5_3(F.relu(self.route1x1_3(x))))route4 = F.relu(self.route1x1_4(self.route3x3_4(x)))out = [route1, route2, route3, route4]return paddle.concat(out, axis=1)  #在通道维度(axis=1)上进行连接def BasicConv2d(in_channels, out_channels, kernel, stride=1, padding=0):layer = paddle.nn.Sequential(paddle.nn.Conv2D(in_channels, out_channels, kernel, stride, padding), paddle.nn.BatchNorm2D(out_channels, epsilon=1e-3),paddle.nn.ReLU())return layerclass GoogLeNet(paddle.nn.Layer):def __init__(self, in_channel, num_classes):super(GoogLeNet, self).__init__()self.b1 = paddle.nn.Sequential(BasicConv2d(in_channel, out_channels=64, kernel=7, stride=2, padding=3),paddle.nn.MaxPool2D(3, 2))self.b2 = paddle.nn.Sequential(BasicConv2d(64, 64, kernel=1),BasicConv2d(64, 192, kernel=3, padding=1),paddle.nn.MaxPool2D(3, 2))self.b3 = paddle.nn.Sequential(Inception(192, 64, (96, 128), (16, 32), 32),Inception(256, 128, (128, 192), (32, 96), 64),paddle.nn.MaxPool2D(3, 2))self.b4 = paddle.nn.Sequential(Inception(480, 192, (96, 208), (16, 48), 64),Inception(512, 160, (112, 224), (24, 64), 64),Inception(512, 128, (128, 256), (24, 64), 64),Inception(512, 112, (144, 288), (32, 64), 64),Inception(528, 256, (160, 320), (32, 128), 128),paddle.nn.MaxPool2D(3, 2))self.b5 = paddle.nn.Sequential(Inception(832, 256, (160, 320), (32, 128), 128),Inception(832, 384, (182, 384), (48, 128), 128),paddle.nn.AvgPool2D(2))self.flatten=paddle.nn.Flatten()self.b6 = paddle.nn.Linear(1024, num_classes)def forward(self, x):x = self.b1(x)x = self.b2(x)x = self.b3(x)x = self.b4(x)x = self.b5(x)x = self.flatten(x)x = self.b6(x)return x

4 构建GoogLeNet做CIFAR图像识别

自行调整超参数

import paddle
import paddle.nn.functional as F
import numpy as np
from paddle.vision.transforms import Compose, Resize, Transpose, Normalizet = Compose([Resize(size=96),Normalize(mean=[127.5, 127.5, 127.5], std=[127.5, 127.5, 127.5], data_format='HWC'),Transpose()]) #数据转换cifar10_train = paddle.vision.datasets.cifar.Cifar10(mode='train', transform=t, backend='cv2')
cifar10_test = paddle.vision.datasets.cifar.Cifar10(mode="test", transform=t, backend='cv2')#构建模型
class Inception(paddle.nn.Layer):def __init__(self, in_channels, c1, c2, c3, c4):'''c1:第一条支路1x1卷积的输出通道数,数据类型是整数c2:第二条支路卷积的输出通道数,数据类型是tuple或list,  其中c2[0]是1x1卷积的输出通道数,c2[1]是3x3c3: 第三条支路卷积的输出通道数,数据类型是tuple或list,  其中c3[0]是1x1卷积的输出通道数,c3[1]是3x3c4:第四条支路1x1卷积的输出通道数,数据类型是整数'''super(Inception, self).__init__()#路线1,卷积核1x1self.route1x1_1 = paddle.nn.Conv2D(in_channels, c1, kernel_size=1)#路线2,卷积层1x1、卷积层3x3self.route1x1_2 = paddle.nn.Conv2D(in_channels, c2[0], kernel_size=1)self.route3x3_2 = paddle.nn.Conv2D(c2[0], c2[1], kernel_size=3, padding=1)#路线3,卷积层1x1、卷积层5x5self.route1x1_3 = paddle.nn.Conv2D(in_channels, c3[0], kernel_size=1)self.route5x5_3 = paddle.nn.Conv2D(c3[0], c3[1], kernel_size=5, padding=2)#路线4,池化层3x3、卷积层1x1self.route3x3_4 = paddle.nn.MaxPool2D(kernel_size=3, stride=1, padding=1)self.route1x1_4 = paddle.nn.Conv2D(in_channels, c4, kernel_size=1)def forward(self, x):route1 = F.relu(self.route1x1_1(x))route2 = F.relu(self.route3x3_2(F.relu(self.route1x1_2(x))))route3 = F.relu(self.route5x5_3(F.relu(self.route1x1_3(x))))route4 = F.relu(self.route1x1_4(self.route3x3_4(x)))out = [route1, route2, route3, route4]return paddle.concat(out, axis=1)  #在通道维度(axis=1)上进行连接def BasicConv2d(in_channels, out_channels, kernel, stride=1, padding=0):layer = paddle.nn.Sequential(paddle.nn.Conv2D(in_channels, out_channels, kernel, stride, padding), paddle.nn.BatchNorm2D(out_channels, epsilon=1e-3),paddle.nn.ReLU())return layerclass GoogLeNet(paddle.nn.Layer):def __init__(self, in_channel, num_classes):super(GoogLeNet, self).__init__()self.b1 = paddle.nn.Sequential(BasicConv2d(in_channel, out_channels=64, kernel=7, stride=2, padding=3),paddle.nn.MaxPool2D(3, 2))self.b2 = paddle.nn.Sequential(BasicConv2d(64, 64, kernel=1),BasicConv2d(64, 192, kernel=3, padding=1),paddle.nn.MaxPool2D(3, 2))self.b3 = paddle.nn.Sequential(Inception(192, 64, (96, 128), (16, 32), 32),Inception(256, 128, (128, 192), (32, 96), 64),paddle.nn.MaxPool2D(3, 2))self.b4 = paddle.nn.Sequential(Inception(480, 192, (96, 208), (16, 48), 64),Inception(512, 160, (112, 224), (24, 64), 64),Inception(512, 128, (128, 256), (24, 64), 64),Inception(512, 112, (144, 288), (32, 64), 64),Inception(528, 256, (160, 320), (32, 128), 128),paddle.nn.MaxPool2D(3, 2))self.b5 = paddle.nn.Sequential(Inception(832, 256, (160, 320), (32, 128), 128),Inception(832, 384, (182, 384), (48, 128), 128),paddle.nn.AvgPool2D(2))self.flatten=paddle.nn.Flatten()self.b6 = paddle.nn.Linear(1024, num_classes)def forward(self, x):x = self.b1(x)x = self.b2(x)x = self.b3(x)x = self.b4(x)x = self.b5(x)x = self.flatten(x)x = self.b6(x)return xepoch_num = 20
batch_size = 256
learning_rate = 0.001val_acc_history = []
val_loss_history = []def train(model):#启动训练模式model.train()opt = paddle.optimizer.Adam(learning_rate=learning_rate, parameters=model.parameters())train_loader = paddle.io.DataLoader(cifar10_train, shuffle=True, batch_size=batch_size)valid_loader = paddle.io.DataLoader(cifar10_test, batch_size=batch_size)for epoch in range(epoch_num):for batch_id, data in enumerate(train_loader()):x_data = paddle.cast(data[0], 'float32')y_data = paddle.cast(data[1], 'int64')y_data = paddle.reshape(y_data, (-1, 1))y_predict = model(x_data)loss = F.cross_entropy(y_predict, y_data)loss.backward()opt.step()opt.clear_grad()print("训练轮次: {}; 损失: {}".format(epoch, loss.numpy()))#启动评估模式model.eval()accuracies = []losses = []for batch_id, data in enumerate(valid_loader()):x_data = paddle.cast(data[0], 'float32')y_data = paddle.cast(data[1], 'int64')y_data = paddle.reshape(y_data, (-1, 1))y_predict = model(x_data)loss = F.cross_entropy(y_predict, y_data)acc = paddle.metric.accuracy(y_predict, y_data)accuracies.append(np.mean(acc.numpy()))losses.append(np.mean(loss.numpy()))avg_acc, avg_loss = np.mean(accuracies), np.mean(losses)print("评估准确度为:{};损失为:{}".format(avg_acc, avg_loss))val_acc_history.append(avg_acc)val_loss_history.append(avg_loss)model.train()model = GoogLeNet(3, 10)
train(model)

深度学习(GoogLeNet)相关推荐

  1. 一网打尽深度学习之卷积神经网络的经典网络(LeNet-5、AlexNet、ZFNet、VGG-16、GoogLeNet、ResNet)

    看过的最全最通俗易懂的卷积神经网络的经典网络总结,在此分享,供更多人学习. 一.CNN卷积神经网络的经典网络综述 下面图片参照博客:http://blog.csdn.net/cyh_24/articl ...

  2. 深度学习——卷积神经网络 的经典网络(LeNet-5、AlexNet、ZFNet、VGG-16、GoogLeNet、ResNet)

    1. CNN卷积神经网络的经典网络综述 下面图片参照博客:http://blog.csdn.net/cyh_24/article/details/51440344 2. LeNet-5网络 输入尺寸: ...

  3. 深度学习之卷积神经网络 GoogleNet

    GoogLeNet Incepetion V1 这是GoogLeNet的最早版本,出现在2014年的<Going deeper with convolutions>.之所以名为" ...

  4. 【深度学习系列】用PaddlePaddle和Tensorflow实现GoogLeNet InceptionV2/V3/V4

    上一篇文章我们引出了GoogLeNet InceptionV1的网络结构,这篇文章中我们会详细讲到Inception V2/V3/V4的发展历程以及它们的网络结构和亮点. GoogLeNet Ince ...

  5. 动手深度学习笔记(四十)7.4. 含并行连结的网络(GoogLeNet)

    动手深度学习笔记(四十)7.4. 含并行连结的网络(GoogLeNet) 7.4. 含并行连结的网络(GoogLeNet) 7.4.1. Inception块 7.4.2. GoogLeNet模型 7 ...

  6. 【卷积神经网络CNN 实战案例 GoogleNet 实现手写数字识别 源码详解 深度学习 Pytorch笔记 B站刘二大人 (9.5/10)】

    卷积神经网络CNN 实战案例 GoogleNet 实现手写数字识别 源码详解 深度学习 Pytorch笔记 B站刘二大人 (9.5/10) 在上一章已经完成了卷积神经网络的结构分析,并通过各个模块理解 ...

  7. 深度学习入门(三十一)卷积神经网络——GoogLeNet

    深度学习入门(三十一)卷积神经网络--GoogLeNet 前言 卷积神经网络--GoogLeNet 课件 最好的卷积层超参数? Inception:全都要 Inception块 GoogLeNet 段 ...

  8. 《动手学深度学习》(四) -- LeNet、AlexNet、VGG、NiN、GoogLeNet、ResNet、DenseNet 实现

    上一小节学习了卷积神经网络的卷积层和池化层的实现,趁热打铁继续学习现代卷积神经网络的搭建,欢迎小伙伴们一起学习和交流~ 为了能够应⽤softmax回归和多层感知机,我们⾸先将每个⼤小为28×2828 ...

  9. 深度学习论文阅读(四):GoogLeNet《Going Deeper with Convolutions》

    深度学习论文阅读(四):GoogLeNet<Going Deeper with Convolutions> Abstract 摘要 1.Introduction 引言 2. Related ...

  10. MATLAB基于深度学习框架GoogLeNet的网络摄像机图像分类

    文章目录 1.GoogLeNet 2.开发环境及前期准备 2.1 安装附加工具 3.Deep Learning Toolbox 开发工具介绍 4.代码实战 1.GoogLeNet 2014年,Goog ...

最新文章

  1. 如何初始化静态地图?
  2. 网络爬虫中Fiddler抓取PC端网页数据包与手机端APP数据包
  3. 编译opencv文件
  4. 通信协议——HTTP、TCP、UDP
  5. 枚举编写单例是可以保证在多线程中的安全性
  6. WordPress我安装成功了,容易!
  7. Tableau数据可视化案例
  8. 【LDC1314】金属传感器(电感传感器)的调试技巧
  9. CDN 网站部署全站加速服务
  10. 计算机视觉开篇---读史可以明智
  11. 至将北漂或刚北漂的程序员
  12. 干货分享 | 最新机器学习视频教程与数据集下载(持续更新......)
  13. 广州红海云计算股份有限公司获全球软件最高级别CMMI5认证
  14. 我开发了一个机器人应用,让 HEXA 机器人可以追逐光——HEXA The Light Chaser
  15. 前端性能优化 —— 前端性能分析
  16. 免费、稳定的天气预报API
  17. 最大公约数的几种求解及代码实现
  18. mysql count join速度慢_MySql两张百万级表关联的count效率求解? 400 报错-问答-阿里云开发者社区-阿里云...
  19. 嗨CE系列教程全套(入门,进阶,高阶)游戏驱动反调试
  20. SDM原理解读与工程实践

热门文章

  1. Java语言中的接口与实现
  2. NG24折腾记 --- 记NG2升级NG4 RC1之修正问题跑起来
  3. 几种常见的JSON数据格式化
  4. 基于主动学习的高光谱图像分类方法研究
  5. Linux日志切割工具Logrotate
  6. Python中求集合交集的intersection()方法
  7. 开源项目::机器人自动驾驶(知名千star)
  8. android Imageview 随心所欲定制四个圆角
  9. C++文件操作——创建和删除文件夹
  10. ROS wiki系列|通过ROS wiki-tutorials学习话题