目录:
InceptionNet的核心组成——inception块
ResNet的核心组成——ResNet块
ResNet块和inception块对比
5种经典卷积神经网络小结
小结:神经网络搭建和CNN小结
1.InceptionNet——多路分支合并,同一层使用不同尺寸卷积核;引入BN
一.InceptionNet的亮点:
1.引入了BN操作,缓解梯度消失
2.同一层使用不同尺寸卷积核,形成四个分支,分支堆叠,提升模型感知力,使用了很多的1*1卷积核。(尺寸越小的卷积核,参数越少,计算量越小)
3. 上述所言构成了Inception块,是Inception的核心单元。
无论是GooLeNet,即Inception v1,还是Inception的后续版本,如v2,v3,v4,都是基于Inception结构块搭建的。二. Inception块:
Inception 结构块在同一层网络中使用了多个尺寸的卷积核,可以提取不同特征。
ps:
1*1卷积核:作用到输入特征的每一个像素点,通过设定少于输入特征图深度的1*1卷积核个数减少了输出特征图的深度,起到了降维作用,减少了参数量和计算量【尺寸越小的卷积核,参数越少,计算量越小】
InceptionNet:代码实现和实验结果见:
TF2.0-自作图+代码实现:LeNet,AlexNet,VggNet,Inception经典神经网络
2.ResNet ——层间残差跳连:使神经网络层数加深成为可能
前四种经典卷积神经网络模型的层数如下[只计算卷积层和全连接层]:
通过上一篇文章的实验结果对比,得出暂时性的结论:
5 → 8 →16/19 → 22:通过加深网络层数,取得了越来越好的效果
于是ResNet的大神作者:何凯明,其在cifar10上做了个实验,发现56层卷积网络的错误率要高于20层的错误率!
他认为,单纯靠卷积网络的堆叠,会造成神经网络的退化
以至于后面的特征丢失了前边特征的原本模样。
问题:神经网络的退化的原因就是随着网络的加深,特征就会被不断的CBAPD处理处理在处理,到了后边,原来特征本身就会被遗忘,那怎么解决这个问题?
何凯明提出了ResNet块:
这一操作有效缓解了神经网络模型堆叠导致的退化
使得神经网络可以向着更深层级发展
正如上图:我们看到x是输入特征图,经过了两层堆叠卷积层,得到非线性输出F(x),我们要解决的问题是我们 还想要把x输入特征图带进来,也要影响到我们的输出H(x) ,这样就能考虑到之前的原始特征了。 那要执行什么操作?+ 加操作。ResNet块中的‘+’:两路特征图对应元素值相加(相当于两个矩阵对应元素值相加) 有两种情况:取决于这个堆叠卷积层有没有对输入特征图x进行缩放 ①输出结果H(x) = 堆叠卷积层输出F(x)+x (堆叠层输出的F(x)维度和输入特征图维度x一样) ②输出结果H(x) = 堆叠卷积层输出F(x)+W(x) (堆叠层输出的F(x)维度和输入特征图维度x不一样 ) 基本组成有了,接下来使用ReNet块来搭建网络 ResNet: 和Inception的实现一样,基本模块被封装在一个class里 代码实现——ResNet块: 将这两种情况封装在一个class里# 将两种ResNet块封装在一起:ResnetBlock类# 每调用一次ResnetBlock类,生成一个ResNet块# 根据 区别两种情况:# ①如果是维度不同ResNet块: residual_path = 1,残差# 调用if里的代码,使用1*1的卷积操作,调整输入特征图inputs的尺寸或深度# 将堆叠卷积输出特征y和if语句算出的residual相加 过激活 输出# ②如果是维度相同的ResNet块:直接将堆叠卷积层输出特征y和输入特征图inputs相加 过激活 输出import tensorflow as tfimport osimport numpy as npfrom matplotlib import pyplot as pltfrom tensorflow.keras.layers import Conv2D, BatchNormalization, Activation, MaxPool2D, Dropout, Flatten, Densefrom tensorflow.keras import Modelimport osos.environ['CUDA_VISIBLE_DEVICES'] = '0'config = tf.compat.v1.ConfigProto(allow_soft_placement=True)config.gpu_options.allow_growth = Truesess =tf.compat.v1.Session(config=config)class ResnetBlock(Model): # 初始 residual_path 为False,默认满足情况② def __init__(self,filters,strides=1,residual_path=False): super(ResnetBlock,self).__init__() self.filters = filters self.strides = strides self.residual_path = residual_path #两层卷积,usebians带上b self.c1 = Conv2D(filters,(3,3),strides=strides,padding='same',use_bias=False) self.b1 = BatchNormalization() self.a1 = Activation('relu') self.c2 = Conv2D(filters,(3,3),strides =1,padding='same',use_bias=False) self.b2 = BatchNormalization() # residual_path 为True时,满足① #对输入进行向下采样:使用1*1的卷积操作,调整输入特征图inputs的尺寸或深度 if residual_path: self.down_c1 = Conv2D(filters,(1,1),strides = strides,padding='same',use_bias=False) self.down_b1 = BatchNormalization() # 激活 self.a2 = Activation('relu') def call(self,inputs): # residual等于输入值本身,即residual =x residual = inputs # 将输入通过卷积,BN,A,计算F(x) x = self.c1(inputs) x = self.b1(x) x = self.a1(x) x = self.c2(x) y = self.b2(x) if self.residual_path: residual = self.down_c1(inputs) residual = self.down_b1(residual) # 输出是两部分的和,即F(x)+x 或 F(x)+W(x),,再过激活函数 out = self.a2(y+ residual) return out
代码实现——ResNet网络:
class ResNet18(Model): # block_list 表示每层Block有几个卷积层 def __init__(self,block_list,initial_filters = 64): super(ResNet18,self).__init__() self.num_blocks = len(block_list) self.block_list = block_list self.out_filters = initial_filters # 第一层卷积 self.c1 = Conv2D(self.out_filters,(3,3),strides = 1,padding = 'same',use_bias=False) self.b1 = BatchNormalization() self.a1 = Activation('relu') # 第一个橙色块:两条实线【维度相同】 # 第二,第三,第四个橙色块:一条虚线+一条实线 # 构建ResNet块 self.blocks = tf.keras.models.Sequential() # 循环次数由 block_list个数决定 为[2,2,2,2] for block_id in range(len(block_list)):# 第几个restnet block for layer_id in range(block_list[block_id]):# 第几个卷积层 # block=生成一个橙色块 # 对除第一个block以外的每个block的输入进行下采样 if block_id != 0 and layer_id ==0: # residual 为T 虚线【维度不同,需处理】 block = ResnetBlock(self.out_filters,strides=2,residual_path =True) else: # residual 为T 虚线【维度不同,需处理】 block = ResnetBlock(self.out_filters,residual_path = False) self.blocks.add(block)# 构建好的block加入restnet self.out_filters *= 2 # 下一个block的卷积核是上一个block的2倍 self.p1 = tf.keras.layers.GlobalAveragePooling2D() self.f1 = tf.keras.layers.Dense(10,activation='softmax', kernel_regularizer=tf.keras.regularizers.l2()) def call(self,inputs): x = self.c1(inputs) x = self.b1(x) x = self.a1(x) x = self.blocks(x) x = self.p1(x) y = self.f1(x) return y
模型构成:
训练过程:
实验结果:
3.Inception和ResNet核心组成单元对比
实际上我们发现之前的三种网络是拿卷积层堆叠的,这个网络是拿ResNet块堆叠的,而ResNet块是拿卷积层堆叠加上残差跳连组成的,说起来差很多,但是好像也差不多。4.五种经典卷积神经网络小结
小结:
经典的5大卷积神经网络,是伴随一篇篇论文发展而来:卷积核共享,换激活函数,加上舍弃层,使用BN,使用小尺寸卷积核减少参数,自建模块实现想要的功能,提升感知力的每层使用不同尺寸卷积核,引入前方信息的残差跳连使得深度加深成为可能...
后来还有很多基于这些经典神经网络的升级版本,如GoogLeNet 就是基于Inception发展而来,也有很多更新奇的点子和有趣的设计,他们能达到更好的效果,为游戏设计的GPU发展更加迅猛,计算能力大幅提升,一起学习其他的CNN吧。
5.神经网络搭建和CNN的有关文章:
推荐按顺序阅读
1.神经网络搭建:告诉我们如何按套路搭建神经网络模型。
TF2.0-神经网络模型搭建6步法,Sequential顺序神经网络结构,Class类搭建带连跳网络结构【含实践】
2.神经网络搭建:教会我们如何完成神经网络搭建的信息存储,模型存储,和可视化,也都是直接套用和有规律的。
TF2.0-应用数据模型的6种办法【自制数据集,数据增强扩充数据集,存取模型,参数提取,acc/loss可视化,应用实例】
3.CNN:明确卷积神经网络就是用来提取特征的,CBAPD模式=特征提取器,根据前两篇文章教会我们的来搭建一个糟糕的Baseline。
TF-2.0 卷积CBAPD特征提取器+六步法【卷积+BN+激活+丢弃+池化】实现Baseline基准神经网络cifar10分类
4.经典CNN的实现:通过复现经典CNN来强化搭建神经网络模型的思路。
TF2.0-自作图+代码实现:LeNet,AlexNet,VggNet,Inception经典神经网络
5.本文
基本搭建神经网络和CNN部分至此
谢谢阅读!
(提取码:re9v)