mirror of
				https://github.com/PaddlePaddle/PaddleOCR.git
				synced 2025-10-31 01:39:11 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			250 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			250 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # copyright (c) 2021 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.
 | |
| 
 | |
| # This code is refer from: https://github.com/PaddlePaddle/PaddleClas/blob/develop/ppcls/arch/backbone/legendary_models/pp_lcnet.py
 | |
| 
 | |
| from __future__ import absolute_import
 | |
| from __future__ import division
 | |
| from __future__ import print_function
 | |
| 
 | |
| import math
 | |
| import numpy as np
 | |
| import paddle
 | |
| from paddle import ParamAttr, reshape, transpose
 | |
| import paddle.nn as nn
 | |
| import paddle.nn.functional as F
 | |
| from paddle.nn import Conv2D, BatchNorm, Linear, Dropout
 | |
| from paddle.nn import AdaptiveAvgPool2D, MaxPool2D, AvgPool2D
 | |
| from paddle.nn.initializer import KaimingNormal
 | |
| from paddle.regularizer import L2Decay
 | |
| from paddle.nn.functional import hardswish, hardsigmoid
 | |
| 
 | |
| 
 | |
| class ConvBNLayer(nn.Layer):
 | |
|     def __init__(self,
 | |
|                  num_channels,
 | |
|                  filter_size,
 | |
|                  num_filters,
 | |
|                  stride,
 | |
|                  padding,
 | |
|                  channels=None,
 | |
|                  num_groups=1,
 | |
|                  act='hard_swish'):
 | |
|         super(ConvBNLayer, self).__init__()
 | |
| 
 | |
|         self._conv = Conv2D(
 | |
|             in_channels=num_channels,
 | |
|             out_channels=num_filters,
 | |
|             kernel_size=filter_size,
 | |
|             stride=stride,
 | |
|             padding=padding,
 | |
|             groups=num_groups,
 | |
|             weight_attr=ParamAttr(initializer=KaimingNormal()),
 | |
|             bias_attr=False)
 | |
| 
 | |
|         self._batch_norm = BatchNorm(
 | |
|             num_filters,
 | |
|             act=act,
 | |
|             param_attr=ParamAttr(regularizer=L2Decay(0.0)),
 | |
|             bias_attr=ParamAttr(regularizer=L2Decay(0.0)))
 | |
| 
 | |
|     def forward(self, inputs):
 | |
|         y = self._conv(inputs)
 | |
|         y = self._batch_norm(y)
 | |
|         return y
 | |
| 
 | |
| 
 | |
| class DepthwiseSeparable(nn.Layer):
 | |
|     def __init__(self,
 | |
|                  num_channels,
 | |
|                  num_filters1,
 | |
|                  num_filters2,
 | |
|                  num_groups,
 | |
|                  stride,
 | |
|                  scale,
 | |
|                  dw_size=3,
 | |
|                  padding=1,
 | |
|                  use_se=False):
 | |
|         super(DepthwiseSeparable, self).__init__()
 | |
|         self.use_se = use_se
 | |
|         self._depthwise_conv = ConvBNLayer(
 | |
|             num_channels=num_channels,
 | |
|             num_filters=int(num_filters1 * scale),
 | |
|             filter_size=dw_size,
 | |
|             stride=stride,
 | |
|             padding=padding,
 | |
|             num_groups=int(num_groups * scale))
 | |
|         if use_se:
 | |
|             self._se = SEModule(int(num_filters1 * scale))
 | |
|         self._pointwise_conv = ConvBNLayer(
 | |
|             num_channels=int(num_filters1 * scale),
 | |
|             filter_size=1,
 | |
|             num_filters=int(num_filters2 * scale),
 | |
|             stride=1,
 | |
|             padding=0)
 | |
| 
 | |
|     def forward(self, inputs):
 | |
|         y = self._depthwise_conv(inputs)
 | |
|         if self.use_se:
 | |
|             y = self._se(y)
 | |
|         y = self._pointwise_conv(y)
 | |
|         return y
 | |
| 
 | |
| 
 | |
| class MobileNetV1Enhance(nn.Layer):
 | |
|     def __init__(self, in_channels=3, scale=0.5, **kwargs):
 | |
|         super().__init__()
 | |
|         self.scale = scale
 | |
|         self.block_list = []
 | |
| 
 | |
|         self.conv1 = ConvBNLayer(
 | |
|             num_channels=3,
 | |
|             filter_size=3,
 | |
|             channels=3,
 | |
|             num_filters=int(32 * scale),
 | |
|             stride=2,
 | |
|             padding=1)
 | |
| 
 | |
|         conv2_1 = DepthwiseSeparable(
 | |
|             num_channels=int(32 * scale),
 | |
|             num_filters1=32,
 | |
|             num_filters2=64,
 | |
|             num_groups=32,
 | |
|             stride=1,
 | |
|             scale=scale)
 | |
|         self.block_list.append(conv2_1)
 | |
| 
 | |
