CNN基本步骤以及经典卷积(LeNet、AlexNet、VGGNet、InceptionNet 和 ResNet)网络讲解以及tensorflow代码实现

课程来源:人工智能实践:Tensorflow笔记2

文章目录

  • 前言
  • 1、卷积神经网络的基本步骤
    • 1、卷积神经网络计算convolution
    • 2、感受野以及卷积核的选取
    • 3、全零填充Padding
    • 4、tf描述卷积层
    • 5、批标准化(BN操作)
    • 6、池化Pooling
    • 7、舍弃Dropout
    • 8、卷积神经网络搭建以及参数分析
  • 2、经典卷积网络讲解
    • 1、LeNet
    • 2、AlexNet
    • 3、VGGNet
    • 4、InceptionNet
    • 5、ResNet
    • 6、经典卷积网络总结
  • 总结


前言

本讲目标:讲解卷积神经网络的基本步骤以及分析比较经典的网络架构,希望对你有所帮助
经典的5个论文的下载链接:
链接:https://pan.baidu.com/s/1rIH1nh28ON6DKM6T9HPXbQ
提取码:kbd8


1、卷积神经网络的基本步骤

1、卷积神经网络计算convolution

卷积概念:

卷积的概念:卷积可以认为是一种有效提取图像特征的方法。一般会用一个正方形的
卷积核,按指定步长,在输入特征图上滑动,遍历输入特征图中的每个像素点。每一个步长,
卷积核会与输入特征图出现重合区域,重合区域对应元素相乘、求和再加上偏置项得到输出
特征的一个像素点

卷积注意点:

输入特征图的深度,决定了卷积核的深度
当前层的卷积核个数,决定了当前层的输出特征图深度
如果觉得某一层的特征提取能力不足,可以在这一层多用几个卷积核
卷积:使用立体卷积核实现了参数的空间共享
执行卷积计算时,卷积核里的参数是固定的,反向传播时会更新参数

示例:
在这里插入图片描述

2、感受野以及卷积核的选取

这个之前有思考过,见下面链接:
为什么两层33卷积核效果比1层55卷积核效果要好?

3、全零填充Padding

在 Tensorflow 框架中,用参数 padding = ‘SAME’或 padding = ‘VALID’表示是否进行全
零填充,其对输出特征尺寸大小的影响如下:
在这里插入图片描述
对于 5×5×1 的图像来说,
当 padding = ‘SAME’时,输出图像边长为 5;当 padding = ‘VALID’时,输出图像边长为 3。

4、tf描述卷积层

