当前位置 博文首页 > 谦曰盛:TensorFlow之keras.layers.Conv2D( )

    谦曰盛:TensorFlow之keras.layers.Conv2D( )

    作者:谦曰盛 时间:2021-06-07 18:22

      keras.layers.Conv2D( ) 函数参数

        def __init__(self, filters,
                     kernel_size,
                     strides=(1, 1),
                     padding='valid',
                     data_format=None,
                     dilation_rate=(1, 1),
                     activation=None,
                     use_bias=True,
                     kernel_initializer='glorot_uniform',
                     bias_initializer='zeros',
                     kernel_regularizer=None,
                     bias_regularizer=None,
                     activity_regularizer=None,
                     kernel_constraint=None,
                     bias_constraint=None,
                     **kwargs):

    参数:

    filters 卷积核个数的变化,filters 影响的是最后输入结果的的第三个维度的变化,例如,输入的维度是 (600, 600, 3), filters 的个数是 64,转变后的维度是 (600, 600, 64)

    >>> from keras.layers import (Input, Reshape)
    >>> input = Input(shape=(600, 600, 3))
    >>> x = Conv2D(64, (1, 1), strides=(1, 1), name='conv1')(input)
    >>> x
    <tf.Tensor 'conv1_1/BiasAdd:0' shape=(?, 600, 600, 64) dtype=float32>

    kernel_size 参数 表示卷积核的大小,可以直接写一个数,影响的是输出结果前两个数据的维度,例如,(600, 600, 3)=> (599, 599, 64)

    >>> from keras.layers import (Input, Conv2D)
    >>> input = Input(shape=(600, 600, 3))
    >>> Conv2D(64, (2, 2), strides=(1, 1), name='conv1')(input)
    <tf.Tensor 'conv1/BiasAdd:0' shape=(?, 599, 599, 64) dtype=float32>

    直接写 2 也是可以的

    >>> from keras.layers import (Input, Conv2D)
    >>> input = Input(shape=(600, 600, 3))
    >>> Conv2D(64, 2, strides=(1, 1), name='conv1')(input)
    <tf.Tensor 'conv1_2/BiasAdd:0' shape=(?, 599, 599, 64) dtype=float32>
    

    strides  步长 同样会影响输出的前两个维度,例如,(600, 600, 3)=> (300, 300, 64),值得注意的是,括号里的数据可以不一致,分别控制横坐标和纵坐标,这里步长的计算公式为:

    >>> from keras.layers import (Input, Conv2D)
    >>> input = Input(shape=(600, 600, 3))
    >>> Conv2D(64, 1, strides=(2, 2), name='conv1')(input)
    <tf.Tensor 'conv1_4/BiasAdd:0' shape=(?, 300, 300, 64) dtype=float32>
    

    padding 是否对周围进行填充,“same” 即使通过kernel_size 缩小了维度,但是四周会填充 0,保持原先的维度;“valid”表示存储不为0的有效信息。多个对比效果如下:

    >>> Conv2D(64, 1, strides=(2, 2), padding="same", name='conv1')(input)
    <tf.Tensor 'conv1_6/BiasAdd:0' shape=(?, 300, 300, 64) dtype=float32>
    >>> Conv2D(64, 3, strides=(2, 2), padding="same", name='conv1')(input)
    <tf.Tensor 'conv1_7/BiasAdd:0' shape=(?, 300, 300, 64) dtype=float32>
    >>> Conv2D(64, 3, strides=(1, 1), padding="same", name='conv1')(input)
    <tf.Tensor 'conv1_8/BiasAdd:0' shape=(?, 600, 600, 64) dtype=float32>
    >>> Conv2D(64, 3, strides=(1, 1), padding="valid", name='conv1')(input)
    <tf.Tensor 'conv1_9/BiasAdd:0' shape=(?, 598, 598, 64) dtype=float32>

    通过这种最简单的方式,可以观察 ResNet50 的组成结构

     Conv Block 的架构:

    def conv_block(input_tensor, kernel_size, filters, stage, block, strides):
    
        filters1, filters2, filters3 = filters  # filters1 64, filters3 256  将数值传入到filters。。。中
        conv_name_base = 'res' + str(stage) + block + '_branch'
        bn_name_base = 'bn' + str(stage) + block + '_branch'
    
        x = Conv2D(filters1, (1, 1), strides=strides, name=conv_name_base + '2a')(input_tensor)
        x = BatchNormalization(name=bn_name_base + '2a')(x)
        x = Activation('relu')(x)
    
        x = Conv2D(filters2, kernel_size, padding='same', name=conv_name_base + '2b')(x)
        x = BatchNormalization(name=bn_name_base + '2b')(x)
        x = Activation('relu')(x)
    
        x = Conv2D(filters3, (1, 1), name=conv_name_base + '2c')(x)
        x = BatchNormalization(name=bn_name_base + '2c')(x)
    
        shortcut = Conv2D(filters3, (1, 1), strides=strides, name=conv_name_base + '1')(input_tensor)
        shortcut = BatchNormalization(name=bn_name_base + '1')(shortcut)
    
        x = layers.add([x, shortcut])
        x = Activation("relu")(x)
        return x

    Identity Block 的架构:

    def identity_block(input_tensor, kernel_size, filters, stage, block):
        filters1, filters2, filters3 = filters
    
        conv_name_base = 'res' + str(stage) + block + '_branch'
        bn_name_base = 'bn' + str(stage) + block + '_branch'
    
        x = Conv2D(filters1, (1, 1), name=conv_name_base + '2a')(input_tensor)
        x = BatchNormalization(name=bn_name_base + '2a')(x)
        x = Activation('relu')(x)
    
        x = Conv2D(filters2, kernel_size, padding='same', name=conv_name_base + '2b')(input_tensor)
        x = BatchNormalization(name=bn_name_base + '2b')(x)
        x = Activation('relu')(x)
    
        x = Conv2D(filters3, (1, 1), name=conv_name_base + '2c')(input_tensor)
        x = BatchNormalization(name=bn_name_base + '2c')(x)
    
        x = layers.add([x, input_tensor])
        x = Activation('relu')(x)
        return x  

    最后是整体架构:

    def ResNet50(inputs):
        #-----------------------------------#
        #   假设输入进来的图片是600,600,3
        #-----------------------------------#
        img_input = inputs
    
        # 600,600,3 -> 300,300,64
        x = ZeroPadding2D((3, 3))(img_input)
        x = Conv2D(64, (7, 7), strides=(2, 2), name='conv1')(x)
        x = BatchNormalization(name='bn_conv1')(x)
        x = Activation('relu')(x)
    
        # 300,300,64 -> 150,150,64
        x = MaxPooling2D((3, 3), strides=(2, 2), padding="same")(x)
    
        # 150,150,64 -> 150,150,256
        x = conv_block(x, 3, [64, 64, 256], stage=2, block='a', strides=(1, 1))
        x = identity_block(x, 3, [64, 64, 256], stage=2, block='b')
        x = identity_block(x, 3, [64, 64, 256], stage=2, block='c')
    
        # 150,150,256 -> 75,75,512
        x = conv_block(x, 3, [128, 128, 512], stage=3, block='a')
        x = identity_block(x, 3, [128, 128, 512], stage=3, block='b')
        x = identity_block(x, 3, [128, 128, 512], stage=3, block='c')
        x = identity_block(x, 3, [128, 128, 512], stage=3, block='d')
    
        # 75,75,512 -> 38,38,1024
        x = conv_block(x, 3, [256, 256, 1024], stage=4, block='a')
        x = identity_block(x, 3, [256, 256, 1024], stage=4, block='b')
        x = identity_block(x, 3, [256, 256, 1024], stage=4, block='c')
        x = identity_block(x, 3, [256, 256, 1024], stage=4, block='d')
        x = identity_block(x, 3, [256, 256, 1024], stage=4, block='e')
        x = identity_block(x, 3, [256, 256, 1024], stage=4, block='f')
    
        # 最终获得一个38,38,1024的共享特征层
        return x

    附上理论链接 Resnet-50网络结构详解  https://www.cnblogs.com/qianchaomoon/p/12315906.html

     

    bk