ResNet50結構
ResNet簡介
隨着網絡的加深,出現了訓練集准確率下降的現象,可以確定這不是由於Overfit過擬合造成的(過擬合的情況訓練集應該准確率很高);針對這個問題提出了一種全新的網絡,稱為深度殘差網絡,允許網絡盡可能的加深,其中引入了全新的結構如圖。
殘差指的是什么?
其中ResNet提出了兩種mapping:一種是identity mapping,指的就是圖中”彎彎的曲線”,另一種residual mapping,指的就是除了”彎彎的曲線“那部分,所以最后的輸出是 y= F(x)+x
identity mapping顧名思義,指本身,也就是公式中的x,而residual mapping指的是“差”,也就是y−x,所以殘差指的就是F(x)部分。
resnet50詳解
block_sizes=[3, 4, 6, 3]指的是stage1(first pool)之后的4個layer的block數, 分別對應res2, res3, res4, res5。
每一個layer的第一個block在shortcut上做conv+BN, 即Conv Block
inputs: (1, 720, 1280, 3)
initial_conv:
conv2d_fixed_padding()
1. kernel_size=7, 先做padding(1, 720, 1280, 3) -> (1, 726, 1286, 3)
2. conv2d kernels=[7, 7, 3, 64], stride=2, VALID 卷積. 7x7的kernel, padding都為3, 為了保證左上角和卷積核中心點對其
(1, 726, 1286, 3) -> (1, 360, 640, 64)
3. BN, Relu (只有resnetv1在第一次conv后面做BN和Relu)
initial_max_pool:
k=3, s=2, padding='SAME', (1, 360, 640, 64) -> (1, 180, 320, 64)
以下均為不使用bottleneck的building_block
block_layer1:
(有3個block, layer間stride=1(上一層做pool了), 64個filter, 不使用bottleneck(若使用bottleneck 卷積核數量,需乘4))
1. 第一個block:
Conv Block有projection_shortcut, 且strides可以等於1或者2
Identity Block沒有projection_shortcut, 且strides只能等於1
`inputs = block_fn(inputs, filters, training, projection_shortcut, strides, data_format)`
shortcut做[1, 1, 64, 64], stride=1的conv和BN, shape不變
然后和主要分支里input做3次卷積后的結果相加, 一起Relu, 注意block里最后一次卷積后只有BN沒有Relu
input: conv-bn-relu-conv-bn-relu-conv-bn 和shortcut相加后再做relu
shortcut: conv-bn
shortcut: [1, 1, 64, 64], s=1, (1, 180, 320, 64) -> (1, 180, 320, 64)
input做兩次[3, 3, 64, 64], s=1的卷積, shape不變(1, 180, 320, 64) -> (1, 180, 320, 64) -> (1, 180, 320, 64)
inputs += shortcut, 再relu
2. 對剩下的2個block, 每個block操作相同:
`inputs = block_fn(inputs, filters, training, None, 1, data_format)`
shortcut直接和input卷積結果相加, 不做conv-bn
input做兩次[3, 3, 64, 64], s=1的卷積, shape不變(1, 180, 320, 64) -> (1, 180, 320, 64) -> (1, 180, 320, 64)
inputs += shortcut, 再relu
block_layer2/3/4同block_layer1, 只是每個layer的identity block數量不同, 卷積核數量和layer間stride也不同, 不過仍然只有第一個conv block的shortcut做conv-bn
block_layer2: 4個block, 128個filter, layer間stride=2 (因為上一層出來后沒有pool)
1. 第一個block:
對shortcut做kernel=[1, 1, 64, 128], s=2的conv和BN, (1, 180, 320, 64) -> (1, 90, 160, 128)
對主要分支先做kernel=[3, 3, 64, 128], s=2的卷積, padding='VALID', (1, 180, 320, 64) -> (1, 90, 160, 128)
再做kernel=[3, 3, 128, 128], s=1的卷積, padding='SAME', (1, 90, 160, 128) -> (1, 90, 160, 128)
2. 剩下的3個block, 每個block操作相同:
shortcut不操作直接和結果相加做Relu
對主要分支做兩次[3, 3, 128, 128], s=1的卷積, padding='SAME', (1, 90, 160, 128) -> (1, 90, 160, 128) -> (1, 90, 160, 128)
block_layer3: 6個block, 256個filter, layer間stride=2
1. 第一個block:
對shortcut做kernel=[1, 1, 128, 256], s=2的conv和BN, (1, 90, 160, 128) -> (1, 45, 80, 256)
對主要分支先做kernel=[3, 3, 128, 256], s=2的卷積, padding='VALID', (1, 90, 160, 128) -> (1, 45, 80, 256)
再做kernel=[3, 3, 256, 256], s=1的卷積, padding='SAME', (1, 45, 80, 256) -> (1, 45, 80, 256)
2. 剩下的5個block, 每個block操作相同:
shortcut不操作直接和結果相加做Relu
對主要分支做兩次[3, 3, 256, 256], s=1的卷積, padding='SAME', (1, 45, 80, 256) -> (1, 45, 80, 256) -> (1, 45, 80, 256)
block_layer4: 3個block, 512個filter, layer間stride=2
1. 第一個block:
對shortcut做kernel=[1, 1, 256, 512], s=2的conv和BN, (1, 45, 80, 256) -> (1, 23, 40, 512)
對主要分支先做kernel=[3, 3, 256, 512], s=2的卷積, padding='VALID', (1, 45, 80, 256) -> (1, 23, 40, 512)
再做kernel=[3, 3, 512, 512], s=1的卷積, padding='SAME', (1, 23, 40, 512) -> (1, 23, 40, 512)
2. 剩下的2個block, 每個block操作相同:
shortcut不操作直接和結果相加做Relu
對主要分支做兩次[3, 3, 512, 512], s=1的卷積, padding='SAME', (1, 23, 40, 512) -> (1, 23, 40, 512)
avg_pool, 7*7
FC, output1000
softmax
輸出prediction
Resnet-18,Resnet-50,等等,不過是層數不一罷了,如下圖,慣用的是Resnet-50與101
如下圖,每個大block里面的
第一個都是IN !==OUT情況,左側支線,命名為:Conv Block
其他都是 IN ==OUT情況,右側支線, 命名為:ID Block
3 = 左+右+右
4 = 左+右+右+右
6 = 左+右+右+右+右+右
3 = 左+右+右
resnet50圖解
參考鏈接:
https://blog.csdn.net/zjc910997316/article/details/102912175
https://blog.csdn.net/lanran2/article/details/79057994
https://www.cnblogs.com/qianchaomoon/p/12315906.html