keras的resnet50模型介绍

网络的完整结构,可通过下面代码显示在控制台上

import keras_resnet.models
import keras
shape, classes = (224, 224, 3), 1000
x = keras.layers.Input(shape)
model = keras_resnet.models.ResNet50(x)
model.summary()

网络源码实现:

下面节选自python3.6/site-packages/keras_resnet/models/_2d.py

刚开始,第一层,含有补边,卷积,BN,激活函数五个部分

备注:网络中,一般把含有可训练参数的模块称为一层,比如卷积层称为一层,而激活函数等不含可训练参数的模块一般不称为一层。

1. keras.layers.ZeroPadding2D(padding=3, name="padding_conv1")(inputs)

功能:对输入inputs的4个边进行补0,比如若输入图像尺寸为(224,224,3),则每个边多补充3行(列)0,

则宽就变成了224+3+3=230, 即经过这一层后,图片尺寸转变为(230,230,3)

2. keras.layers.Conv2D(64, (7, 7), strides=(2, 2), use_bias=False, name="conv1")(x)

功能:卷积层,卷积核(7,7,64), strid=2, 若输入图片x的尺寸为(230,230,3),则经过这个卷积层后的尺寸为:

根据计算公式\frac{W-F+1}{S},可得,新的宽为

(230-7+1)/2=112, 因此输入(230,230,3)的图片经过这个卷积层后,输出尺寸为(112,112,64)

3.keras_resnet.layers.BatchNormalization(axis=axis, epsilon=1e-5, freeze=freeze_bn, name="bn_conv1")(x)

BN层,对输入进行归一化,不改变输入的尺寸,输出尺寸为(112,112,64)

4.keras.layers.Activation("relu", name="conv1_relu")(x)

激活函数层,用的relu激活函数,不改变输入的尺寸,输出尺寸为(112,112,64)

5.keras.layers.MaxPooling2D((3, 3), strides=(2, 2), padding="same", name="pool1")(x)

池化层, 输出的计算公式同上述卷积层,若输入维度(112,112,64),则输出尺寸为(56,56,64)

(112-3+1)/2=????这里结论是56,怎么算出来的,不知道哦

6. 后面是block的构造

另外,对于resnet来讲,还有一个重要的bottleneck_2d模块,位于python3.6/site_packages/keras_resnet/blocks/_2d.py中

def bottleneck_2d(filters, stage=0, block=0, kernel_size=3, numerical_name=False, stride=None, freeze_bn=False):
    if stride is None:
        if block != 0 or stage == 0:
            stride = 1
        else:
            stride = 2
    def f(x):
        y = keras.layers.Conv2D(filters, (1, 1), strides=stride, use_bias=False, name="res{}{}_branch2a".format(stage_char, block_char), **parameters)(x)
        y = keras_resnet.layers.BatchNormalization(axis=axis, epsilon=1e-5, freeze=freeze_bn, name="bn{}{}_branch2a".format(stage_char, block_char))(y)
        y = keras.layers.Activation("relu", name="res{}{}_branch2a_relu".format(stage_char, block_char))(y)

        y = keras.layers.ZeroPadding2D(padding=1, name="padding{}{}_branch2b".format(stage_char, block_char))(y)
        y = keras.layers.Conv2D(filters, kernel_size, use_bias=False, name="res{}{}_branch2b".format(stage_char, block_char), **parameters)(y)
        y = keras_resnet.layers.BatchNormalization(axis=axis, epsilon=1e-5, freeze=freeze_bn, name="bn{}{}_branch2b".format(stage_char, block_char))(y)
        y = keras.layers.Activation("relu", name="res{}{}_branch2b_relu".format(stage_char, block_char))(y)

        y = keras.layers.Conv2D(filters * 4, (1, 1), use_bias=False, name="res{}{}_branch2c".format(stage_char, block_char), **parameters)(y)
        y = keras_resnet.layers.BatchNormalization(axis=axis, epsilon=1e-5, freeze=freeze_bn, name="bn{}{}_branch2c".format(stage_char, block_char))(y)

        if block == 0:
            shortcut = keras.layers.Conv2D(filters * 4, (1, 1), strides=stride, use_bias=False, name="res{}{}_branch1".format(stage_char, block_char), **parameters)(x)
            shortcut = keras_resnet.layers.BatchNormalization(axis=axis, epsilon=1e-5, freeze=freeze_bn, name="bn{}{}_branch1".format(stage_char, block_char))(shortcut)
        else:
            shortcut = x

        y = keras.layers.Add(name="res{}{}".format(stage_char, block_char))([y, shortcut])
        y = keras.layers.Activation("relu", name="res{}{}_relu".format(stage_char, block_char))(y)

        return y

    return f

把这个称为block2a,可以看出,这个块中,共包含了3层,

第一层:stride=1,filters=64卷积层keras.layers.Conv2D(filters, (1, 1), strides=stride),这里会哟stride的确定,可以看出stride会在1和2之间确定, 输出尺寸宽=(56-1+1)/1=56, 输出尺寸为(56,56,64)

       BN模块,对输入进行归一化,不改变输入的尺寸,输出尺寸为(56,56,64)

        激活函数,用的relu激活函数,不改变输入的尺寸输出尺寸为(56,56,64)

        ZeroPadding2D(padding=1)层,输出尺寸为(58,58,64)

