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,一经查实,立即删除!

相关文章

第十九章 趣味编程

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

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

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

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

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

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

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

视频图像质量评价

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

recovery编译问题汇总

1、修改支持USB大容量存储 (1)、首先需要查看手机lun位置 手机链接电脑,打开cmd命令行,依次输入以下命令: adb shell find /sys -name "lun" 输出以下结果: 发现手机输出结果有两个,需要进一步查…

【数据结构基础笔记】【栈】

代码参考《妙趣横生的算法.C语言实现》 文章目录前言1、栈的定义2、创建一个栈3、入栈和出栈操作4、栈的清空、销毁、计算栈的当前容量5、实例分析前言 本章总结:栈的定义、创建栈,销毁栈,入栈出栈操作等操作。 1、栈的定义 栈是一种重要的…

用HTML语言制作list标记,html5 datalist标签的用法是什么?这里有datalist标签的用法实例...

本篇文章主要为大家讲述了关于html5 datalist标签的用法及html5 datalist标签的用法实例。本文说了两个常用的选项框的实例供大家选择观看,下面就让我们一起来看这篇文章吧我们先来看看html5 datalist标签的用法:标签定义选项列表。请与input元素配合使用…

【数据结构基础笔记】【队列】

代码参考《妙趣横生的算法.C语言实现》 文章目录前言1、队列定义2、创建一个队列3、入队列4、出队列5、销毁一个队列6、循环队列的概念7、循环队列的实现8、实例分析前言 本章总结:链队列定义,创建,出队入队操作,销毁操作&#x…

html图片自动循环轮播图,js实现图片无缝循环轮播

本文实例为大家分享了js实现图片无缝循环轮播的具体代码,供大家参考,具体内容如下代码如下Document#container{overflow:hidden;width:400px;height:300px;margin:auto;}#front,#container{display:flex;flex-direction:row;}#container img{width:400px…

五、json模块

一、json模块的介绍 json模块是Python自带的模块,用于json和Python数据之间的相互转换 Json与Python数据类型的对应关系 JsonPythonobjectdictarrayliststringstrnumber(int)int,longnumber(real)floattrueTruefalseFalsenullNone [#中括号括起来的,对…

【数据结构基础笔记】【树】

代码参考《妙趣横生的算法.C语言实现》 文章目录前言1、树的概念2、二叉树3、二叉树的遍历4、创建二叉树5、实例分析前言 本章总结:树的概念、二叉树的创建、遍历 1、树的概念 树结构是以分支关系定义得一种层次结构。 树的定义:树是由n(n>0)个结点…

可以自动撑起的html样式,好好玩:CSS3抖动样式CSS Shake让你的网页酷炫起来

之前在一些网站发现了一个好玩的样式,就是鼠标移到网站LOGO上,logo会自动抖动起来,显得非常炫酷。我也是十分感兴趣。自从本站新添加了一个视觉设计的分类之后,我也是想起来有个抖动CSS样式CSS Shake,所以今天给小伙伴…

爬虫项目(一)---采集最近一日世界各国的疫情数据信息

该内容出自黑马程序员教程 采集最近一日世界各国疫情数据 步骤: 发送请求,获取疫情首页从疫情首页中提取最近一日各国疫情字符串从最近一日各国疫情字符串中提取json格式字符串把json格式字符串转换为Python类型把Python类型的数据,以json…

【数据结构基础应用】【顺序表】

代码参考《妙趣横生的算法.C语言实现》、《剑指OFFER 名企面试官精讲典型编程题 第2版》等 文章目录前言1、合并两个顺序表前言 本章总结在看书过程中的一些关于顺序表的算法题并可能含有一些自己的一些疑问。题目数量不定,随阅历增加而增加; 1、合并两…

html上下滚动切换顶端tab,jQuery实现Tab菜单滚动切换的方法

本文实例讲述了jQuery实现Tab菜单滚动切换的方法。分享给大家供大家参考。具体如下:这是一款jQuery实现让你的Tab菜单滚动的代码,先运行一下看看效果咋样?是不是超不错,让你的网页变得灵动起来,不再静止,学习jquery的朋友也可作为范例来参考吧.运行效果截图如下&am…

[转载]十四步实现拥有强大AI的五子棋游戏

又是本人一份人工智能作业……首先道歉,从Word贴到Livewrter,好多格式没了,也没做代码高亮……大家凑活着看……想做个好的人机对弈的五子棋,可以说需要考虑的问题还是很多的,我们将制作拥有强大AI五子棋的过程分为十四…

爬虫项目(二)---采集从03月02号以来的世界各国疫情数据

该内容出自黑马程序员教程 采集从03月02号以来的世界各国疫情数据 步骤: Ⅰ,重构项目(一)的代码,以提高扩展性 把功能封装到一个类中每一个小功能变成一个方法通过run方法启动爬虫 import requests import re import json from bs4 impor…

【原创】StreamInsight查询系列(二十)——查询模式之检测间隙事件

上篇文章介绍了查询模式中如何检测异常事件,这篇博文将介绍StreamInsight中如何检测间隙事件。 测试数据准备 为了方便测试查询,我们首先准备一个静态的测试数据源:// 创建数据源,要注意的是4:16和4:30之间存在的事件间隙 var sou…

【数据结构基础应用】【查找和排序算法】

代码参考《妙趣横生的算法.C语言实现》 文章目录前言1、顺序查找2、折半查找3、直接插入排序4、选择排序5、冒泡排序6、希尔排序7、快速排序8、堆排序9、排序算法性能比较10、所有算法的code(C语言)前言 本章总结查找和排序算法:顺序查找、折…