mirror of
				https://github.com/PaddlePaddle/PaddleOCR.git
				synced 2025-10-31 09:49:30 +00:00 
			
		
		
		
	
		
			
	
	
		
			252 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			252 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | #copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve. | ||
|  | # | ||
|  | #Licensed under the Apache License, Version 2.0 (the "License"); | ||
|  | #you may not use this file except in compliance with the License. | ||
|  | #You may obtain a copy of the License at | ||
|  | # | ||
|  | #    http://www.apache.org/licenses/LICENSE-2.0 | ||
|  | # | ||
|  | #Unless required by applicable law or agreed to in writing, software | ||
|  | #distributed under the License is distributed on an "AS IS" BASIS, | ||
|  | #WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
|  | #See the License for the specific language governing permissions and | ||
|  | #limitations under the License. | ||
|  | 
 | ||
|  | from __future__ import absolute_import | ||
|  | from __future__ import division | ||
|  | from __future__ import print_function | ||
|  | 
 | ||
|  | import paddle.fluid as fluid | ||
|  | from paddle.fluid.initializer import MSRA | ||
|  | from paddle.fluid.param_attr import ParamAttr | ||
|  | 
 | ||
|  | __all__ = ['MobileNetV3'] | ||
|  | 
 | ||
|  | 
 | ||
|  | class MobileNetV3(): | ||
|  |     def __init__(self, params): | ||
|  |         """
 | ||
|  |         the MobilenetV3 backbone network for detection module. | ||
|  |         Args: | ||
|  |             params(dict): the super parameters for build network | ||
|  |         """
 | ||
|  |         self.scale = params['scale'] | ||
|  |         model_name = params['model_name'] | ||
|  |         self.inplanes = 16 | ||
|  |         if model_name == "large": | ||
|  |             self.cfg = [ | ||
|  |                 # k, exp, c,  se,     nl,  s, | ||
|  |                 [3, 16, 16, False, 'relu', 1], | ||
|  |                 [3, 64, 24, False, 'relu', 2], | ||
|  |                 [3, 72, 24, False, 'relu', 1], | ||
|  |                 [5, 72, 40, True, 'relu', 2], | ||
|  |                 [5, 120, 40, True, 'relu', 1], | ||
|  |                 [5, 120, 40, True, 'relu', 1], | ||
|  |                 [3, 240, 80, False, 'hard_swish', 2], | ||
|  |                 [3, 200, 80, False, 'hard_swish', 1], | ||
|  |                 [3, 184, 80, False, 'hard_swish', 1], | ||
|  |                 [3, 184, 80, False, 'hard_swish', 1], | ||
|  |                 [3, 480, 112, True, 'hard_swish', 1], | ||
|  |                 [3, 672, 112, True, 'hard_swish', 1], | ||
|  |                 [5, 672, 160, True, 'hard_swish', 2], | ||
|  |                 [5, 960, 160, True, 'hard_swish', 1], | ||
|  |                 [5, 960, 160, True, 'hard_swish', 1], | ||
|  |             ] | ||
|  |             self.cls_ch_squeeze = 960 | ||
|  |             self.cls_ch_expand = 1280 | ||
|  |         elif model_name == "small": | ||
|  |             self.cfg = [ | ||
|  |                 # k, exp, c,  se,     nl,  s, | ||
|  |                 [3, 16, 16, True, 'relu', 2], | ||
|  |                 [3, 72, 24, False, 'relu', 2], | ||
|  |                 [3, 88, 24, False, 'relu', 1], | ||
|  |                 [5, 96, 40, True, 'hard_swish', 2], | ||
|  |                 [5, 240, 40, True, 'hard_swish', 1], | ||
|  |                 [5, 240, 40, True, 'hard_swish', 1], | ||
|  |                 [5, 120, 48, True, 'hard_swish', 1], | ||
|  |                 [5, 144, 48, True, 'hard_swish', 1], | ||
|  |                 [5, 288, 96, True, 'hard_swish', 2], | ||
|  |                 [5, 576, 96, True, 'hard_swish', 1], | ||
|  |                 [5, 576, 96, True, 'hard_swish', 1], | ||
|  |             ] | ||
|  |             self.cls_ch_squeeze = 576 | ||
|  |             self.cls_ch_expand = 1280 | ||
|  |         else: | ||
|  |             raise NotImplementedError("mode[" + model_name + | ||
|  |                                       "_model] is not implemented!") | ||
|  | 
 | ||
