EfficientNet

EfficientNet

背景介绍

  EfficientNet:谷歌公司于2019年提出的高效神经网络,故得名为EfficientNet,大幅度的缩小了参数的同时提高了预测准确度

EfficientNet

EfficientNet特点

  和MobileNet_V3类似,在Block中先进行1x1卷积提升通道数,然后进行DepthwiseConv深度卷积减少参数量,并且在Block中引入残差结构和Squeeze-and-Excitation模块
  建立多个网络深度,网络宽度,图像分辨率不同的模型,从三个方面拓展网络性能

Depthwise Convolution

depthwise
  Depthwise Convolution(深度卷积):在每一个通道上单独进行卷积**
  参数depth_multiplier默认为1,代表每个通道数进行一次单独卷积,输出的通道数和输入通道数相等,设置depth_multiplier=n,则代表每个通道数进行n次单独卷积,输出通道数是输入通道数的n倍
  主要作用是大大降低网络的参数量。如果一个8x8x1024的特征图,经过5x5的卷积核后变为8x8x1024的图像,经过普通卷积的参数量为1024x(1024x5x5+1)=26215424,而深度卷积参数量为1024x(1x5x5+1)=26624,参数量缩小了约1024倍。

Squeeze-and-Excitation

SENet
  Squeeze-and-Excitation:又称为特征重标定卷积,或者注意力机制。具体来说,就是通过学习的方式来自动获取到每个特征通道的重要程度,然后依照这个重要程度去提升有用的特征并抑制对当前任务用处不大的特征
  首先是 Squeeze操作,先进行全局池化,具有全局的感受野,并且输出的维度和输入的特征通道数相匹配,它表征着在特征通道上响应的全局分布。
  然后是Excitation操作通过全连接层为每个特征通道生成权重,建立通道间的相关性输出的权重看做是进过特征选择后的每个特征通道的重要性,然后通过乘法逐通道加权到先前的特征上,完成在通道维度上的对原始特征的重标定。

EfficientNet基模型B0图像分析

EfficientNet

基模型B0的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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
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 Swish(keras.layers.Layer):
def __init__(self, name='swish'):
super(Swish, self).__init__()
self._name = name

def call(self, inputs, **kwargs):

return inputs * keras.activations.sigmoid(inputs)


def se_block(x, down_filters, up_filters, name):
shortcut = x
x = compose(keras.layers.GlobalAveragePooling2D(name='{}_global_averagepool'.format(name)),
keras.layers.Reshape((1, 1, up_filters), name='{}_reshape'.format(name)),
keras.layers.Conv2D(down_filters, (1, 1), activation=Swish(name='{}_swish'.format(name)), name='{}_conv1'.format(name)),
keras.layers.Conv2D(up_filters, (1, 1), activation='sigmoid', name='{}_conv2'.format(name)))(x)

x = keras.layers.Multiply(name='{}_multiply'.format(name))([x, shortcut])

return x


class Conv_Bn_Swish(keras.layers.Layer):
def __init__(self, filters, kernel_size, strides, padding, name):
super(Conv_Bn_Swish, self).__init__()
self._name = name
self.block = keras.Sequential()
if name.find('depthwise') == -1:
self.block.add(keras.layers.Conv2D(filters, kernel_size, strides, padding=padding))
else:
self.block.add(keras.layers.DepthwiseConv2D(kernel_size, strides, padding=padding))
self.block.add(keras.layers.BatchNormalization())
if name.find('swish') != -1:
self.block.add(Swish())

def call(self, inputs, **kwargs):

return self.block(inputs)


def block(x, in_channel, out_channel, times1, times2, kernel_size, strides, name):
shortcut = x
x = compose(Conv_Bn_Swish(in_channel * times1, (1, 1), (1, 1), 'same', name='{}_conv_bn_swish'.format(name)),
Conv_Bn_Swish(None, kernel_size, strides, 'same', name='{}_depthwiseconv_bn_swish'.format(name)))(x)

x = se_block(x, in_channel // times2, in_channel * times1, name='{}_se_block'.format(name))

x = Conv_Bn_Swish(out_channel, (1, 1), (1, 1), 'same', name='{}_conv_bn'.format(name))(x)

if in_channel == out_channel and strides == (1, 1):
x = keras.layers.Add(name='{}_add'.format(name))([x, shortcut])

return x


def efficientnet(input_shape):
input_tensor = keras.layers.Input(input_shape, name='input')
x = input_tensor

x = compose(keras.layers.ZeroPadding2D(name='zeropadding'),
Conv_Bn_Swish(32, (3, 3), (2, 2), 'valid', name='conv_bn_swish1'))(x)

x = block(x, in_channel=32, out_channel=16, times1=1, times2=4, kernel_size=(3, 3), strides=(1, 1), name='block1')

x = block(x, in_channel=16, out_channel=24, times1=6, times2=4, kernel_size=(3, 3), strides=(2, 2), name='block2_1')
x = block(x, in_channel=24, out_channel=24, times1=6, times2=4, kernel_size=(3, 3), strides=(1, 1), name='block2_2')

x = block(x, in_channel=24, out_channel=40, times1=6, times2=4, kernel_size=(5, 5), strides=(2, 2), name='block3_1')
x = block(x, in_channel=40, out_channel=40, times1=6, times2=4, kernel_size=(5, 5), strides=(1, 1), name='block3_2')

x = block(x, in_channel=40, out_channel=80, times1=6, times2=4, kernel_size=(3, 3), strides=(2, 2), name='block4_1')
x = block(x, in_channel=80, out_channel=80, times1=6, times2=4, kernel_size=(3, 3), strides=(1, 1), name='block4_2')
x = block(x, in_channel=80, out_channel=80, times1=6, times2=4, kernel_size=(3, 3), strides=(1, 1), name='block4_3')

x = block(x, in_channel=80, out_channel=112, times1=6, times2=4, kernel_size=(5, 5), strides=(1, 1), name='block5_1')
x = block(x, in_channel=112, out_channel=112, times1=6, times2=4, kernel_size=(5, 5), strides=(1, 1), name='block5_2')
x = block(x, in_channel=112, out_channel=112, times1=6, times2=4, kernel_size=(5, 5), strides=(1, 1), name='block5_3')

x = block(x, in_channel=112, out_channel=192, times1=6, times2=4, kernel_size=(5, 5), strides=(2, 2), name='block6_1')
x = block(x, in_channel=192, out_channel=192, times1=6, times2=4, kernel_size=(5, 5), strides=(1, 1), name='block6_2')
x = block(x, in_channel=192, out_channel=192, times1=6, times2=4, kernel_size=(5, 5), strides=(1, 1), name='block6_3')
x = block(x, in_channel=192, out_channel=192, times1=6, times2=4, kernel_size=(5, 5), strides=(1, 1), name='block6_4')

x = block(x, in_channel=192, out_channel=320, times1=6, times2=4, kernel_size=(3, 3), strides=(1, 1), name='block7')

x = compose(Conv_Bn_Swish(1280, (1, 1), (1, 1), 'same', name='conv_bn_swish2'),
keras.layers.GlobalAveragePooling2D(name='global_averagepool'),
keras.layers.Dropout(0.2, name='dropout'),
keras.layers.Dense(1000, activation='softmax', name='dense'))(x)

model = keras.Model(input_tensor, x, name='EfficientNet')

return model


if __name__ == '__main__':

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

EfficientNet

EfficientNet小结

  EfficientNet是一种复杂的深度学习网络,从上图可以看出EfficientNet基模型B0的参数量有5M,其考虑网络深度网络宽度图像分辨率等因素的思想值得我们学习。

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