美文网首页
keras ResNet50

keras ResNet50

作者: 谢小帅 | 来源:发表于2019-03-10 12:07 被阅读0次
from keras.layers import Input, Conv2D, BatchNormalization, Activation, ZeroPadding2D
from keras.layers import MaxPool2D, GlobalAveragePooling2D, Dense
from keras.layers import add  # merge
from keras.models import Model
from keras.utils import plot_model


def conv_block(input_tensor, kernel_size, filters, stage, block, strides):
    """A block that has a conv layer at shortcut.
        Note:
            kernel_size, only the middle conv use
            stage and block, both used for generating layer names
            strides, used to reduce fm size in first conv layer and shortcut conv layer

        # Arguments
            input_tensor: input tensor
            kernel_size: default 3, the kernel size of middle conv layer at main path (core operation)
            filters: list of integers, the filters of 3 conv layer at main path, 3 filters
            stage: integer, current stage label, used for generating layer names
            block: 'a','b'..., current block label, used for generating layer names
            strides:
                - Strides for the first conv layer in the block.
                - Strides for the shortcut conv layer in the block.

        # Returns
            Output tensor for the block.

        Note that from stage 3, fm size 减半
        the first conv layer at main path is with strides=(2, 2)
        And the shortcut should have strides=(2, 2) as well
        """
    assert len(filters) == 3
    filters1, filters2, filters3 = filters

    # conv, bn name
    conv_name_base = 'conv' + str(stage) + block + '_branch'
    bn_name_base = 'bn' + str(stage) + block + '_branch'

    # bottleneck design, example [64, 64, 256]
    # main path name: a,b,c; shortcut name: 1

    # 1x1 conv, reduce fms 256->64 (last conv_block output 256fms)
    x = Conv2D(filters1, (1, 1), strides=strides,  # stage2, strides=1; stage345, strides=2
               kernel_initializer='he_normal',
               name=conv_name_base + '2a')(input_tensor)
    x = BatchNormalization(axis=3, name=bn_name_base + '2a')(x)  # channel last
    x = Activation('relu')(x)

    # 3x3 conv, core operation 128
    x = Conv2D(filters2, kernel_size,  # default strides=1
               padding='same',  # no change fm shape
               kernel_initializer='he_normal',
               name=conv_name_base + '2b')(x)
    x = BatchNormalization(axis=3, name=bn_name_base + '2b')(x)
    x = Activation('relu')(x)

    # 1x1 conv, recover fms 128->512
    x = Conv2D(filters3, (1, 1),
               kernel_initializer='he_normal',
               name=conv_name_base + '2c')(x)
    x = BatchNormalization(axis=3, name=bn_name_base + '2c')(x)
    # x = Activation('relu')(x), relu after add

    shortcut = Conv2D(filters3, (1, 1), strides=strides,
                      kernel_initializer='he_normal',
                      name=conv_name_base + '1')(input_tensor)
    shortcut = BatchNormalization(axis=3, name=bn_name_base + '1')(shortcut)

    # merge, main path 和 shortcut 的 bn 结果 add
    x = add([x, shortcut])
    x = Activation('relu')(x)

    return x


def identity_block(input_tensor, kernel_size, filters, stage, block):
    """The identity block is the block that has no conv layer at shortcut.
    与 conv_block 相比,少了参数 strides,没有 shortcut 操作

    # Arguments
        input_tensor: input tensor
        kernel_size: default 3, the kernel size of middle conv layer at main path
        filters: list of integers, the filters of 3 conv layer at main path
        # stage and block, used for generating layer names
        stage: integer, current stage label, used for generating layer names
        block: 'a','b'..., current block label, used for generating layer names

    # Returns
        Output tensor for the block.
    """
    assert len(filters) == 3
    filters1, filters2, filters3 = filters

    conv_name_base = 'res' + str(stage) + block + '_branch'
    bn_name_base = 'bn' + str(stage) + block + '_branch'

    # 1x1, strides use default 1, fm size no change
    x = Conv2D(filters1, (1, 1),
               kernel_initializer='he_normal',
               name=conv_name_base + '2a')(input_tensor)
    x = BatchNormalization(axis=3, name=bn_name_base + '2a')(x)  # channel last
    x = Activation('relu')(x)

    # 3x3
    x = Conv2D(filters2, kernel_size,
               padding='same',
               kernel_initializer='he_normal',
               name=conv_name_base + '2b')(x)
    x = BatchNormalization(axis=3, name=bn_name_base + '2b')(x)
    x = Activation('relu')(x)

    # 1x1
    x = Conv2D(filters3, (1, 1),
               kernel_initializer='he_normal',
               name=conv_name_base + '2c')(x)
    x = BatchNormalization(axis=3, name=bn_name_base + '2c')(x)

    # shortcut has no conv! cus no need to change fm size
    x = add([x, input_tensor])  # 直接把 input 和 x 相加
    x = Activation('relu')(x)

    return x


def ResNet50(input_tensor, include_top=True, classes=1000):  # 224x224
    # stage1
    # x = ZeroPadding2D(padding=(3, 3), name='conv1_pad')(input_tensor)  # 230x230 上下左右
    x = Conv2D(64, (7, 7), strides=(2, 2),  # 224->112
               padding='same',  # 使用 same 可以不用 padding
               kernel_initializer='he_normal',
               name='conv1')(input_tensor)
    x = BatchNormalization(axis=3, name='conv1_bn')(x)  # channel last
    x = Activation('relu', name='conv1_relu')(x)
    x = MaxPool2D((3, 3), strides=(2, 2), padding='same')(x)  # 112->56

    # stage 2 repeat 3 times
    x = conv_block(x, 3, [64, 64, 256], stage=2, block='a', strides=(1, 1))  # 56x56
    x = identity_block(x, 3, [64, 64, 256], stage=2, block='b')
    x = identity_block(x, 3, [64, 64, 256], stage=2, block='c')

    # stage 3 repeat 4 times
    x = conv_block(x, 3, [128, 128, 512], stage=3, block='a', strides=(2, 2))  # 28x28
    x = identity_block(x, 3, [128, 128, 512], stage=3, block='b')  # defa
    x = identity_block(x, 3, [128, 128, 512], stage=3, block='c')
    x = identity_block(x, 3, [128, 128, 512], stage=3, block='d')

    # stage 4 repeat 6 times
    x = conv_block(x, 3, [256, 256, 1024], stage=4, block='a', strides=(2, 2))  # 14x14
    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')

    # stage 5 repeat 3 times
    x = conv_block(x, 3, [512, 512, 2048], stage=5, block='a', strides=(2, 2))  # 7x7
    x = identity_block(x, 3, [512, 512, 2048], stage=5, block='b')
    x = identity_block(x, 3, [512, 512, 2048], stage=5, block='c')

    # fc
    if include_top:
        x = GlobalAveragePooling2D(name='avg_pool')(x)
        x = Dense(classes, activation='softmax', name='fc1000')(x)

    model = Model(inputs=[inputs], outputs=[x], name='resnet50')
    return model


# set input
inputs = Input(shape=(224, 224, 3))

# build model
model = ResNet50(inputs)

# plot model structure
plot_model(model, to_file='res50.png', show_shapes=True)
resnet50

相关文章

网友评论

      本文标题:keras ResNet50

      本文链接:https://www.haomeiwen.com/subject/gojupqtx.html