当前位置: 代码迷 >> 综合 >> EfficientNet 网络原理与 Tensorflow2.0 实现
  详细解决方案

EfficientNet 网络原理与 Tensorflow2.0 实现

热度:110   发布时间:2023-10-28 13:37:53.0

文章目录

  • 介绍
  • 网络参数优化方法
  • 网络效果
  • 代码实现

介绍

2019 年,Google 在 Ef?cientNet: Rethinking Model Scaling for Convolutional Neural Networks 一文中提出了 EfficientNet。和 MnasNet 一样,EfficientNet 也使用了神经架构搜索方法。不同的是,EfficientNet 使用该方法搜索的是一个 Baseline 网络,称之为 EfficientNet-B0,然后对该 Baseline 网络的参数进行优化从而得到最终的网络。

网络参数优化方法

在以前的研究中可以看到,对卷积网络进行扩展可以获得更好的性能,这分为以下三类:

  • 扩展网络深度:比如 ResNet,从18层扩展到200层;
  • 扩展网络宽度(增加卷积核数量);
  • 扩展网络输入图片的分辨率(比较少见)。

但是之前的研究只是关注这三者之一,如果要同时扩展这三者,则通常需要手工进行繁琐的网络优化,而效果也并不理想。下图是网络扩展的几种形式:
在这里插入图片描述

作者分别对同一个 Baseline 网络单独进行深度,宽度,图像分辨率扩展所带来的性能提升如下图所示:
在这里插入图片描述
图中,w、d、r 分别是网络宽度,网络高度,分辨率相对于 Baseline 网络的倍率。

从上图可以看到,三个维度中任一维度的放大都可以带来精度的提升,但随着倍率越来越大,提升却越来越小。

在不同的 d, r 组合下变动 w 时,效果如下:
在这里插入图片描述
从实验结果可以看出最高精度比之前已经有所提升,且不同的组合效果还不一样,最高可以到 82% 左右。因此,得到更高的精度以及效率的关键是平衡网络宽度,网络深度,图像分辨率三个维度的放缩倍率 (d, r, w)。

首先,作者采用 NAS 搜索的方式设计了一个有效的 Baseline 网络,命名为 EfficientNet-B0,网络的结构如下:
在这里插入图片描述
这个网络结构和 MnasNet 非常相似。另外在这个 MBConv 的模块中还增加了 SE 模块。

基于这个 Baseline 模型,作者提出了一种混合维度放大法 (compound scaling method),该方法使用一个放大系数 ?\phi? 来决定三个维度的放大倍率:
在这里插入图片描述

  • 第一步,首先固定 ?\phi? 为 1,在这样一个小模型上做网格搜索 (grid search),得到了最佳系数为 α=1.2,β=1.1,γ=1.15\alpha=1.2,\beta=1.1,\gamma=1.15α=1.2,β=1.1,γ=1.15
  • 第二步,固定 α=1.2,β=1.1,γ=1.15\alpha=1.2,\beta=1.1,\gamma=1.15α=1.2,β=1.1,γ=1.15,使用不同的混合系数 ?\phi?(从 1 到 7) 来放大初代网络得到 EfficientNet-B1 ~ EfficientNet-B7。

网络效果

在这里插入图片描述
在这里插入图片描述

代码实现