tf.keras.layers.Conv2D(
filters=卷积核个数,
kernel_size=卷积核尺寸、#正方形写核长整数,或(核高h,核宽w)
strides=滑动步长,#横纵向相同写步长整数,或(纵向步长h,横向步长w),默认1
padding ="same" or "valid", #使用全零填充是"same",不使用是"valid"(默认)
activation ="relu" or "sigmoid" or"train" or"softmax",#如果有BN此处不填
input_shape =(高,宽,通道数) #输入特征维度,可省略) 

调用方法如下:
代码解释:

1、使用6个(5,5)的卷积核卷积,不全零填充,使用sigmoid作为激活函数
2、使用(2,2)的池化核,步长为2,选用最大池化
3、使用Flatten将输出拉直成一维数组
4、使用10个神经元构成的全连接,激活函数使用softmax

model=tf.keras.models.Sequential([Conv2D(6,5,padding='valid',activation='sigmoid'),MaxPool2D(2,2),#或者这样调用#Conv2D(6,(5,5),padding='valid',activation='sigmoid'),#MaxPool2D(2,(2,2),#也可以这样调用#Conv2D(filters=6,kenrnel_size=(5,5),padding='valid',activation='sigmoid'),#MaxPool2D(pool_size=(2,2),strides=2),Flatten(),Dense(10,activation='softmax')
])

在利用 Tensorflow 框架构建卷积网络时,一般会利用 BatchNormalization
函数来构建 BN 层,进行批归一化操作,所以在 Conv2D 函数中经常不写 BN

5、批标准化(BN操作)

神经网络对0附近的数据更敏感
但是随着网络层数的增加,特征数据会出现偏离0均值的情况
使用标准化,将偏移的数据重新拉回
批标准化:是对一个batch的数据做标准化处理,常用在卷积操作和激活操作之间

在这里插入图片描述
第K个,batch张输出特征图:
在这里插入图片描述

BN操作,将原本偏移的特征数据,重新拉回到0均值,使进入激活函数的数据分布在激活函数线性区,使得输入数据的微小变化,更明显地体现到输出上,提升了激活函数对输入数据的区分力。
在这里插入图片描述

但是这种简单的特征数据标准化,使特征数据完全满足标准正太分布,集中在激活函数的线性区域,使激活函数丧失了非线性性质,因此在BN操作中为每个卷积核引入两个可训练参数。
反向传播时,缩放因子和偏移因子会与其他待训练参数一同呗训练优化。使标准正太分布后的特征数据,通过缩放因子和偏移因子,优化了特征数据分布的宽窄和偏移量。保证了网络的非线性表达力。
在这里插入图片描述

BN层位于卷积层与激活层之间
tf提供了BN操作的函数BatchNormalization()

model=tf.keras.models.Sequential([Conv2D(filters=6,kernel_size=(5,5),padding='same'),#卷积层BatchNormalization(),							   #BN层Activation('relu'),								   #激活层MaxPool2D(pool_size=(2,2),strides=2,padding='same'),#池化层Dropout(0.2),										#dropout层
])

6、池化Pooling

池化用于减少特征数据量
最大值池化可以提取图片纹理,均值池化可以保留背景特征
如果用2 * 2的池化核对输入图片进行步长为2的池化操作,输出图片将变为输入图片的四分之一大小
tf描述池化操作:

tf.keras.layers.MaxPool2D(
pool_size=池化核尺寸,
strides=池化步长,
padding='valid'or'same'#same全零填充,valid不全零填充、
)
tf.keras.layers.AveragePooling2D(
pool_size=池化核尺寸,
strides=池化步长,
padding='valid'or'same'#same全零填充,valid不全零填充
)

调用例子:

model=tf.keras.models.Sequential([Conv2D(filters=6,kernel_size=(5,5),padding='same'),#卷积层BatchNormalization(),							   #BN层Activation('relu'),								   #激活层MaxPool2D(pool_size=(2,2),strides=2,padding='same'),#池化层Dropout(0.2),										#dropout层
])

7、舍弃Dropout

为了缓解神经网络过拟合,在神经网络训练中常常把隐藏层的部分神经元按照一定比例从神经网络中临时舍弃,
在使用神经网络时,再把所有神经元恢复到神经网络中。
在这里插入图片描述

Dropout函数:

tf.keras.layers.Dropout(舍弃的概率)

8、卷积神经网络搭建以及参数分析

卷积神经网络:借助卷积核提取特征后,送入全连接网络
卷积神经网络的主要模块:
卷积(conv)
批标准化(BN)
激活(Activation)
池化(Pooling)
卷积是什么:卷积就是特征提取器,就是CBAPD

在这里我们仍然套用网络八股的构架:

1、import引入tensorflow及keras、numpy等所需模块
2、读取数据集
3、搭建所需的网络结构,当网络结构比较简单时,可以利用keras模块中的tf.keras.Sequential来搭建顺序网络模型;但是当网络不再是简单的顺序结构,而是有其他特殊的结构出现(如ResNet中的跳连结构),急需要利用class来定义自己的网络结构
4、对搭建好的网络进行编译(compile),通常在这一步指定所采用的优化器(Adam、SGD、RMSdrop)以及损失函数(交叉熵函数、均方差函数等)
5、将数据输入编译好的网络来训练(model.fit),在这一步中指定训练轮数epochs以及batch_size等信息。由于参数量和计算量一般都比较大,训练所需的时间也会比较长,这一步中通常会加入断点续训以及模型参数保存
6、将神经网络模型具体信息打印出来(model.summary),包括网络结构、网络各层参数

这里还要讲一下flatten函数:

Flatten层用来将输入“压平”,即把多维的输入一维化,常用在从卷积层到全连接层的过渡。Flatten不影响batch的大小。

接下来我们使用类搭建5x5的卷积核,6个,池化核2x2,步长2的网络结构:

#使用类搭建网络结构,CBAPD
class Baseline(Model):def _init_(self):super(Baseline,self)._init_()self.c1 =Conv2D(filters=6,kernel_size=(5,5),padding='same')self.b1 =BatchNormalization()self.a1 =Activaction('relu')self.p1 =MaxPool2D(pool_size=(2,2),strides=2,padding ='same')self.d1 =Dropout(0.2)self.flatten =Flatten()self.f1 =Dense(128,activation='relu')self.d2 =Dropout(0.2)self.f2 =Dense(10,activation='softmax')
#call函数调用init函数中搭建好的每层网络结构
def call(self,x):x=self.c1(x)x=self.b1(x)x=self.a1(x)x=self.p1(x)x=self.d1(x)x=self.flatten(x)x=self.f1(x)x=self.d2(x)y=self.f2(x)return y
#从输入到输出过一次前向传播,返回推理结果

我们来分析一下参数:

打开weights文件:
baseline/conv2d/kernel:0
第一层网络 5x5x3的卷积核 一共6个
(5, 5, 3, 6)=>450
baseline/conv2d/bias:0
每个卷积核的偏置项b
(6,)=>6
baseline/batch_normalization/gamma:0
BN操作中的缩放因子γ,每个卷积核一个γ
(6,)=>6
baseline/batch_normalization/beta:0
BN操作中的偏移因子γ,每个卷积核一个γ
(6,)=>6
baseline/dense/kernel:0
第一层全连接网络
(1536, 128)=>196608
baseline/dense/bias:0
第一层全连接网络128个偏置b
(128,)=>128
baseline/dense_1/kernel:0
第二层全连接网络
(128, 10)=>1280
baseline/dense_1/bias:0
第二层全连接网络10个偏置b
(10,)=>10
总共:450+6+6+6+196608+128+1280+10=198494
有了这些参数就可以复现出神经网络的前向传播实现应用
可以发现,神经网络的网络参数十分多,多大十几万甚至更多(当网络复杂层数增加),并且可以发现绝大部分参数都集中在全连接层上,卷积层的参数占比较小。然而卷积核的参数却是非常重要的(因为卷积是特征提取器,特征的参数才是图片识别的重点)。所以减少全连接网络的参数或许会是一个不错的网络优化方法。

至此,基本的神经网络的搭建方法已经讲解完毕。接下来会逐一讲解LeNet、AlexNet、VGGNet、InceptionNet 和 ResNet的特点,并且用基于tensorflow的代码复现出网络架构。

2、经典卷积网络讲解

1、LeNet

网络结构:
在这里插入图片描述
tf复现模型:
这里对原模型进行调整,输入图片大小修改为32 * 32 * 3,用来适应数据集cifar10,并且将大的卷积核用小卷积核来替代
在这里插入图片描述

class LeNet5(Model):def __init__(self):super(LeNet5,self).__init__()self.c1=Conv2D(filters=6,kernel_size=(5,5),padding='valid',input_shape=(32,32,3),activation='sigmoid')self.p1=MaxPool2D(pool_size=(2,2),strides=2)self.c2=Conv2D(filters=16,kernel_size=(5,5),padding='valid',activation='sigmoid')self.p2=MaxPool2D(pool_size=(2,2),strides=2)self.flatten =Flatten()self.f1 =Dense(120,activation='sigmoid')self.f1 =Dense(84,activation='sigmoid')self.f1 =Dense(10,activation='softmax')def call(self, x):x = self.c1(x)x = self.p1(x)x = self.c2(x)x = self.p2(x)x = self.flatten(x)x = self.f1(x)x = self.f2(x)y = self.f3(x)return ymodel = LeNet5()		

优点:共享卷积核,减少网络参数.
如何理解卷积神经网络中的权值共享?

2、AlexNet

网络结构:
在这里插入图片描述
当时由于显存不足,训练分成两部分完成。这里对原模型进行调整,输入图片大小修改为32 * 32 * 3,用来适应数据集cifar10,并且将大的卷积核用小卷积核来替代。
在这里插入图片描述

class AlexNet8(Model):def __init__(self):super(AlexNet8,self).__init__()self.c1=Conv2D(filters=96,kernel_size=(3,3))self.b1=BatchNormalization()self.a1=Activation('relu')self.p1=MaxPool2D(pool_size=(3,3),strides=2)self.c2=Conv2D(filters=256,kernel_size=(3,3))self.b2=BatchNormalization()self.a2=Activation('relu')self.p2=MaxPool2D(pool_size=(3,3),strides=2)self.c3=Conv2D(filters=384,kernel_size=(3,3,padding='same',activation='relu')self.c4=Conv2D(filters=384,kernel_size=(3,3,padding='same',activation='relu')self.c5=Conv2D(filters=256,kernel_size=(3,3,padding='same',activation='relu')self.p3=MaxPool2D(pool_size=(3,3),strides=2)self.flatten =Flatten()self.f1 =Dense(2048,activation='relu')self.d1 =Dropout(0.5)self.f1 =Dense(2048,activation='relu')self.d1 =Dropout(0.5)self.f1 =Dense(10,activation='softmax')
def call(self, x):x = self.c1(x)x = self.b1(x)x = self.a1(x)x = self.p1(x)x = self.c2(x)x = self.b2(x)x = self.a2(x)x = self.p2(x)x = self.c3(x)x = self.c4(x)x = self.c5(x)x = self.p3(x)x = self.flatten(x)x = self.f1(x)x = self.d1(x)x = self.f2(x)x = self.d2(x)y = self.f3(x)return ymodel = AlexNet8()

优点:激活函数使用 Relu,提升训练速度;Dropout 防止过拟合

3、VGGNet

网络结构:
在这里插入图片描述
为适应 cifar10 数据集,将输入图像尺寸由 224 * 244 * 3 调整为 32 * 32 * 3
在这里插入图片描述

class VGG16(Model):def __init__(self):super(VGG16, self).__init__()self.c1 = Conv2D(filters=64, kernel_size=(3, 3), padding='same')  # 卷积层1self.b1 = BatchNormalization()  # BN层1self.a1 = Activation('relu')  # 激活层1self.c2 = Conv2D(filters=64, kernel_size=(3, 3), padding='same', )self.b2 = BatchNormalization()  # BN层1self.a2 = Activation('relu')  # 激活层1self.p1 = MaxPool2D(pool_size=(2, 2), strides=2, padding='same')self.d1 = Dropout(0.2)  # dropout层self.c3 = Conv2D(filters=128, kernel_size=(3, 3), padding='same')self.b3 = BatchNormalization()  # BN层1self.a3 = Activation('relu')  # 激活层1self.c4 = Conv2D(filters=128, kernel_size=(3, 3), padding='same')self.b4 = BatchNormalization()  # BN层1self.a4 = Activation('relu')  # 激活层1self.p2 = MaxPool2D(pool_size=(2, 2), strides=2, padding='same')self.d2 = Dropout(0.2)  # dropout层self.c5 = Conv2D(filters=256, kernel_size=(3, 3), padding='same')self.b5 = BatchNormalization()  # BN层1self.a5 = Activation('relu')  # 激活层1self.c6 = Conv2D(filters=256, kernel_size=(3, 3), padding='same')self.b6 = BatchNormalization()  # BN层1self.a6 = Activation('relu')  # 激活层1self.c7 = Conv2D(filters=256, kernel_size=(3, 3), padding='same')self.b7 = BatchNormalization()self.a7 = Activation('relu')self.p3 = MaxPool2D(pool_size=(2, 2), strides=2, padding='same')self.d3 = Dropout(0.2)self.c8 = Conv2D(filters=512, kernel_size=(3, 3), padding='same')self.b8 = BatchNormalization()  # BN层1self.a8 = Activation('relu')  # 激活层1self.c9 = Conv2D(filters=512, kernel_size=(3, 3), padding='same')self.b9 = BatchNormalization()  # BN层1self.a9 = Activation('relu')  # 激活层1self.c10 = Conv2D(filters=512, kernel_size=(3, 3), padding='same')self.b10 = BatchNormalization()self.a10 = Activation('relu')self.p4 = MaxPool2D(pool_size=(2, 2), strides=2, padding='same')self.d4 = Dropout(0.2)self.c11 = Conv2D(filters=512, kernel_size=(3, 3), padding='same')self.b11 = BatchNormalization()  # BN层1self.a11 = Activation('relu')  # 激活层1self.c12 = Conv2D(filters=512, kernel_size=(3, 3), padding='same')self.b12 = BatchNormalization()  # BN层1self.a12 = Activation('relu')  # 激活层1self.c13 = Conv2D(filters=512, kernel_size=(3, 3), padding='same')self.b13 = BatchNormalization()self.a13 = Activation('relu')self.p5 = MaxPool2D(pool_size=(2, 2), strides=2, padding='same')self.d5 = Dropout(0.2)self.flatten = Flatten()self.f1 = Dense(512, activation='relu')self.d6 = Dropout(0.2)self.f2 = Dense(512, activation='relu')self.d7 = Dropout(0.2)self.f3 = Dense(10, activation='softmax')def call(self, x):x = self.c1(x)x = self.b1(x)x = self.a1(x)x = self.c2(x)x = self.b2(x)x = self.a2(x)x = self.p1(x)x = self.d1(x)x = self.c3(x)x = self.b3(x)x = self.a3(x)x = self.c4(x)x = self.b4(x)x = self.a4(x)x = self.p2(x)x = self.d2(x)x = self.c5(x)x = self.b5(x)x = self.a5(x)x = self.c6(x)x = self.b6(x)x = self.a6(x)x = self.c7(x)x = self.b7(x)x = self.a7(x)x = self.p3(x)x = self.d3(x)x = self.c8(x)x = self.b8(x)x = self.a8(x)x = self.c9(x)x = self.b9(x)x = self.a9(x)x = self.c10(x)x = self.b10(x)x = self.a10(x)x = self.p4(x)x = self.d4(x)x = self.c11(x)x = self.b11(x)x = self.a11(x)x = self.c12(x)x = self.b12(x)x = self.a12(x)x = self.c13(x)x = self.b13(x)x = self.a13(x)x = self.p5(x)x = self.d5(x)x = self.flatten(x)x = self.f1(x)x = self.d6(x)x = self.f2(x)x = self.d7(x)y = self.f3(x)return ymodel = VGG16()

总体来看,VGGNet的结构是相当规整的,它继承了 AlexNet中的Relu激活函数、Dropout操作等有效的方法,同时采用了单一尺寸的 3 * 3 小卷积核,形成了规整的 C(Convolution,卷积)、B(Batch normalization)、A(Activation,激活)、P(Pooling,池化)、D(Dropout)结构,这一典型结构在卷积神经网络中的应用是非常广的
优点:小卷积核减少参数的同时,提高识别准确率;网络结构规整,适合并行加速。

4、InceptionNet

优点:一层内使用不同尺寸的卷积核,提升感知力(通过 padding 实现输出特征面积一致);使用 1 * 1 卷积核,改变输出特征 channel 数(减少网络参数)。
基本单元:
在这里插入图片描述

class ConvBNRelu(Model):def __init__(self,ch,kernelsz=3,strides=1,padding='same'):super(ConvBNRelu,self).__init__()self.model=tf.keras.models.Sequential([Conv2D(ch,kernelsz,strides=strides,padding=padding),BatchNormalization(),Activation('relu')])def call(self,x,training=None):x=self.model(x,training=training)return x
#ch 特征图的通道数,即卷积核个数
class InceptionBlk(Model)def __init__(self,ch,strides=1):super(InceptionBlk,self).__init__()self.ch=chself.strides=stridesself.c1=ConvBNRelu(ch,kernelsz=1,strides=strides)self.c2_1=ConvBNRelu(ch,kernelsz=1,strides=strides)self.c2_2=ConvBNRelu(ch,kernelsz=3,strides=1)self.c3_1=ConvBNRelu(ch,kernelsz=1,strides=strides)self.c3_2=ConvBNRelu(ch,kernelsz=5,strides=1)self.p4_1=MaxPool2D(3,strides=1,padding='same')self.c4_2=ConvBNRelu(ch,kernelsz=1,strides=strides)def call(self,x):x1=self.c1(x)x2_1=self.c2_1(x)x2_2=self.c2_2(x2_1)x3_1=self.c3_1(x)x3_2=self.c3_2(c3_1)x4_1=self.p4_1(x)x4_2=self.c4_2(x4_1)#concat along axis=channelx=tf.concat([x1,x2_2,x3_2,x4_2],axis=3)return x

其实基本单元一开始是长这样的,通过不同尺寸的卷积层和池化层的横向组合(卷积和池化后的尺寸相同,便于叠加)来拓宽网络深度,增强网络对尺寸的适应性。但由于卷积核都是在上一层的输出上直接计算的,导致参数变多以及运算变得复杂,所以加入1 * 1卷积核,减少特征厚度。
以5 * 5的卷积运算为例说明这个
问题。假设网络上一层的输出为 100 * 100 * 128(H * W * C),通过 32 * 5 * 5(32 个大小
为 5 * 5 的卷积核)的卷积层(步长为 1、全零填充)后,输出为 100 * 100 * 32,卷积层的
参数量为 32 * 5 * 5 * 128 = 102400;如果先通过 32 * 1 * 1 的卷积层(输出为 100 * 100 * 32),
再通过 32 * 5 * 5 的卷积层,输出仍为 100 * 100 * 32,但卷积层的参数量变为 32 * 1 * 1 * 128

  • 32 * 5 * 5 * 32 = 29696,仅为原参数量的 30 %左右,这就是小卷积核的降维作用。
    在这里插入图片描述
    由基本模块组成网络构架如下:
    在这里插入图片描述
    代码描述:
class Inception10(Model):def __init__(self,num_blocks,num_classes,init_ch=16,**kwargs):super(Inception10,self).__init__(**kwargs)self.in_channels=init_chself.out_channels=init_chself.num_blocks=num_blocksself.init_ch=init_chself.c1=ConvBNRelu(init_ch)self.blocks=tf.keras.models.Sequential()for block_id in range(num_blocks):for layer_id in range (2):if layer_id==0:block=InceptionBlk(self.out_channels,strides=2)else:block=InceptionBlk(self.out_channels,strides=1)self.blocks.add(block)#self.out_channels*=2self.p1 = GlobalAveragePooling2D()self.f1 = Dense(num_classes,activation='softmax')def call(self,x):x=self.c1(x)x=self.blocks(x)x=self.p1(x)y=self.f1(x)return y
model=Inception10(num_blocks=2,num_classes=10)	

参数num_blocks代表InceptionNet的Block数,每个Block由两个基本单元构成,每经过一个
Block,特征图尺寸变为1/2,通道数变为原来的两倍; num_classes代表分类数
init_ch代表初始通道数,代表InceptionNet基本单元的初始卷积核个数

InceptionNet采用"全局平均池化+全连接层",VGGNet(有三层全连接层)
平均池化:在特征图上以窗口的形式滑动,取窗口内的平均值为采样值
全局平均池化:直接针对特征图取平均值,每一个特征图输出一个值,通过这种方式,每个特征图都与分类概率直接联系起来替代了全连接层的功能,并且不会产生额外的训练参数,减少了过拟合的可能,但会导致网络收敛速度变慢。
InceptionNet采用多尺寸卷积再聚合的方式拓宽了网络结构,并通过 1 * 1卷积运算来减少参数量。

5、ResNet

优点:层间残差跳连,引入前方信息,减少梯度消失,使神经网络层数变深成为可能。
已知:对于一个深度比较合适的网络来说,继续增加层数反而会导致训练错误率的提升:
在这里插入图片描述
ResNet核心思路为:对一个准确率达到饱和的浅层网络,在它后面加几个恒等映射层(即 y = x,输出等于输入),增加网络深度的同时不增加误差。这使得神经网络的层数可以超越之前的约束,提高准确率。
这种残差结构的示意图如下:
在这里插入图片描述
注意,这里的相加与 InceptionNet 中的相加是有本质区别的,Inception 中的相加是沿深度方向叠加,像“千层蛋糕”一样,对层数进行叠加;ResNet 中的相加则是特征图对应元素的数值相加。
代码描述:

class ResnetBlock(Model):def __init__(self,filters,strides=1,residual_path=False):super(ResnetBlock,self).__init__()self.filters = filtersself.strides = stridesself.residual_path = residual_pathself.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为Ture时,对输入进行下采样,用1x1的卷积核卷积,保证x和F(x)维度相同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 = inputs	#residual等于输入值本身,即residual=x#将输入通过卷积、BN层,激活层,计算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)out = self.a2(y+residual)  #最后输出两部分的和,F(x)+x或者F(x)+Wx,再过激活函数return out

ResNet18网络结构以及其利用tf构建模型示意:

图1
图2
class ResNet(Model):def __init__(self,block_list,initial_filters=64):		#block_list表示每个block有几个卷积层super(ResNet,self).__init__()self.num_blocks =len(block_list)self.block_list =block_listself.out_filters = initial_filtersself.c1 = Conv2D(self.out_filters,(3,3),strides=1,padding='same',use_bias=False,kernel_initialize='he_normal')self.b1 = tf.keras.layers.BatchNormalization()self.a1 = Activation('relu')self.blocks = tf.keras.models.Sequential()#构建ResNet网络结构for block_id in range(len(block_list)):			#第几个resnet_blockfor layer_id in range(block_list(block_list[block_id])):		#第几个卷积层if block_id!=0 and layer_id==0 : 			#对除第一个block以外的每个block的输入进行下采样,对于一个样值序列间隔几个样值取样一次,这样得到新序列就是原序列的下采样block = ResnetBlock(self.out_filters,strides=2,residual_path = True)else:block = ResnetBlock(self.out_filters,residual_path=False)self.blocks.add(block)		#将构建好的block加入resnetself.out_filters *=2			#下一个block的卷积核个数是上一个block的2倍self.p1 = tf.keras.layers.GlobalAveragePooling2D()self.f1 = tf.keras.layers.Dense(10)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)		#由于使用了GAP,所以不需要dropout操作(不再是黑箱操作了)return y

三层残差单元用于构建更深的网络:
在这里插入图片描述

6、经典卷积网络总结

在这里插入图片描述

总结

课程链接:MOOC人工智能实践:TensorFlow笔记2
参考以及知识点补充链接:
卷积神经网络—AlexNet、VGG、GoogleNet、ResNet论文解读
CNN浅析和历年ImageNet冠军模型解析

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/378244.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

String.valueOf()

1. 由 基本数据型态转换成 String String 类别中已经提供了将基本数据型态转换成 String 的 static 方法 也就是 String.valueOf() 这个参数多载的方法 有下列几种 String.valueOf(boolean b) : 将 boolean 变量 b 转换成字符串 String.valueOf(char c) : 将 char 变量 c 转换成…

emacs gdb 调试

写下linux下用emacs调用dgb调试的方法 emacs中使用gdb 说明C等价于ctrl M等价于alt 1,编写 .c函数 test.c 2,gcc一把 看看对不对 带上-g gcc -g -o test .debug test.c 如果要用gdb调试器,必须使用g选项。 3,#ema…

第十九章 趣味编程

第十九章 趣味编程 本章将介绍一些通用的Python编程指南。 为何要有趣 Python有趣的地方之一就是让用户的编程效率非常高效。 极限编程是一种软件开发方法 编程柔术 python的灵活性描述原型设计Python的优点之一是让你能够快速地编写程序。要更深入地了解面临的问题&#…

android按钮在容器下方,使用flex布局解决安卓手机上固定在底部的按钮,在键盘弹起后挡住input输入框的问题...

移动端经常会出现,一个表单里面,确定按钮固定在底部这样的布局,一般会让按钮absolute或者fixed,这样在ios上没有问题,但是在安卓手机上,当表单里面的input输入框获得焦点的时候,按钮会挡在表单上…

dbms支持哪几种数据模型_DBMS中不同类型的数据模型

dbms支持哪几种数据模型资料模型 (Data Model) A data model is a model that defines in which format the data are represented and accessed. Data model mainly defines some of the data elements and relationships that exist between them. 数据模型是定义数据以哪种格…

JS 数组迭代方法

var arr [3,4,5,6,7,"a"]; var isNum function(elem,index,AAA){ return !isNaN(elem);} var toUpperCase function(elem){ return String.prototype.toUpperCase.apply(elem);} var print function(elem,index){ console.log(index"."elem);} /*对数组…

php开源问答_PHP基础知识能力问答

php开源问答This section contains Aptitude Questions and Answers on PHP Basics. 本部分包含有关PHP基础知识的 Aptitude问题和解答。 1) There are the following statements that are given below, which of them are correct PHP? PHP stands for the Preprocessor Hom…

【数据结构基础笔记】【顺序表】

代码参考《妙趣横生的算法.C语言实现》 文章目录前言1、创建顺序表2、顺序表插入元素3、顺序表删除元素4、顺序表实例分析1、静态2、动态5、顺序表总结前言 本章总结:从静态和动态分别进行顺序表的创建、插入、删除、以及实例分析 1、创建顺序表 1、静态地生成一张…

ubuntu安装oracle unzip: No such file or directory

$ln -s /usr/bin/unzip /你的oracle11安装目录/install/unzip$sudo chmod 777 /usr/bin/unzip转载于:https://www.cnblogs.com/qm4050/archive/2011/08/25/2241466.html

一、网络爬虫概述

1,浏览器与网络爬虫的区别 答: 对于浏览器而言:浏览器打开一个网站,会对网站服务器发送一个request请求,服务器收到该请求之后,会给浏览器一个respond响应,该响应携带很多数据,之后…

百度android广告sdk下载,IS_Freedom

美数广告 SDK接入流程1.嵌入广告SDK将 sdk-android-demo/app/libs 中的 meishu-sdk_xxx_release.aar、open_ad_sdk_xxx.aar、Baidu_MobAds_SDK-release-xxx.aar、GDTSDK.unionNormal.xxx.aar、msa_mdid_1.0.13 拷贝到项目的 libs 下,对应的 build.gradle 文件里面添…

关于《加密与解密》的读后感----对dump脱壳的一点思考

偶然翻了一下手机日历,原来今天是夏至啊,时间过的真快。ISCC的比赛已经持续了2个多月了,我也跟着比赛的那些题目学了2个月.......虽然过程很辛苦,但感觉还是很幸运的,能在大三的时候遇到ISCC,不管怎样&…

java vector_Java Vector elements()方法与示例

java vector向量类elements()方法 (Vector Class elements() method) elements() method is available in java.util package. elements()方法在java.util包中可用。 elements() method is used to get an enumeration of the elements that exist in this Vector. elements()方…

【数据结构基础笔记】【链表】

代码参考《妙趣横生的算法.C语言实现》 文章目录前言1、链表基础2、创建一个链表3、插入结点4、删除结点5、销毁链表6、实例分析前言 本章总结:链表的定义、创建、销毁,结点的插入与删除 1、链表基础 链表的物理存储结构是用一组地址任意的存储单元存储…

动态添加,删除行之心理测试系统

动态添加,删除行之考试系统 数据库设计: xl_option 题目选项 20090105134755404(编号) 20090105134904421(外键) 比较符合(选项内容) ②(选项标号) 2(选项分值) xl_subject 题目信息 20090105134943608(编号&#xff…

android bitmap裁剪中间,Android裁剪中心位图

虽然上面的大多数答案提供了一种方法来实现这一点,但已经有一种内置的方法来实现这一点,它是一行代码(ThumbnailUtils.extractThumbnail())int dimension getSquareCropDimensionForBitmap(bitmap);bitmap ThumbnailUtils.extractThumbnail(bitmap, di…

二、request请求库

一、requests介绍与安装 1,requests介绍 答:requests是一个优雅且简单的Python HTTP请求库 2,requests作用 答:requests的作用是发送请求获取响应数据 3,requests安装 答:pip install requests 二、…

Java Vector Capacity()方法与示例

向量类的Capacity()方法 (Vector Class capacity() method) capacity() method is available in java.util package. Capacity()方法在java.util包中可用。 capacity() method is used to return the current capacity (i.e. initially, how many object exists) of this Vecto…

MFC和GTK的区别

关键技术 http://blog.csdn.net/master_max/article/details/1540204 MFC和GTK的区别?? 1.  两者都是基于面向对象设计的。尽管MFC是用C写的,而GTK是用C写的,但思想都是面向对象的。GTK使用glib的对象机制,由于用C写…

视频图像质量评价

目录1、人眼视觉特性1、眼的适应性2、对比灵敏度3、空间分辨率和时间分辨率4、马赫效应5、可见度阈值2、图像质量测度3、图像评价方法4、图像评价方法的优劣1、人眼视觉特性 1、眼的适应性 暗适应性:从亮环境到暗环境,适应暗环境的特性 亮适应性&#…