import os
import warnings
import h5py
import numpy as np
from keras.models import Model
from keras.layers import Input
from keras.layers import Activation
from keras.layers import Dropout
from keras.layers import Reshape
from keras.layers import BatchNormalization
from keras.layers import GlobalAveragePooling2D
from keras.layers import GlobalMaxPooling2D
from keras.layers import Conv2D
from keras.layers import AveragePooling2D
from keras.layers import Flatten
from keras.layers import Add, Multiply
from keras.layers import Dense
from keras.layers import DepthwiseConv2D
from keras import initializers
from keras import regularizers
from keras import constraints
from keras.utils import conv_utils
from keras.utils.data_utils import get_file
from keras.engine.topology import get_source_inputs
from keras.engine import InputSpec
from keras.applications import imagenet_utils
from keras.applications.imagenet_utils import _obtain_input_shape
from keras.applications.imagenet_utils import decode_predictions
from keras import backend as K
def relu6(x):
return K.relu(x, max_value=6)
def hard_swish(x):
return x*K.relu(x+3.0, max_value=6.0)/6.0
def preprocess_input(x):
x /= 128.
x -= 1.
return x.astype(np.float32)
def _make_divisible(v, divisor, min_value=None):
if min_value is None:
min_value = divisor
new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
if new_v < 0.9 * v:
new_v += divisor
return new_v
def _inverted_res_block(inputs, expansion, stride, alpha, filters, block_id):
in_channels = inputs._keras_shape[-1]
# prefix = 'features.' + str(block_id) + '.conv.'
pointwise_conv_filters = int(filters * alpha)
pointwise_filters = _make_divisible(pointwise_conv_filters, 8)
# Expand
x = Conv2D(expansion * in_channels, kernel_size=1, padding='same', use_bias=False, activation=None,
name='mobl%d_conv_%d_expand' % (block_id, block_id))(inputs)
x = BatchNormalization(epsilon=0.001, name='bn%d_conv_%d_bn_expand' %
(block_id, block_id))(x)
x = Activation(relu6, name='conv_%d_relu' % block_id)(x)
# x = Activation(hard_swish, name='conv_%d_relu' % block_id)(x)
# Depthwise
x = DepthwiseConv2D(kernel_size=3, strides=stride, activation=None, use_bias=False, padding='same',
name='mobl%d_conv_%d_depthwise' % (block_id, block_id))(x)
x = BatchNormalization(epsilon=0.001, name='bn%d_conv_%d_bn_depthwise' %
(block_id, block_id))(x)
x = Activation(relu6, name='conv_dw_%d_relu' % block_id)(x)
# x = Activation(hard_swish, name='conv_dw_%d_relu' % block_id)(x)
# 引入注意力机制
# if stride==2:
# x = squeeze_dw(x, block_id=block_id)
# Project
x = Conv2D(pointwise_filters, kernel_size=1, padding='same', use_bias=False,
activation=None, name='mobl%d_conv_%d_project' % (block_id, block_id))(x)
x = BatchNormalization(epsilon=0.001, name='bn%d_conv_%d_bn_project' %
(block_id, block_id))(x)
if in_channels == pointwise_filters and stride == 1:
return Add(name='res_connect_' + str(block_id))([inputs, x])
return x
def _first_inverted_res_block(inputs, expansion, stride, alpha, filters, block_id):
in_channels = inputs._keras_shape[-1]
# prefix = 'features.' + str(block_id) + '.conv.'
pointwise_conv_filters = int(filters * alpha)
pointwise_filters = _make_divisible(pointwise_conv_filters, 8)
# Depthwise
x = DepthwiseConv2D(kernel_size=3, strides=stride, activation=None, use_bias=False, padding='same',
name='mobl%d_conv_%d_depthwise' % (block_id, block_id))(inputs)
x = BatchNormalization(epsilon=0.001, name='bn%d_conv_%d_bn_depthwise' %
(block_id, block_id))(x)
x = Activation(relu6, name='conv_dw_%d_relu' % block_id)(x)
# x = Activation(hard_swish, name='conv_dw_%d_relu' % block_id)(x)
# Project
x = Conv2D(pointwise_filters, kernel_size=1, padding='same', use_bias=False,
activation=None, name='mobl%d_conv_%d_project' % (block_id, block_id))(x)
x = BatchNormalization(epsilon=0.001, name='bn%d_conv_%d_bn_project' %
(block_id, block_id))(x)
if in_channels == pointwise_filters and stride == 1:
return Add(name='res_connect_' + str(block_id))([inputs, x])
return x
def squeeze_dw(inputs, block_id=0):
# 注意力机制单元
input_channels = int(inputs.shape[-1])
x = GlobalAveragePooling2D(name="conv_dw_%d_se_gap" % block_id)(inputs)
x = Dense(int(input_channels / 16), kernel_initializer='random_uniform', name="conv_dw_%d_se_fc1" % block_id)(x)
x = Activation(K.relu, name="conv_dw_%d_se_relu" % block_id)(x)
x = Dense(input_channels, kernel_initializer='random_uniform', name="conv_dw_%d_se_fc2" % block_id)(x)
x = Activation(K.sigmoid, name="conv_dw_%d_se_sigmoid" % block_id)(x)
x = Reshape((1, 1, input_channels), name="conv_dw_%d_se_reshape" % block_id)(x)
x = Multiply()([inputs, x])
return x
def MobileNet_V2(inputs,embedding_size=128,dropout_keep_prob=0.4, alpha=1.0, depth_multiplier=1):
# 32
first_block_filters = _make_divisible(32 * alpha, 8)
# 160,160,3 -> 80,80,32
x = Conv2D(first_block_filters, kernel_size=3, strides=(2, 2), padding='same',
use_bias=False, name='Conv1')(inputs)
x = BatchNormalization(epsilon=1e-5, name='bn_Conv1')(x)
x = Activation(relu6, name='Conv1_relu')(x)
# 80,80,32 -> 80,80,16
x = _first_inverted_res_block(x, filters=16, alpha=alpha, stride=1, expansion=1, block_id=0)
# 80,80,16 -> 40,40,24
x = _inverted_res_block(x, filters=24, alpha=alpha, stride=2, expansion=6, block_id=1)
x = _inverted_res_block(x, filters=24, alpha=alpha, stride=1, expansion=6, block_id=2)
# 40,40,24 -> 20,20,32
x = _inverted_res_block(x, filters=32, alpha=alpha, stride=2, expansion=6, block_id=3)
x = _inverted_res_block(x, filters=32, alpha=alpha, stride=1, expansion=6, block_id=4)
x = _inverted_res_block(x, filters=32, alpha=alpha, stride=1,expansion=6, block_id=5)
# 20,20,32 -> 10,10,64
x = _inverted_res_block(x, filters=64, alpha=alpha, stride=2, expansion=6, block_id=6)
x = _inverted_res_block(x, filters=64, alpha=alpha, stride=1, expansion=6, block_id=7)
x = _inverted_res_block(x, filters=64, alpha=alpha, stride=1, expansion=6, block_id=8)
x = _inverted_res_block(x, filters=64, alpha=alpha, stride=1, expansion=6, block_id=9)
# 10,10,64 -> 10,10,96
x = _inverted_res_block(x, filters=96, alpha=alpha, stride=1, expansion=6, block_id=10)
x = _inverted_res_block(x, filters=96, alpha=alpha, stride=1, expansion=6, block_id=11)
x = _inverted_res_block(x, filters=96, alpha=alpha, stride=1, expansion=6, block_id=12)
# 10,10,96 -> 5, 5, 160
x = _inverted_res_block(x, filters=160, alpha=alpha, stride=2, expansion=6, block_id=13)
x = _inverted_res_block(x, filters=160, alpha=alpha, stride=1, expansion=6, block_id=14)
x = _inverted_res_block(x, filters=160, alpha=alpha, stride=1, expansion=6, block_id=15)
# 5, 5, 160 -> 5, 5, 320
x = _inverted_res_block(x, filters=320, alpha=alpha, stride=1, expansion=6, block_id=16)
# 5, 5, 320 -> 5, 5, 1280
x = Conv2D(1280, kernel_size=1, use_bias=False, name='Conv_1')(x)
x = BatchNormalization(epsilon=0.001, name='Conv_1_bn')(x)
x = Activation(relu6, name='out_relu')(x)
# 5, 5, 1280 -> 1280
# pool_size = tuple(x.get_shape().as_list()[1:3])
# x = AveragePooling2D(pool_size=pool_size)(x)
# x = Flatten()(x)
x = GlobalAveragePooling2D()(x)
# 防止网络过拟合,训练的时候起作用
x = Dropout(1.0 - dropout_keep_prob, name='Dropout')(x)
# 全连接层到128
# 128
x = Dense(embedding_size,use_bias=False, name='Bottleneck')(x)
x = BatchNormalization(momentum=0.995, epsilon=0.001, scale=False,
name='BatchNorm_Bottleneck')(x)
model = Model(inputs, x, name='mobilenet_v2')
return model
if __name__ == '__main__':
inputs = Input([160, 160, 3])
model = MobileNet_V2(inputs)
model.summary()
mobilenet_v2
最新推荐文章于 2025-07-15 14:07:32 发布
本文详细介绍了MobileNet V2模型的设计,包括扩张瓶颈块、深度可分离卷积和注意力机制的应用。通过Alpha参数调整,实现在保持准确性的前提下降低计算复杂度,适用于移动端和资源受限设备的部署。
984

被折叠的 条评论
为什么被折叠?



