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.pswp.cn/news/378244.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/378244.shtml
英文地址,請注明出處:http://en.pswp.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、眼的適應性 暗適應性:從亮環境到暗環境,適應暗環境的特性 亮適應性&#…