让我们开始实现ResNet-34.
一、创建一个ResidualUnit层。
from functools import partial
import tensorflow as tf
from tensorflow import keras
DefaultConv2D = partial(keras.layers.Conv2D, kernel_size=3, strides=1,
padding="SAME", use_bias=False)
class ResidualUnit(keras.layers.Layer):
def __init__(self, filters, strides=1, activation="relu", **kwargs):
super().__init__(**kwargs)
self.activation = keras.activations.get(activation)
self.main_layers = [
DefaultConv2D(filters, strides=strides),
keras.layers.BatchNormalization(),
self.activation,
DefaultConv2D(filters),
keras.layers.BatchNormalization()]
self.skip_layers = []
if strides > 1:
self.skip_layers = [
DefaultConv2D(filters, kernel_size=1, strides=strides),
keras.layers.BatchNormalization()]
def call(self, inputs):
Z = inputs
for layer in self.main_layers:
Z = layer(Z)
skip_Z = inputs
for layer in self.skip_layers:
skip_Z = layer(skip_Z)
return self.activation(Z + skip_Z)
由上,在构造函数中,我们创建了所需要的所有层:
主要层、跳过层(当步幅大于1时需要)。
在call()方法中,我们使输入经过主要层、跳过层,然后添加输出层并应用激活函数。
二、用Sequential 模型来构建ResNet-34.
这个模型 实际上是一个 非常长的 层序列。
现在有了上面的ResidualUnit类,我们可以将每个残差单元是为一个层。
model = keras.models.Sequential()
model.add(DefaultConv2D(64, kernel_size=7, strides=2,
input_shape=[224, 224, 3]))
model.add(keras.layers.BatchNormalization())
model.add(keras.layers.Activation("relu"))
model.add(keras.layers.MaxPool2D(pool_size=3, strides=2, padding="SAME"))
prev_filters = 64
for filters in [64] * 3 + [128] * 4 + [256] * 6 + [512] * 3:
strides = 1 if filters == prev_filters else 2
model.add(ResidualUnit(filters, strides=strides))
prev_filters = filters
model.add(keras.layers.GlobalAvgPool2D())
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(10, activation="softmax"))
这里将ResidualUnit 层 加到模型的循环:
前3个RU(残差单元) 具有64个滤波器,然后余下4个有128个。以此类推。
当滤波器的数量与上一个RU层相同时,将步幅设置为1,否则为2.
然后添加ResidualUnit ,最后更新prev_filters.
三、别忘了实例化模型。
model.summary()
结果:
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 112, 112, 64) 9408
batch_normalization (BatchN (None, 112, 112, 64) 256
ormalization)
activation (Activation) (None, 112, 112, 64) 0
max_pooling2d (MaxPooling2D (None, 56, 56, 64) 0
)
residual_unit (ResidualUnit (None, 56, 56, 64) 74240
)
residual_unit_1 (ResidualUn (None, 56, 56, 64) 74240
it)
residual_unit_2 (ResidualUn (None, 56, 56, 64) 74240
it)
residual_unit_3 (ResidualUn (None, 28, 28, 128) 230912
it)
residual_unit_4 (ResidualUn (None, 28, 28, 128) 295936
it)
residual_unit_5 (ResidualUn (None, 28, 28, 128) 295936
it)
residual_unit_6 (ResidualUn (None, 28, 28, 128) 295936
it)
residual_unit_7 (ResidualUn (None, 14, 14, 256) 920576
it)
residual_unit_8 (ResidualUn (None, 14, 14, 256) 1181696
it)
residual_unit_9 (ResidualUn (None, 14, 14, 256) 1181696
it)
residual_unit_10 (ResidualU (None, 14, 14, 256) 1181696
nit)
residual_unit_11 (ResidualU (None, 14, 14, 256) 1181696
nit)
residual_unit_12 (ResidualU (None, 14, 14, 256) 1181696
nit)
residual_unit_13 (ResidualU (None, 7, 7, 512) 3676160
nit)
residual_unit_14 (ResidualU (None, 7, 7, 512) 4722688
nit)
residual_unit_15 (ResidualU (None, 7, 7, 512) 4722688
nit)
global_average_pooling2d (G (None, 512) 0
lobalAveragePooling2D)
flatten (Flatten) (None, 512) 0
dense (Dense) (None, 10) 5130
=================================================================
Total params: 21,306,826
Trainable params: 21,289,802
Non-trainable params: 17,024
_________________________________________________________________
参考:
Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow, 2nd Edition, 作者: Aurelien Geron(法语) , 又 O Reilly 出版, 书号 978-1-492-03264-9。