ResNet

ResNet

背景介绍

  ResNet:华人学者何凯明大神于2015年提出,其主要体现出了残差相连的优势,故简称ResNet,是2015年ILSVRC竞赛的第一名,是一个很好的图像特征提取模型。

ResNet

ResNet特点

  使用残差块结构,使得网络能够更多获取之前的信息,并且使学习结果对于权重的变化更加敏感
  使用瓶颈结构,先使用1x1的卷积核进行降维,最后再次使用1x1的卷积核升维,可以降低模型的参数量
  Conv Block:作用是改变图像大小,输入和输出的尺寸不同,因此无法直接残差相连
  Identity Block:作用是增加网络深度,输入和输出的尺寸相同,可以直接残差相连

不同尺寸ResNet网络结构

ResNet

ResNet50图像分析

ResNet

TensorFlow2.0实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
from functools import reduce
import tensorflow.keras as keras


def compose(*funcs):
if funcs:
return reduce(lambda f, g: lambda *a, **kw: g(f(*a, **kw)), funcs)
else:
raise ValueError('Composition of empty sequence not supported.')


class Conv_Bn_Relu(keras.layers.Layer):
def __init__(self, filters, kernel_size, strides, padding, name):
super(Conv_Bn_Relu, self).__init__()
self._name = name
self.conv = keras.layers.Conv2D(filters, kernel_size, strides, padding)
self.bn = keras.layers.BatchNormalization()
self.relu = keras.layers.ReLU()

def call(self, inputs, **kwargs):
conv = self.conv(inputs)
bn = self.bn(conv)
output = self.relu(bn)

return output


class Conv_Bn(keras.layers.Layer):
def __init__(self, filters, kernel_size, strides, padding, name):
super(Conv_Bn, self).__init__()
self._name = name
self.conv = keras.layers.Conv2D(filters, kernel_size, strides, padding)
self.bn = keras.layers.BatchNormalization()

def call(self, inputs, **kwargs):
conv = self.conv(inputs)
output = self.bn(conv)

return output


def res_block(x, filters, strides, type, name):
shortcut = x
x = compose(Conv_Bn_Relu(filters // 4, (1, 1), (1, 1), padding='same', name='{}{}_conv_bn_relu1'.format(type, name)),
Conv_Bn_Relu(filters // 4, (3, 3), strides, padding='same', name='{}{}_conv_bn_relu2'.format(type, name)),
Conv_Bn(filters, (1, 1), (1, 1), padding='same', name='{}{}_conv_bn3'.format(type, name)))(x)
if type == 'conv_block':
shortcut = keras.layers.Conv2D(filters, (1, 1), strides, name='{}{}_shortcut'.format(type, name))(shortcut)
x = keras.layers.Add(name='{}{}_add'.format(type, name))([x, shortcut])
x = keras.layers.ReLU(name='{}{}_relu3'.format(type, name))(x)

return x


def ResNet50(input_shape):
input_tensor = keras.layers.Input(input_shape, name='input')
x = input_tensor
x = compose(keras.layers.ZeroPadding2D((3, 3), name='zeropadding'),
Conv_Bn_Relu(64, (7, 7), (2, 2), padding='valid', name='conv_bn_relu'),
keras.layers.MaxPool2D((3, 3), (2, 2), padding='same', name='maxpool'))(x)
filters = [256, 512, 1024, 2048]
strides = [(1, 1), (2, 2), (2, 2), (2, 2)]
times = [3, 4, 6, 3]
for i in range(len(times)):
x = res_block(x, filters[i], strides[i], 'conv_block', i + 1)
for j in range(times[i] - 1):
x = res_block(x, filters[i], (1, 1), 'identity_block{}_'.format(i + 1), j + 1)
x = compose(keras.layers.GlobalAveragePooling2D(name='global_averagepool'),
keras.layers.Dense(1000, activation='softmax', name='dense'))(x)
model = keras.Model(input_tensor, x, name='ResNet50')

return model


if __name__ == '__main__':

model = resnet50(input_shape=(224, 224, 3))
model.build(input_shape=(None, 224, 224, 3))
model.summary()

ResNet

ResNet小结

  ResNet是一种非常有效的特征提取网络,由于减少了Dense层的数量,因此参数量相比于VGG大大减少,参数量只有25M,因此实际任务经常使用。

-------------本文结束感谢您的阅读-------------
0%