|  |         supported_scale = [0.35, 0.5, 0.75, 1.0, 1.25] | ||
|  |         assert self.scale in supported_scale, \ | ||
|  |             "supported scale are {} but input scale is {}".format(supported_scale, self.scale) | ||
|  | 
 | ||
|  |     def __call__(self, input): | ||
|  |         scale = self.scale | ||
|  |         inplanes = self.inplanes | ||
|  |         cfg = self.cfg | ||
|  |         cls_ch_squeeze = self.cls_ch_squeeze | ||
|  |         cls_ch_expand = self.cls_ch_expand | ||
|  |         #conv1 | ||
|  |         conv = self.conv_bn_layer( | ||
|  |             input, | ||
|  |             filter_size=3, | ||
|  |             num_filters=self.make_divisible(inplanes * scale), | ||
|  |             stride=2, | ||
|  |             padding=1, | ||
|  |             num_groups=1, | ||
|  |             if_act=True, | ||
|  |             act='hard_swish', | ||
|  |             name='conv1') | ||
|  |         i = 0 | ||
|  |         inplanes = self.make_divisible(inplanes * scale) | ||
|  |         outs = [] | ||
|  |         for layer_cfg in cfg: | ||
|  |             if layer_cfg[5] == 2 and i > 2: | ||
|  |                 outs.append(conv) | ||
|  |             conv = self.residual_unit( | ||
|  |                 input=conv, | ||
|  |                 num_in_filter=inplanes, | ||
|  |                 num_mid_filter=self.make_divisible(scale * layer_cfg[1]), | ||
|  |                 num_out_filter=self.make_divisible(scale * layer_cfg[2]), | ||
|  |                 act=layer_cfg[4], | ||
|  |                 stride=layer_cfg[5], | ||
|  |                 filter_size=layer_cfg[0], | ||
|  |                 use_se=layer_cfg[3], | ||
|  |                 name='conv' + str(i + 2)) | ||
|  |             inplanes = self.make_divisible(scale * layer_cfg[2]) | ||
|  |             i += 1 | ||
|  | 
 | ||
|  |         conv = self.conv_bn_layer( | ||
|  |             input=conv, | ||
|  |             filter_size=1, | ||
|  |             num_filters=self.make_divisible(scale * cls_ch_squeeze), | ||
|  |             stride=1, | ||
|  |             padding=0, | ||
|  |             num_groups=1, | ||
|  |             if_act=True, | ||
|  |             act='hard_swish', | ||
|  |             name='conv_last') | ||
|  |         outs.append(conv) | ||
|  |         return outs | ||
|  | 
 | ||
|  |     def conv_bn_layer(self, | ||
|  |                       input, | ||
|  |                       filter_size, | ||
|  |                       num_filters, | ||
|  |                       stride, | ||
|  |                       padding, | ||
|  |                       num_groups=1, | ||
|  |                       if_act=True, | ||
|  |                       act=None, | ||
|  |                       name=None, | ||
|  |                       use_cudnn=True, | ||
|  |                       res_last_bn_init=False): | ||
|  |         conv = fluid.layers.conv2d( | ||
|  |             input=input, | ||
|  |             num_filters=num_filters, | ||
|  |             filter_size=filter_size, | ||
|  |             stride=stride, | ||
|  |             padding=padding, | ||
|  |             groups=num_groups, | ||
|  |             act=None, | ||
|  |             use_cudnn=use_cudnn, | ||
|  |             param_attr=ParamAttr(name=name + '_weights'), | ||
|  |             bias_attr=False) | ||
|  |         bn_name = name + '_bn' | ||
|  |         bn = fluid.layers.batch_norm( | ||
|  |             input=conv, | ||
|  |             param_attr=ParamAttr( | ||
|  |                 name=bn_name + "_scale", | ||
|  |                 regularizer=fluid.regularizer.L2DecayRegularizer( | ||
|  |                     regularization_coeff=0.0)), | ||
|  |             bias_attr=ParamAttr( | ||
|  |                 name=bn_name + "_offset", | ||
|  |                 regularizer=fluid.regularizer.L2DecayRegularizer( | ||
|  |                     regularization_coeff=0.0)), | ||
|  |             moving_mean_name=bn_name + '_mean', | ||
|  |             moving_variance_name=bn_name + '_variance') | ||
|  |         if if_act: | ||
|  |             if act == 'relu': | ||
|  |                 bn = fluid.layers.relu(bn)
 | ||
