由于ResNet模型结构 比之前几篇介绍基础模型 复杂,这里使用Functional模型(即函数式模型)来替代 Sequential模型,因为Functional模型使用起来更加灵活,可以处理分支网络等情况。
ResNet Block包含了1个卷积层,1个BN层(对输出参数做归一化,使网络更易训练,一般地,加了BN层的网络,可以不必再用Droput层),1个激活层。
def resnet_block(inputs, num_filters = 16,
kernel_size = 3,
strides = 1,
activation = 'relu'):
x = Conv2D(num_filters,
kernel_size = kernel_size,
strides = strides,
padding = 'same',
kernel_initializer = 'he_normal',
kernel_regularizer = l2(1e-4))(inputs)
x = BatchNormalization()(x)
if (activation):
x = Activation('relu')(x)
return x
其中,在卷积层中加入L2正则化,可以提高模型泛化能力。
注意,在Functional模型中,必须初始化模型,才真正完成模型的搭建。
def resnet_simple(input_shape):
inputs = Input(shape = input_shape)
# 第1层
x = resnet_block(inputs)
# 第2-7层
for i in range(6):
a = resnet_block(inputs = x)
b = resnet_block(inputs = a, activation=None)
x = keras.layers.add([x, b])
x = Activation('relu')(x)
# 第8-13层
for i in range(6):
if i == 0:
a = resnet_block(inputs = x,
strides = 2,
num_filters = 32)
else:
a = resnet_block(inputs = x,
num_filters = 32)
b = resnet_block(inputs = a,
activation = None,
num_filters = 32)
if i == 0:
x = Conv2D(32, kernel_size=3,
strides = 2,
padding = 'same',
kernel_initializer = 'he_normal',
kernel_regularizer = l2(1e-4))(x)
x = keras.layers.add([x, b])
x = Activation('relu')(x)
# 第14-19层
for i in range(6):
if i == 0:
a = resnet_block(inputs = x,
strides = 2,
num_filters = 64)
else:
a = resnet_block(inputs = x,
num_filters = 64)
b = resnet_block(inputs = a,
activation = None,
num_filters = 64)
if i == 0:
x = Conv2D(64, kernel_size=3,
strides = 2,
padding = 'same',
kernel_initializer = 'he_normal',
kernel_regularizer = l2(1e-4))(x)
x = keras.layers.add([x, b])
x = Activation('relu')(x)
# 第20层
x = AveragePooling2D(pool_size=2)(x)
y = Flatten()(x)
outputs = Dense(10, activation = 'softmax',
kernel_initializer = 'he_normal')(y)
# 初始化模型
model = Model(inputs = inputs,
outputs = outputs)
return model