第二层:卷积模块tride=1,filters=64,kernel_size=(3,3)输出尺寸宽=(58-3+1)/1=56, 输出尺寸为(56,56,64)

          BN模块,,对输入进行归一化,不改变输入的尺寸,输出尺寸为(56,56,64)

         激活函数层,用的relu激活函数,不改变输入的尺寸输出尺寸为(56,56,64)

第三层::卷积层,stride=1,filters=64*4,kernel_size=(1,1)输出尺寸宽=(56-1+1)/1=56, 输出尺寸为(56,56,256)

           BN模块,,对输入进行归一化,不改变输入的尺寸,输出尺寸为(56,56,256)

构造shortcut参差块

若block=0

第10层:卷积层,stride=1,filters=64*4,kernel_size=(1,1)输出尺寸宽=(56-1+1)/1=56, 输出尺寸为(56,56,256)

第11层:shortcut=BN层,对输入进行归一化,不改变输入的尺寸,输出尺寸为(56,56,256)

若block!=0

shortcut=block的输入

     ADD层,将第9层输出与shortcut相加, 输出尺寸(56,56,256)

      激活函数,用的relu激活函数,不改变输入的尺寸输出尺寸为(56,56,256)

block构造结束后,block2a的输出(56,56,256),直接添加进模型的outputs, 并是下一个block的输入,,第一个block结束,到此共有5+13=18层,

循环进入第2个block2b,,其基本结构同block2a,但少了2层,共11层

下面分析第2个个block2b,共11层,

1: 卷积层,2.BN层,3.激活层4.zeropadding层,5:卷积层,6.BN层,7.激活层8.卷积9.BN 10. ADD 11.relu ,

 block2b的输出(56,56,256), 到此共有5+13+11=29层,

循环进入第3个block2c,,其基本结构同block2b,共11层

1: 卷积层,2.BN层,3.激活层4.zeropadding层,5:卷积层,6.BN层,7.激活层8.卷积9.BN 10. ADD 11.relu ,

block2c的输出(56,56,256), 到此共有5+13+11+11=40层,

循环进入第4个block3a,,其基本结构同block2a,共13层

1: 卷积层,2.BN层,3.激活层4.zeropadding层,5:卷积层,6.BN层,7.激活层8.卷积9.卷积,10.BN 11.BN12. ADD 13.relu ,

block3a的输出(28,28,512), 到此共有5+13+11+11+13=53层,

循环进入第5个block3b,,其基本结构同block2b,共11层

block3b的输出(28,28,512), 到此共有5+13+11+11+13+11=64层,

循环进入第6个block3c,其基本结构同block2c,共11层

block3b的输出(28,28,512), 到此共有5+13+11+11+13+11+11=75层,

循环进入第7个block3d,,其基本结构同block2c,共11层

block3d的输出(28,28,512), 到此共有5+13+11+11+13+11+11+11=86层,

循环进入第8个block4a,,其基本结构同block2c,共11层

block3d的输出(28,28,512), 到此共有5+13+11+11+13+11+11+11=86层,

循环进入第block4b(11层),block4c(11层),.block4d(11层),block4e(11层),block4f(11层)....

block4f的输出(14,14,1024), 到此共有5+13+11+11+13+11+11+11+13+11*5=152层,

循环进入block5a(13层),block5b(11层),block5c(11层)

block5c的输出(7,7,2048), 到此共有152+13+11+11=187层

由此看来,并不50层啊,一直以为其是50层,为什么叫resnet50呢?

对于骨干网络resnet50来说,其输出共包含4个block的输出,有block2c,输出(?, 56, 56, 256),有block3d,(?, 28, 28, 512)
有block4f,(?, 14, 14, 1024),有block5c,(?, 7, 7, 2048)

下面只取出了3,4,5block的输出, 用上述的resnet作为骨干,我们又继续向下构造网络

pyramid_layer_1:卷积层, feature_depth=256, kernerl_size=1, stride=1, 输入为block5c,(?, 7, 7, 2048),输出宽

(7-1+1)/1=7, 输出p1_out尺寸:(?, 7, 7, 256),

pyramid_layer_2:upsamplelike层,  输入为[p1_out,block4f],则输入尺寸:[7,7,256],[14,14,1024],输出p2_out?

pyramid_layer_3:卷积层,输入为p1_out, feature_depth=256, kernerl_size=3, stride=1,输出宽

(7-3+1)/1=5, 输出p3_out尺寸:(?,5, 5, 256)

pyramid_layer_4:卷积层,输入为block4f, feature_depth=256, kernerl_size=1, stride=1,输出宽

(14-1+1)/1=14, 输出p4_out尺寸:(?,14, 14, 256)

pyramid_layer_5:ADD层,输入为p2_out,p4_out(?,14, 14, 256), , 输出p5_out尺寸:?

pyramid_layer_2:upsamplelike层,  输入为[p1_out,block4f],则输入尺寸:[7,7,256],[14,14,1024],输出p2_out?

待续:retinanet/keras_retinanet/models/retinanet.py/_create_pyramid_features()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(keras的resnet50模型介绍)