使用keras框架,给出MobileNetV3的神经网络模型实现
以下是MobileNetV3的神经网络模型实现,使用了Keras框架:
from keras import layers
from keras.models import Model
def _make_divisible(v, divisor, min_value=None):
"""
This function is taken from the original tf repo.
It ensures that all layers have a channel number that is divisible by 8
It can be seen here:
https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py
"""
if min_value is None:
min_value = divisor
new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
# Make sure that round down does not go down by more than 10%.
if new_v < 0.9 * v:
new_v += divisor
return new_v
def _relu6(x):
"""Relu 6
"""
return layers.ReLU(max_value=6)(x)
def _hard_swish(x):
"""Hard swish
"""
return layers.Multiply()([layers.Activation(_relu6)(x), x])
def _conv_block(inputs, filters, kernel, strides):
"""Convolution Block
This function defines a 2D convolution operation with BN and relu6.
# Arguments
inputs: Tensor, input tensor of conv layer.
filters: Integer, the dimensionality of the output space.
kernel: An integer or tuple/list of 2 integers, specifying the width and
height of the 2D convolution window.
strides: An integer or tuple/list of 2 integers,
specifying the strides of the convolution along the width and height.
Can be a single integer to specify the same value for all spatial dimensions.
# Returns
Output tensor.
"""
channel_axis = 1 if layers.K.image_data_format() == 'channels_first' else -1
filters = _make_divisible(filters, 8)
x = layers.Conv2D(filters, kernel, padding='same', strides=strides, kernel_initializer='he_normal', use_bias=False)(inputs)
x = layers.BatchNormalization(axis=channel_axis)(x)
return layers.Activation(_relu6)(x)
def _bottleneck(inputs, filters, kernel, up_dim, stride, use_se):
"""Bottleneck
This function defines a basic bottleneck structure.
# Arguments
inputs: Tensor, input tensor of conv layer.
filters: Integer, the dimensionality of the output space.
kernel: An integer or tuple/list of 2 integers, specifying the width and
height of the 2D convolution window.
up_dim: Integer, scaling ratio for the upsample layer.
stride: An integer or tuple/list of 2 integers,
specifying the strides of the convolution along the width and height.
Can be a single integer to specify the same value for all spatial dimensions.
use_se: Boolean, whether to use SE module.
# Returns
Output tensor.
"""
channel_axis = 1 if layers.K.image_data_format() == 'channels_first' else -1
filters = _make_divisible(filters, 8)
up_pointwise_filters = _make_divisible(up_dim, 8)
x = _conv_block(inputs, up_pointwise_filters, (1, 1), (1, 1))
x = layers.DepthwiseConv2D(kernel, strides=(stride, stride), depthwise_initializer='he_normal', padding='same', use_bias=False)(x)
x = layers.BatchNormalization(axis=channel_axis)(x)
x = layers.Activation(_relu6)(x)
if use_se:
x = _se_block(x, filters)
x = layers.Conv2D(filters, (1, 1), padding='same', use_bias=False, kernel_initializer='he_normal')(x)
x = layers.BatchNormalization(axis=channel_axis)(x)
if stride == 1 and x.shape[channel_axis] == inputs.shape[channel_axis]:
x = layers.Add()([x, inputs])
return x
def _se_block(inputs, filters):
"""Squeeze and Excitation block
This function defines a squeeze and excitation block.
# Arguments
inputs: Tensor, input tensor of conv layer.
filters: Integer, the dimensionality of the output space.
# Returns
Output tensor.
"""
channel_axis = 1 if layers.K.image_data_format() == 'channels_first' else -1
se_shape = (1, 1, filters)
se = layers.GlobalAveragePooling2D()(inputs)
se = layers.Reshape(se_shape)(se)
se = layers.Conv2D(filters // 4, (1, 1), padding='same', activation=_relu6, kernel_initializer='he_normal', use_bias=False)(se)
se = layers.Conv2D(filters, (1, 1), padding='same', activation='sigmoid', kernel_initializer='he_normal', use_bias=False)(se)
x = layers.Multiply()([inputs, se])
return x
def MobileNetV3Small(input_shape, num_classes):
"""MobileNetv3 small model
This function defines a MobileNetv3 small model.
# Arguments
input_shape: An integer or tuple/list of 3 integers, shape
of input tensor.
num_classes: Number of classes.
# Returns
MobileNetv3 small model.
"""
inputs = layers.Input(shape=input_shape)
x = _conv_block(inputs, 16, (3, 3), strides=(2, 2))
x = _bottleneck(x, 16, (3, 3), up_dim=16, stride=2, use_se=False)
x = _bottleneck(x, 24, (3, 3), up_dim=72, stride=2, use_se=False)
x = _bottleneck(x, 24, (3, 3), up_dim=88, stride=1, use_se=False)
x = _bottleneck(x, 40, (5, 5), up_dim=96, stride=2, use_se=True)
x = _bottleneck(x, 40, (5, 5), up_dim=240, stride=1, use_se=True)
x = _bottleneck(x, 40, (5, 5), up_dim=240, stride=1, use_se=True)
x = _bottleneck(x, 48, (5, 5), up_dim=120, stride=1, use_se=True)
x = _bottleneck(x, 48, (5, 5), up_dim=144, stride=1, use_se=True)
x = _bottleneck(x, 96, (5, 5), up_dim=288, stride=2, use_se=True)
x = _bottleneck(x, 96, (5, 5), up_dim=576, stride=1, use_se=True)
x = _bottleneck(x, 96, (5, 5), up_dim=576, stride=1, use_se=True)
x = _conv_block(x, 576, (1, 1), strides=(1, 1))
x = layers.GlobalAveragePooling2D()(x)
x = layers.Reshape((1, 1, 576))(x)
x = layers.Conv2D(1024, (1, 1), padding='same', use_bias=False, kernel_initializer='he_normal')(x)
x = layers.BatchNormalization()(x)
x = layers.Activation(_hard_swish)(x)
x = layers.Conv2D(num_classes, (1, 1), padding='same', kernel_initializer='he_normal')(x)
x = layers.Flatten()(x)
x = layers.Activation('softmax')(x)
model = Model(inputs, x)
return model
原文地址: https://www.cveoy.top/t/topic/zFE 著作权归作者所有。请勿转载和采集!