import tensorflow as tf
import mathdef swish(x):return x * tf.nn.sigmoid(x)def round_filters(filters, multiplier):depth_divisor = 8min_depth = Nonemin_depth = min_depth or depth_divisorfilters = filters * multipliernew_filters = max(min_depth, int(filters + depth_divisor / 2) // depth_divisor * depth_divisor)if new_filters < 0.9 * filters:new_filters += depth_divisorreturn int(new_filters)def round_repeats(repeats, multiplier):if not multiplier:return repeatsreturn int(math.ceil(multiplier * repeats))def conv_bn(x, filters, kernel_size, strides, activation=True):x = tf.keras.layers.Conv2D(filters=filters, kernel_size=kernel_size, strides=strides, padding='SAME')(x)x = tf.keras.layers.BatchNormalization()(x)if activation:x = swish(x)return xdef depthwiseConv_bn(x, kernel_size, strides):x = tf.keras.layers.DepthwiseConv2D(kernel_size, padding='same', strides=strides)(x)x = tf.keras.layers.BatchNormalization()(x)x = tf.keras.layers.Activation(tf.nn.relu6)(x)return xdef Squeeze_excitation_layer(x):inputs = xsqueeze = inputs.shape[-1]/2excitation = inputs.shape[-1]x = tf.keras.layers.GlobalAveragePooling2D()(x)x = tf.keras.layers.Dense(squeeze)(x)x = swish(x)x = tf.keras.layers.Dense(excitation)(x)x = tf.keras.layers.Activation('sigmoid')(x)x = tf.keras.layers.Reshape((1, 1, excitation))(x)x = inputs * xreturn xdef MBConv_idskip(x, filters, drop_connect_rate, kernel_size, strides, t):x_input = xx = conv_bn(x, filters=x.shape[-1] * t, kernel_size=1, strides=1)x = depthwiseConv_bn(x, kernel_size=kernel_size, strides=strides)x = Squeeze_excitation_layer(x)x = swish(x)x = conv_bn(x, filters=filters, kernel_size=1, strides=1, activation=False)if strides==1 and x.shape[-1] == x_input.shape[-1]:if drop_connect_rate:x = tf.keras.layers.Dropout(rate=drop_connect_rate)(x)x = tf.keras.layers.add([x_input, x])return  xdef MBConv(x, filters, drop_connect_rate, kernel_size, strides, t, n):x = MBConv_idskip(x, filters, drop_connect_rate, kernel_size, strides, t)for _ in range(1, n):x = MBConv_idskip(x, filters, drop_connect_rate, kernel_size, strides=1, t=t)return xclass EfficientNet(tf.keras.Model):def __init__(self, width_coefficient, depth_coefficient, dropout_rate, n_classes=1000):super().__init__()self.width_coefficient = width_coefficientself.depth_coefficient = depth_coefficientself.dropout_rate = dropout_rateself.n_classes = n_classesdef call(self, inputs):x = conv_bn(inputs, round_filters(32, self.width_coefficient), kernel_size=3, strides=2, activation=True)x = MBConv(x, filters=round_filters(16, self.width_coefficient), kernel_size=3,drop_connect_rate=self.dropout_rate, strides=1, t=1, n=round_repeats(1, self.depth_coefficient))x = MBConv(x, filters=round_filters(24, self.width_coefficient), kernel_size=3,drop_connect_rate=self.dropout_rate, strides=2, t=6, n=round_repeats(2, self.depth_coefficient))x = MBConv(x, filters=round_filters(40, self.width_coefficient), kernel_size=5,drop_connect_rate=self.dropout_rate, strides=2, t=6, n=round_repeats(2, self.depth_coefficient))x = MBConv(x, filters=round_filters(80, self.width_coefficient), kernel_size=3,drop_connect_rate=self.dropout_rate, strides=2, t=6, n=round_repeats(3, self.depth_coefficient))x = MBConv(x, filters=round_filters(112, self.width_coefficient), kernel_size=5,drop_connect_rate=self.dropout_rate, strides=1, t=6, n=round_repeats(3, self.depth_coefficient))x = MBConv(x, filters=round_filters(192, self.width_coefficient), kernel_size=5,drop_connect_rate=self.dropout_rate, strides=2, t=6, n=round_repeats(4, self.depth_coefficient))x = MBConv(x, filters=round_filters(320, self.width_coefficient), kernel_size=3,drop_connect_rate=self.dropout_rate, strides=1, t=6, n=round_repeats(1, self.depth_coefficient))x = conv_bn(x, filters=round_filters(1280, self.width_coefficient), kernel_size=1, strides=1)x = tf.keras.layers.GlobalAveragePooling2D()(x)x = tf.keras.layers.Dropout(rate=self.dropout_rate)(x)predictions = tf.keras.layers.Dense(self.n_classes, activation='softmax')(x)return predictionsdef get_efficient_net(width_coefficient, depth_coefficient, resolution, dropout_rate):net = EfficientNet(width_coefficient=width_coefficient,depth_coefficient=depth_coefficient,dropout_rate=dropout_rate)net.build(input_shape=(None, resolution, resolution, 3))return netdef efficient_net_b0():return get_efficient_net(1.0, 1.0, 224, 0.2)def efficient_net_b1():return get_efficient_net(1.1, 1.2, 260, 0.3)def efficient_net_b2():return get_efficient_net(1.2, 1.4, 300, 0.3)def efficient_net_b3():return get_efficient_net(1.4, 1.8, 380, 0.4)def efficient_net_b4():return get_efficient_net(1.6, 2.2, 456, 0.4)def efficient_net_b5():return get_efficient_net(1.8, 2.6, 528, 0.5)def efficient_net_b6():return get_efficient_net(2.0, 3.1, 600, 0.5)def efficient_net_b7():return get_efficient_net(2.2, 3.6, 672, 0.5)
  相关解决方案