tf.keras.applications.resnet50.ResNet50(
include_top=True,
weights='imagenet',
input_tensor=None,
input_shape=None,
pooling=None,
classes=1000,
**kwargs
)
- include_top:是否保留顶层的全连接网络 -- True为保留
- weights:None代表随机初始化,即不加载预训练权重;'imagenet’代表加载预训练权重。
- input_tensor:可填入Keras tensor作为模型的图像输出tensor
- input_shape:可选,仅当include_top=False有效,应为长为3的tuple,指明输入图片的shape,图片的宽高必须大于197,如(200,200,3)
- pooling:当include_top=False时,该参数指定了池化方式。None代表不池化,最后一个卷积层的输出为4D张量。‘avg’代表全局平均池化,‘max’代表全局最大值池化。
- classes:可选,图片分类的类别数,仅当include_top=True并且不加载预训练权重时可用。
分解Resnet50内部结构,笔记来源于:keras构建resnet50网络代码解读 - 简书 (jianshu.com)
1. Resnet50的整体结构框图:
2. ResNet50代码:
def ResNet50(input_shape=[224,224,3],classes=1000):
# [224,224,3]
img_input = Input(shape=input_shape)
x = ZeroPadding2D((3, 3))(img_input) # [230,230,3]
# [112,112,64]
x = Conv2D(64, (7, 7), strides=(2, 2), name='conv1')(x) #[112,112,64]
x = BatchNormalization(name='bn_conv1')(x)
x = Activation('relu')(x)
# [56,56,64]
x = MaxPooling2D((3, 3), strides=(2, 2))(x)
# [56,56,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')
# [28,28,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')
# [14,14,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')
# [7,7,2048]
x = conv_block(x, 3, [512, 512, 2048], stage=5, block='a')
x = identity_block(x, 3, [512, 512, 2048], stage=5, block='b')
x = identity_block(x, 3, [512, 512, 2048], stage=5, block='c')
# 代替全连接层
x = AveragePooling2D((7, 7), name='avg_pool')(x)
# 进行预测
x = Flatten()(x)
x = Dense(classes, activation='softmax', name='fc1000')(x)
model = Model(img_input, x, name='resnet50')
return model
x = ZeroPadding2D((3, 3))(img_input)
:在img_input
的外围进行padding=0的填充,填充数量为3个像素点,最后得到的维度为224+3*2 = 230,所以x的维度为230,230,3。
输入图像的尺寸为[224, 224, 3],经过简单的卷积和池化操作后形状变为[56, 56, 64]。接下来,就是ResNet50网络的重点,Conv Block和Identity Block。下面我们分别以第一次使用Conv Block和Identity Block为例,讲解这两个模块内部是如何操作的。
3. Conv Block模块
def conv_block(input_tensor, kernel_size, filters, stage, block, strides=(2, 2)):
# 64,64,256
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), strides=strides,
name=conv_name_base + '2a')(input_tensor)
x = BatchNormalization(name=bn_name_base + '2a')(x)
x = Activation('relu')(x)
# 3x3卷积
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
4. Idnetity 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)
# 3x3卷积
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)
x = layers.add([x, input_tensor])
x = Activation('relu')(x)
return x