|  |             elif act == 'hard_swish': | ||
|  |                 bn = fluid.layers.hard_swish(bn) | ||
|  |         return bn | ||
|  | 
 | ||
|  |     def make_divisible(self, v, divisor=8, 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 se_block(self, input, num_out_filter, ratio=4, name=None): | ||
|  |         num_mid_filter = num_out_filter // ratio | ||
|  |         pool = fluid.layers.pool2d( | ||
|  |             input=input, pool_type='avg', global_pooling=True, use_cudnn=False) | ||
|  |         conv1 = fluid.layers.conv2d( | ||
|  |             input=pool, | ||
|  |             filter_size=1, | ||
|  |             num_filters=num_mid_filter, | ||
|  |             act='relu', | ||
|  |             param_attr=ParamAttr(name=name + '_1_weights'), | ||
|  |             bias_attr=ParamAttr(name=name + '_1_offset')) | ||
|  |         conv2 = fluid.layers.conv2d( | ||
|  |             input=conv1, | ||
|  |             filter_size=1, | ||
|  |             num_filters=num_out_filter, | ||
|  |             act='hard_sigmoid', | ||
|  |             param_attr=ParamAttr(name=name + '_2_weights'), | ||
|  |             bias_attr=ParamAttr(name=name + '_2_offset')) | ||
|  |         scale = fluid.layers.elementwise_mul(x=input, y=conv2, axis=0) | ||
|  |         return scale | ||
|  | 
 | ||
|  |     def residual_unit(self, | ||
|  |                       input, | ||
|  |                       num_in_filter, | ||
|  |                       num_mid_filter, | ||
|  |                       num_out_filter, | ||
|  |                       stride, | ||
|  |                       filter_size, | ||
|  |                       act=None, | ||
|  |                       use_se=False, | ||
|  |                       name=None): | ||
|  | 
 | ||
|  |         conv0 = self.conv_bn_layer( | ||
|  |             input=input, | ||
|  |             filter_size=1, | ||
|  |             num_filters=num_mid_filter, | ||
|  |             stride=1, | ||
|  |             padding=0, | ||
|  |             if_act=True, | ||
|  |             act=act, | ||
|  |             name=name + '_expand') | ||
|  | 
 | ||
|  |         conv1 = self.conv_bn_layer( | ||
|  |             input=conv0, | ||
|  |             filter_size=filter_size, | ||
|  |             num_filters=num_mid_filter, | ||
|  |             stride=stride, | ||
|  |             padding=int((filter_size - 1) // 2), | ||
|  |             if_act=True, | ||
|  |             act=act, | ||
|  |             num_groups=num_mid_filter, | ||
|  |             use_cudnn=False, | ||
|  |             name=name + '_depthwise') | ||
|  |         if use_se: | ||
|  |             conv1 = self.se_block( | ||
|  |                 input=conv1, num_out_filter=num_mid_filter, name=name + '_se') | ||
|  | 
 | ||
|  |         conv2 = self.conv_bn_layer( | ||
|  |             input=conv1, | ||
|  |             filter_size=1, | ||
|  |             num_filters=num_out_filter, | ||
|  |             stride=1, | ||
|  |             padding=0, | ||
|  |             if_act=False, | ||
|  |             name=name + '_linear', | ||
|  |             res_last_bn_init=True) | ||
|  |         if num_in_filter != num_out_filter or stride != 1: | ||
|  |             return conv2 | ||
|  |         else: | ||
|  |             return fluid.layers.elementwise_add(x=input, y=conv2, act=None) |