介绍
作者希望找到一个可以同时兼顾速度与精度的模型放缩方法,为此,作者重新审视了前人提出的模型放缩的几个维度:网络深度、网络宽度、图像分辨率,前人的文章多是放大其中的一个维度以达到更高的准确率,比如 ResNet-18 到 ResNet-152 是通过增加网络深度的方法来提高准确率。
图中红色的那条就是 EfficientNet 的曲线,横轴为模型大小,纵轴为准确率。这个网络还是比较牛的。
问题抽象化
w、d、r 分别是网络宽度,网络高度,分辨率的倍率。
实验
第一个实验,对三个维度固定两个,只放大其中一个,得到结果如下:
图中从左至右分别是只放大网络宽度(width, w 为放大倍率)、网络深度(depth, d 为放大倍率)、图像分辨率(resolution, r 为放大倍率) 的结果,可以观察到单个维度的放大最高精度只在 80 左右。本次实验作者得出一个观点:三个维度中任一维度的放大都可以带来精度的提升,但随着倍率越来越大,提升却越来越小。
第二个实验,尝试在不同的 d, r 组合下变动 w,得到下图:
得到更高的精度以及效率的关键是平衡网络宽度,网络深度,图像分辨率三个维度的放缩倍率(d, r, w)。
混合维度放大法&EfficientNet-B0~B7
为了找到满足前面工事中的3个维度参数,这篇论文引入Φ参数,并将3个待优化参数都用Φ指数表示。
作者提出了一种混合维度放大法(compound scaling method),该方法使用一个混合系数来决定三个维度的放大倍率:
准备好优化公式后,作者还通过网络结构搜索设计了一个baseline网络,也就是EfficientNet-B0:
class MBConv(tf.keras.layers.Layer):
def __init__(self, in_channels, out_channels, expansion_factor, stride, k, drop_connect_rate):
super(MBConv, self).__init__()
self.in_channels = in_channels
self.out_channels = out_channels
self.stride = stride
self.drop_connect_rate = drop_connect_rate
self.conv1 = tf.keras.layers.Conv2D(filters=in_channels * expansion_factor,
kernel_size=(1, 1),
strides=1,
padding="same")
self.bn1 = tf.keras.layers.BatchNormalization()
self.dwconv = tf.keras.layers.DepthwiseConv2D(kernel_size=(k, k),
strides=stride,
padding="same")
self.bn2 = tf.keras.layers.BatchNormalization()
self.se = SEBlock(input_channels=in_channels * expansion_factor)
self.conv2 = tf.keras.layers.Conv2D(filters=out_channels,
kernel_size=(1, 1),
strides=1,
padding="same")
self.bn3 = tf.keras.layers.BatchNormalization()
self.dropout = tf.keras.layers.Dropout(rate=drop_connect_rate)
def call(self, inputs, training=None, **kwargs):
x = self.conv1(inputs)
x = self.bn1(x, training=training)
x = swish(x)
x = self.dwconv(x)
x = self.bn2(x, training=training)
x = self.se(x)
x = swish(x)
x = self.conv2(x)
x = self.bn3(x, training=training)
if self.stride == 1 and self.in_channels == self.out_channels:
if self.drop_connect_rate:
x = self.dropout(x, training=training)
x = tf.keras.layers.add([x, inputs])
return x
优化求解:
- 第一步是固定Φ=1,然后通过网格搜索找到满足公式3的最优α、β、γ,比如对于EfficientNet-B0网络而言,最佳的参数分别是α=1.2、β=1.1、γ=1.15(此时得到的也就是EfficientNet-B1)。
- 第二步是固定第一步求得的α、β、γ参数,然后用不同的Φ参数得到EfficientNet-B1到EfficientNet-B7网络
EfficientNet-B1~B7相对于B0来说改变了4个参数:width_coefficient, depth_coefficient, resolution和dropout_rate,分别是宽度系数、深度系数、输入图片分辨率和dropout比例。具体参数如下:
b0 = get_efficient_net(1.0, 1.0, 224, 0.2)
b1 = get_efficient_net(1.0, 1.1, 240, 0.2)
b2 = get_efficient_net(1.1, 1.2, 260, 0.3)
b3 = get_efficient_net(1.2, 1.4, 300, 0.3)
b4 = get_efficient_net(1.4, 1.8, 380, 0.4)
b5 = get_efficient_net(1.6, 2.2, 456, 0.4)
b6 = get_efficient_net(1.8, 2.6, 528, 0.5)
b7 = get_efficient_net(2.0, 3.1, 600, 0.5)
参考:
https://www.jianshu.com/p/2ac06d97a830
https://blog.csdn.net/u014380165/article/details/90812249
https://zhuanlan.zhihu.com/p/84836782