|         conv2_2 = DepthwiseSeparable(
 | |
|             num_channels=int(64 * scale),
 | |
|             num_filters1=64,
 | |
|             num_filters2=128,
 | |
|             num_groups=64,
 | |
|             stride=1,
 | |
|             scale=scale)
 | |
|         self.block_list.append(conv2_2)
 | |
| 
 | |
|         conv3_1 = DepthwiseSeparable(
 | |
|             num_channels=int(128 * scale),
 | |
|             num_filters1=128,
 | |
|             num_filters2=128,
 | |
|             num_groups=128,
 | |
|             stride=1,
 | |
|             scale=scale)
 | |
|         self.block_list.append(conv3_1)
 | |
| 
 | |
|         conv3_2 = DepthwiseSeparable(
 | |
|             num_channels=int(128 * scale),
 | |
|             num_filters1=128,
 | |
|             num_filters2=256,
 | |
|             num_groups=128,
 | |
|             stride=(2, 1),
 | |
|             scale=scale)
 | |
|         self.block_list.append(conv3_2)
 | |
| 
 | |
|         conv4_1 = DepthwiseSeparable(
 | |
|             num_channels=int(256 * scale),
 | |
|             num_filters1=256,
 | |
|             num_filters2=256,
 | |
|             num_groups=256,
 | |
|             stride=1,
 | |
|             scale=scale)
 | |
|         self.block_list.append(conv4_1)
 | |
| 
 | |
|         conv4_2 = DepthwiseSeparable(
 | |
|             num_channels=int(256 * scale),
 | |
|             num_filters1=256,
 | |
|             num_filters2=512,
 | |
|             num_groups=256,
 | |
|             stride=(2, 1),
 | |
|             scale=scale)
 | |
|         self.block_list.append(conv4_2)
 | |
| 
 | |
|         for _ in range(5):
 | |
|             conv5 = DepthwiseSeparable(
 | |
|                 num_channels=int(512 * scale),
 | |
|                 num_filters1=512,
 | |
|                 num_filters2=512,
 | |
|                 num_groups=512,
 | |
|                 stride=1,
 | |
|                 dw_size=5,
 | |
|                 padding=2,
 | |
|                 scale=scale,
 | |
|                 use_se=False)
 | |
|             self.block_list.append(conv5)
 | |
| 
 | |
|         conv5_6 = DepthwiseSeparable(
 | |
|             num_channels=int(512 * scale),
 | |
|             num_filters1=512,
 | |
|             num_filters2=1024,
 | |
|             num_groups=512,
 | |
|             stride=(2, 1),
 | |
|             dw_size=5,
 | |
|             padding=2,
 | |
|             scale=scale,
 | |
|             use_se=True)
 | |
|         self.block_list.append(conv5_6)
 | |
| 
 | |
|         conv6 = DepthwiseSeparable(
 | |
|             num_channels=int(1024 * scale),
 | |
|             num_filters1=1024,
 | |
|             num_filters2=1024,
 | |
|             num_groups=1024,
 | |
|             stride=1,
 | |
|             dw_size=5,
 | |
|             padding=2,
 | |
|             use_se=True,
 | |
|             scale=scale)
 | |
|         self.block_list.append(conv6)
 | |
| 
 | |
|         self.block_list = nn.Sequential(*self.block_list)
 | |
| 
 | |
|         self.pool = nn.MaxPool2D(kernel_size=2, stride=2, padding=0)
 | |
|         self.out_channels = int(1024 * scale)
 | |
| 
 | |
|     def forward(self, inputs):
 | |
|         y = self.conv1(inputs)
 | |
|         y = self.block_list(y)
 | |
|         y = self.pool(y)
 | |
|         return y
 | |
| 
 | |
| 
 | |
| class SEModule(nn.Layer):
 | |
|     def __init__(self, channel, reduction=4):
 | |
|         super(SEModule, self).__init__()
 | |
|         self.avg_pool = AdaptiveAvgPool2D(1)
 | |
|         self.conv1 = Conv2D(
 | |
|             in_channels=channel,
 | |
|             out_channels=channel // reduction,
 | |
|             kernel_size=1,
 | |
|             stride=1,
 | |
|             padding=0,
 | |
|             weight_attr=ParamAttr(),
 | |
|             bias_attr=ParamAttr())
 | |
|         self.conv2 = Conv2D(
 | |
|             in_channels=channel // reduction,
 | |
|             out_channels=channel,
 | |
|             kernel_size=1,
 | |
|             stride=1,
 | |
|             padding=0,
 | |
|             weight_attr=ParamAttr(),
 | |
|             bias_attr=ParamAttr())
 | |
| 
 | |
|     def forward(self, inputs):
 | |
|         outputs = self.avg_pool(inputs)
 | |
|         outputs = self.conv1(outputs)
 | |
|         outputs = F.relu(outputs)
 | |
|         outputs = self.conv2(outputs)
 | |
|         outputs = hardsigmoid(outputs)
 | |
|         return paddle.multiply(x=inputs, y=outputs)
 | 
