add mobilenet, resnet and senet series dymodels
parent
0e7bea5183
commit
7f80e25c9d
|
@ -12,7 +12,19 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .resnet_name import *
|
||||
from .resnet import ResNet18, ResNet34, ResNet50, ResNet101, ResNet152
|
||||
from .resnet_vc import ResNet18_vc, ResNet34_vc, ResNet50_vc, ResNet101_vc, ResNet152_vc
|
||||
from .resnet_vd import ResNet18_vd, ResNet34_vd, ResNet50_vd, ResNet101_vd, ResNet152_vd, ResNet200_vd
|
||||
from .resnext import ResNeXt50_32x4d, ResNeXt50_64x4d, ResNeXt101_32x4d, ResNeXt101_64x4d, ResNeXt152_32x4d, ResNeXt152_64x4d
|
||||
from .resnext_vd import ResNeXt50_vd_32x4d, ResNeXt50_vd_64x4d, ResNeXt101_vd_32x4d, ResNeXt101_vd_64x4d, ResNeXt152_vd_32x4d, ResNeXt152_vd_64x4d
|
||||
from .res2net import Res2Net50_48w_2s, Res2Net50_26w_4s, Res2Net50_14w_8s, Res2Net50_48w_2s, Res2Net50_26w_6s, Res2Net50_26w_8s, Res2Net101_26w_4s, Res2Net152_26w_4s, Res2Net200_26w_4s
|
||||
from .res2net_vd import Res2Net50_vd_48w_2s, Res2Net50_vd_26w_4s, Res2Net50_vd_14w_8s, Res2Net50_vd_48w_2s, Res2Net50_vd_26w_6s, Res2Net50_vd_26w_8s, Res2Net101_vd_26w_4s, Res2Net152_vd_26w_4s, Res2Net200_vd_26w_4s
|
||||
from .se_resnet_vd import SE_ResNet18_vd, SE_ResNet34_vd, SE_ResNet50_vd, SE_ResNet101_vd, SE_ResNet152_vd, SE_ResNet200_vd
|
||||
from .se_resnext_vd import SE_ResNeXt50_vd_32x4d, SE_ResNeXt50_vd_32x4d, SENet154_vd
|
||||
from .dpn import DPN68
|
||||
from .densenet import DenseNet121
|
||||
from .hrnet import HRNet_W18_C
|
||||
from .hrnet import HRNet_W18_C
|
||||
from .mobilenet_v1 import MobileNetV1_x0_25, MobileNetV1_x0_5, MobileNetV1_x0_75, MobileNetV1
|
||||
from .mobilenet_v2 import MobileNetV2_x0_25, MobileNetV2_x0_5, MobileNetV2_x0_75, MobileNetV2, MobileNetV2_x1_5, MobileNetV2_x2_0
|
||||
from .mobilenet_v3 import MobileNetV3_small_x0_35, MobileNetV3_small_x0_5, MobileNetV3_small_x0_75, MobileNetV3_small_x1_0, MobileNetV3_small_x1_25, MobileNetV3_large_x0_35, MobileNetV3_large_x0_5, MobileNetV3_large_x0_75, MobileNetV3_large_x1_0, MobileNetV3_large_x1_25
|
||||
from .shufflenet_v2 import ShuffleNetV2_x0_25, ShuffleNetV2_x0_33, ShuffleNetV2_x0_5, ShuffleNetV2, ShuffleNetV2_x1_5, ShuffleNetV2_x2_0, ShuffleNetV2_swish
|
||||
|
|
|
@ -1,156 +1,51 @@
|
|||
#copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
|
||||
# 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
|
||||
# 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.
|
||||
# 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 numpy as np
|
||||
import paddle
|
||||
import paddle.fluid as fluid
|
||||
from paddle.fluid.initializer import MSRA
|
||||
from paddle.fluid.param_attr import ParamAttr
|
||||
from paddle.fluid.layer_helper import LayerHelper
|
||||
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, Linear, Dropout
|
||||
from paddle.fluid.initializer import MSRA
|
||||
import math
|
||||
|
||||
__all__ = [
|
||||
'MobileNetV1', 'MobileNetV1_x0_25', 'MobileNetV1_x0_5', 'MobileNetV1_x1_0',
|
||||
'MobileNetV1_x0_75'
|
||||
"MobileNetV1_x0_25", "MobileNetV1_x0_5", "MobileNetV1_x0_75", "MobileNetV1"
|
||||
]
|
||||
|
||||
|
||||
class MobileNetV1():
|
||||
def __init__(self, scale=1.0):
|
||||
self.scale = scale
|
||||
class ConvBNLayer(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
num_channels,
|
||||
filter_size,
|
||||
num_filters,
|
||||
stride,
|
||||
padding,
|
||||
channels=None,
|
||||
num_groups=1,
|
||||
act='relu',
|
||||
use_cudnn=True,
|
||||
name=None):
|
||||
super(ConvBNLayer, self).__init__()
|
||||
|
||||
def net(self, input, class_dim=1000):
|
||||
scale = self.scale
|
||||
# conv1: 112x112
|
||||
input = self.conv_bn_layer(
|
||||
input,
|
||||
filter_size=3,
|
||||
channels=3,
|
||||
num_filters=int(32 * scale),
|
||||
stride=2,
|
||||
padding=1,
|
||||
name="conv1")
|
||||
|
||||
# 56x56
|
||||
input = self.depthwise_separable(
|
||||
input,
|
||||
num_filters1=32,
|
||||
num_filters2=64,
|
||||
num_groups=32,
|
||||
stride=1,
|
||||
scale=scale,
|
||||
name="conv2_1")
|
||||
|
||||
input = self.depthwise_separable(
|
||||
input,
|
||||
num_filters1=64,
|
||||
num_filters2=128,
|
||||
num_groups=64,
|
||||
stride=2,
|
||||
scale=scale,
|
||||
name="conv2_2")
|
||||
|
||||
# 28x28
|
||||
input = self.depthwise_separable(
|
||||
input,
|
||||
num_filters1=128,
|
||||
num_filters2=128,
|
||||
num_groups=128,
|
||||
stride=1,
|
||||
scale=scale,
|
||||
name="conv3_1")
|
||||
|
||||
input = self.depthwise_separable(
|
||||
input,
|
||||
num_filters1=128,
|
||||
num_filters2=256,
|
||||
num_groups=128,
|
||||
stride=2,
|
||||
scale=scale,
|
||||
name="conv3_2")
|
||||
|
||||
# 14x14
|
||||
input = self.depthwise_separable(
|
||||
input,
|
||||
num_filters1=256,
|
||||
num_filters2=256,
|
||||
num_groups=256,
|
||||
stride=1,
|
||||
scale=scale,
|
||||
name="conv4_1")
|
||||
|
||||
input = self.depthwise_separable(
|
||||
input,
|
||||
num_filters1=256,
|
||||
num_filters2=512,
|
||||
num_groups=256,
|
||||
stride=2,
|
||||
scale=scale,
|
||||
name="conv4_2")
|
||||
|
||||
# 14x14
|
||||
for i in range(5):
|
||||
input = self.depthwise_separable(
|
||||
input,
|
||||
num_filters1=512,
|
||||
num_filters2=512,
|
||||
num_groups=512,
|
||||
stride=1,
|
||||
scale=scale,
|
||||
name="conv5" + "_" + str(i + 1))
|
||||
# 7x7
|
||||
input = self.depthwise_separable(
|
||||
input,
|
||||
num_filters1=512,
|
||||
num_filters2=1024,
|
||||
num_groups=512,
|
||||
stride=2,
|
||||
scale=scale,
|
||||
name="conv5_6")
|
||||
|
||||
input = self.depthwise_separable(
|
||||
input,
|
||||
num_filters1=1024,
|
||||
num_filters2=1024,
|
||||
num_groups=1024,
|
||||
stride=1,
|
||||
scale=scale,
|
||||
name="conv6")
|
||||
|
||||
input = fluid.layers.pool2d(
|
||||
input=input, pool_type='avg', global_pooling=True)
|
||||
|
||||
output = fluid.layers.fc(input=input,
|
||||
size=class_dim,
|
||||
param_attr=ParamAttr(
|
||||
initializer=MSRA(), name="fc7_weights"),
|
||||
bias_attr=ParamAttr(name="fc7_offset"))
|
||||
return output
|
||||
|
||||
def conv_bn_layer(self,
|
||||
input,
|
||||
filter_size,
|
||||
num_filters,
|
||||
stride,
|
||||
padding,
|
||||
channels=None,
|
||||
num_groups=1,
|
||||
act='relu',
|
||||
use_cudnn=True,
|
||||
name=None):
|
||||
conv = fluid.layers.conv2d(
|
||||
input=input,
|
||||
self._conv = Conv2D(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=stride,
|
||||
|
@ -161,58 +56,214 @@ class MobileNetV1():
|
|||
param_attr=ParamAttr(
|
||||
initializer=MSRA(), name=name + "_weights"),
|
||||
bias_attr=False)
|
||||
bn_name = name + "_bn"
|
||||
return fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
act=act,
|
||||
param_attr=ParamAttr(name=bn_name + "_scale"),
|
||||
bias_attr=ParamAttr(name=bn_name + "_offset"),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
|
||||
def depthwise_separable(self,
|
||||
input,
|
||||
num_filters1,
|
||||
num_filters2,
|
||||
num_groups,
|
||||
stride,
|
||||
scale,
|
||||
name=None):
|
||||
depthwise_conv = self.conv_bn_layer(
|
||||
input=input,
|
||||
filter_size=3,
|
||||
self._batch_norm = BatchNorm(
|
||||
num_filters,
|
||||
act=act,
|
||||
param_attr=ParamAttr(name + "_bn_scale"),
|
||||
bias_attr=ParamAttr(name + "_bn_offset"),
|
||||
moving_mean_name=name + "_bn_mean",
|
||||
moving_variance_name=name + "_bn_variance")
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self._conv(inputs)
|
||||
y = self._batch_norm(y)
|
||||
return y
|
||||
|
||||
|
||||
class DepthwiseSeparable(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
num_channels,
|
||||
num_filters1,
|
||||
num_filters2,
|
||||
num_groups,
|
||||
stride,
|
||||
scale,
|
||||
name=None):
|
||||
super(DepthwiseSeparable, self).__init__()
|
||||
|
||||
self._depthwise_conv = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=int(num_filters1 * scale),
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
padding=1,
|
||||
num_groups=int(num_groups * scale),
|
||||
use_cudnn=False,
|
||||
name=name + "_dw")
|
||||
|
||||
pointwise_conv = self.conv_bn_layer(
|
||||
input=depthwise_conv,
|
||||
self._pointwise_conv = ConvBNLayer(
|
||||
num_channels=int(num_filters1 * scale),
|
||||
filter_size=1,
|
||||
num_filters=int(num_filters2 * scale),
|
||||
stride=1,
|
||||
padding=0,
|
||||
name=name + "_sep")
|
||||
return pointwise_conv
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self._depthwise_conv(inputs)
|
||||
y = self._pointwise_conv(y)
|
||||
return y
|
||||
|
||||
|
||||
def MobileNetV1_x0_25():
|
||||
model = MobileNetV1(scale=0.25)
|
||||
class MobileNet(fluid.dygraph.Layer):
|
||||
def __init__(self, scale=1.0, class_dim=1000):
|
||||
super(MobileNet, self).__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,
|
||||
name="conv1")
|
||||
|
||||
conv2_1 = self.add_sublayer(
|
||||
"conv2_1",
|
||||
sublayer=DepthwiseSeparable(
|
||||
num_channels=int(32 * scale),
|
||||
num_filters1=32,
|
||||
num_filters2=64,
|
||||
num_groups=32,
|
||||
stride=1,
|
||||
scale=scale,
|
||||
name="conv2_1"))
|
||||
self.block_list.append(conv2_1)
|
||||
|
||||
conv2_2 = self.add_sublayer(
|
||||
"conv2_2",
|
||||
sublayer=DepthwiseSeparable(
|
||||
num_channels=int(64 * scale),
|
||||
num_filters1=64,
|
||||
num_filters2=128,
|
||||
num_groups=64,
|
||||
stride=2,
|
||||
scale=scale,
|
||||
name="conv2_2"))
|
||||
self.block_list.append(conv2_2)
|
||||
|
||||
conv3_1 = self.add_sublayer(
|
||||
"conv3_1",
|
||||
sublayer=DepthwiseSeparable(
|
||||
num_channels=int(128 * scale),
|
||||
num_filters1=128,
|
||||
num_filters2=128,
|
||||
num_groups=128,
|
||||
stride=1,
|
||||
scale=scale,
|
||||
name="conv3_1"))
|
||||
self.block_list.append(conv3_1)
|
||||
|
||||
conv3_2 = self.add_sublayer(
|
||||
"conv3_2",
|
||||
sublayer=DepthwiseSeparable(
|
||||
num_channels=int(128 * scale),
|
||||
num_filters1=128,
|
||||
num_filters2=256,
|
||||
num_groups=128,
|
||||
stride=2,
|
||||
scale=scale,
|
||||
name="conv3_2"))
|
||||
self.block_list.append(conv3_2)
|
||||
|
||||
conv4_1 = self.add_sublayer(
|
||||
"conv4_1",
|
||||
sublayer=DepthwiseSeparable(
|
||||
num_channels=int(256 * scale),
|
||||
num_filters1=256,
|
||||
num_filters2=256,
|
||||
num_groups=256,
|
||||
stride=1,
|
||||
scale=scale,
|
||||
name="conv4_1"))
|
||||
self.block_list.append(conv4_1)
|
||||
|
||||
conv4_2 = self.add_sublayer(
|
||||
"conv4_2",
|
||||
sublayer=DepthwiseSeparable(
|
||||
num_channels=int(256 * scale),
|
||||
num_filters1=256,
|
||||
num_filters2=512,
|
||||
num_groups=256,
|
||||
stride=2,
|
||||
scale=scale,
|
||||
name="conv4_2"))
|
||||
self.block_list.append(conv4_2)
|
||||
|
||||
for i in range(5):
|
||||
conv5 = self.add_sublayer(
|
||||
"conv5_" + str(i + 1),
|
||||
sublayer=DepthwiseSeparable(
|
||||
num_channels=int(512 * scale),
|
||||
num_filters1=512,
|
||||
num_filters2=512,
|
||||
num_groups=512,
|
||||
stride=1,
|
||||
scale=scale,
|
||||
name="conv5_" + str(i + 1)))
|
||||
self.block_list.append(conv5)
|
||||
|
||||
conv5_6 = self.add_sublayer(
|
||||
"conv5_6",
|
||||
sublayer=DepthwiseSeparable(
|
||||
num_channels=int(512 * scale),
|
||||
num_filters1=512,
|
||||
num_filters2=1024,
|
||||
num_groups=512,
|
||||
stride=2,
|
||||
scale=scale,
|
||||
name="conv5_6"))
|
||||
self.block_list.append(conv5_6)
|
||||
|
||||
conv6 = self.add_sublayer(
|
||||
"conv6",
|
||||
sublayer=DepthwiseSeparable(
|
||||
num_channels=int(1024 * scale),
|
||||
num_filters1=1024,
|
||||
num_filters2=1024,
|
||||
num_groups=1024,
|
||||
stride=1,
|
||||
scale=scale,
|
||||
name="conv6"))
|
||||
self.block_list.append(conv6)
|
||||
|
||||
self.pool2d_avg = Pool2D(pool_type='avg', global_pooling=True)
|
||||
|
||||
self.out = Linear(
|
||||
int(1024 * scale),
|
||||
class_dim,
|
||||
param_attr=ParamAttr(
|
||||
initializer=MSRA(), name="fc7_weights"),
|
||||
bias_attr=ParamAttr(name="fc7_offset"))
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self.conv1(inputs)
|
||||
for block in self.block_list:
|
||||
y = block(y)
|
||||
y = self.pool2d_avg(y)
|
||||
y = fluid.layers.reshape(y, shape=[-1, int(1024 * self.scale)])
|
||||
y = self.out(y)
|
||||
return y
|
||||
|
||||
|
||||
def MobileNetV1_x0_25(**args):
|
||||
model = MobileNet(scale=0.25, **args)
|
||||
return model
|
||||
|
||||
|
||||
def MobileNetV1_x0_5():
|
||||
model = MobileNetV1(scale=0.5)
|
||||
def MobileNetV1_x0_5(**args):
|
||||
model = MobileNet(scale=0.5, **args)
|
||||
return model
|
||||
|
||||
|
||||
def MobileNetV1_x1_0():
|
||||
model = MobileNetV1(scale=1.0)
|
||||
def MobileNetV1_x0_75(**args):
|
||||
model = MobileNet(scale=0.75, **args)
|
||||
return model
|
||||
|
||||
|
||||
def MobileNetV1_x0_75():
|
||||
model = MobileNetV1(scale=0.75)
|
||||
def MobileNetV1(**args):
|
||||
model = MobileNet(scale=1.0, **args)
|
||||
return model
|
||||
|
|
|
@ -1,37 +1,160 @@
|
|||
#copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
|
||||
# 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
|
||||
# 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.
|
||||
# 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 numpy as np
|
||||
import paddle
|
||||
import paddle.fluid as fluid
|
||||
from paddle.fluid.initializer import MSRA
|
||||
from paddle.fluid.param_attr import ParamAttr
|
||||
from paddle.fluid.layer_helper import LayerHelper
|
||||
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, Linear, Dropout
|
||||
|
||||
import math
|
||||
|
||||
__all__ = [
|
||||
'MobileNetV2_x0_25', 'MobileNetV2_x0_5'
|
||||
'MobileNetV2_x0_75', 'MobileNetV2_x1_0', 'MobileNetV2_x1_5',
|
||||
'MobileNetV2_x2_0', 'MobileNetV2'
|
||||
"MobileNetV2_x0_25", "MobileNetV2_x0_5", "MobileNetV2_x0_75",
|
||||
"MobileNetV2", "MobileNetV2_x1_5", "MobileNetV2_x2_0"
|
||||
]
|
||||
|
||||
|
||||
class MobileNetV2():
|
||||
def __init__(self, scale=1.0):
|
||||
self.scale = scale
|
||||
class ConvBNLayer(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
num_channels,
|
||||
filter_size,
|
||||
num_filters,
|
||||
stride,
|
||||
padding,
|
||||
channels=None,
|
||||
num_groups=1,
|
||||
name=None,
|
||||
use_cudnn=True):
|
||||
super(ConvBNLayer, self).__init__()
|
||||
|
||||
self._conv = Conv2D(
|
||||
num_channels=num_channels,
|
||||
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)
|
||||
|
||||
self._batch_norm = BatchNorm(
|
||||
num_filters,
|
||||
param_attr=ParamAttr(name=name + "_bn_scale"),
|
||||
bias_attr=ParamAttr(name=name + "_bn_offset"),
|
||||
moving_mean_name=name + "_bn_mean",
|
||||
moving_variance_name=name + "_bn_variance")
|
||||
|
||||
def forward(self, inputs, if_act=True):
|
||||
y = self._conv(inputs)
|
||||
y = self._batch_norm(y)
|
||||
if if_act:
|
||||
y = fluid.layers.relu6(y)
|
||||
return y
|
||||
|
||||
|
||||
class InvertedResidualUnit(fluid.dygraph.Layer):
|
||||
def __init__(self, num_channels, num_in_filter, num_filters, stride,
|
||||
filter_size, padding, expansion_factor, name):
|
||||
super(InvertedResidualUnit, self).__init__()
|
||||
num_expfilter = int(round(num_in_filter * expansion_factor))
|
||||
self._expand_conv = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_expfilter,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
num_groups=1,
|
||||
name=name + "_expand")
|
||||
|
||||
self._bottleneck_conv = ConvBNLayer(
|
||||
num_channels=num_expfilter,
|
||||
num_filters=num_expfilter,
|
||||
filter_size=filter_size,
|
||||
stride=stride,
|
||||
padding=padding,
|
||||
num_groups=num_expfilter,
|
||||
use_cudnn=False,
|
||||
name=name + "_dwise")
|
||||
|
||||
self._linear_conv = ConvBNLayer(
|
||||
num_channels=num_expfilter,
|
||||
num_filters=num_filters,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
num_groups=1,
|
||||
name=name + "_linear")
|
||||
|
||||
def forward(self, inputs, ifshortcut):
|
||||
y = self._expand_conv(inputs, if_act=True)
|
||||
y = self._bottleneck_conv(y, if_act=True)
|
||||
y = self._linear_conv(y, if_act=False)
|
||||
if ifshortcut:
|
||||
y = fluid.layers.elementwise_add(inputs, y)
|
||||
return y
|
||||
|
||||
|
||||
class InvresiBlocks(fluid.dygraph.Layer):
|
||||
def __init__(self, in_c, t, c, n, s, name):
|
||||
super(InvresiBlocks, self).__init__()
|
||||
|
||||
self._first_block = InvertedResidualUnit(
|
||||
num_channels=in_c,
|
||||
num_in_filter=in_c,
|
||||
num_filters=c,
|
||||
stride=s,
|
||||
filter_size=3,
|
||||
padding=1,
|
||||
expansion_factor=t,
|
||||
name=name + "_1")
|
||||
|
||||
self._block_list = []
|
||||
for i in range(1, n):
|
||||
block = self.add_sublayer(
|
||||
name + "_" + str(i + 1),
|
||||
sublayer=InvertedResidualUnit(
|
||||
num_channels=c,
|
||||
num_in_filter=c,
|
||||
num_filters=c,
|
||||
stride=1,
|
||||
filter_size=3,
|
||||
padding=1,
|
||||
expansion_factor=t,
|
||||
name=name + "_" + str(i + 1)))
|
||||
self._block_list.append(block)
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self._first_block(inputs, ifshortcut=False)
|
||||
for block in self._block_list:
|
||||
y = block(y, ifshortcut=True)
|
||||
return y
|
||||
|
||||
|
||||
class MobileNet(fluid.dygraph.Layer):
|
||||
def __init__(self, class_dim=1000, scale=1.0):
|
||||
super(MobileNet, self).__init__()
|
||||
self.scale = scale
|
||||
self.class_dim = class_dim
|
||||
|
||||
def net(self, input, class_dim=1000):
|
||||
scale = self.scale
|
||||
bottleneck_params_list = [
|
||||
(1, 16, 1, 1),
|
||||
(6, 24, 2, 2),
|
||||
|
@ -42,189 +165,85 @@ class MobileNetV2():
|
|||
(6, 320, 1, 1),
|
||||
]
|
||||
|
||||
#conv1
|
||||
input = self.conv_bn_layer(
|
||||
input,
|
||||
self.conv1 = ConvBNLayer(
|
||||
num_channels=3,
|
||||
num_filters=int(32 * scale),
|
||||
filter_size=3,
|
||||
stride=2,
|
||||
padding=1,
|
||||
if_act=True,
|
||||
name='conv1_1')
|
||||
name="conv1_1")
|
||||
|
||||
# bottleneck sequences
|
||||
self.block_list = []
|
||||
i = 1
|
||||
in_c = int(32 * scale)
|
||||
for layer_setting in bottleneck_params_list:
|
||||
t, c, n, s = layer_setting
|
||||
i += 1
|
||||
input = self.invresi_blocks(
|
||||
input=input,
|
||||
in_c=in_c,
|
||||
t=t,
|
||||
c=int(c * scale),
|
||||
n=n,
|
||||
s=s,
|
||||
name='conv' + str(i))
|
||||
block = self.add_sublayer(
|
||||
"conv" + str(i),
|
||||
sublayer=InvresiBlocks(
|
||||
in_c=in_c,
|
||||
t=t,
|
||||
c=int(c * scale),
|
||||
n=n,
|
||||
s=s,
|
||||
name="conv" + str(i)))
|
||||
self.block_list.append(block)
|
||||
in_c = int(c * scale)
|
||||
#last_conv
|
||||
input = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=int(1280 * scale) if scale > 1.0 else 1280,
|
||||
|
||||
self.out_c = int(1280 * scale) if scale > 1.0 else 1280
|
||||
self.conv9 = ConvBNLayer(
|
||||
num_channels=in_c,
|
||||
num_filters=self.out_c,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
if_act=True,
|
||||
name='conv9')
|
||||
name="conv9")
|
||||
|
||||
input = fluid.layers.pool2d(
|
||||
input=input, pool_type='avg', global_pooling=True)
|
||||
self.pool2d_avg = Pool2D(pool_type="avg", global_pooling=True)
|
||||
|
||||
output = fluid.layers.fc(input=input,
|
||||
size=class_dim,
|
||||
param_attr=ParamAttr(name='fc10_weights'),
|
||||
bias_attr=ParamAttr(name='fc10_offset'))
|
||||
return output
|
||||
self.out = Linear(
|
||||
self.out_c,
|
||||
class_dim,
|
||||
param_attr=ParamAttr(name="fc10_weights"),
|
||||
bias_attr=ParamAttr(name="fc10_offset"))
|
||||
|
||||
def conv_bn_layer(self,
|
||||
input,
|
||||
filter_size,
|
||||
num_filters,
|
||||
stride,
|
||||
padding,
|
||||
channels=None,
|
||||
num_groups=1,
|
||||
if_act=True,
|
||||
name=None,
|
||||
use_cudnn=True):
|
||||
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"),
|
||||
bias_attr=ParamAttr(name=bn_name + "_offset"),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
if if_act:
|
||||
return fluid.layers.relu6(bn)
|
||||
else:
|
||||
return bn
|
||||
|
||||
def shortcut(self, input, data_residual):
|
||||
return fluid.layers.elementwise_add(input, data_residual)
|
||||
|
||||
def inverted_residual_unit(self,
|
||||
input,
|
||||
num_in_filter,
|
||||
num_filters,
|
||||
ifshortcut,
|
||||
stride,
|
||||
filter_size,
|
||||
padding,
|
||||
expansion_factor,
|
||||
name=None):
|
||||
num_expfilter = int(round(num_in_filter * expansion_factor))
|
||||
|
||||
channel_expand = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=num_expfilter,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
num_groups=1,
|
||||
if_act=True,
|
||||
name=name + '_expand')
|
||||
|
||||
bottleneck_conv = self.conv_bn_layer(
|
||||
input=channel_expand,
|
||||
num_filters=num_expfilter,
|
||||
filter_size=filter_size,
|
||||
stride=stride,
|
||||
padding=padding,
|
||||
num_groups=num_expfilter,
|
||||
if_act=True,
|
||||
name=name + '_dwise',
|
||||
use_cudnn=False)
|
||||
|
||||
linear_out = self.conv_bn_layer(
|
||||
input=bottleneck_conv,
|
||||
num_filters=num_filters,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
num_groups=1,
|
||||
if_act=False,
|
||||
name=name + '_linear')
|
||||
if ifshortcut:
|
||||
out = self.shortcut(input=input, data_residual=linear_out)
|
||||
return out
|
||||
else:
|
||||
return linear_out
|
||||
|
||||
def invresi_blocks(self, input, in_c, t, c, n, s, name=None):
|
||||
first_block = self.inverted_residual_unit(
|
||||
input=input,
|
||||
num_in_filter=in_c,
|
||||
num_filters=c,
|
||||
ifshortcut=False,
|
||||
stride=s,
|
||||
filter_size=3,
|
||||
padding=1,
|
||||
expansion_factor=t,
|
||||
name=name + '_1')
|
||||
|
||||
last_residual_block = first_block
|
||||
last_c = c
|
||||
|
||||
for i in range(1, n):
|
||||
last_residual_block = self.inverted_residual_unit(
|
||||
input=last_residual_block,
|
||||
num_in_filter=last_c,
|
||||
num_filters=c,
|
||||
ifshortcut=True,
|
||||
stride=1,
|
||||
filter_size=3,
|
||||
padding=1,
|
||||
expansion_factor=t,
|
||||
name=name + '_' + str(i + 1))
|
||||
return last_residual_block
|
||||
def forward(self, inputs):
|
||||
y = self.conv1(inputs, if_act=True)
|
||||
for block in self.block_list:
|
||||
y = block(y)
|
||||
y = self.conv9(y, if_act=True)
|
||||
y = self.pool2d_avg(y)
|
||||
y = fluid.layers.reshape(y, shape=[-1, self.out_c])
|
||||
y = self.out(y)
|
||||
return y
|
||||
|
||||
|
||||
def MobileNetV2_x0_25():
|
||||
model = MobileNetV2(scale=0.25)
|
||||
def MobileNetV2_x0_25(**args):
|
||||
model = MobileNet(scale=0.25, **args)
|
||||
return model
|
||||
|
||||
|
||||
def MobileNetV2_x0_5():
|
||||
model = MobileNetV2(scale=0.5)
|
||||
def MobileNetV2_x0_5(**args):
|
||||
model = MobileNet(scale=0.5, **args)
|
||||
return model
|
||||
|
||||
|
||||
def MobileNetV2_x0_75():
|
||||
model = MobileNetV2(scale=0.75)
|
||||
def MobileNetV2_x0_75(**args):
|
||||
model = MobileNet(scale=0.75, **args)
|
||||
return model
|
||||
|
||||
|
||||
def MobileNetV2_x1_0():
|
||||
model = MobileNetV2(scale=1.0)
|
||||
def MobileNetV2(**args):
|
||||
model = MobileNet(scale=1.0, **args)
|
||||
return model
|
||||
|
||||
|
||||
def MobileNetV2_x1_5():
|
||||
model = MobileNetV2(scale=1.5)
|
||||
def MobileNetV2_x1_5(**args):
|
||||
model = MobileNet(scale=1.5, **args)
|
||||
return model
|
||||
|
||||
|
||||
def MobileNetV2_x2_0():
|
||||
model = MobileNetV2(scale=2.0)
|
||||
def MobileNetV2_x2_0(**args):
|
||||
model = MobileNet(scale=2.0, **args)
|
||||
return model
|
||||
|
|
|
@ -16,320 +16,342 @@ from __future__ import absolute_import
|
|||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import paddle
|
||||
import paddle.fluid as fluid
|
||||
from paddle.fluid.param_attr import ParamAttr
|
||||
from paddle.fluid.layer_helper import LayerHelper
|
||||
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, Linear, Dropout
|
||||
|
||||
import math
|
||||
|
||||
__all__ = [
|
||||
'MobileNetV3', 'MobileNetV3_small_x0_35', 'MobileNetV3_small_x0_5',
|
||||
'MobileNetV3_small_x0_75', 'MobileNetV3_small_x1_0',
|
||||
'MobileNetV3_small_x1_25', 'MobileNetV3_large_x0_35',
|
||||
'MobileNetV3_large_x0_5', 'MobileNetV3_large_x0_75',
|
||||
'MobileNetV3_large_x1_0', 'MobileNetV3_large_x1_25'
|
||||
"MobileNetV3_small_x0_35", "MobileNetV3_small_x0_5",
|
||||
"MobileNetV3_small_x0_75", "MobileNetV3_small_x1_0",
|
||||
"MobileNetV3_small_x1_25", "MobileNetV3_large_x0_35",
|
||||
"MobileNetV3_large_x0_5", "MobileNetV3_large_x0_75",
|
||||
"MobileNetV3_large_x1_0", "MobileNetV3_large_x1_25"
|
||||
]
|
||||
|
||||
|
||||
class MobileNetV3():
|
||||
def __init__(self,
|
||||
scale=1.0,
|
||||
model_name='small',
|
||||
lr_mult_list=[1.0, 1.0, 1.0, 1.0, 1.0]):
|
||||
self.scale = scale
|
||||
self.inplanes = 16
|
||||
def make_divisible(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
|
||||
|
||||
self.lr_mult_list = lr_mult_list
|
||||
assert len(self.lr_mult_list) == 5, \
|
||||
"lr_mult_list length in MobileNetV3 must be 5 but got {}!!".format(
|
||||
len(self.lr_mult_list))
|
||||
self.curr_stage = 0
|
||||
|
||||
class MobileNetV3(fluid.dygraph.Layer):
|
||||
def __init__(self, scale=1.0, model_name="small", class_dim=1000):
|
||||
super(MobileNetV3, self).__init__()
|
||||
|
||||
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],
|
||||
[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
|
||||
self.lr_interval = 3
|
||||
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],
|
||||
[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
|
||||
self.lr_interval = 2
|
||||
else:
|
||||
raise NotImplementedError(
|
||||
"mode[{}_model] is not implemented!".format(model_name))
|
||||
|
||||
def net(self, input, class_dim=1000):
|
||||
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,
|
||||
self.conv1 = ConvBNLayer(
|
||||
in_c=3,
|
||||
out_c=make_divisible(inplanes * scale),
|
||||
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)
|
||||
for layer_cfg in cfg:
|
||||
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
|
||||
self.curr_stage = i
|
||||
act="hard_swish",
|
||||
name="conv1")
|
||||
|
||||
conv = self.conv_bn_layer(
|
||||
input=conv,
|
||||
self.block_list = []
|
||||
i = 0
|
||||
inplanes = make_divisible(inplanes * scale)
|
||||
for (k, exp, c, se, nl, s) in self.cfg:
|
||||
self.block_list.append(
|
||||
ResidualUnit(
|
||||
in_c=inplanes,
|
||||
mid_c=make_divisible(scale * exp),
|
||||
out_c=make_divisible(scale * c),
|
||||
filter_size=k,
|
||||
stride=s,
|
||||
use_se=se,
|
||||
act=nl,
|
||||
name="conv" + str(i + 2)))
|
||||
self.add_sublayer(
|
||||
sublayer=self.block_list[-1], name="conv" + str(i + 2))
|
||||
inplanes = make_divisible(scale * c)
|
||||
i += 1
|
||||
|
||||
self.last_second_conv = ConvBNLayer(
|
||||
in_c=inplanes,
|
||||
out_c=make_divisible(scale * self.cls_ch_squeeze),
|
||||
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')
|
||||
conv = fluid.layers.pool2d(
|
||||
input=conv, pool_type='avg', global_pooling=True, use_cudnn=False)
|
||||
conv = fluid.layers.conv2d(
|
||||
input=conv,
|
||||
num_filters=cls_ch_expand,
|
||||
act="hard_swish",
|
||||
name="conv_last")
|
||||
|
||||
self.pool = Pool2D(
|
||||
pool_type="avg", global_pooling=True, use_cudnn=False)
|
||||
|
||||
self.last_conv = Conv2D(
|
||||
num_channels=make_divisible(scale * self.cls_ch_squeeze),
|
||||
num_filters=self.cls_ch_expand,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
act=None,
|
||||
param_attr=ParamAttr(name='last_1x1_conv_weights'),
|
||||
param_attr=ParamAttr(name="last_1x1_conv_weights"),
|
||||
bias_attr=False)
|
||||
conv = fluid.layers.hard_swish(conv)
|
||||
drop = fluid.layers.dropout(x=conv, dropout_prob=0.2)
|
||||
out = fluid.layers.fc(input=drop,
|
||||
size=class_dim,
|
||||
param_attr=ParamAttr(name='fc_weights'),
|
||||
bias_attr=ParamAttr(name='fc_offset'))
|
||||
return out
|
||||
|
||||
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):
|
||||
lr_idx = self.curr_stage // self.lr_interval
|
||||
lr_idx = min(lr_idx, len(self.lr_mult_list) - 1)
|
||||
lr_mult = self.lr_mult_list[lr_idx]
|
||||
self.out = Linear(
|
||||
input_dim=self.cls_ch_expand,
|
||||
output_dim=class_dim,
|
||||
param_attr=ParamAttr("fc_weights"),
|
||||
bias_attr=ParamAttr(name="fc_offset"))
|
||||
|
||||
conv = fluid.layers.conv2d(
|
||||
input=input,
|
||||
num_filters=num_filters,
|
||||
def forward(self, inputs, label=None, dropout_prob=0.2):
|
||||
x = self.conv1(inputs)
|
||||
for block in self.block_list:
|
||||
x = block(x)
|
||||
x = self.last_second_conv(x)
|
||||
x = self.pool(x)
|
||||
x = self.last_conv(x)
|
||||
x = fluid.layers.hard_swish(x)
|
||||
x = fluid.layers.dropout(x=x, dropout_prob=dropout_prob)
|
||||
x = fluid.layers.reshape(x, shape=[x.shape[0], x.shape[1]])
|
||||
x = self.out(x)
|
||||
|
||||
return x
|
||||
|
||||
|
||||
class ConvBNLayer(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
in_c,
|
||||
out_c,
|
||||
filter_size,
|
||||
stride,
|
||||
padding,
|
||||
num_groups=1,
|
||||
if_act=True,
|
||||
act=None,
|
||||
use_cudnn=True,
|
||||
name=""):
|
||||
super(ConvBNLayer, self).__init__()
|
||||
self.if_act = if_act
|
||||
self.act = act
|
||||
self.conv = fluid.dygraph.Conv2D(
|
||||
num_channels=in_c,
|
||||
num_filters=out_c,
|
||||
filter_size=filter_size,
|
||||
stride=stride,
|
||||
padding=padding,
|
||||
groups=num_groups,
|
||||
act=None,
|
||||
param_attr=ParamAttr(name=name + "_weights"),
|
||||
bias_attr=False,
|
||||
use_cudnn=use_cudnn,
|
||||
act=None)
|
||||
self.bn = fluid.dygraph.BatchNorm(
|
||||
num_channels=out_c,
|
||||
act=None,
|
||||
param_attr=ParamAttr(
|
||||
name=name + '_weights', learning_rate=lr_mult),
|
||||
bias_attr=False)
|
||||
bn_name = name + '_bn'
|
||||
bn = fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
param_attr=ParamAttr(
|
||||
name=bn_name + "_scale",
|
||||
name=name + "_bn_scale",
|
||||
regularizer=fluid.regularizer.L2DecayRegularizer(
|
||||
regularization_coeff=0.0)),
|
||||
bias_attr=ParamAttr(
|
||||
name=bn_name + "_offset",
|
||||
name=name + "_bn_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
|
||||
moving_mean_name=name + "_bn_mean",
|
||||
moving_variance_name=name + "_bn_variance")
|
||||
|
||||
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 forward(self, x):
|
||||
x = self.conv(x)
|
||||
x = self.bn(x)
|
||||
if self.if_act:
|
||||
if self.act == "relu":
|
||||
x = fluid.layers.relu(x)
|
||||
elif self.act == "hard_swish":
|
||||
x = fluid.layers.hard_swish(x)
|
||||
else:
|
||||
print("The activation function is selected incorrectly.")
|
||||
exit()
|
||||
return x
|
||||
|
||||
def se_block(self, input, num_out_filter, ratio=4, name=None):
|
||||
lr_idx = self.curr_stage // self.lr_interval
|
||||
lr_idx = min(lr_idx, len(self.lr_mult_list) - 1)
|
||||
lr_mult = self.lr_mult_list[lr_idx]
|
||||
|
||||
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,
|
||||
class ResidualUnit(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
in_c,
|
||||
mid_c,
|
||||
out_c,
|
||||
filter_size,
|
||||
stride,
|
||||
use_se,
|
||||
act=None,
|
||||
name=''):
|
||||
super(ResidualUnit, self).__init__()
|
||||
self.if_shortcut = stride == 1 and in_c == out_c
|
||||
self.if_se = use_se
|
||||
|
||||
self.expand_conv = ConvBNLayer(
|
||||
in_c=in_c,
|
||||
out_c=mid_c,
|
||||
filter_size=1,
|
||||
num_filters=num_mid_filter,
|
||||
act='relu',
|
||||
param_attr=ParamAttr(
|
||||
name=name + '_1_weights', learning_rate=lr_mult),
|
||||
bias_attr=ParamAttr(
|
||||
name=name + '_1_offset', learning_rate=lr_mult))
|
||||
conv2 = fluid.layers.conv2d(
|
||||
input=conv1,
|
||||
filter_size=1,
|
||||
num_filters=num_out_filter,
|
||||
act='hard_sigmoid',
|
||||
param_attr=ParamAttr(
|
||||
name=name + '_2_weights', learning_rate=lr_mult),
|
||||
bias_attr=ParamAttr(
|
||||
name=name + '_2_offset', learning_rate=lr_mult))
|
||||
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,
|
||||
name=name + "_expand")
|
||||
self.bottleneck_conv = ConvBNLayer(
|
||||
in_c=mid_c,
|
||||
out_c=mid_c,
|
||||
filter_size=filter_size,
|
||||
num_filters=num_mid_filter,
|
||||
stride=stride,
|
||||
padding=int((filter_size - 1) // 2),
|
||||
num_groups=mid_c,
|
||||
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,
|
||||
name=name + "_depthwise")
|
||||
if self.if_se:
|
||||
self.mid_se = SEModule(mid_c, name=name + "_se")
|
||||
self.linear_conv = ConvBNLayer(
|
||||
in_c=mid_c,
|
||||
out_c=out_c,
|
||||
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)
|
||||
act=None,
|
||||
name=name + "_linear")
|
||||
|
||||
def forward(self, inputs):
|
||||
x = self.expand_conv(inputs)
|
||||
x = self.bottleneck_conv(x)
|
||||
if self.if_se:
|
||||
x = self.mid_se(x)
|
||||
x = self.linear_conv(x)
|
||||
if self.if_shortcut:
|
||||
x = fluid.layers.elementwise_add(inputs, x)
|
||||
return x
|
||||
|
||||
|
||||
def MobileNetV3_small_x0_35():
|
||||
model = MobileNetV3(model_name='small', scale=0.35)
|
||||
class SEModule(fluid.dygraph.Layer):
|
||||
def __init__(self, channel, reduction=4, name=""):
|
||||
super(SEModule, self).__init__()
|
||||
self.avg_pool = fluid.dygraph.Pool2D(
|
||||
pool_type="avg", global_pooling=True, use_cudnn=False)
|
||||
self.conv1 = fluid.dygraph.Conv2D(
|
||||
num_channels=channel,
|
||||
num_filters=channel // reduction,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
act="relu",
|
||||
param_attr=ParamAttr(name=name + "_1_weights"),
|
||||
bias_attr=ParamAttr(name=name + "_1_offset"))
|
||||
self.conv2 = fluid.dygraph.Conv2D(
|
||||
num_channels=channel // reduction,
|
||||
num_filters=channel,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
act=None,
|
||||
param_attr=ParamAttr(name + "_2_weights"),
|
||||
bias_attr=ParamAttr(name=name + "_2_offset"))
|
||||
|
||||
def forward(self, inputs):
|
||||
outputs = self.avg_pool(inputs)
|
||||
outputs = self.conv1(outputs)
|
||||
outputs = self.conv2(outputs)
|
||||
outputs = fluid.layers.hard_sigmoid(outputs)
|
||||
return fluid.layers.elementwise_mul(x=inputs, y=outputs, axis=0)
|
||||
|
||||
|
||||
def MobileNetV3_small_x0_35(**args):
|
||||
model = MobileNetV3(model_name="small", scale=0.35, **args)
|
||||
return model
|
||||
|
||||
|
||||
def MobileNetV3_small_x0_5():
|
||||
model = MobileNetV3(model_name='small', scale=0.5)
|
||||
def MobileNetV3_small_x0_5(**args):
|
||||
model = MobileNetV3(model_name="small", scale=0.5, **args)
|
||||
return model
|
||||
|
||||
|
||||
def MobileNetV3_small_x0_75():
|
||||
model = MobileNetV3(model_name='small', scale=0.75)
|
||||
def MobileNetV3_small_x0_75(**args):
|
||||
model = MobileNetV3(model_name="small", scale=0.75, **args)
|
||||
return model
|
||||
|
||||
|
||||
def MobileNetV3_small_x1_0(**args):
|
||||
model = MobileNetV3(model_name='small', scale=1.0, **args)
|
||||
model = MobileNetV3(model_name="small", scale=1.0, **args)
|
||||
return model
|
||||
|
||||
|
||||
def MobileNetV3_small_x1_25():
|
||||
model = MobileNetV3(model_name='small', scale=1.25)
|
||||
def MobileNetV3_small_x1_25(**args):
|
||||
model = MobileNetV3(model_name="small", scale=1.25, **args)
|
||||
return model
|
||||
|
||||
|
||||
def MobileNetV3_large_x0_35():
|
||||
model = MobileNetV3(model_name='large', scale=0.35)
|
||||
def MobileNetV3_large_x0_35(**args):
|
||||
model = MobileNetV3(model_name="large", scale=0.35, **args)
|
||||
return model
|
||||
|
||||
|
||||
def MobileNetV3_large_x0_5():
|
||||
model = MobileNetV3(model_name='large', scale=0.5)
|
||||
def MobileNetV3_large_x0_5(**args):
|
||||
model = MobileNetV3(model_name="large", scale=0.5, **args)
|
||||
return model
|
||||
|
||||
|
||||
def MobileNetV3_large_x0_75():
|
||||
model = MobileNetV3(model_name='large', scale=0.75)
|
||||
def MobileNetV3_large_x0_75(**args):
|
||||
model = MobileNetV3(model_name="large", scale=0.75, **args)
|
||||
return model
|
||||
|
||||
|
||||
def MobileNetV3_large_x1_0(**args):
|
||||
model = MobileNetV3(model_name='large', scale=1.0, **args)
|
||||
model = MobileNetV3(model_name="large", scale=1.0, **args)
|
||||
return model
|
||||
|
||||
|
||||
def MobileNetV3_large_x1_25():
|
||||
model = MobileNetV3(model_name='large', scale=1.25)
|
||||
def MobileNetV3_large_x1_25(**args):
|
||||
model = MobileNetV3(model_name="large", scale=1.25, **args)
|
||||
return model
|
||||
|
|
|
@ -1,111 +1,51 @@
|
|||
#copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
|
||||
# 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
|
||||
# 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.
|
||||
# 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 numpy as np
|
||||
import paddle
|
||||
import paddle.fluid as fluid
|
||||
import math
|
||||
from paddle.fluid.param_attr import ParamAttr
|
||||
from paddle.fluid.layer_helper import LayerHelper
|
||||
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, Linear, Dropout
|
||||
|
||||
import math
|
||||
|
||||
__all__ = [
|
||||
"Res2Net", "Res2Net50_48w_2s", "Res2Net50_26w_4s", "Res2Net50_14w_8s",
|
||||
"Res2Net50_26w_6s", "Res2Net50_26w_8s", "Res2Net101_26w_4s",
|
||||
"Res2Net152_26w_4s"
|
||||
"Res2Net50_48w_2s", "Res2Net50_26w_4s", "Res2Net50_14w_8s",
|
||||
"Res2Net50_48w_2s", "Res2Net50_26w_6s", "Res2Net50_26w_8s",
|
||||
"Res2Net101_26w_4s", "Res2Net152_26w_4s", "Res2Net200_26w_4s"
|
||||
]
|
||||
|
||||
|
||||
class Res2Net():
|
||||
def __init__(self, layers=50, scales=4, width=26):
|
||||
self.layers = layers
|
||||
self.scales = scales
|
||||
self.width = width
|
||||
class ConvBNLayer(fluid.dygraph.Layer):
|
||||
def __init__(
|
||||
self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
act=None,
|
||||
name=None, ):
|
||||
super(ConvBNLayer, self).__init__()
|
||||
|
||||
def net(self, input, class_dim=1000):
|
||||
layers = self.layers
|
||||
supported_layers = [50, 101, 152]
|
||||
assert layers in supported_layers, \
|
||||
"supported layers are {} but input layer is {}".format(supported_layers, layers)
|
||||
basic_width = self.width * self.scales
|
||||
num_filters1 = [basic_width * t for t in [1, 2, 4, 8]]
|
||||
num_filters2 = [256 * t for t in [1, 2, 4, 8]]
|
||||
|
||||
if layers == 50:
|
||||
depth = [3, 4, 6, 3]
|
||||
elif layers == 101:
|
||||
depth = [3, 4, 23, 3]
|
||||
elif layers == 152:
|
||||
depth = [3, 8, 36, 3]
|
||||
conv = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=64,
|
||||
filter_size=7,
|
||||
stride=2,
|
||||
act='relu',
|
||||
name="conv1")
|
||||
|
||||
conv = fluid.layers.pool2d(
|
||||
input=conv,
|
||||
pool_size=3,
|
||||
pool_stride=2,
|
||||
pool_padding=1,
|
||||
pool_type='max')
|
||||
|
||||
for block in range(len(depth)):
|
||||
for i in range(depth[block]):
|
||||
if layers in [101, 152] and block == 2:
|
||||
if i == 0:
|
||||
conv_name = "res" + str(block + 2) + "a"
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + "b" + str(i)
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + chr(97 + i)
|
||||
conv = self.bottleneck_block(
|
||||
input=conv,
|
||||
num_filters1=num_filters1[block],
|
||||
num_filters2=num_filters2[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
name=conv_name)
|
||||
pool = fluid.layers.pool2d(
|
||||
input=conv,
|
||||
pool_size=7,
|
||||
pool_stride=1,
|
||||
pool_type='avg',
|
||||
global_pooling=True)
|
||||
|
||||
stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0)
|
||||
out = fluid.layers.fc(
|
||||
input=pool,
|
||||
size=class_dim,
|
||||
param_attr=fluid.param_attr.ParamAttr(
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv),
|
||||
name='fc_weights'),
|
||||
bias_attr=fluid.param_attr.ParamAttr(name='fc_offset'))
|
||||
return out
|
||||
|
||||
def conv_bn_layer(self,
|
||||
input,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
act=None,
|
||||
name=None):
|
||||
conv = fluid.layers.conv2d(
|
||||
input=input,
|
||||
self._conv = Conv2D(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=stride,
|
||||
|
@ -114,112 +54,227 @@ class Res2Net():
|
|||
act=None,
|
||||
param_attr=ParamAttr(name=name + "_weights"),
|
||||
bias_attr=False)
|
||||
|
||||
if name == "conv1":
|
||||
bn_name = "bn_" + name
|
||||
else:
|
||||
bn_name = "bn" + name[3:]
|
||||
|
||||
return fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
self._batch_norm = BatchNorm(
|
||||
num_filters,
|
||||
act=act,
|
||||
param_attr=ParamAttr(name=bn_name + '_scale'),
|
||||
bias_attr=ParamAttr(bn_name + '_offset'),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
|
||||
def shortcut(self, input, ch_out, stride, name):
|
||||
ch_in = input.shape[1]
|
||||
if ch_in != ch_out or stride != 1:
|
||||
return self.conv_bn_layer(input, ch_out, 1, stride, name=name)
|
||||
else:
|
||||
return input
|
||||
def forward(self, inputs):
|
||||
y = self._conv(inputs)
|
||||
y = self._batch_norm(y)
|
||||
return y
|
||||
|
||||
def bottleneck_block(self, input, num_filters1, num_filters2, stride,
|
||||
name):
|
||||
conv0 = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=num_filters1,
|
||||
|
||||
class BottleneckBlock(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
num_channels1,
|
||||
num_channels2,
|
||||
num_filters,
|
||||
stride,
|
||||
scales,
|
||||
shortcut=True,
|
||||
if_first=False,
|
||||
name=None):
|
||||
super(BottleneckBlock, self).__init__()
|
||||
self.stride = stride
|
||||
self.scales = scales
|
||||
self.conv0 = ConvBNLayer(
|
||||
num_channels=num_channels1,
|
||||
num_filters=num_filters,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name=name + '_branch2a')
|
||||
xs = fluid.layers.split(conv0, self.scales, 1)
|
||||
ys = []
|
||||
for s in range(self.scales - 1):
|
||||
if s == 0 or stride == 2:
|
||||
ys.append(
|
||||
self.conv_bn_layer(
|
||||
input=xs[s],
|
||||
num_filters=num_filters1 // self.scales,
|
||||
stride=stride,
|
||||
filter_size=3,
|
||||
act='relu',
|
||||
name=name + '_branch2b_' + str(s + 1)))
|
||||
else:
|
||||
ys.append(
|
||||
self.conv_bn_layer(
|
||||
input=xs[s] + ys[-1],
|
||||
num_filters=num_filters1 // self.scales,
|
||||
stride=stride,
|
||||
filter_size=3,
|
||||
act='relu',
|
||||
name=name + '_branch2b_' + str(s + 1)))
|
||||
if stride == 1:
|
||||
ys.append(xs[-1])
|
||||
else:
|
||||
ys.append(
|
||||
fluid.layers.pool2d(
|
||||
input=xs[-1],
|
||||
pool_size=3,
|
||||
pool_stride=stride,
|
||||
pool_padding=1,
|
||||
pool_type='avg'))
|
||||
name=name + "_branch2a")
|
||||
self.conv1_list = []
|
||||
for s in range(scales - 1):
|
||||
conv1 = self.add_sublayer(
|
||||
name + '_branch2b_' + str(s + 1),
|
||||
ConvBNLayer(
|
||||
num_channels=num_filters // scales,
|
||||
num_filters=num_filters // scales,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
act='relu',
|
||||
name=name + '_branch2b_' + str(s + 1)))
|
||||
self.conv1_list.append(conv1)
|
||||
self.pool2d_avg = Pool2D(
|
||||
pool_size=3, pool_stride=stride, pool_padding=1, pool_type='avg')
|
||||
|
||||
conv1 = fluid.layers.concat(ys, axis=1)
|
||||
conv2 = self.conv_bn_layer(
|
||||
input=conv1,
|
||||
num_filters=num_filters2,
|
||||
self.conv2 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_channels2,
|
||||
filter_size=1,
|
||||
act=None,
|
||||
name=name + "_branch2c")
|
||||
|
||||
short = self.shortcut(
|
||||
input, num_filters2, stride, name=name + "_branch1")
|
||||
if not shortcut:
|
||||
self.short = ConvBNLayer(
|
||||
num_channels=num_channels1,
|
||||
num_filters=num_channels2,
|
||||
filter_size=1,
|
||||
stride=stride,
|
||||
name=name + "_branch1")
|
||||
|
||||
return fluid.layers.elementwise_add(x=short, y=conv2, act='relu')
|
||||
self.shortcut = shortcut
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self.conv0(inputs)
|
||||
xs = fluid.layers.split(y, self.scales, 1)
|
||||
ys = []
|
||||
for s, conv1 in enumerate(self.conv1_list):
|
||||
if s == 0 or self.stride == 2:
|
||||
ys.append(conv1(xs[s]))
|
||||
else:
|
||||
ys.append(conv1(xs[s] + ys[-1]))
|
||||
if self.stride == 1:
|
||||
ys.append(xs[-1])
|
||||
else:
|
||||
ys.append(self.pool2d_avg(xs[-1]))
|
||||
conv1 = fluid.layers.concat(ys, axis=1)
|
||||
conv2 = self.conv2(conv1)
|
||||
|
||||
if self.shortcut:
|
||||
short = inputs
|
||||
else:
|
||||
short = self.short(inputs)
|
||||
y = fluid.layers.elementwise_add(x=short, y=conv2)
|
||||
layer_helper = LayerHelper(self.full_name(), act='relu')
|
||||
return layer_helper.append_activation(y)
|
||||
|
||||
|
||||
def Res2Net50_48w_2s():
|
||||
model = Res2Net(layers=50, scales=2, width=48)
|
||||
class Res2Net(fluid.dygraph.Layer):
|
||||
def __init__(self, layers=50, scales=4, width=26, class_dim=1000):
|
||||
super(Res2Net, self).__init__()
|
||||
|
||||
self.layers = layers
|
||||
self.scales = scales
|
||||
self.width = width
|
||||
basic_width = self.width * self.scales
|
||||
supported_layers = [50, 101, 152, 200]
|
||||
assert layers in supported_layers, \
|
||||
"supported layers are {} but input layer is {}".format(
|
||||
supported_layers, layers)
|
||||
|
||||
if layers == 50:
|
||||
depth = [3, 4, 6, 3]
|
||||
elif layers == 101:
|
||||
depth = [3, 4, 23, 3]
|
||||
elif layers == 152:
|
||||
depth = [3, 8, 36, 3]
|
||||
elif layers == 200:
|
||||
depth = [3, 12, 48, 3]
|
||||
num_channels = [64, 256, 512, 1024]
|
||||
num_channels2 = [256, 512, 1024, 2048]
|
||||
num_filters = [basic_width * t for t in [1, 2, 4, 8]]
|
||||
|
||||
self.conv1 = ConvBNLayer(
|
||||
num_channels=3,
|
||||
num_filters=64,
|
||||
filter_size=7,
|
||||
stride=2,
|
||||
act='relu',
|
||||
name="conv1")
|
||||
self.pool2d_max = Pool2D(
|
||||
pool_size=3, pool_stride=2, pool_padding=1, pool_type='max')
|
||||
|
||||
self.block_list = []
|
||||
for block in range(len(depth)):
|
||||
shortcut = False
|
||||
for i in range(depth[block]):
|
||||
if layers in [101, 152] and block == 2:
|
||||
if i == 0:
|
||||
conv_name = "res" + str(block + 2) + "a"
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + "b" + str(i)
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + chr(97 + i)
|
||||
bottleneck_block = self.add_sublayer(
|
||||
'bb_%d_%d' % (block, i),
|
||||
BottleneckBlock(
|
||||
num_channels1=num_channels[block]
|
||||
if i == 0 else num_channels2[block],
|
||||
num_channels2=num_channels2[block],
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
scales=scales,
|
||||
shortcut=shortcut,
|
||||
if_first=block == i == 0,
|
||||
name=conv_name))
|
||||
self.block_list.append(bottleneck_block)
|
||||
shortcut = True
|
||||
|
||||
self.pool2d_avg = Pool2D(
|
||||
pool_size=7, pool_type='avg', global_pooling=True)
|
||||
|
||||
self.pool2d_avg_channels = num_channels[-1] * 2
|
||||
|
||||
stdv = 1.0 / math.sqrt(self.pool2d_avg_channels * 1.0)
|
||||
|
||||
self.out = Linear(
|
||||
self.pool2d_avg_channels,
|
||||
class_dim,
|
||||
param_attr=ParamAttr(
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv),
|
||||
name="fc_weights"),
|
||||
bias_attr=ParamAttr(name="fc_offset"))
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self.conv1(inputs)
|
||||
y = self.pool2d_max(y)
|
||||
for block in self.block_list:
|
||||
y = block(y)
|
||||
y = self.pool2d_avg(y)
|
||||
y = fluid.layers.reshape(y, shape=[-1, self.pool2d_avg_channels])
|
||||
y = self.out(y)
|
||||
return y
|
||||
|
||||
|
||||
def Res2Net50_48w_2s(**args):
|
||||
model = Res2Net(layers=50, scales=2, width=48, **args)
|
||||
return model
|
||||
|
||||
|
||||
def Res2Net50_26w_4s():
|
||||
model = Res2Net(layers=50, scales=4, width=26)
|
||||
def Res2Net50_26w_4s(**args):
|
||||
model = Res2Net(layers=50, scales=4, width=26, **args)
|
||||
return model
|
||||
|
||||
|
||||
def Res2Net50_14w_8s():
|
||||
model = Res2Net(layers=50, scales=8, width=14)
|
||||
def Res2Net50_14w_8s(**args):
|
||||
model = Res2Net(layers=50, scales=8, width=14, **args)
|
||||
return model
|
||||
|
||||
|
||||
def Res2Net50_26w_6s():
|
||||
model = Res2Net(layers=50, scales=6, width=26)
|
||||
def Res2Net50_48w_2s(**args):
|
||||
model = Res2Net(layers=50, scales=2, width=48, **args)
|
||||
return model
|
||||
|
||||
|
||||
def Res2Net50_26w_8s():
|
||||
model = Res2Net(layers=50, scales=8, width=26)
|
||||
def Res2Net50_26w_6s(**args):
|
||||
model = Res2Net(layers=50, scales=6, width=26, **args)
|
||||
return model
|
||||
|
||||
|
||||
def Res2Net101_26w_4s():
|
||||
model = Res2Net(layers=101, scales=4, width=26)
|
||||
def Res2Net50_26w_8s(**args):
|
||||
model = Res2Net(layers=50, scales=8, width=26, **args)
|
||||
return model
|
||||
|
||||
|
||||
def Res2Net152_26w_4s():
|
||||
model = Res2Net(layers=152, scales=4, width=26)
|
||||
def Res2Net101_26w_4s(**args):
|
||||
model = Res2Net(layers=101, scales=4, width=26, **args)
|
||||
return model
|
||||
|
||||
|
||||
def Res2Net152_26w_4s(**args):
|
||||
model = Res2Net(layers=152, scales=4, width=26, **args)
|
||||
return model
|
||||
|
||||
|
||||
def Res2Net200_26w_4s(**args):
|
||||
model = Res2Net(layers=200, scales=4, width=26, **args)
|
||||
return model
|
||||
|
|
|
@ -16,112 +16,40 @@ from __future__ import absolute_import
|
|||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import math
|
||||
|
||||
import numpy as np
|
||||
import paddle
|
||||
import paddle.fluid as fluid
|
||||
from paddle.fluid.param_attr import ParamAttr
|
||||
from paddle.fluid.layer_helper import LayerHelper
|
||||
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, Linear, Dropout
|
||||
|
||||
import math
|
||||
|
||||
__all__ = [
|
||||
"Res2Net_vd", "Res2Net50_vd_48w_2s", "Res2Net50_vd_26w_4s",
|
||||
"Res2Net50_vd_14w_8s", "Res2Net50_vd_26w_6s", "Res2Net50_vd_26w_8s",
|
||||
"Res2Net50_vd_48w_2s", "Res2Net50_vd_26w_4s", "Res2Net50_vd_14w_8s",
|
||||
"Res2Net50_vd_48w_2s", "Res2Net50_vd_26w_6s", "Res2Net50_vd_26w_8s",
|
||||
"Res2Net101_vd_26w_4s", "Res2Net152_vd_26w_4s", "Res2Net200_vd_26w_4s"
|
||||
]
|
||||
|
||||
|
||||
class Res2Net_vd():
|
||||
def __init__(self, layers=50, scales=4, width=26):
|
||||
self.layers = layers
|
||||
self.scales = scales
|
||||
self.width = width
|
||||
|
||||
def net(self, input, class_dim=1000):
|
||||
layers = self.layers
|
||||
supported_layers = [50, 101, 152, 200]
|
||||
assert layers in supported_layers, \
|
||||
"supported layers are {} but input layer is {}".format(
|
||||
supported_layers, layers)
|
||||
basic_width = self.width * self.scales
|
||||
num_filters1 = [basic_width * t for t in [1, 2, 4, 8]]
|
||||
num_filters2 = [256 * t for t in [1, 2, 4, 8]]
|
||||
if layers == 50:
|
||||
depth = [3, 4, 6, 3]
|
||||
elif layers == 101:
|
||||
depth = [3, 4, 23, 3]
|
||||
elif layers == 152:
|
||||
depth = [3, 8, 36, 3]
|
||||
elif layers == 200:
|
||||
depth = [3, 12, 48, 3]
|
||||
conv = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
stride=2,
|
||||
act='relu',
|
||||
name='conv1_1')
|
||||
conv = self.conv_bn_layer(
|
||||
input=conv,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
class ConvBNLayer(fluid.dygraph.Layer):
|
||||
def __init__(
|
||||
self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name='conv1_2')
|
||||
conv = self.conv_bn_layer(
|
||||
input=conv,
|
||||
num_filters=64,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name='conv1_3')
|
||||
groups=1,
|
||||
is_vd_mode=False,
|
||||
act=None,
|
||||
name=None, ):
|
||||
super(ConvBNLayer, self).__init__()
|
||||
|
||||
conv = fluid.layers.pool2d(
|
||||
input=conv,
|
||||
pool_size=3,
|
||||
pool_stride=2,
|
||||
pool_padding=1,
|
||||
pool_type='max')
|
||||
for block in range(len(depth)):
|
||||
for i in range(depth[block]):
|
||||
if layers in [101, 152, 200] and block == 2:
|
||||
if i == 0:
|
||||
conv_name = "res" + str(block + 2) + "a"
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + "b" + str(i)
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + chr(97 + i)
|
||||
conv = self.bottleneck_block(
|
||||
input=conv,
|
||||
num_filters1=num_filters1[block],
|
||||
num_filters2=num_filters2[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
if_first=block == i == 0,
|
||||
name=conv_name)
|
||||
pool = fluid.layers.pool2d(
|
||||
input=conv,
|
||||
pool_size=7,
|
||||
pool_stride=1,
|
||||
pool_type='avg',
|
||||
global_pooling=True)
|
||||
|
||||
stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0)
|
||||
out = fluid.layers.fc(
|
||||
input=pool,
|
||||
size=class_dim,
|
||||
param_attr=fluid.param_attr.ParamAttr(
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv),
|
||||
name='fc_weights'),
|
||||
bias_attr=fluid.param_attr.ParamAttr(name='fc_offset'))
|
||||
return out
|
||||
|
||||
def conv_bn_layer(self,
|
||||
input,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
act=None,
|
||||
name=None):
|
||||
conv = fluid.layers.conv2d(
|
||||
input=input,
|
||||
self.is_vd_mode = is_vd_mode
|
||||
self._pool2d_avg = Pool2D(
|
||||
pool_size=2, pool_stride=2, pool_padding=0, pool_type='avg')
|
||||
self._conv = Conv2D(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=stride,
|
||||
|
@ -134,161 +62,242 @@ class Res2Net_vd():
|
|||
bn_name = "bn_" + name
|
||||
else:
|
||||
bn_name = "bn" + name[3:]
|
||||
return fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
self._batch_norm = BatchNorm(
|
||||
num_filters,
|
||||
act=act,
|
||||
param_attr=ParamAttr(name=bn_name + '_scale'),
|
||||
bias_attr=ParamAttr(bn_name + '_offset'),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
|
||||
def conv_bn_layer_new(self,
|
||||
input,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
act=None,
|
||||
name=None):
|
||||
pool = fluid.layers.pool2d(
|
||||
input=input,
|
||||
pool_size=2,
|
||||
pool_stride=2,
|
||||
pool_padding=0,
|
||||
pool_type='avg',
|
||||
ceil_mode=True)
|
||||
def forward(self, inputs):
|
||||
if self.is_vd_mode:
|
||||
inputs = self._pool2d_avg(inputs)
|
||||
y = self._conv(inputs)
|
||||
y = self._batch_norm(y)
|
||||
return y
|
||||
|
||||
conv = fluid.layers.conv2d(
|
||||
input=pool,
|
||||
|
||||
class BottleneckBlock(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
num_channels1,
|
||||
num_channels2,
|
||||
num_filters,
|
||||
stride,
|
||||
scales,
|
||||
shortcut=True,
|
||||
if_first=False,
|
||||
name=None):
|
||||
super(BottleneckBlock, self).__init__()
|
||||
self.stride = stride
|
||||
self.scales = scales
|
||||
self.conv0 = ConvBNLayer(
|
||||
num_channels=num_channels1,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=1,
|
||||
padding=(filter_size - 1) // 2,
|
||||
groups=groups,
|
||||
act=None,
|
||||
param_attr=ParamAttr(name=name + "_weights"),
|
||||
bias_attr=False)
|
||||
if name == "conv1":
|
||||
bn_name = "bn_" + name
|
||||
else:
|
||||
bn_name = "bn" + name[3:]
|
||||
return fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
act=act,
|
||||
param_attr=ParamAttr(name=bn_name + '_scale'),
|
||||
bias_attr=ParamAttr(bn_name + '_offset'),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
|
||||
def shortcut(self, input, ch_out, stride, name, if_first=False):
|
||||
ch_in = input.shape[1]
|
||||
if ch_in != ch_out or stride != 1:
|
||||
if if_first:
|
||||
return self.conv_bn_layer(input, ch_out, 1, stride, name=name)
|
||||
else:
|
||||
return self.conv_bn_layer_new(
|
||||
input, ch_out, 1, stride, name=name)
|
||||
elif if_first:
|
||||
return self.conv_bn_layer(input, ch_out, 1, stride, name=name)
|
||||
else:
|
||||
return input
|
||||
|
||||
def bottleneck_block(self, input, num_filters1, num_filters2, stride, name,
|
||||
if_first):
|
||||
conv0 = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=num_filters1,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name=name + '_branch2a')
|
||||
name=name + "_branch2a")
|
||||
self.conv1_list = []
|
||||
for s in range(scales - 1):
|
||||
conv1 = self.add_sublayer(
|
||||
name + '_branch2b_' + str(s + 1),
|
||||
ConvBNLayer(
|
||||
num_channels=num_filters // scales,
|
||||
num_filters=num_filters // scales,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
act='relu',
|
||||
name=name + '_branch2b_' + str(s + 1)))
|
||||
self.conv1_list.append(conv1)
|
||||
self.pool2d_avg = Pool2D(
|
||||
pool_size=3, pool_stride=stride, pool_padding=1, pool_type='avg')
|
||||
|
||||
xs = fluid.layers.split(conv0, self.scales, 1)
|
||||
ys = []
|
||||
for s in range(self.scales - 1):
|
||||
if s == 0 or stride == 2:
|
||||
ys.append(
|
||||
self.conv_bn_layer(
|
||||
input=xs[s],
|
||||
num_filters=num_filters1 // self.scales,
|
||||
stride=stride,
|
||||
filter_size=3,
|
||||
act='relu',
|
||||
name=name + '_branch2b_' + str(s + 1)))
|
||||
else:
|
||||
ys.append(
|
||||
self.conv_bn_layer(
|
||||
input=xs[s] + ys[-1],
|
||||
num_filters=num_filters1 // self.scales,
|
||||
stride=stride,
|
||||
filter_size=3,
|
||||
act='relu',
|
||||
name=name + '_branch2b_' + str(s + 1)))
|
||||
|
||||
if stride == 1:
|
||||
ys.append(xs[-1])
|
||||
else:
|
||||
ys.append(
|
||||
fluid.layers.pool2d(
|
||||
input=xs[-1],
|
||||
pool_size=3,
|
||||
pool_stride=stride,
|
||||
pool_padding=1,
|
||||
pool_type='avg'))
|
||||
|
||||
conv1 = fluid.layers.concat(ys, axis=1)
|
||||
conv2 = self.conv_bn_layer(
|
||||
input=conv1,
|
||||
num_filters=num_filters2,
|
||||
self.conv2 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_channels2,
|
||||
filter_size=1,
|
||||
act=None,
|
||||
name=name + "_branch2c")
|
||||
|
||||
short = self.shortcut(
|
||||
input,
|
||||
num_filters2,
|
||||
stride,
|
||||
if_first=if_first,
|
||||
name=name + "_branch1")
|
||||
if not shortcut:
|
||||
self.short = ConvBNLayer(
|
||||
num_channels=num_channels1,
|
||||
num_filters=num_channels2,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
is_vd_mode=False if if_first else True,
|
||||
name=name + "_branch1")
|
||||
|
||||
return fluid.layers.elementwise_add(x=short, y=conv2, act='relu')
|
||||
self.shortcut = shortcut
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self.conv0(inputs)
|
||||
xs = fluid.layers.split(y, self.scales, 1)
|
||||
ys = []
|
||||
for s, conv1 in enumerate(self.conv1_list):
|
||||
if s == 0 or self.stride == 2:
|
||||
ys.append(conv1(xs[s]))
|
||||
else:
|
||||
ys.append(conv1(xs[s] + ys[-1]))
|
||||
if self.stride == 1:
|
||||
ys.append(xs[-1])
|
||||
else:
|
||||
ys.append(self.pool2d_avg(xs[-1]))
|
||||
conv1 = fluid.layers.concat(ys, axis=1)
|
||||
conv2 = self.conv2(conv1)
|
||||
|
||||
if self.shortcut:
|
||||
short = inputs
|
||||
else:
|
||||
short = self.short(inputs)
|
||||
y = fluid.layers.elementwise_add(x=short, y=conv2)
|
||||
layer_helper = LayerHelper(self.full_name(), act='relu')
|
||||
return layer_helper.append_activation(y)
|
||||
|
||||
|
||||
def Res2Net50_vd_48w_2s():
|
||||
model = Res2Net_vd(layers=50, scales=2, width=48)
|
||||
class Res2Net_vd(fluid.dygraph.Layer):
|
||||
def __init__(self, layers=50, scales=4, width=26, class_dim=1000):
|
||||
super(Res2Net_vd, self).__init__()
|
||||
|
||||
self.layers = layers
|
||||
self.scales = scales
|
||||
self.width = width
|
||||
basic_width = self.width * self.scales
|
||||
supported_layers = [50, 101, 152, 200]
|
||||
assert layers in supported_layers, \
|
||||
"supported layers are {} but input layer is {}".format(
|
||||
supported_layers, layers)
|
||||
|
||||
if layers == 50:
|
||||
depth = [3, 4, 6, 3]
|
||||
elif layers == 101:
|
||||
depth = [3, 4, 23, 3]
|
||||
elif layers == 152:
|
||||
depth = [3, 8, 36, 3]
|
||||
elif layers == 200:
|
||||
depth = [3, 12, 48, 3]
|
||||
num_channels = [64, 256, 512, 1024]
|
||||
num_channels2 = [256, 512, 1024, 2048]
|
||||
num_filters = [basic_width * t for t in [1, 2, 4, 8]]
|
||||
|
||||
self.conv1_1 = ConvBNLayer(
|
||||
num_channels=3,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
stride=2,
|
||||
act='relu',
|
||||
name="conv1_1")
|
||||
self.conv1_2 = ConvBNLayer(
|
||||
num_channels=32,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name="conv1_2")
|
||||
self.conv1_3 = ConvBNLayer(
|
||||
num_channels=32,
|
||||
num_filters=64,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name="conv1_3")
|
||||
self.pool2d_max = Pool2D(
|
||||
pool_size=3, pool_stride=2, pool_padding=1, pool_type='max')
|
||||
|
||||
self.block_list = []
|
||||
for block in range(len(depth)):
|
||||
shortcut = False
|
||||
for i in range(depth[block]):
|
||||
if layers in [101, 152, 200] and block == 2:
|
||||
if i == 0:
|
||||
conv_name = "res" + str(block + 2) + "a"
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + "b" + str(i)
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + chr(97 + i)
|
||||
bottleneck_block = self.add_sublayer(
|
||||
'bb_%d_%d' % (block, i),
|
||||
BottleneckBlock(
|
||||
num_channels1=num_channels[block]
|
||||
if i == 0 else num_channels2[block],
|
||||
num_channels2=num_channels2[block],
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
scales=scales,
|
||||
shortcut=shortcut,
|
||||
if_first=block == i == 0,
|
||||
name=conv_name))
|
||||
self.block_list.append(bottleneck_block)
|
||||
shortcut = True
|
||||
|
||||
self.pool2d_avg = Pool2D(
|
||||
pool_size=7, pool_type='avg', global_pooling=True)
|
||||
|
||||
self.pool2d_avg_channels = num_channels[-1] * 2
|
||||
|
||||
stdv = 1.0 / math.sqrt(self.pool2d_avg_channels * 1.0)
|
||||
|
||||
self.out = Linear(
|
||||
self.pool2d_avg_channels,
|
||||
class_dim,
|
||||
param_attr=ParamAttr(
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv),
|
||||
name="fc_weights"),
|
||||
bias_attr=ParamAttr(name="fc_offset"))
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self.conv1_1(inputs)
|
||||
y = self.conv1_2(y)
|
||||
y = self.conv1_3(y)
|
||||
y = self.pool2d_max(y)
|
||||
for block in self.block_list:
|
||||
y = block(y)
|
||||
y = self.pool2d_avg(y)
|
||||
y = fluid.layers.reshape(y, shape=[-1, self.pool2d_avg_channels])
|
||||
y = self.out(y)
|
||||
return y
|
||||
|
||||
|
||||
def Res2Net50_vd_48w_2s(**args):
|
||||
model = Res2Net_vd(layers=50, scales=2, width=48, **args)
|
||||
return model
|
||||
|
||||
|
||||
def Res2Net50_vd_26w_4s():
|
||||
model = Res2Net_vd(layers=50, scales=4, width=26)
|
||||
def Res2Net50_vd_26w_4s(**args):
|
||||
model = Res2Net_vd(layers=50, scales=4, width=26, **args)
|
||||
return model
|
||||
|
||||
|
||||
def Res2Net50_vd_14w_8s():
|
||||
model = Res2Net_vd(layers=50, scales=8, width=14)
|
||||
def Res2Net50_vd_14w_8s(**args):
|
||||
model = Res2Net_vd(layers=50, scales=8, width=14, **args)
|
||||
return model
|
||||
|
||||
|
||||
def Res2Net50_vd_26w_6s():
|
||||
model = Res2Net_vd(layers=50, scales=6, width=26)
|
||||
def Res2Net50_vd_48w_2s(**args):
|
||||
model = Res2Net_vd(layers=50, scales=2, width=48, **args)
|
||||
return model
|
||||
|
||||
|
||||
def Res2Net50_vd_26w_8s():
|
||||
model = Res2Net_vd(layers=50, scales=8, width=26)
|
||||
def Res2Net50_vd_26w_6s(**args):
|
||||
model = Res2Net_vd(layers=50, scales=6, width=26, **args)
|
||||
return model
|
||||
|
||||
|
||||
def Res2Net101_vd_26w_4s():
|
||||
model = Res2Net_vd(layers=101, scales=4, width=26)
|
||||
def Res2Net50_vd_26w_8s(**args):
|
||||
model = Res2Net_vd(layers=50, scales=8, width=26, **args)
|
||||
return model
|
||||
|
||||
|
||||
def Res2Net152_vd_26w_4s():
|
||||
model = Res2Net_vd(layers=152, scales=4, width=26)
|
||||
def Res2Net101_vd_26w_4s(**args):
|
||||
model = Res2Net_vd(layers=101, scales=4, width=26, **args)
|
||||
return model
|
||||
|
||||
|
||||
def Res2Net200_vd_26w_4s():
|
||||
model = Res2Net_vd(layers=200, scales=4, width=26)
|
||||
def Res2Net152_vd_26w_4s(**args):
|
||||
model = Res2Net_vd(layers=152, scales=4, width=26, **args)
|
||||
return model
|
||||
|
||||
|
||||
def Res2Net200_vd_26w_4s(**args):
|
||||
model = Res2Net_vd(layers=200, scales=4, width=26, **args)
|
||||
return model
|
||||
|
|
|
@ -12,19 +12,20 @@
|
|||
# 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 numpy as np
|
||||
import paddle
|
||||
import paddle.fluid as fluid
|
||||
from paddle.fluid.param_attr import ParamAttr
|
||||
from paddle.fluid.layer_helper import LayerHelper
|
||||
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, Linear
|
||||
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, Linear, Dropout
|
||||
|
||||
import math
|
||||
|
||||
__all__ = [
|
||||
"ResNet18",
|
||||
"ResNet34",
|
||||
"ResNet50",
|
||||
"ResNet101",
|
||||
"ResNet152",
|
||||
]
|
||||
__all__ = ["ResNet18", "ResNet34", "ResNet50", "ResNet101", "ResNet152"]
|
||||
|
||||
|
||||
class ConvBNLayer(fluid.dygraph.Layer):
|
||||
|
@ -34,7 +35,8 @@ class ConvBNLayer(fluid.dygraph.Layer):
|
|||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
act=None):
|
||||
act=None,
|
||||
name=None):
|
||||
super(ConvBNLayer, self).__init__()
|
||||
|
||||
self._conv = Conv2D(
|
||||
|
@ -45,44 +47,62 @@ class ConvBNLayer(fluid.dygraph.Layer):
|
|||
padding=(filter_size - 1) // 2,
|
||||
groups=groups,
|
||||
act=None,
|
||||
param_attr=ParamAttr(name=name + "_weights"),
|
||||
bias_attr=False)
|
||||
|
||||
self._batch_norm = BatchNorm(num_filters, act=act)
|
||||
if name == "conv1":
|
||||
bn_name = "bn_" + name
|
||||
else:
|
||||
bn_name = "bn" + name[3:]
|
||||
self._batch_norm = BatchNorm(
|
||||
num_filters,
|
||||
act=act,
|
||||
param_attr=ParamAttr(name=bn_name + "_scale"),
|
||||
bias_attr=ParamAttr(bn_name + "_offset"),
|
||||
moving_mean_name=bn_name + "_mean",
|
||||
moving_variance_name=bn_name + "_variance")
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self._conv(inputs)
|
||||
y = self._batch_norm(y)
|
||||
|
||||
return y
|
||||
|
||||
|
||||
class BottleneckBlock(fluid.dygraph.Layer):
|
||||
def __init__(self, num_channels, num_filters, stride, shortcut=True):
|
||||
def __init__(self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
stride,
|
||||
shortcut=True,
|
||||
name=None):
|
||||
super(BottleneckBlock, self).__init__()
|
||||
|
||||
self.conv0 = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=1,
|
||||
act='relu')
|
||||
act="relu",
|
||||
name=name + "_branch2a")
|
||||
self.conv1 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
act='relu')
|
||||
act="relu",
|
||||
name=name + "_branch2b")
|
||||
self.conv2 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_filters * 4,
|
||||
filter_size=1,
|
||||
act=None)
|
||||
act=None,
|
||||
name=name + "_branch2c")
|
||||
|
||||
if not shortcut:
|
||||
self.short = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters * 4,
|
||||
filter_size=1,
|
||||
stride=stride)
|
||||
stride=stride,
|
||||
name=name + "_branch1")
|
||||
|
||||
self.shortcut = shortcut
|
||||
|
||||
|
@ -100,7 +120,54 @@ class BottleneckBlock(fluid.dygraph.Layer):
|
|||
|
||||
y = fluid.layers.elementwise_add(x=short, y=conv2)
|
||||
|
||||
layer_helper = LayerHelper(self.full_name(), act='relu')
|
||||
layer_helper = LayerHelper(self.full_name(), act="relu")
|
||||
return layer_helper.append_activation(y)
|
||||
|
||||
|
||||
class BisicBlock(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
stride,
|
||||
shortcut=True,
|
||||
name=None):
|
||||
super(BisicBlock, self).__init__()
|
||||
self.stride = stride
|
||||
self.conv0 = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
act="relu",
|
||||
name=name + "_branch2a")
|
||||
self.conv1 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
act=None,
|
||||
name=name + "_branch2b")
|
||||
|
||||
if not shortcut:
|
||||
self.short = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=1,
|
||||
stride=stride,
|
||||
name=name + "_branch1")
|
||||
|
||||
self.shortcut = shortcut
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self.conv0(inputs)
|
||||
conv1 = self.conv1(y)
|
||||
|
||||
if self.shortcut:
|
||||
short = inputs
|
||||
else:
|
||||
short = self.short(inputs)
|
||||
y = fluid.layers.elementwise_add(x=short, y=conv1)
|
||||
|
||||
layer_helper = LayerHelper(self.full_name(), act="relu")
|
||||
return layer_helper.append_activation(y)
|
||||
|
||||
|
||||
|
@ -109,18 +176,21 @@ class ResNet(fluid.dygraph.Layer):
|
|||
super(ResNet, self).__init__()
|
||||
|
||||
self.layers = layers
|
||||
supported_layers = [50, 101, 152]
|
||||
supported_layers = [18, 34, 50, 101, 152]
|
||||
assert layers in supported_layers, \
|
||||
"supported layers are {} but input layer is {}".format(
|
||||
supported_layers, layers)
|
||||
|
||||
if layers == 50:
|
||||
if layers == 18:
|
||||
depth = [2, 2, 2, 2]
|
||||
elif layers == 34 or layers == 50:
|
||||
depth = [3, 4, 6, 3]
|
||||
elif layers == 101:
|
||||
depth = [3, 4, 23, 3]
|
||||
elif layers == 152:
|
||||
depth = [3, 8, 36, 3]
|
||||
num_channels = [64, 256, 512, 1024]
|
||||
num_channels = [64, 256, 512,
|
||||
1024] if layers >= 50 else [64, 64, 128, 256]
|
||||
num_filters = [64, 128, 256, 512]
|
||||
|
||||
self.conv = ConvBNLayer(
|
||||
|
@ -128,69 +198,97 @@ class ResNet(fluid.dygraph.Layer):
|
|||
num_filters=64,
|
||||
filter_size=7,
|
||||
stride=2,
|
||||
act='relu')
|
||||
act="relu",
|
||||
name="conv1")
|
||||
self.pool2d_max = Pool2D(
|
||||
pool_size=3, pool_stride=2, pool_padding=1, pool_type='max')
|
||||
pool_size=3, pool_stride=2, pool_padding=1, pool_type="max")
|
||||
|
||||
self.bottleneck_block_list = []
|
||||
for block in range(len(depth)):
|
||||
shortcut = False
|
||||
for i in range(depth[block]):
|
||||
bottleneck_block = self.add_sublayer(
|
||||
'bb_%d_%d' % (block, i),
|
||||
BottleneckBlock(
|
||||
num_channels=num_channels[block]
|
||||
if i == 0 else num_filters[block] * 4,
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
shortcut=shortcut))
|
||||
self.bottleneck_block_list.append(bottleneck_block)
|
||||
shortcut = True
|
||||
self.block_list = []
|
||||
if layers >= 50:
|
||||
for block in range(len(depth)):
|
||||
shortcut = False
|
||||
for i in range(depth[block]):
|
||||
if layers in [101, 152] and block == 2:
|
||||
if i == 0:
|
||||
conv_name = "res" + str(block + 2) + "a"
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + "b" + str(i)
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + chr(97 + i)
|
||||
bottleneck_block = self.add_sublayer(
|
||||
conv_name,
|
||||
BottleneckBlock(
|
||||
num_channels=num_channels[block]
|
||||
if i == 0 else num_filters[block] * 4,
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
shortcut=shortcut,
|
||||
name=conv_name))
|
||||
self.block_list.append(bottleneck_block)
|
||||
shortcut = True
|
||||
else:
|
||||
for block in range(len(depth)):
|
||||
shortcut = False
|
||||
for i in range(depth[block]):
|
||||
conv_name = "res" + str(block + 2) + chr(97 + i)
|
||||
bisic_block = self.add_sublayer(
|
||||
conv_name,
|
||||
BisicBlock(
|
||||
num_channels=num_channels[block]
|
||||
if i == 0 else num_filters[block],
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
shortcut=shortcut,
|
||||
name=conv_name))
|
||||
self.block_list.append(bisic_block)
|
||||
shortcut = True
|
||||
|
||||
self.pool2d_avg = Pool2D(
|
||||
pool_size=7, pool_type='avg', global_pooling=True)
|
||||
|
||||
self.pool2d_avg_output = num_filters[len(num_filters) - 1] * 4 * 1 * 1
|
||||
self.pool2d_avg_channels = num_channels[-1] * 2
|
||||
|
||||
stdv = 1.0 / math.sqrt(2048 * 1.0)
|
||||
stdv = 1.0 / math.sqrt(self.pool2d_avg_channels * 1.0)
|
||||
|
||||
self.out = Linear(
|
||||
self.pool2d_avg_output,
|
||||
self.pool2d_avg_channels,
|
||||
class_dim,
|
||||
param_attr=fluid.param_attr.ParamAttr(
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv)))
|
||||
param_attr=ParamAttr(
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv),
|
||||
name="fc_0.w_0"),
|
||||
bias_attr=ParamAttr(name="fc_0.b_0"))
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self.conv(inputs)
|
||||
y = self.pool2d_max(y)
|
||||
for bottleneck_block in self.bottleneck_block_list:
|
||||
y = bottleneck_block(y)
|
||||
for block in self.block_list:
|
||||
y = block(y)
|
||||
y = self.pool2d_avg(y)
|
||||
y = fluid.layers.reshape(y, shape=[-1, self.pool2d_avg_output])
|
||||
y = fluid.layers.reshape(y, shape=[-1, self.pool2d_avg_channels])
|
||||
y = self.out(y)
|
||||
return y
|
||||
|
||||
|
||||
def ResNet18(**kwargs):
|
||||
model = ResNet(layers=18, **kwargs)
|
||||
def ResNet18(**args):
|
||||
model = ResNet(layers=18, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNet34(**kwargs):
|
||||
model = ResNet(layers=34, **kwargs)
|
||||
def ResNet34(**args):
|
||||
model = ResNet(layers=34, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNet50(**kwargs):
|
||||
model = ResNet(layers=50, **kwargs)
|
||||
def ResNet50(**args):
|
||||
model = ResNet(layers=50, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNet101(**kwargs):
|
||||
model = ResNet(layers=101, **kwargs)
|
||||
def ResNet101(**args):
|
||||
model = ResNet(layers=101, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNet152(class_dim=1000):
|
||||
model = ResNet(layers=152, class_dim=class_dim)
|
||||
def ResNet152(**args):
|
||||
model = ResNet(layers=152, **args)
|
||||
return model
|
||||
|
|
|
@ -1,127 +1,48 @@
|
|||
#copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
|
||||
# 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
|
||||
# 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.
|
||||
# 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 math
|
||||
|
||||
import numpy as np
|
||||
import paddle
|
||||
import paddle.fluid as fluid
|
||||
from paddle.fluid.param_attr import ParamAttr
|
||||
from paddle.fluid.layer_helper import LayerHelper
|
||||
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, Linear, Dropout
|
||||
|
||||
__all__ = ["ResNet", "ResNet50_vc", "ResNet101_vc", "ResNet152_vc"]
|
||||
import math
|
||||
|
||||
train_parameters = {
|
||||
"input_size": [3, 224, 224],
|
||||
"input_mean": [0.485, 0.456, 0.406],
|
||||
"input_std": [0.229, 0.224, 0.225],
|
||||
"learning_strategy": {
|
||||
"name": "piecewise_decay",
|
||||
"batch_size": 256,
|
||||
"epochs": [30, 60, 90],
|
||||
"steps": [0.1, 0.01, 0.001, 0.0001]
|
||||
}
|
||||
}
|
||||
__all__ = [
|
||||
"ResNet18_vc", "ResNet34_vc", "ResNet50_vc", "ResNet101_vc", "ResNet152_vc"
|
||||
]
|
||||
|
||||
|
||||
class ResNet():
|
||||
def __init__(self, layers=50):
|
||||
self.params = train_parameters
|
||||
self.layers = layers
|
||||
class ConvBNLayer(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
act=None,
|
||||
name=None):
|
||||
super(ConvBNLayer, self).__init__()
|
||||
|
||||
def net(self, input, class_dim=1000):
|
||||
layers = self.layers
|
||||
supported_layers = [50, 101, 152]
|
||||
assert layers in supported_layers, \
|
||||
"supported layers are {} but input layer is {}".format(supported_layers, layers)
|
||||
|
||||
if layers == 50:
|
||||
depth = [3, 4, 6, 3]
|
||||
elif layers == 101:
|
||||
depth = [3, 4, 23, 3]
|
||||
elif layers == 152:
|
||||
depth = [3, 8, 36, 3]
|
||||
num_filters = [64, 128, 256, 512]
|
||||
|
||||
conv = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
stride=2,
|
||||
act='relu',
|
||||
name='conv1_1')
|
||||
conv = self.conv_bn_layer(
|
||||
input=conv,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name='conv1_2')
|
||||
conv = self.conv_bn_layer(
|
||||
input=conv,
|
||||
num_filters=64,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name='conv1_3')
|
||||
|
||||
conv = fluid.layers.pool2d(
|
||||
input=conv,
|
||||
pool_size=3,
|
||||
pool_stride=2,
|
||||
pool_padding=1,
|
||||
pool_type='max')
|
||||
|
||||
for block in range(len(depth)):
|
||||
for i in range(depth[block]):
|
||||
if layers in [101, 152] and block == 2:
|
||||
if i == 0:
|
||||
conv_name = "res" + str(block + 2) + "a"
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + "b" + str(i)
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + chr(97 + i)
|
||||
conv = self.bottleneck_block(
|
||||
input=conv,
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
name=conv_name)
|
||||
|
||||
pool = fluid.layers.pool2d(
|
||||
input=conv, pool_type='avg', global_pooling=True)
|
||||
stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0)
|
||||
out = fluid.layers.fc(input=pool,
|
||||
size=class_dim,
|
||||
param_attr=fluid.param_attr.ParamAttr(
|
||||
name="fc_0.w_0",
|
||||
initializer=fluid.initializer.Uniform(-stdv,
|
||||
stdv)),
|
||||
bias_attr=ParamAttr(name="fc_0.b_0"))
|
||||
return out
|
||||
|
||||
def conv_bn_layer(self,
|
||||
input,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
act=None,
|
||||
name=None):
|
||||
conv = fluid.layers.conv2d(
|
||||
input=input,
|
||||
self._conv = Conv2D(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=stride,
|
||||
|
@ -129,66 +50,264 @@ class ResNet():
|
|||
groups=groups,
|
||||
act=None,
|
||||
param_attr=ParamAttr(name=name + "_weights"),
|
||||
bias_attr=False,
|
||||
name=name + '.conv2d.output.1')
|
||||
bias_attr=False)
|
||||
if name == "conv1":
|
||||
bn_name = "bn_" + name
|
||||
else:
|
||||
bn_name = "bn" + name[3:]
|
||||
return fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
self._batch_norm = BatchNorm(
|
||||
num_filters,
|
||||
act=act,
|
||||
name=bn_name + '.output.1',
|
||||
param_attr=ParamAttr(name=bn_name + '_scale'),
|
||||
bias_attr=ParamAttr(bn_name + '_offset'),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance', )
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
|
||||
def shortcut(self, input, ch_out, stride, name):
|
||||
ch_in = input.shape[1]
|
||||
if ch_in != ch_out or stride != 1:
|
||||
return self.conv_bn_layer(input, ch_out, 1, stride, name=name)
|
||||
else:
|
||||
return input
|
||||
def forward(self, inputs):
|
||||
y = self._conv(inputs)
|
||||
y = self._batch_norm(y)
|
||||
return y
|
||||
|
||||
def bottleneck_block(self, input, num_filters, stride, name):
|
||||
conv0 = self.conv_bn_layer(
|
||||
input=input,
|
||||
|
||||
class BottleneckBlock(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
stride,
|
||||
shortcut=True,
|
||||
name=None):
|
||||
super(BottleneckBlock, self).__init__()
|
||||
|
||||
self.conv0 = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=1,
|
||||
act='relu',
|
||||
name=name + "_branch2a")
|
||||
conv1 = self.conv_bn_layer(
|
||||
input=conv0,
|
||||
self.conv1 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
act='relu',
|
||||
name=name + "_branch2b")
|
||||
conv2 = self.conv_bn_layer(
|
||||
input=conv1,
|
||||
self.conv2 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_filters * 4,
|
||||
filter_size=1,
|
||||
act=None,
|
||||
name=name + "_branch2c")
|
||||
|
||||
short = self.shortcut(
|
||||
input, num_filters * 4, stride, name=name + "_branch1")
|
||||
if not shortcut:
|
||||
self.short = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters * 4,
|
||||
filter_size=1,
|
||||
stride=stride,
|
||||
name=name + "_branch1")
|
||||
|
||||
return fluid.layers.elementwise_add(
|
||||
x=short, y=conv2, act='relu', name=name + ".add.output.5")
|
||||
self.shortcut = shortcut
|
||||
|
||||
self._num_channels_out = num_filters * 4
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self.conv0(inputs)
|
||||
conv1 = self.conv1(y)
|
||||
conv2 = self.conv2(conv1)
|
||||
|
||||
if self.shortcut:
|
||||
short = inputs
|
||||
else:
|
||||
short = self.short(inputs)
|
||||
|
||||
y = fluid.layers.elementwise_add(x=short, y=conv2)
|
||||
|
||||
layer_helper = LayerHelper(self.full_name(), act='relu')
|
||||
return layer_helper.append_activation(y)
|
||||
|
||||
|
||||
def ResNet50_vc():
|
||||
model = ResNet(layers=50)
|
||||
class BisicBlock(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
stride,
|
||||
shortcut=True,
|
||||
name=None):
|
||||
super(BisicBlock, self).__init__()
|
||||
self.stride = stride
|
||||
self.conv0 = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
act='relu',
|
||||
name=name + "_branch2a")
|
||||
self.conv1 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
act=None,
|
||||
name=name + "_branch2b")
|
||||
|
||||
if not shortcut:
|
||||
self.short = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=1,
|
||||
stride=stride,
|
||||
name=name + "_branch1")
|
||||
|
||||
self.shortcut = shortcut
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self.conv0(inputs)
|
||||
conv1 = self.conv1(y)
|
||||
|
||||
if self.shortcut:
|
||||
short = inputs
|
||||
else:
|
||||
short = self.short(inputs)
|
||||
y = fluid.layers.elementwise_add(x=short, y=conv1)
|
||||
|
||||
layer_helper = LayerHelper(self.full_name(), act='relu')
|
||||
return layer_helper.append_activation(y)
|
||||
|
||||
|
||||
class ResNet_vc(fluid.dygraph.Layer):
|
||||
def __init__(self, layers=50, class_dim=1000):
|
||||
super(ResNet_vc, self).__init__()
|
||||
|
||||
self.layers = layers
|
||||
supported_layers = [18, 34, 50, 101, 152]
|
||||
assert layers in supported_layers, \
|
||||
"supported layers are {} but input layer is {}".format(
|
||||
supported_layers, layers)
|
||||
|
||||
if layers == 18:
|
||||
depth = [2, 2, 2, 2]
|
||||
elif layers == 34 or layers == 50:
|
||||
depth = [3, 4, 6, 3]
|
||||
elif layers == 101:
|
||||
depth = [3, 4, 23, 3]
|
||||
elif layers == 152:
|
||||
depth = [3, 8, 36, 3]
|
||||
num_channels = [64, 256, 512,
|
||||
1024] if layers >= 50 else [64, 64, 128, 256]
|
||||
num_filters = [64, 128, 256, 512]
|
||||
|
||||
self.conv1_1 = ConvBNLayer(
|
||||
num_channels=3,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
stride=2,
|
||||
act='relu',
|
||||
name="conv1_1")
|
||||
self.conv1_2 = ConvBNLayer(
|
||||
num_channels=32,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name="conv1_2")
|
||||
self.conv1_3 = ConvBNLayer(
|
||||
num_channels=32,
|
||||
num_filters=64,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name="conv1_3")
|
||||
|
||||
self.pool2d_max = Pool2D(
|
||||
pool_size=3, pool_stride=2, pool_padding=1, pool_type='max')
|
||||
|
||||
self.block_list = []
|
||||
if layers >= 50:
|
||||
for block in range(len(depth)):
|
||||
shortcut = False
|
||||
for i in range(depth[block]):
|
||||
if layers in [101, 152] and block == 2:
|
||||
if i == 0:
|
||||
conv_name = "res" + str(block + 2) + "a"
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + "b" + str(i)
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + chr(97 + i)
|
||||
bottleneck_block = self.add_sublayer(
|
||||
'bb_%d_%d' % (block, i),
|
||||
BottleneckBlock(
|
||||
num_channels=num_channels[block]
|
||||
if i == 0 else num_filters[block] * 4,
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
shortcut=shortcut,
|
||||
name=conv_name))
|
||||
self.block_list.append(bottleneck_block)
|
||||
shortcut = True
|
||||
else:
|
||||
for block in range(len(depth)):
|
||||
shortcut = False
|
||||
for i in range(depth[block]):
|
||||
conv_name = "res" + str(block + 2) + chr(97 + i)
|
||||
bisic_block = self.add_sublayer(
|
||||
'bb_%d_%d' % (block, i),
|
||||
BisicBlock(
|
||||
num_channels=num_channels[block]
|
||||
if i == 0 else num_filters[block],
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
shortcut=shortcut,
|
||||
name=conv_name))
|
||||
self.block_list.append(bisic_block)
|
||||
shortcut = True
|
||||
|
||||
self.pool2d_avg = Pool2D(
|
||||
pool_size=7, pool_type='avg', global_pooling=True)
|
||||
|
||||
self.pool2d_avg_channels = num_channels[-1] * 2
|
||||
|
||||
stdv = 1.0 / math.sqrt(self.pool2d_avg_channels * 1.0)
|
||||
|
||||
self.out = Linear(
|
||||
self.pool2d_avg_channels,
|
||||
class_dim,
|
||||
param_attr=ParamAttr(
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv),
|
||||
name="fc_0.w_0"),
|
||||
bias_attr=ParamAttr(name="fc_0.b_0"))
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self.conv1_1(inputs)
|
||||
y = self.conv1_2(y)
|
||||
y = self.conv1_3(y)
|
||||
y = self.pool2d_max(y)
|
||||
for block in self.block_list:
|
||||
y = block(y)
|
||||
y = self.pool2d_avg(y)
|
||||
y = fluid.layers.reshape(y, shape=[-1, self.pool2d_avg_channels])
|
||||
y = self.out(y)
|
||||
return y
|
||||
|
||||
|
||||
def ResNet18_vc(**args):
|
||||
model = ResNet_vc(layers=18, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNet101_vc():
|
||||
model = ResNet(layers=101)
|
||||
def ResNet34_vc(**args):
|
||||
model = ResNet_vc(layers=34, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNet152_vc():
|
||||
model = ResNet(layers=152)
|
||||
def ResNet50_vc(**args):
|
||||
model = ResNet_vc(layers=50, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNet101_vc(**args):
|
||||
model = ResNet_vc(layers=101, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNet152_vc(**args):
|
||||
model = ResNet_vc(layers=152, **args)
|
||||
return model
|
||||
|
|
|
@ -1,55 +1,195 @@
|
|||
#copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
|
||||
# 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
|
||||
# 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.
|
||||
# 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 math
|
||||
|
||||
import numpy as np
|
||||
import paddle
|
||||
import paddle.fluid as fluid
|
||||
from paddle.fluid.param_attr import ParamAttr
|
||||
from paddle.fluid.layer_helper import LayerHelper
|
||||
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, Linear, Dropout
|
||||
|
||||
import math
|
||||
|
||||
__all__ = [
|
||||
"ResNet", "ResNet18_vd", "ResNet34_vd", "ResNet50_vd", "ResNet101_vd",
|
||||
"ResNet152_vd", "ResNet200_vd"
|
||||
"ResNet18_vd", "ResNet34_vd", "ResNet50_vd", "ResNet101_vd", "ResNet152_vd"
|
||||
]
|
||||
|
||||
|
||||
class ResNet():
|
||||
def __init__(self,
|
||||
layers=50,
|
||||
is_3x3=False,
|
||||
postfix_name="",
|
||||
lr_mult_list=[1.0, 1.0, 1.0, 1.0, 1.0]):
|
||||
self.layers = layers
|
||||
self.is_3x3 = is_3x3
|
||||
self.postfix_name = "" if postfix_name is None else postfix_name
|
||||
self.lr_mult_list = lr_mult_list
|
||||
assert len(
|
||||
self.lr_mult_list
|
||||
) == 5, "lr_mult_list length in ResNet must be 5 but got {}!!".format(
|
||||
len(self.lr_mult_list))
|
||||
self.curr_stage = 0
|
||||
class ConvBNLayer(fluid.dygraph.Layer):
|
||||
def __init__(
|
||||
self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
is_vd_mode=False,
|
||||
act=None,
|
||||
name=None, ):
|
||||
super(ConvBNLayer, self).__init__()
|
||||
|
||||
def net(self, input, class_dim=1000):
|
||||
is_3x3 = self.is_3x3
|
||||
layers = self.layers
|
||||
self.is_vd_mode = is_vd_mode
|
||||
self._pool2d_avg = Pool2D(
|
||||
pool_size=2, pool_stride=2, pool_padding=0, pool_type='avg')
|
||||
self._conv = Conv2D(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=stride,
|
||||
padding=(filter_size - 1) // 2,
|
||||
groups=groups,
|
||||
act=None,
|
||||
param_attr=ParamAttr(name=name + "_weights"),
|
||||
bias_attr=False)
|
||||
if name == "conv1":
|
||||
bn_name = "bn_" + name
|
||||
else:
|
||||
bn_name = "bn" + name[3:]
|
||||
self._batch_norm = BatchNorm(
|
||||
num_filters,
|
||||
act=act,
|
||||
param_attr=ParamAttr(name=bn_name + '_scale'),
|
||||
bias_attr=ParamAttr(bn_name + '_offset'),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
|
||||
def forward(self, inputs):
|
||||
if self.is_vd_mode:
|
||||
inputs = self._pool2d_avg(inputs)
|
||||
y = self._conv(inputs)
|
||||
y = self._batch_norm(y)
|
||||
return y
|
||||
|
||||
|
||||
class BottleneckBlock(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
stride,
|
||||
shortcut=True,
|
||||
if_first=False,
|
||||
name=None):
|
||||
super(BottleneckBlock, self).__init__()
|
||||
|
||||
self.conv0 = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=1,
|
||||
act='relu',
|
||||
name=name + "_branch2a")
|
||||
self.conv1 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
act='relu',
|
||||
name=name + "_branch2b")
|
||||
self.conv2 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_filters * 4,
|
||||
filter_size=1,
|
||||
act=None,
|
||||
name=name + "_branch2c")
|
||||
|
||||
if not shortcut:
|
||||
self.short = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters * 4,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
is_vd_mode=False if if_first else True,
|
||||
name=name + "_branch1")
|
||||
|
||||
self.shortcut = shortcut
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self.conv0(inputs)
|
||||
conv1 = self.conv1(y)
|
||||
conv2 = self.conv2(conv1)
|
||||
|
||||
if self.shortcut:
|
||||
short = inputs
|
||||
else:
|
||||
short = self.short(inputs)
|
||||
y = fluid.layers.elementwise_add(x=short, y=conv2)
|
||||
|
||||
layer_helper = LayerHelper(self.full_name(), act='relu')
|
||||
return layer_helper.append_activation(y)
|
||||
|
||||
|
||||
class BisicBlock(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
stride,
|
||||
shortcut=True,
|
||||
if_first=False,
|
||||
name=None):
|
||||
super(BisicBlock, self).__init__()
|
||||
self.stride = stride
|
||||
self.conv0 = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
act='relu',
|
||||
name=name + "_branch2a")
|
||||
self.conv1 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
act=None,
|
||||
name=name + "_branch2b")
|
||||
|
||||
if not shortcut:
|
||||
self.short = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
is_vd_mode=False if if_first else True,
|
||||
name=name + "_branch1")
|
||||
|
||||
self.shortcut = shortcut
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self.conv0(inputs)
|
||||
conv1 = self.conv1(y)
|
||||
|
||||
if self.shortcut:
|
||||
short = inputs
|
||||
else:
|
||||
short = self.short(inputs)
|
||||
y = fluid.layers.elementwise_add(x=short, y=conv1)
|
||||
|
||||
layer_helper = LayerHelper(self.full_name(), act='relu')
|
||||
return layer_helper.append_activation(y)
|
||||
|
||||
|
||||
class ResNet_vd(fluid.dygraph.Layer):
|
||||
def __init__(self, layers=50, class_dim=1000):
|
||||
super(ResNet_vd, self).__init__()
|
||||
|
||||
self.layers = layers
|
||||
supported_layers = [18, 34, 50, 101, 152, 200]
|
||||
assert layers in supported_layers, \
|
||||
"supported layers are {} but input layer is {}".format(supported_layers, layers)
|
||||
"supported layers are {} but input layer is {}".format(
|
||||
supported_layers, layers)
|
||||
|
||||
if layers == 18:
|
||||
depth = [2, 2, 2, 2]
|
||||
|
@ -61,254 +201,129 @@ class ResNet():
|
|||
depth = [3, 8, 36, 3]
|
||||
elif layers == 200:
|
||||
depth = [3, 12, 48, 3]
|
||||
num_channels = [64, 256, 512,
|
||||
1024] if layers >= 50 else [64, 64, 128, 256]
|
||||
num_filters = [64, 128, 256, 512]
|
||||
if is_3x3 == False:
|
||||
conv = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=64,
|
||||
filter_size=7,
|
||||
stride=2,
|
||||
act='relu')
|
||||
else:
|
||||
conv = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
stride=2,
|
||||
act='relu',
|
||||
name='conv1_1')
|
||||
conv = self.conv_bn_layer(
|
||||
input=conv,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name='conv1_2')
|
||||
conv = self.conv_bn_layer(
|
||||
input=conv,
|
||||
num_filters=64,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name='conv1_3')
|
||||
|
||||
conv = fluid.layers.pool2d(
|
||||
input=conv,
|
||||
pool_size=3,
|
||||
pool_stride=2,
|
||||
pool_padding=1,
|
||||
pool_type='max')
|
||||
self.conv1_1 = ConvBNLayer(
|
||||
num_channels=3,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
stride=2,
|
||||
act='relu',
|
||||
name="conv1_1")
|
||||
self.conv1_2 = ConvBNLayer(
|
||||
num_channels=32,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name="conv1_2")
|
||||
self.conv1_3 = ConvBNLayer(
|
||||
num_channels=32,
|
||||
num_filters=64,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name="conv1_3")
|
||||
self.pool2d_max = Pool2D(
|
||||
pool_size=3, pool_stride=2, pool_padding=1, pool_type='max')
|
||||
|
||||
self.block_list = []
|
||||
if layers >= 50:
|
||||
for block in range(len(depth)):
|
||||
self.curr_stage += 1
|
||||
shortcut = False
|
||||
for i in range(depth[block]):
|
||||
if layers in [101, 152, 200] and block == 2:
|
||||
if layers in [101, 152] and block == 2:
|
||||
if i == 0:
|
||||
conv_name = "res" + str(block + 2) + "a"
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + "b" + str(i)
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + chr(97 + i)
|
||||
conv = self.bottleneck_block(
|
||||
input=conv,
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
if_first=block == i == 0,
|
||||
name=conv_name)
|
||||
bottleneck_block = self.add_sublayer(
|
||||
'bb_%d_%d' % (block, i),
|
||||
BottleneckBlock(
|
||||
num_channels=num_channels[block]
|
||||
if i == 0 else num_filters[block] * 4,
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
shortcut=shortcut,
|
||||
if_first=block == i == 0,
|
||||
name=conv_name))
|
||||
self.block_list.append(bottleneck_block)
|
||||
shortcut = True
|
||||
else:
|
||||
for block in range(len(depth)):
|
||||
self.curr_stage += 1
|
||||
shortcut = False
|
||||
for i in range(depth[block]):
|
||||
conv_name = "res" + str(block + 2) + chr(97 + i)
|
||||
conv = self.basic_block(
|
||||
input=conv,
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
if_first=block == i == 0,
|
||||
name=conv_name)
|
||||
bisic_block = self.add_sublayer(
|
||||
'bb_%d_%d' % (block, i),
|
||||
BisicBlock(
|
||||
num_channels=num_channels[block]
|
||||
if i == 0 else num_filters[block],
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
shortcut=shortcut,
|
||||
if_first=block == i == 0,
|
||||
name=conv_name))
|
||||
self.block_list.append(bisic_block)
|
||||
shortcut = True
|
||||
|
||||
pool = fluid.layers.pool2d(
|
||||
input=conv, pool_type='avg', global_pooling=True)
|
||||
stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0)
|
||||
self.pool2d_avg = Pool2D(
|
||||
pool_size=7, pool_type='avg', global_pooling=True)
|
||||
|
||||
out = fluid.layers.fc(
|
||||
input=pool,
|
||||
size=class_dim,
|
||||
param_attr=fluid.param_attr.ParamAttr(
|
||||
name="fc_0.w_0" + self.postfix_name,
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv)),
|
||||
bias_attr=ParamAttr(name="fc_0.b_0" + self.postfix_name))
|
||||
self.pool2d_avg_channels = num_channels[-1] * 2
|
||||
|
||||
return out
|
||||
stdv = 1.0 / math.sqrt(self.pool2d_avg_channels * 1.0)
|
||||
|
||||
def conv_bn_layer(self,
|
||||
input,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
act=None,
|
||||
name=None):
|
||||
lr_mult = self.lr_mult_list[self.curr_stage]
|
||||
conv = fluid.layers.conv2d(
|
||||
input=input,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=stride,
|
||||
padding=(filter_size - 1) // 2,
|
||||
groups=groups,
|
||||
act=None,
|
||||
param_attr=ParamAttr(name=name + "_weights" + self.postfix_name),
|
||||
bias_attr=False)
|
||||
if name == "conv1":
|
||||
bn_name = "bn_" + name
|
||||
else:
|
||||
bn_name = "bn" + name[3:]
|
||||
return fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
act=act,
|
||||
param_attr=ParamAttr(name=bn_name + '_scale' + self.postfix_name),
|
||||
bias_attr=ParamAttr(bn_name + '_offset' + self.postfix_name),
|
||||
moving_mean_name=bn_name + '_mean' + self.postfix_name,
|
||||
moving_variance_name=bn_name + '_variance' + self.postfix_name)
|
||||
|
||||
def conv_bn_layer_new(self,
|
||||
input,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
act=None,
|
||||
name=None):
|
||||
lr_mult = self.lr_mult_list[self.curr_stage]
|
||||
pool = fluid.layers.pool2d(
|
||||
input=input,
|
||||
pool_size=2,
|
||||
pool_stride=2,
|
||||
pool_padding=0,
|
||||
pool_type='avg',
|
||||
ceil_mode=True)
|
||||
|
||||
conv = fluid.layers.conv2d(
|
||||
input=pool,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=1,
|
||||
padding=(filter_size - 1) // 2,
|
||||
groups=groups,
|
||||
act=None,
|
||||
self.out = Linear(
|
||||
self.pool2d_avg_channels,
|
||||
class_dim,
|
||||
param_attr=ParamAttr(
|
||||
name=name + "_weights" + self.postfix_name,
|
||||
learning_rate=lr_mult),
|
||||
bias_attr=False)
|
||||
if name == "conv1":
|
||||
bn_name = "bn_" + name
|
||||
else:
|
||||
bn_name = "bn" + name[3:]
|
||||
return fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
act=act,
|
||||
param_attr=ParamAttr(
|
||||
name=bn_name + '_scale' + self.postfix_name,
|
||||
learning_rate=lr_mult),
|
||||
bias_attr=ParamAttr(
|
||||
bn_name + '_offset' + self.postfix_name,
|
||||
learning_rate=lr_mult),
|
||||
moving_mean_name=bn_name + '_mean' + self.postfix_name,
|
||||
moving_variance_name=bn_name + '_variance' + self.postfix_name)
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv),
|
||||
name="fc_0.w_0"),
|
||||
bias_attr=ParamAttr(name="fc_0.b_0"))
|
||||
|
||||
def shortcut(self, input, ch_out, stride, name, if_first=False):
|
||||
ch_in = input.shape[1]
|
||||
if ch_in != ch_out or stride != 1:
|
||||
if if_first:
|
||||
return self.conv_bn_layer(input, ch_out, 1, stride, name=name)
|
||||
else:
|
||||
return self.conv_bn_layer_new(
|
||||
input, ch_out, 1, stride, name=name)
|
||||
elif if_first:
|
||||
return self.conv_bn_layer(input, ch_out, 1, stride, name=name)
|
||||
else:
|
||||
return input
|
||||
|
||||
def bottleneck_block(self, input, num_filters, stride, name, if_first):
|
||||
conv0 = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=num_filters,
|
||||
filter_size=1,
|
||||
act='relu',
|
||||
name=name + "_branch2a")
|
||||
conv1 = self.conv_bn_layer(
|
||||
input=conv0,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
act='relu',
|
||||
name=name + "_branch2b")
|
||||
conv2 = self.conv_bn_layer(
|
||||
input=conv1,
|
||||
num_filters=num_filters * 4,
|
||||
filter_size=1,
|
||||
act=None,
|
||||
name=name + "_branch2c")
|
||||
|
||||
short = self.shortcut(
|
||||
input,
|
||||
num_filters * 4,
|
||||
stride,
|
||||
if_first=if_first,
|
||||
name=name + "_branch1")
|
||||
|
||||
return fluid.layers.elementwise_add(x=short, y=conv2, act='relu')
|
||||
|
||||
def basic_block(self, input, num_filters, stride, name, if_first):
|
||||
conv0 = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
act='relu',
|
||||
stride=stride,
|
||||
name=name + "_branch2a")
|
||||
conv1 = self.conv_bn_layer(
|
||||
input=conv0,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
act=None,
|
||||
name=name + "_branch2b")
|
||||
short = self.shortcut(
|
||||
input,
|
||||
num_filters,
|
||||
stride,
|
||||
if_first=if_first,
|
||||
name=name + "_branch1")
|
||||
return fluid.layers.elementwise_add(x=short, y=conv1, act='relu')
|
||||
def forward(self, inputs):
|
||||
y = self.conv1_1(inputs)
|
||||
y = self.conv1_2(y)
|
||||
y = self.conv1_3(y)
|
||||
y = self.pool2d_max(y)
|
||||
for block in self.block_list:
|
||||
y = block(y)
|
||||
y = self.pool2d_avg(y)
|
||||
y = fluid.layers.reshape(y, shape=[-1, self.pool2d_avg_channels])
|
||||
y = self.out(y)
|
||||
return y
|
||||
|
||||
|
||||
def ResNet18_vd():
|
||||
model = ResNet(layers=18, is_3x3=True)
|
||||
def ResNet18_vd(**args):
|
||||
model = ResNet_vd(layers=18, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNet34_vd():
|
||||
model = ResNet(layers=34, is_3x3=True)
|
||||
def ResNet34_vd(**args):
|
||||
model = ResNet_vd(layers=34, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNet50_vd(**args):
|
||||
model = ResNet(layers=50, is_3x3=True, **args)
|
||||
model = ResNet_vd(layers=50, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNet101_vd():
|
||||
model = ResNet(layers=101, is_3x3=True)
|
||||
def ResNet101_vd(**args):
|
||||
model = ResNet_vd(layers=101, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNet152_vd():
|
||||
model = ResNet(layers=152, is_3x3=True)
|
||||
def ResNet152_vd(**args):
|
||||
model = ResNet_vd(layers=152, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNet200_vd():
|
||||
model = ResNet(layers=200, is_3x3=True)
|
||||
def ResNet200_vd(**args):
|
||||
model = ResNet_vd(layers=200, **args)
|
||||
return model
|
||||
|
|
|
@ -1,70 +1,170 @@
|
|||
#copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
|
||||
# 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
|
||||
# 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.
|
||||
# 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 math
|
||||
|
||||
import numpy as np
|
||||
import paddle
|
||||
import paddle.fluid as fluid
|
||||
from paddle.fluid.param_attr import ParamAttr
|
||||
from paddle.fluid.layer_helper import LayerHelper
|
||||
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, Linear, Dropout
|
||||
|
||||
import math
|
||||
|
||||
__all__ = [
|
||||
"ResNeXt", "ResNeXt50_64x4d", "ResNeXt101_64x4d", "ResNeXt152_64x4d",
|
||||
"ResNeXt50_32x4d", "ResNeXt101_32x4d", "ResNeXt152_32x4d"
|
||||
"ResNeXt50_32x4d", "ResNeXt50_64x4d", "ResNeXt101_32x4d",
|
||||
"ResNeXt101_64x4d", "ResNeXt152_32x4d", "ResNeXt152_64x4d"
|
||||
]
|
||||
|
||||
|
||||
class ResNeXt():
|
||||
def __init__(self, layers=50, cardinality=64):
|
||||
class ConvBNLayer(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
act=None,
|
||||
name=None):
|
||||
super(ConvBNLayer, self).__init__()
|
||||
|
||||
self._conv = Conv2D(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=stride,
|
||||
padding=(filter_size - 1) // 2,
|
||||
groups=groups,
|
||||
act=None,
|
||||
param_attr=ParamAttr(name=name + "_weights"),
|
||||
bias_attr=False)
|
||||
if name == "conv1":
|
||||
bn_name = "bn_" + name
|
||||
else:
|
||||
bn_name = "bn" + name[3:]
|
||||
self._batch_norm = BatchNorm(
|
||||
num_filters,
|
||||
act=act,
|
||||
param_attr=ParamAttr(name=bn_name + '_scale'),
|
||||
bias_attr=ParamAttr(bn_name + '_offset'),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self._conv(inputs)
|
||||
y = self._batch_norm(y)
|
||||
return y
|
||||
|
||||
|
||||
class BottleneckBlock(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
stride,
|
||||
cardinality,
|
||||
shortcut=True,
|
||||
name=None):
|
||||
super(BottleneckBlock, self).__init__()
|
||||
|
||||
self.conv0 = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=1,
|
||||
act='relu',
|
||||
name=name + "_branch2a")
|
||||
self.conv1 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
groups=cardinality,
|
||||
stride=stride,
|
||||
act='relu',
|
||||
name=name + "_branch2b")
|
||||
self.conv2 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_filters * 2 if cardinality == 32 else num_filters,
|
||||
filter_size=1,
|
||||
act=None,
|
||||
name=name + "_branch2c")
|
||||
|
||||
if not shortcut:
|
||||
self.short = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters * 2
|
||||
if cardinality == 32 else num_filters,
|
||||
filter_size=1,
|
||||
stride=stride,
|
||||
name=name + "_branch1")
|
||||
|
||||
self.shortcut = shortcut
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self.conv0(inputs)
|
||||
conv1 = self.conv1(y)
|
||||
conv2 = self.conv2(conv1)
|
||||
|
||||
if self.shortcut:
|
||||
short = inputs
|
||||
else:
|
||||
short = self.short(inputs)
|
||||
|
||||
y = fluid.layers.elementwise_add(x=short, y=conv2)
|
||||
|
||||
layer_helper = LayerHelper(self.full_name(), act='relu')
|
||||
return layer_helper.append_activation(y)
|
||||
|
||||
|
||||
class ResNeXt(fluid.dygraph.Layer):
|
||||
def __init__(self, layers=50, class_dim=1000, cardinality=32):
|
||||
super(ResNeXt, self).__init__()
|
||||
|
||||
self.layers = layers
|
||||
self.cardinality = cardinality
|
||||
|
||||
def net(self, input, class_dim=1000):
|
||||
layers = self.layers
|
||||
cardinality = self.cardinality
|
||||
supported_layers = [50, 101, 152]
|
||||
assert layers in supported_layers, \
|
||||
"supported layers are {} but input layer is {}".format(supported_layers, layers)
|
||||
|
||||
"supported layers are {} but input layer is {}".format(
|
||||
supported_layers, layers)
|
||||
supported_cardinality = [32, 64]
|
||||
assert cardinality in supported_cardinality, \
|
||||
"supported cardinality is {} but input cardinality is {}" \
|
||||
.format(supported_cardinality, cardinality)
|
||||
if layers == 50:
|
||||
depth = [3, 4, 6, 3]
|
||||
elif layers == 101:
|
||||
depth = [3, 4, 23, 3]
|
||||
elif layers == 152:
|
||||
depth = [3, 8, 36, 3]
|
||||
num_channels = [64, 256, 512, 1024]
|
||||
num_filters = [128, 256, 512,
|
||||
1024] if cardinality == 32 else [256, 512, 1024, 2048]
|
||||
|
||||
num_filters1 = [256, 512, 1024, 2048]
|
||||
num_filters2 = [128, 256, 512, 1024]
|
||||
|
||||
conv = self.conv_bn_layer(
|
||||
input=input,
|
||||
self.conv = ConvBNLayer(
|
||||
num_channels=3,
|
||||
num_filters=64,
|
||||
filter_size=7,
|
||||
stride=2,
|
||||
act='relu',
|
||||
name="res_conv1") #debug
|
||||
conv = fluid.layers.pool2d(
|
||||
input=conv,
|
||||
pool_size=3,
|
||||
pool_stride=2,
|
||||
pool_padding=1,
|
||||
pool_type='max')
|
||||
name="res_conv1")
|
||||
self.pool2d_max = Pool2D(
|
||||
pool_size=3, pool_stride=2, pool_padding=1, pool_type='max')
|
||||
|
||||
self.block_list = []
|
||||
for block in range(len(depth)):
|
||||
shortcut = False
|
||||
for i in range(depth[block]):
|
||||
if layers in [101, 152] and block == 2:
|
||||
if i == 0:
|
||||
|
@ -73,123 +173,70 @@ class ResNeXt():
|
|||
conv_name = "res" + str(block + 2) + "b" + str(i)
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + chr(97 + i)
|
||||
conv = self.bottleneck_block(
|
||||
input=conv,
|
||||
num_filters=num_filters1[block]
|
||||
if cardinality == 64 else num_filters2[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
cardinality=cardinality,
|
||||
name=conv_name)
|
||||
bottleneck_block = self.add_sublayer(
|
||||
'bb_%d_%d' % (block, i),
|
||||
BottleneckBlock(
|
||||
num_channels=num_channels[block] if i == 0 else
|
||||
num_filters[block] * int(64 // self.cardinality),
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
cardinality=self.cardinality,
|
||||
shortcut=shortcut,
|
||||
name=conv_name))
|
||||
self.block_list.append(bottleneck_block)
|
||||
shortcut = True
|
||||
|
||||
pool = fluid.layers.pool2d(
|
||||
input=conv, pool_type='avg', global_pooling=True)
|
||||
stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0)
|
||||
out = fluid.layers.fc(
|
||||
input=pool,
|
||||
size=class_dim,
|
||||
param_attr=fluid.param_attr.ParamAttr(
|
||||
self.pool2d_avg = Pool2D(
|
||||
pool_size=7, pool_type='avg', global_pooling=True)
|
||||
|
||||
self.pool2d_avg_channels = num_channels[-1] * 2
|
||||
|
||||
stdv = 1.0 / math.sqrt(self.pool2d_avg_channels * 1.0)
|
||||
|
||||
self.out = Linear(
|
||||
self.pool2d_avg_channels,
|
||||
class_dim,
|
||||
param_attr=ParamAttr(
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv),
|
||||
name='fc_weights'),
|
||||
bias_attr=fluid.param_attr.ParamAttr(name='fc_offset'))
|
||||
return out
|
||||
name="fc_weights"),
|
||||
bias_attr=ParamAttr(name="fc_offset"))
|
||||
|
||||
def conv_bn_layer(self,
|
||||
input,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
act=None,
|
||||
name=None):
|
||||
conv = fluid.layers.conv2d(
|
||||
input=input,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=stride,
|
||||
padding=(filter_size - 1) // 2,
|
||||
groups=groups,
|
||||
act=None,
|
||||
param_attr=ParamAttr(name=name + "_weights"),
|
||||
bias_attr=False,
|
||||
name=name + '.conv2d.output.1')
|
||||
if name == "conv1":
|
||||
bn_name = "bn_" + name
|
||||
else:
|
||||
bn_name = "bn" + name[3:]
|
||||
return fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
act=act,
|
||||
name=bn_name + '.output.1',
|
||||
param_attr=ParamAttr(name=bn_name + '_scale'),
|
||||
bias_attr=ParamAttr(bn_name + '_offset'),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance', )
|
||||
|
||||
def shortcut(self, input, ch_out, stride, name):
|
||||
ch_in = input.shape[1]
|
||||
if ch_in != ch_out or stride != 1:
|
||||
return self.conv_bn_layer(input, ch_out, 1, stride, name=name)
|
||||
else:
|
||||
return input
|
||||
|
||||
def bottleneck_block(self, input, num_filters, stride, cardinality, name):
|
||||
cardinality = self.cardinality
|
||||
conv0 = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=num_filters,
|
||||
filter_size=1,
|
||||
act='relu',
|
||||
name=name + "_branch2a")
|
||||
conv1 = self.conv_bn_layer(
|
||||
input=conv0,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
groups=cardinality,
|
||||
act='relu',
|
||||
name=name + "_branch2b")
|
||||
conv2 = self.conv_bn_layer(
|
||||
input=conv1,
|
||||
num_filters=num_filters if cardinality == 64 else num_filters * 2,
|
||||
filter_size=1,
|
||||
act=None,
|
||||
name=name + "_branch2c")
|
||||
|
||||
short = self.shortcut(
|
||||
input,
|
||||
num_filters if cardinality == 64 else num_filters * 2,
|
||||
stride,
|
||||
name=name + "_branch1")
|
||||
|
||||
return fluid.layers.elementwise_add(
|
||||
x=short, y=conv2, act='relu', name=name + ".add.output.5")
|
||||
def forward(self, inputs):
|
||||
y = self.conv(inputs)
|
||||
y = self.pool2d_max(y)
|
||||
for block in self.block_list:
|
||||
y = block(y)
|
||||
y = self.pool2d_avg(y)
|
||||
y = fluid.layers.reshape(y, shape=[-1, self.pool2d_avg_channels])
|
||||
y = self.out(y)
|
||||
return y
|
||||
|
||||
|
||||
def ResNeXt50_64x4d():
|
||||
model = ResNeXt(layers=50, cardinality=64)
|
||||
def ResNeXt50_32x4d(**args):
|
||||
model = ResNeXt(layers=50, cardinality=32, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNeXt50_32x4d():
|
||||
model = ResNeXt(layers=50, cardinality=32)
|
||||
def ResNeXt50_64x4d(**args):
|
||||
model = ResNeXt(layers=50, cardinality=64, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNeXt101_64x4d():
|
||||
model = ResNeXt(layers=101, cardinality=64)
|
||||
def ResNeXt101_32x4d(**args):
|
||||
model = ResNeXt(layers=101, cardinality=32, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNeXt101_32x4d():
|
||||
model = ResNeXt(layers=101, cardinality=32)
|
||||
def ResNeXt101_64x4d(**args):
|
||||
model = ResNeXt(layers=101, cardinality=64, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNeXt152_64x4d():
|
||||
model = ResNeXt(layers=152, cardinality=64)
|
||||
def ResNeXt152_32x4d(**args):
|
||||
model = ResNeXt(layers=152, cardinality=32, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNeXt152_32x4d():
|
||||
model = ResNeXt(layers=152, cardinality=32)
|
||||
def ResNeXt152_64x4d(**args):
|
||||
model = ResNeXt(layers=152, cardinality=64, **args)
|
||||
return model
|
||||
|
|
|
@ -1,257 +1,269 @@
|
|||
#copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
|
||||
# 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
|
||||
# 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.
|
||||
# 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 numpy as np
|
||||
import paddle
|
||||
import paddle.fluid as fluid
|
||||
from paddle.fluid.param_attr import ParamAttr
|
||||
from paddle.fluid.layer_helper import LayerHelper
|
||||
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, Linear, Dropout
|
||||
|
||||
import math
|
||||
|
||||
__all__ = [
|
||||
"ResNeXt", "ResNeXt50_vd_64x4d", "ResNeXt101_vd_64x4d",
|
||||
"ResNeXt152_vd_64x4d", "ResNeXt50_vd_32x4d", "ResNeXt101_vd_32x4d",
|
||||
"ResNeXt152_vd_32x4d"
|
||||
"ResNeXt50_vd_32x4d", "ResNeXt50_vd_64x4d", "ResNeXt101_vd_32x4d",
|
||||
"ResNeXt101_vd_64x4d", "ResNeXt152_vd_32x4d", "ResNeXt152_vd_64x4d"
|
||||
]
|
||||
|
||||
|
||||
class ResNeXt():
|
||||
def __init__(self, layers=50, is_3x3=False, cardinality=64):
|
||||
self.layers = layers
|
||||
self.is_3x3 = is_3x3
|
||||
self.cardinality = cardinality
|
||||
class ConvBNLayer(fluid.dygraph.Layer):
|
||||
def __init__(
|
||||
self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
is_vd_mode=False,
|
||||
act=None,
|
||||
name=None, ):
|
||||
super(ConvBNLayer, self).__init__()
|
||||
|
||||
def net(self, input, class_dim=1000):
|
||||
is_3x3 = self.is_3x3
|
||||
layers = self.layers
|
||||
cardinality = self.cardinality
|
||||
self.is_vd_mode = is_vd_mode
|
||||
self._pool2d_avg = Pool2D(
|
||||
pool_size=2, pool_stride=2, pool_padding=0, pool_type='avg')
|
||||
self._conv = Conv2D(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=stride,
|
||||
padding=(filter_size - 1) // 2,
|
||||
groups=groups,
|
||||
act=None,
|
||||
param_attr=ParamAttr(name=name + "_weights"),
|
||||
bias_attr=False)
|
||||
if name == "conv1":
|
||||
bn_name = "bn_" + name
|
||||
else:
|
||||
bn_name = "bn" + name[3:]
|
||||
self._batch_norm = BatchNorm(
|
||||
num_filters,
|
||||
act=act,
|
||||
param_attr=ParamAttr(name=bn_name + '_scale'),
|
||||
bias_attr=ParamAttr(bn_name + '_offset'),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
|
||||
def forward(self, inputs):
|
||||
if self.is_vd_mode:
|
||||
inputs = self._pool2d_avg(inputs)
|
||||
y = self._conv(inputs)
|
||||
y = self._batch_norm(y)
|
||||
return y
|
||||
|
||||
|
||||
class BottleneckBlock(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
stride,
|
||||
cardinality,
|
||||
shortcut=True,
|
||||
if_first=False,
|
||||
name=None):
|
||||
super(BottleneckBlock, self).__init__()
|
||||
|
||||
self.conv0 = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=1,
|
||||
act='relu',
|
||||
name=name + "_branch2a")
|
||||
self.conv1 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
groups=cardinality,
|
||||
stride=stride,
|
||||
act='relu',
|
||||
name=name + "_branch2b")
|
||||
self.conv2 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_filters * 2 if cardinality == 32 else num_filters,
|
||||
filter_size=1,
|
||||
act=None,
|
||||
name=name + "_branch2c")
|
||||
|
||||
if not shortcut:
|
||||
self.short = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters * 2
|
||||
if cardinality == 32 else num_filters,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
is_vd_mode=False if if_first else True,
|
||||
name=name + "_branch1")
|
||||
|
||||
self.shortcut = shortcut
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self.conv0(inputs)
|
||||
conv1 = self.conv1(y)
|
||||
conv2 = self.conv2(conv1)
|
||||
|
||||
if self.shortcut:
|
||||
short = inputs
|
||||
else:
|
||||
short = self.short(inputs)
|
||||
|
||||
y = fluid.layers.elementwise_add(x=short, y=conv2)
|
||||
|
||||
layer_helper = LayerHelper(self.full_name(), act='relu')
|
||||
return layer_helper.append_activation(y)
|
||||
|
||||
|
||||
class ResNeXt(fluid.dygraph.Layer):
|
||||
def __init__(self, layers=50, class_dim=1000, cardinality=32):
|
||||
super(ResNeXt, self).__init__()
|
||||
|
||||
self.layers = layers
|
||||
self.cardinality = cardinality
|
||||
supported_layers = [50, 101, 152]
|
||||
assert layers in supported_layers, \
|
||||
"supported layers are {} but input layer is {}".format(supported_layers, layers)
|
||||
|
||||
"supported layers are {} but input layer is {}".format(
|
||||
supported_layers, layers)
|
||||
supported_cardinality = [32, 64]
|
||||
assert cardinality in supported_cardinality, \
|
||||
"supported cardinality is {} but input cardinality is {}" \
|
||||
.format(supported_cardinality, cardinality)
|
||||
if layers == 50:
|
||||
depth = [3, 4, 6, 3]
|
||||
elif layers == 101:
|
||||
depth = [3, 4, 23, 3]
|
||||
elif layers == 152:
|
||||
depth = [3, 8, 36, 3]
|
||||
num_filters1 = [256, 512, 1024, 2048]
|
||||
num_filters2 = [128, 256, 512, 1024]
|
||||
num_channels = [64, 256, 512, 1024]
|
||||
num_filters = [128, 256, 512,
|
||||
1024] if cardinality == 32 else [256, 512, 1024, 2048]
|
||||
|
||||
if is_3x3 == False:
|
||||
conv = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=64,
|
||||
filter_size=7,
|
||||
stride=2,
|
||||
act='relu')
|
||||
else:
|
||||
conv = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
stride=2,
|
||||
act='relu',
|
||||
name='conv1_1')
|
||||
conv = self.conv_bn_layer(
|
||||
input=conv,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name='conv1_2')
|
||||
conv = self.conv_bn_layer(
|
||||
input=conv,
|
||||
num_filters=64,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name='conv1_3')
|
||||
self.conv1_1 = ConvBNLayer(
|
||||
num_channels=3,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
stride=2,
|
||||
act='relu',
|
||||
name="conv1_1")
|
||||
self.conv1_2 = ConvBNLayer(
|
||||
num_channels=32,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name="conv1_2")
|
||||
self.conv1_3 = ConvBNLayer(
|
||||
num_channels=32,
|
||||
num_filters=64,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name="conv1_3")
|
||||
|
||||
conv = fluid.layers.pool2d(
|
||||
input=conv,
|
||||
pool_size=3,
|
||||
pool_stride=2,
|
||||
pool_padding=1,
|
||||
pool_type='max')
|
||||
self.pool2d_max = Pool2D(
|
||||
pool_size=3, pool_stride=2, pool_padding=1, pool_type='max')
|
||||
|
||||
self.block_list = []
|
||||
for block in range(len(depth)):
|
||||
shortcut = False
|
||||
for i in range(depth[block]):
|
||||
if layers in [101, 152, 200] and block == 2:
|
||||
if layers in [101, 152] and block == 2:
|
||||
if i == 0:
|
||||
conv_name = "res" + str(block + 2) + "a"
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + "b" + str(i)
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + chr(97 + i)
|
||||
conv = self.bottleneck_block(
|
||||
input=conv,
|
||||
num_filters=num_filters1[block]
|
||||
if cardinality == 64 else num_filters2[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
cardinality=cardinality,
|
||||
if_first=block == 0,
|
||||
name=conv_name)
|
||||
bottleneck_block = self.add_sublayer(
|
||||
'bb_%d_%d' % (block, i),
|
||||
BottleneckBlock(
|
||||
num_channels=num_channels[block] if i == 0 else
|
||||
num_filters[block] * int(64 // self.cardinality),
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
cardinality=self.cardinality,
|
||||
shortcut=shortcut,
|
||||
if_first=block == i == 0,
|
||||
name=conv_name))
|
||||
self.block_list.append(bottleneck_block)
|
||||
shortcut = True
|
||||
|
||||
pool = fluid.layers.pool2d(
|
||||
input=conv, pool_type='avg', global_pooling=True)
|
||||
stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0)
|
||||
out = fluid.layers.fc(
|
||||
input=pool,
|
||||
size=class_dim,
|
||||
param_attr=fluid.param_attr.ParamAttr(
|
||||
self.pool2d_avg = Pool2D(
|
||||
pool_size=7, pool_type='avg', global_pooling=True)
|
||||
|
||||
self.pool2d_avg_channels = num_channels[-1] * 2
|
||||
|
||||
stdv = 1.0 / math.sqrt(self.pool2d_avg_channels * 1.0)
|
||||
|
||||
self.out = Linear(
|
||||
self.pool2d_avg_channels,
|
||||
class_dim,
|
||||
param_attr=ParamAttr(
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv),
|
||||
name='fc_weights'),
|
||||
bias_attr=fluid.param_attr.ParamAttr(name='fc_offset'))
|
||||
name="fc_weights"),
|
||||
bias_attr=ParamAttr(name="fc_offset"))
|
||||
|
||||
return out
|
||||
|
||||
def conv_bn_layer(self,
|
||||
input,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
act=None,
|
||||
name=None):
|
||||
conv = fluid.layers.conv2d(
|
||||
input=input,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=stride,
|
||||
padding=(filter_size - 1) // 2,
|
||||
groups=groups,
|
||||
act=None,
|
||||
param_attr=ParamAttr(name=name + "_weights"),
|
||||
bias_attr=False)
|
||||
if name == "conv1":
|
||||
bn_name = "bn_" + name
|
||||
else:
|
||||
bn_name = "bn" + name[3:]
|
||||
return fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
act=act,
|
||||
param_attr=ParamAttr(name=bn_name + '_scale'),
|
||||
bias_attr=ParamAttr(bn_name + '_offset'),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
|
||||
def conv_bn_layer_new(self,
|
||||
input,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
act=None,
|
||||
name=None):
|
||||
pool = fluid.layers.pool2d(
|
||||
input=input,
|
||||
pool_size=2,
|
||||
pool_stride=2,
|
||||
pool_padding=0,
|
||||
pool_type='avg',
|
||||
ceil_mode=True)
|
||||
|
||||
conv = fluid.layers.conv2d(
|
||||
input=pool,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=1,
|
||||
padding=(filter_size - 1) // 2,
|
||||
groups=groups,
|
||||
act=None,
|
||||
param_attr=ParamAttr(name=name + "_weights"),
|
||||
bias_attr=False)
|
||||
if name == "conv1":
|
||||
bn_name = "bn_" + name
|
||||
else:
|
||||
bn_name = "bn" + name[3:]
|
||||
return fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
act=act,
|
||||
param_attr=ParamAttr(name=bn_name + '_scale'),
|
||||
bias_attr=ParamAttr(bn_name + '_offset'),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
|
||||
def shortcut(self, input, ch_out, stride, name, if_first=False):
|
||||
ch_in = input.shape[1]
|
||||
if ch_in != ch_out or stride != 1:
|
||||
if if_first:
|
||||
return self.conv_bn_layer(input, ch_out, 1, stride, name=name)
|
||||
else:
|
||||
return self.conv_bn_layer_new(
|
||||
input, ch_out, 1, stride, name=name)
|
||||
else:
|
||||
return input
|
||||
|
||||
def bottleneck_block(self, input, num_filters, stride, cardinality, name,
|
||||
if_first):
|
||||
conv0 = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=num_filters,
|
||||
filter_size=1,
|
||||
act='relu',
|
||||
name=name + "_branch2a")
|
||||
conv1 = self.conv_bn_layer(
|
||||
input=conv0,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
act='relu',
|
||||
groups=cardinality,
|
||||
name=name + "_branch2b")
|
||||
conv2 = self.conv_bn_layer(
|
||||
input=conv1,
|
||||
num_filters=num_filters if cardinality == 64 else num_filters * 2,
|
||||
filter_size=1,
|
||||
act=None,
|
||||
name=name + "_branch2c")
|
||||
|
||||
short = self.shortcut(
|
||||
input,
|
||||
num_filters if cardinality == 64 else num_filters * 2,
|
||||
stride,
|
||||
if_first=if_first,
|
||||
name=name + "_branch1")
|
||||
|
||||
return fluid.layers.elementwise_add(x=short, y=conv2, act='relu')
|
||||
def forward(self, inputs):
|
||||
y = self.conv1_1(inputs)
|
||||
y = self.conv1_2(y)
|
||||
y = self.conv1_3(y)
|
||||
y = self.pool2d_max(y)
|
||||
for block in self.block_list:
|
||||
y = block(y)
|
||||
y = self.pool2d_avg(y)
|
||||
y = fluid.layers.reshape(y, shape=[-1, self.pool2d_avg_channels])
|
||||
y = self.out(y)
|
||||
return y
|
||||
|
||||
|
||||
def ResNeXt50_vd_64x4d():
|
||||
model = ResNeXt(layers=50, is_3x3=True)
|
||||
def ResNeXt50_vd_32x4d(**args):
|
||||
model = ResNeXt(layers=50, cardinality=32, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNeXt50_vd_32x4d():
|
||||
model = ResNeXt(layers=50, cardinality=32, is_3x3=True)
|
||||
def ResNeXt50_vd_64x4d(**args):
|
||||
model = ResNeXt(layers=50, cardinality=64, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNeXt101_vd_64x4d():
|
||||
model = ResNeXt(layers=101, is_3x3=True)
|
||||
def ResNeXt101_vd_32x4d(**args):
|
||||
model = ResNeXt(layers=101, cardinality=32, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNeXt101_vd_32x4d():
|
||||
model = ResNeXt(layers=101, cardinality=32, is_3x3=True)
|
||||
def ResNeXt101_vd_64x4d(**args):
|
||||
model = ResNeXt(layers=101, cardinality=64, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNeXt152_vd_64x4d():
|
||||
model = ResNeXt(layers=152, is_3x3=True)
|
||||
def ResNeXt152_vd_32x4d(**args):
|
||||
model = ResNeXt(layers=152, cardinality=32, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ResNeXt152_vd_32x4d():
|
||||
model = ResNeXt(layers=152, cardinality=32, is_3x3=True)
|
||||
def ResNeXt152_vd_64x4d(**args):
|
||||
model = ResNeXt(layers=152, cardinality=64, **args)
|
||||
return model
|
||||
|
|
|
@ -1,44 +1,250 @@
|
|||
#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
|
||||
# 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.
|
||||
# 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 math
|
||||
|
||||
import numpy as np
|
||||
import paddle
|
||||
import paddle.fluid as fluid
|
||||
from paddle.fluid.param_attr import ParamAttr
|
||||
from paddle.fluid.layer_helper import LayerHelper
|
||||
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, Linear, Dropout
|
||||
|
||||
import math
|
||||
|
||||
__all__ = [
|
||||
"SE_ResNet_vd", "SE_ResNet18_vd", "SE_ResNet34_vd", "SE_ResNet50_vd",
|
||||
"SE_ResNet101_vd", "SE_ResNet152_vd", "SE_ResNet200_vd"
|
||||
"SE_ResNet18_vd", "SE_ResNet34_vd", "SE_ResNet50_vd", "SE_ResNet101_vd",
|
||||
"SE_ResNet152_vd", "SE_ResNet200_vd"
|
||||
]
|
||||
|
||||
|
||||
class SE_ResNet_vd():
|
||||
def __init__(self, layers=50, is_3x3=False):
|
||||
self.layers = layers
|
||||
self.is_3x3 = is_3x3
|
||||
class ConvBNLayer(fluid.dygraph.Layer):
|
||||
def __init__(
|
||||
self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
is_vd_mode=False,
|
||||
act=None,
|
||||
name=None, ):
|
||||
super(ConvBNLayer, self).__init__()
|
||||
|
||||
def net(self, input, class_dim=1000):
|
||||
is_3x3 = self.is_3x3
|
||||
layers = self.layers
|
||||
self.is_vd_mode = is_vd_mode
|
||||
self._pool2d_avg = Pool2D(
|
||||
pool_size=2, pool_stride=2, pool_padding=0, pool_type='avg')
|
||||
self._conv = Conv2D(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=stride,
|
||||
padding=(filter_size - 1) // 2,
|
||||
groups=groups,
|
||||
act=None,
|
||||
param_attr=ParamAttr(name=name + "_weights"),
|
||||
bias_attr=False)
|
||||
if name == "conv1":
|
||||
bn_name = "bn_" + name
|
||||
else:
|
||||
bn_name = "bn" + name[3:]
|
||||
self._batch_norm = BatchNorm(
|
||||
num_filters,
|
||||
act=act,
|
||||
param_attr=ParamAttr(name=bn_name + '_scale'),
|
||||
bias_attr=ParamAttr(bn_name + '_offset'),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
|
||||
def forward(self, inputs):
|
||||
if self.is_vd_mode:
|
||||
inputs = self._pool2d_avg(inputs)
|
||||
y = self._conv(inputs)
|
||||
y = self._batch_norm(y)
|
||||
return y
|
||||
|
||||
|
||||
class BottleneckBlock(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
stride,
|
||||
shortcut=True,
|
||||
if_first=False,
|
||||
reduction_ratio=16,
|
||||
name=None):
|
||||
super(BottleneckBlock, self).__init__()
|
||||
|
||||
self.conv0 = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=1,
|
||||
act='relu',
|
||||
name=name + "_branch2a")
|
||||
self.conv1 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
act='relu',
|
||||
name=name + "_branch2b")
|
||||
self.conv2 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_filters * 4,
|
||||
filter_size=1,
|
||||
act=None,
|
||||
name=name + "_branch2c")
|
||||
self.scale = SELayer(
|
||||
num_channels=num_filters * 4,
|
||||
num_filters=num_filters * 4,
|
||||
reduction_ratio=reduction_ratio,
|
||||
name='fc_' + name)
|
||||
|
||||
if not shortcut:
|
||||
self.short = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters * 4,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
is_vd_mode=False if if_first else True,
|
||||
name=name + "_branch1")
|
||||
|
||||
self.shortcut = shortcut
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self.conv0(inputs)
|
||||
conv1 = self.conv1(y)
|
||||
conv2 = self.conv2(conv1)
|
||||
scale = self.scale(conv2)
|
||||
|
||||
if self.shortcut:
|
||||
short = inputs
|
||||
else:
|
||||
short = self.short(inputs)
|
||||
y = fluid.layers.elementwise_add(x=short, y=scale)
|
||||
|
||||
layer_helper = LayerHelper(self.full_name(), act='relu')
|
||||
return layer_helper.append_activation(y)
|
||||
|
||||
|
||||
class BisicBlock(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
stride,
|
||||
shortcut=True,
|
||||
if_first=False,
|
||||
reduction_ratio=16,
|
||||
name=None):
|
||||
super(BisicBlock, self).__init__()
|
||||
self.stride = stride
|
||||
self.conv0 = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
act='relu',
|
||||
name=name + "_branch2a")
|
||||
self.conv1 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
act=None,
|
||||
name=name + "_branch2b")
|
||||
|
||||
self.scale = SELayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_filters,
|
||||
reduction_ratio=reduction_ratio,
|
||||
name='fc_' + name)
|
||||
|
||||
if not shortcut:
|
||||
self.short = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
is_vd_mode=False if if_first else True,
|
||||
name=name + "_branch1")
|
||||
|
||||
self.shortcut = shortcut
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self.conv0(inputs)
|
||||
conv1 = self.conv1(y)
|
||||
scale = self.scale(conv1)
|
||||
|
||||
if self.shortcut:
|
||||
short = inputs
|
||||
else:
|
||||
short = self.short(inputs)
|
||||
y = fluid.layers.elementwise_add(x=short, y=scale)
|
||||
|
||||
layer_helper = LayerHelper(self.full_name(), act='relu')
|
||||
return layer_helper.append_activation(y)
|
||||
|
||||
|
||||
class SELayer(fluid.dygraph.Layer):
|
||||
def __init__(self, num_channels, num_filters, reduction_ratio, name=None):
|
||||
super(SELayer, self).__init__()
|
||||
|
||||
self.pool2d_gap = Pool2D(pool_type='avg', global_pooling=True)
|
||||
|
||||
self._num_channels = num_channels
|
||||
|
||||
med_ch = int(num_channels / reduction_ratio)
|
||||
stdv = 1.0 / math.sqrt(num_channels * 1.0)
|
||||
self.squeeze = Linear(
|
||||
num_channels,
|
||||
med_ch,
|
||||
act="relu",
|
||||
param_attr=ParamAttr(
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv),
|
||||
name=name + "_sqz_weights"),
|
||||
bias_attr=ParamAttr(name=name + '_sqz_offset'))
|
||||
|
||||
stdv = 1.0 / math.sqrt(med_ch * 1.0)
|
||||
self.excitation = Linear(
|
||||
med_ch,
|
||||
num_filters,
|
||||
act="sigmoid",
|
||||
param_attr=ParamAttr(
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv),
|
||||
name=name + "_exc_weights"),
|
||||
bias_attr=ParamAttr(name=name + '_exc_offset'))
|
||||
|
||||
def forward(self, input):
|
||||
pool = self.pool2d_gap(input)
|
||||
pool = fluid.layers.reshape(pool, shape=[-1, self._num_channels])
|
||||
squeeze = self.squeeze(pool)
|
||||
excitation = self.excitation(squeeze)
|
||||
excitation = fluid.layers.reshape(
|
||||
excitation, shape=[-1, self._num_channels, 1, 1])
|
||||
out = input * excitation
|
||||
return out
|
||||
|
||||
|
||||
class SE_ResNet_vd(fluid.dygraph.Layer):
|
||||
def __init__(self, layers=50, class_dim=1000):
|
||||
super(SE_ResNet_vd, self).__init__()
|
||||
|
||||
self.layers = layers
|
||||
supported_layers = [18, 34, 50, 101, 152, 200]
|
||||
assert layers in supported_layers, \
|
||||
"supported layers are {} but input layer is {}".format(supported_layers, layers)
|
||||
"supported layers are {} but input layer is {}".format(
|
||||
supported_layers, layers)
|
||||
|
||||
if layers == 18:
|
||||
depth = [2, 2, 2, 2]
|
||||
|
@ -50,287 +256,129 @@ class SE_ResNet_vd():
|
|||
depth = [3, 8, 36, 3]
|
||||
elif layers == 200:
|
||||
depth = [3, 12, 48, 3]
|
||||
num_channels = [64, 256, 512,
|
||||
1024] if layers >= 50 else [64, 64, 128, 256]
|
||||
num_filters = [64, 128, 256, 512]
|
||||
reduction_ratio = 16
|
||||
if is_3x3 == False:
|
||||
conv = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=64,
|
||||
filter_size=7,
|
||||
stride=2,
|
||||
act='relu')
|
||||
else:
|
||||
conv = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
stride=2,
|
||||
act='relu',
|
||||
name='conv1_1')
|
||||
conv = self.conv_bn_layer(
|
||||
input=conv,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name='conv1_2')
|
||||
conv = self.conv_bn_layer(
|
||||
input=conv,
|
||||
num_filters=64,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name='conv1_3')
|
||||
|
||||
conv = fluid.layers.pool2d(
|
||||
input=conv,
|
||||
pool_size=3,
|
||||
pool_stride=2,
|
||||
pool_padding=1,
|
||||
pool_type='max')
|
||||
self.conv1_1 = ConvBNLayer(
|
||||
num_channels=3,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
stride=2,
|
||||
act='relu',
|
||||
name="conv1_1")
|
||||
self.conv1_2 = ConvBNLayer(
|
||||
num_channels=32,
|
||||
num_filters=32,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name="conv1_2")
|
||||
self.conv1_3 = ConvBNLayer(
|
||||
num_channels=32,
|
||||
num_filters=64,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name="conv1_3")
|
||||
self.pool2d_max = Pool2D(
|
||||
pool_size=3, pool_stride=2, pool_padding=1, pool_type='max')
|
||||
|
||||
self.block_list = []
|
||||
if layers >= 50:
|
||||
for block in range(len(depth)):
|
||||
shortcut = False
|
||||
for i in range(depth[block]):
|
||||
if layers in [101, 152, 200] and block == 2:
|
||||
if layers in [101, 152] and block == 2:
|
||||
if i == 0:
|
||||
conv_name = "res" + str(block + 2) + "a"
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + "b" + str(i)
|
||||
else:
|
||||
conv_name = "res" + str(block + 2) + chr(97 + i)
|
||||
conv = self.bottleneck_block(
|
||||
input=conv,
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
if_first=block == i == 0,
|
||||
reduction_ratio=reduction_ratio,
|
||||
name=conv_name)
|
||||
|
||||
bottleneck_block = self.add_sublayer(
|
||||
'bb_%d_%d' % (block, i),
|
||||
BottleneckBlock(
|
||||
num_channels=num_channels[block]
|
||||
if i == 0 else num_filters[block] * 4,
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
shortcut=shortcut,
|
||||
if_first=block == i == 0,
|
||||
name=conv_name))
|
||||
self.block_list.append(bottleneck_block)
|
||||
shortcut = True
|
||||
else:
|
||||
for block in range(len(depth)):
|
||||
shortcut = False
|
||||
for i in range(depth[block]):
|
||||
conv_name = "res" + str(block + 2) + chr(97 + i)
|
||||
conv = self.basic_block(
|
||||
input=conv,
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
if_first=block == i == 0,
|
||||
reduction_ratio=reduction_ratio,
|
||||
name=conv_name)
|
||||
bisic_block = self.add_sublayer(
|
||||
'bb_%d_%d' % (block, i),
|
||||
BisicBlock(
|
||||
num_channels=num_channels[block]
|
||||
if i == 0 else num_filters[block],
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
shortcut=shortcut,
|
||||
if_first=block == i == 0,
|
||||
name=conv_name))
|
||||
self.block_list.append(bisic_block)
|
||||
shortcut = True
|
||||
|
||||
pool = fluid.layers.pool2d(
|
||||
input=conv, pool_size=7, pool_type='avg', global_pooling=True)
|
||||
self.pool2d_avg = Pool2D(
|
||||
pool_size=7, pool_type='avg', global_pooling=True)
|
||||
|
||||
stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0)
|
||||
out = fluid.layers.fc(
|
||||
input=pool,
|
||||
size=class_dim,
|
||||
param_attr=fluid.param_attr.ParamAttr(
|
||||
self.pool2d_avg_channels = num_channels[-1] * 2
|
||||
|
||||
stdv = 1.0 / math.sqrt(self.pool2d_avg_channels * 1.0)
|
||||
|
||||
self.out = Linear(
|
||||
self.pool2d_avg_channels,
|
||||
class_dim,
|
||||
param_attr=ParamAttr(
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv),
|
||||
name='fc6_weights'),
|
||||
bias_attr=ParamAttr(name='fc6_offset'))
|
||||
name="fc6_weights"),
|
||||
bias_attr=ParamAttr(name="fc6_offset"))
|
||||
|
||||
return out
|
||||
|
||||
def conv_bn_layer(self,
|
||||
input,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
act=None,
|
||||
name=None):
|
||||
conv = fluid.layers.conv2d(
|
||||
input=input,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=stride,
|
||||
padding=(filter_size - 1) // 2,
|
||||
groups=groups,
|
||||
act=None,
|
||||
param_attr=ParamAttr(name=name + "_weights"),
|
||||
bias_attr=False)
|
||||
if name == "conv1":
|
||||
bn_name = "bn_" + name
|
||||
else:
|
||||
bn_name = "bn" + name[3:]
|
||||
return fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
act=act,
|
||||
param_attr=ParamAttr(name=bn_name + '_scale'),
|
||||
bias_attr=ParamAttr(bn_name + '_offset'),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
|
||||
def conv_bn_layer_new(self,
|
||||
input,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
act=None,
|
||||
name=None):
|
||||
pool = fluid.layers.pool2d(
|
||||
input=input,
|
||||
pool_size=2,
|
||||
pool_stride=2,
|
||||
pool_padding=0,
|
||||
pool_type='avg',
|
||||
ceil_mode=True)
|
||||
|
||||
conv = fluid.layers.conv2d(
|
||||
input=pool,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=1,
|
||||
padding=(filter_size - 1) // 2,
|
||||
groups=groups,
|
||||
act=None,
|
||||
param_attr=ParamAttr(name=name + "_weights"),
|
||||
bias_attr=False)
|
||||
if name == "conv1":
|
||||
bn_name = "bn_" + name
|
||||
else:
|
||||
bn_name = "bn" + name[3:]
|
||||
return fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
act=act,
|
||||
param_attr=ParamAttr(name=bn_name + '_scale'),
|
||||
bias_attr=ParamAttr(bn_name + '_offset'),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
|
||||
def shortcut(self, input, ch_out, stride, name, if_first=False):
|
||||
ch_in = input.shape[1]
|
||||
if ch_in != ch_out or stride != 1:
|
||||
if if_first:
|
||||
return self.conv_bn_layer(input, ch_out, 1, stride, name=name)
|
||||
else:
|
||||
return self.conv_bn_layer_new(
|
||||
input, ch_out, 1, stride, name=name)
|
||||
elif if_first:
|
||||
return self.conv_bn_layer(input, ch_out, 1, stride, name=name)
|
||||
else:
|
||||
return input
|
||||
|
||||
def bottleneck_block(self, input, num_filters, stride, name, if_first,
|
||||
reduction_ratio):
|
||||
conv0 = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=num_filters,
|
||||
filter_size=1,
|
||||
act='relu',
|
||||
name=name + "_branch2a")
|
||||
conv1 = self.conv_bn_layer(
|
||||
input=conv0,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
act='relu',
|
||||
name=name + "_branch2b")
|
||||
conv2 = self.conv_bn_layer(
|
||||
input=conv1,
|
||||
num_filters=num_filters * 4,
|
||||
filter_size=1,
|
||||
act=None,
|
||||
name=name + "_branch2c")
|
||||
scale = self.squeeze_excitation(
|
||||
input=conv2,
|
||||
num_channels=num_filters * 4,
|
||||
reduction_ratio=reduction_ratio,
|
||||
name='fc_' + name)
|
||||
|
||||
short = self.shortcut(
|
||||
input,
|
||||
num_filters * 4,
|
||||
stride,
|
||||
if_first=if_first,
|
||||
name=name + "_branch1")
|
||||
|
||||
return fluid.layers.elementwise_add(x=short, y=scale, act='relu')
|
||||
|
||||
def basic_block(self, input, num_filters, stride, name, if_first,
|
||||
reduction_ratio):
|
||||
conv0 = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
act='relu',
|
||||
stride=stride,
|
||||
name=name + "_branch2a")
|
||||
conv1 = self.conv_bn_layer(
|
||||
input=conv0,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
act=None,
|
||||
name=name + "_branch2b")
|
||||
scale = self.squeeze_excitation(
|
||||
input=conv1,
|
||||
num_channels=num_filters,
|
||||
reduction_ratio=reduction_ratio,
|
||||
name='fc_' + name)
|
||||
short = self.shortcut(
|
||||
input,
|
||||
num_filters,
|
||||
stride,
|
||||
if_first=if_first,
|
||||
name=name + "_branch1")
|
||||
return fluid.layers.elementwise_add(x=short, y=scale, act='relu')
|
||||
|
||||
def squeeze_excitation(self,
|
||||
input,
|
||||
num_channels,
|
||||
reduction_ratio,
|
||||
name=None):
|
||||
pool = fluid.layers.pool2d(
|
||||
input=input, pool_size=0, pool_type='avg', global_pooling=True)
|
||||
stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0)
|
||||
squeeze = fluid.layers.fc(
|
||||
input=pool,
|
||||
size=num_channels // reduction_ratio,
|
||||
act='relu',
|
||||
param_attr=fluid.param_attr.ParamAttr(
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv),
|
||||
name=name + '_sqz_weights'),
|
||||
bias_attr=ParamAttr(name=name + '_sqz_offset'))
|
||||
stdv = 1.0 / math.sqrt(squeeze.shape[1] * 1.0)
|
||||
excitation = fluid.layers.fc(
|
||||
input=squeeze,
|
||||
size=num_channels,
|
||||
act='sigmoid',
|
||||
param_attr=fluid.param_attr.ParamAttr(
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv),
|
||||
name=name + '_exc_weights'),
|
||||
bias_attr=ParamAttr(name=name + '_exc_offset'))
|
||||
scale = fluid.layers.elementwise_mul(x=input, y=excitation, axis=0)
|
||||
return scale
|
||||
def forward(self, inputs):
|
||||
y = self.conv1_1(inputs)
|
||||
y = self.conv1_2(y)
|
||||
y = self.conv1_3(y)
|
||||
y = self.pool2d_max(y)
|
||||
for block in self.block_list:
|
||||
y = block(y)
|
||||
y = self.pool2d_avg(y)
|
||||
y = fluid.layers.reshape(y, shape=[-1, self.pool2d_avg_channels])
|
||||
y = self.out(y)
|
||||
return y
|
||||
|
||||
|
||||
def SE_ResNet18_vd():
|
||||
model = SE_ResNet_vd(layers=18, is_3x3=True)
|
||||
def SE_ResNet18_vd(**args):
|
||||
model = SE_ResNet_vd(layers=18, **args)
|
||||
return model
|
||||
|
||||
|
||||
def SE_ResNet34_vd():
|
||||
model = SE_ResNet_vd(layers=34, is_3x3=True)
|
||||
def SE_ResNet34_vd(**args):
|
||||
model = SE_ResNet_vd(layers=34, **args)
|
||||
return model
|
||||
|
||||
|
||||
def SE_ResNet50_vd():
|
||||
model = SE_ResNet_vd(layers=50, is_3x3=True)
|
||||
def SE_ResNet50_vd(**args):
|
||||
model = SE_ResNet_vd(layers=50, **args)
|
||||
return model
|
||||
|
||||
|
||||
def SE_ResNet101_vd():
|
||||
model = SE_ResNet_vd(layers=101, is_3x3=True)
|
||||
def SE_ResNet101_vd(**args):
|
||||
model = SE_ResNet_vd(layers=101, **args)
|
||||
return model
|
||||
|
||||
|
||||
def SE_ResNet152_vd():
|
||||
model = SE_ResNet_vd(layers=152, is_3x3=True)
|
||||
def SE_ResNet152_vd(**args):
|
||||
model = SE_ResNet_vd(layers=152, **args)
|
||||
return model
|
||||
|
||||
|
||||
def SE_ResNet200_vd():
|
||||
model = SE_ResNet_vd(layers=200, is_3x3=True)
|
||||
def SE_ResNet200_vd(**args):
|
||||
model = SE_ResNet_vd(layers=200, **args)
|
||||
return model
|
||||
|
|
|
@ -1,329 +1,291 @@
|
|||
#copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
|
||||
# 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
|
||||
# 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.
|
||||
# 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 math
|
||||
|
||||
import numpy as np
|
||||
import paddle
|
||||
import paddle.fluid as fluid
|
||||
from paddle.fluid.param_attr import ParamAttr
|
||||
from paddle.fluid.layer_helper import LayerHelper
|
||||
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, Linear, Dropout
|
||||
|
||||
__all__ = [
|
||||
"SE_ResNeXt_vd", "SE_ResNeXt50_32x4d_vd", "SE_ResNeXt101_32x4d_vd",
|
||||
"SENet154_vd"
|
||||
]
|
||||
import math
|
||||
|
||||
__all__ = ["SE_ResNeXt50_vd_32x4d", "SE_ResNeXt50_vd_32x4d", "SENet154_vd"]
|
||||
|
||||
|
||||
class SE_ResNeXt_vd():
|
||||
def __init__(self, layers=50):
|
||||
self.layers = layers
|
||||
|
||||
def net(self, input, class_dim=1000):
|
||||
layers = self.layers
|
||||
supported_layers = [50, 101, 152]
|
||||
assert layers in supported_layers, \
|
||||
"supported layers are {} but input layer is {}".format(supported_layers, layers)
|
||||
if layers == 50:
|
||||
cardinality = 32
|
||||
reduction_ratio = 16
|
||||
depth = [3, 4, 6, 3]
|
||||
num_filters = [128, 256, 512, 1024]
|
||||
|
||||
conv = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=64,
|
||||
filter_size=3,
|
||||
stride=2,
|
||||
act='relu',
|
||||
name='conv1_1')
|
||||
conv = self.conv_bn_layer(
|
||||
input=conv,
|
||||
num_filters=64,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name='conv1_2')
|
||||
conv = self.conv_bn_layer(
|
||||
input=conv,
|
||||
num_filters=128,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name='conv1_3')
|
||||
conv = fluid.layers.pool2d(
|
||||
input=conv,
|
||||
pool_size=3,
|
||||
pool_stride=2,
|
||||
pool_padding=1,
|
||||
pool_type='max')
|
||||
elif layers == 101:
|
||||
cardinality = 32
|
||||
reduction_ratio = 16
|
||||
depth = [3, 4, 23, 3]
|
||||
num_filters = [128, 256, 512, 1024]
|
||||
|
||||
conv = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=64,
|
||||
filter_size=3,
|
||||
stride=2,
|
||||
act='relu',
|
||||
name='conv1_1')
|
||||
conv = self.conv_bn_layer(
|
||||
input=conv,
|
||||
num_filters=64,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name='conv1_2')
|
||||
conv = self.conv_bn_layer(
|
||||
input=conv,
|
||||
num_filters=128,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name='conv1_3')
|
||||
conv = fluid.layers.pool2d(
|
||||
input=conv,
|
||||
pool_size=3,
|
||||
pool_stride=2,
|
||||
pool_padding=1,
|
||||
pool_type='max')
|
||||
elif layers == 152:
|
||||
cardinality = 64
|
||||
reduction_ratio = 16
|
||||
depth = [3, 8, 36, 3]
|
||||
num_filters = [256, 512, 1024, 2048]
|
||||
|
||||
conv = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=64,
|
||||
filter_size=3,
|
||||
stride=2,
|
||||
act='relu',
|
||||
name='conv1_1')
|
||||
conv = self.conv_bn_layer(
|
||||
input=conv,
|
||||
num_filters=64,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name='conv1_2')
|
||||
conv = self.conv_bn_layer(
|
||||
input=conv,
|
||||
num_filters=128,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name='conv1_3')
|
||||
conv = fluid.layers.pool2d(
|
||||
input=conv, pool_size=3, pool_stride=2, pool_padding=1, \
|
||||
pool_type='max')
|
||||
n = 1 if layers == 50 or layers == 101 else 3
|
||||
for block in range(len(depth)):
|
||||
n += 1
|
||||
for i in range(depth[block]):
|
||||
conv = self.bottleneck_block(
|
||||
input=conv,
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
cardinality=cardinality,
|
||||
reduction_ratio=reduction_ratio,
|
||||
if_first=block == 0,
|
||||
name=str(n) + '_' + str(i + 1))
|
||||
|
||||
pool = fluid.layers.pool2d(
|
||||
input=conv, pool_type='avg', global_pooling=True)
|
||||
if layers == 152:
|
||||
pool = fluid.layers.dropout(x=pool, dropout_prob=0.2)
|
||||
stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0)
|
||||
out = fluid.layers.fc(
|
||||
input=pool,
|
||||
size=class_dim,
|
||||
param_attr=ParamAttr(
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv),
|
||||
name='fc6_weights'),
|
||||
bias_attr=ParamAttr(name='fc6_offset'))
|
||||
|
||||
return out
|
||||
|
||||
def shortcut(self, input, ch_out, stride, name, if_first=False):
|
||||
ch_in = input.shape[1]
|
||||
if ch_in != ch_out or stride != 1:
|
||||
filter_size = 1
|
||||
if if_first:
|
||||
return self.conv_bn_layer(
|
||||
input,
|
||||
ch_out,
|
||||
filter_size,
|
||||
stride,
|
||||
name='conv' + name + '_prj')
|
||||
else:
|
||||
return self.conv_bn_layer_new(
|
||||
input,
|
||||
ch_out,
|
||||
filter_size,
|
||||
stride,
|
||||
name='conv' + name + '_prj')
|
||||
else:
|
||||
return input
|
||||
|
||||
def bottleneck_block(self,
|
||||
input,
|
||||
num_filters,
|
||||
stride,
|
||||
cardinality,
|
||||
reduction_ratio,
|
||||
if_first,
|
||||
name=None):
|
||||
conv0 = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=num_filters,
|
||||
filter_size=1,
|
||||
act='relu',
|
||||
name='conv' + name + '_x1')
|
||||
conv1 = self.conv_bn_layer(
|
||||
input=conv0,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
groups=cardinality,
|
||||
act='relu',
|
||||
name='conv' + name + '_x2')
|
||||
if cardinality == 64:
|
||||
num_filters = num_filters // 2
|
||||
conv2 = self.conv_bn_layer(
|
||||
input=conv1,
|
||||
num_filters=num_filters * 2,
|
||||
filter_size=1,
|
||||
act=None,
|
||||
name='conv' + name + '_x3')
|
||||
scale = self.squeeze_excitation(
|
||||
input=conv2,
|
||||
num_channels=num_filters * 2,
|
||||
reduction_ratio=reduction_ratio,
|
||||
name='fc' + name)
|
||||
|
||||
short = self.shortcut(
|
||||
input, num_filters * 2, stride, if_first=if_first, name=name)
|
||||
|
||||
return fluid.layers.elementwise_add(x=short, y=scale, act='relu')
|
||||
|
||||
def conv_bn_layer(self,
|
||||
input,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
act=None,
|
||||
name=None):
|
||||
conv = fluid.layers.conv2d(
|
||||
input=input,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=stride,
|
||||
padding=(filter_size - 1) // 2,
|
||||
groups=groups,
|
||||
act=None,
|
||||
bias_attr=False,
|
||||
param_attr=ParamAttr(name=name + '_weights'), )
|
||||
bn_name = name + "_bn"
|
||||
return fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
act=act,
|
||||
param_attr=ParamAttr(name=bn_name + '_scale'),
|
||||
bias_attr=ParamAttr(bn_name + '_offset'),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
|
||||
def conv_bn_layer_new(self,
|
||||
input,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
act=None,
|
||||
name=None):
|
||||
pool = fluid.layers.pool2d(
|
||||
input=input,
|
||||
pool_size=2,
|
||||
pool_stride=2,
|
||||
pool_padding=0,
|
||||
pool_type='avg',
|
||||
ceil_mode=True)
|
||||
|
||||
conv = fluid.layers.conv2d(
|
||||
input=pool,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
class ConvBNLayer(fluid.dygraph.Layer):
|
||||
def __init__(
|
||||
self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
filter_size,
|
||||
stride=1,
|
||||
groups=1,
|
||||
is_vd_mode=False,
|
||||
act=None,
|
||||
name=None, ):
|
||||
super(ConvBNLayer, self).__init__()
|
||||
|
||||
self.is_vd_mode = is_vd_mode
|
||||
self._pool2d_avg = Pool2D(
|
||||
pool_size=2, pool_stride=2, pool_padding=0, pool_type='avg')
|
||||
self._conv = Conv2D(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=stride,
|
||||
padding=(filter_size - 1) // 2,
|
||||
groups=groups,
|
||||
act=None,
|
||||
param_attr=ParamAttr(name=name + "_weights"),
|
||||
bias_attr=False)
|
||||
bn_name = name + "_bn"
|
||||
return fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
bn_name = name + '_bn'
|
||||
self._batch_norm = BatchNorm(
|
||||
num_filters,
|
||||
act=act,
|
||||
param_attr=ParamAttr(name=bn_name + '_scale'),
|
||||
bias_attr=ParamAttr(bn_name + '_offset'),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
|
||||
def squeeze_excitation(self,
|
||||
input,
|
||||
num_channels,
|
||||
reduction_ratio,
|
||||
name=None):
|
||||
pool = fluid.layers.pool2d(
|
||||
input=input, pool_type='avg', global_pooling=True)
|
||||
stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0)
|
||||
squeeze = fluid.layers.fc(
|
||||
input=pool,
|
||||
size=num_channels // reduction_ratio,
|
||||
def forward(self, inputs):
|
||||
if self.is_vd_mode:
|
||||
inputs = self._pool2d_avg(inputs)
|
||||
y = self._conv(inputs)
|
||||
y = self._batch_norm(y)
|
||||
return y
|
||||
|
||||
|
||||
class BottleneckBlock(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
stride,
|
||||
cardinality,
|
||||
reduction_ratio,
|
||||
shortcut=True,
|
||||
if_first=False,
|
||||
name=None):
|
||||
super(BottleneckBlock, self).__init__()
|
||||
|
||||
self.conv0 = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=1,
|
||||
act='relu',
|
||||
param_attr=fluid.param_attr.ParamAttr(
|
||||
name='conv' + name + '_x1')
|
||||
self.conv1 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_filters,
|
||||
filter_size=3,
|
||||
groups=cardinality,
|
||||
stride=stride,
|
||||
act='relu',
|
||||
name='conv' + name + '_x2')
|
||||
self.conv2 = ConvBNLayer(
|
||||
num_channels=num_filters,
|
||||
num_filters=num_filters * 2 if cardinality == 32 else num_filters,
|
||||
filter_size=1,
|
||||
act=None,
|
||||
name='conv' + name + '_x3')
|
||||
self.scale = SELayer(
|
||||
num_channels=num_filters * 2 if cardinality == 32 else num_filters,
|
||||
num_filters=num_filters * 2 if cardinality == 32 else num_filters,
|
||||
reduction_ratio=reduction_ratio,
|
||||
name='fc_' + name)
|
||||
|
||||
if not shortcut:
|
||||
self.short = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters * 2
|
||||
if cardinality == 32 else num_filters,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
is_vd_mode=False if if_first else True,
|
||||
name='conv' + name + '_prj')
|
||||
|
||||
self.shortcut = shortcut
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self.conv0(inputs)
|
||||
conv1 = self.conv1(y)
|
||||
conv2 = self.conv2(conv1)
|
||||
scale = self.scale(conv2)
|
||||
|
||||
if self.shortcut:
|
||||
short = inputs
|
||||
else:
|
||||
short = self.short(inputs)
|
||||
y = fluid.layers.elementwise_add(x=short, y=scale)
|
||||
|
||||
layer_helper = LayerHelper(self.full_name(), act='relu')
|
||||
return layer_helper.append_activation(y)
|
||||
|
||||
|
||||
class SELayer(fluid.dygraph.Layer):
|
||||
def __init__(self, num_channels, num_filters, reduction_ratio, name=None):
|
||||
super(SELayer, self).__init__()
|
||||
|
||||
self.pool2d_gap = Pool2D(pool_type='avg', global_pooling=True)
|
||||
|
||||
self._num_channels = num_channels
|
||||
|
||||
med_ch = int(num_channels / reduction_ratio)
|
||||
stdv = 1.0 / math.sqrt(num_channels * 1.0)
|
||||
self.squeeze = Linear(
|
||||
num_channels,
|
||||
med_ch,
|
||||
act="relu",
|
||||
param_attr=ParamAttr(
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv),
|
||||
name=name + '_sqz_weights'),
|
||||
name=name + "_sqz_weights"),
|
||||
bias_attr=ParamAttr(name=name + '_sqz_offset'))
|
||||
stdv = 1.0 / math.sqrt(squeeze.shape[1] * 1.0)
|
||||
excitation = fluid.layers.fc(
|
||||
input=squeeze,
|
||||
size=num_channels,
|
||||
act='sigmoid',
|
||||
param_attr=fluid.param_attr.ParamAttr(
|
||||
|
||||
stdv = 1.0 / math.sqrt(med_ch * 1.0)
|
||||
self.excitation = Linear(
|
||||
med_ch,
|
||||
num_filters,
|
||||
act="sigmoid",
|
||||
param_attr=ParamAttr(
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv),
|
||||
name=name + '_exc_weights'),
|
||||
name=name + "_exc_weights"),
|
||||
bias_attr=ParamAttr(name=name + '_exc_offset'))
|
||||
scale = fluid.layers.elementwise_mul(x=input, y=excitation, axis=0)
|
||||
return scale
|
||||
|
||||
def forward(self, input):
|
||||
pool = self.pool2d_gap(input)
|
||||
pool = fluid.layers.reshape(pool, shape=[-1, self._num_channels])
|
||||
squeeze = self.squeeze(pool)
|
||||
excitation = self.excitation(squeeze)
|
||||
excitation = fluid.layers.reshape(
|
||||
excitation, shape=[-1, self._num_channels, 1, 1])
|
||||
out = input * excitation
|
||||
return out
|
||||
|
||||
|
||||
def SE_ResNeXt50_vd_32x4d():
|
||||
model = SE_ResNeXt_vd(layers=50)
|
||||
class ResNeXt(fluid.dygraph.Layer):
|
||||
def __init__(self, layers=50, class_dim=1000, cardinality=32):
|
||||
super(ResNeXt, self).__init__()
|
||||
|
||||
self.layers = layers
|
||||
self.cardinality = cardinality
|
||||
self.reduction_ratio = 16
|
||||
supported_layers = [50, 101, 152]
|
||||
assert layers in supported_layers, \
|
||||
"supported layers are {} but input layer is {}".format(
|
||||
supported_layers, layers)
|
||||
supported_cardinality = [32, 64]
|
||||
assert cardinality in supported_cardinality, \
|
||||
"supported cardinality is {} but input cardinality is {}" \
|
||||
.format(supported_cardinality, cardinality)
|
||||
if layers == 50:
|
||||
depth = [3, 4, 6, 3]
|
||||
elif layers == 101:
|
||||
depth = [3, 4, 23, 3]
|
||||
elif layers == 152:
|
||||
depth = [3, 8, 36, 3]
|
||||
num_channels = [128, 256, 512, 1024]
|
||||
num_filters = [128, 256, 512,
|
||||
1024] if cardinality == 32 else [256, 512, 1024, 2048]
|
||||
|
||||
self.conv1_1 = ConvBNLayer(
|
||||
num_channels=3,
|
||||
num_filters=64,
|
||||
filter_size=3,
|
||||
stride=2,
|
||||
act='relu',
|
||||
name="conv1_1")
|
||||
self.conv1_2 = ConvBNLayer(
|
||||
num_channels=64,
|
||||
num_filters=64,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name="conv1_2")
|
||||
self.conv1_3 = ConvBNLayer(
|
||||
num_channels=64,
|
||||
num_filters=128,
|
||||
filter_size=3,
|
||||
stride=1,
|
||||
act='relu',
|
||||
name="conv1_3")
|
||||
|
||||
self.pool2d_max = Pool2D(
|
||||
pool_size=3, pool_stride=2, pool_padding=1, pool_type='max')
|
||||
|
||||
self.block_list = []
|
||||
n = 1 if layers == 50 or layers == 101 else 3
|
||||
for block in range(len(depth)):
|
||||
n += 1
|
||||
shortcut = False
|
||||
for i in range(depth[block]):
|
||||
bottleneck_block = self.add_sublayer(
|
||||
'bb_%d_%d' % (block, i),
|
||||
BottleneckBlock(
|
||||
num_channels=num_channels[block] if i == 0 else
|
||||
num_filters[block] * int(64 // self.cardinality),
|
||||
num_filters=num_filters[block],
|
||||
stride=2 if i == 0 and block != 0 else 1,
|
||||
cardinality=self.cardinality,
|
||||
reduction_ratio=self.reduction_ratio,
|
||||
shortcut=shortcut,
|
||||
if_first=block == 0,
|
||||
name=str(n) + '_' + str(i + 1)))
|
||||
self.block_list.append(bottleneck_block)
|
||||
shortcut = True
|
||||
|
||||
self.pool2d_avg = Pool2D(
|
||||
pool_size=7, pool_type='avg', global_pooling=True)
|
||||
|
||||
self.pool2d_avg_channels = num_channels[-1] * 2
|
||||
|
||||
stdv = 1.0 / math.sqrt(self.pool2d_avg_channels * 1.0)
|
||||
|
||||
self.out = Linear(
|
||||
self.pool2d_avg_channels,
|
||||
class_dim,
|
||||
param_attr=ParamAttr(
|
||||
initializer=fluid.initializer.Uniform(-stdv, stdv),
|
||||
name="fc6_weights"),
|
||||
bias_attr=ParamAttr(name="fc6_offset"))
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self.conv1_1(inputs)
|
||||
y = self.conv1_2(y)
|
||||
y = self.conv1_3(y)
|
||||
y = self.pool2d_max(y)
|
||||
for block in self.block_list:
|
||||
y = block(y)
|
||||
y = self.pool2d_avg(y)
|
||||
y = fluid.layers.reshape(y, shape=[-1, self.pool2d_avg_channels])
|
||||
y = self.out(y)
|
||||
return y
|
||||
|
||||
|
||||
def SE_ResNeXt50_vd_32x4d(**args):
|
||||
model = ResNeXt(layers=50, cardinality=32, **args)
|
||||
return model
|
||||
|
||||
|
||||
def SE_ResNeXt101_vd_32x4d():
|
||||
model = SE_ResNeXt_vd(layers=101)
|
||||
def SE_ResNeXt101_vd_32x4d(**args):
|
||||
model = ResNeXt(layers=101, cardinality=32, **args)
|
||||
return model
|
||||
|
||||
|
||||
def SENet154_vd():
|
||||
model = SE_ResNeXt_vd(layers=152)
|
||||
def SENet154_vd(**args):
|
||||
model = ResNeXt(layers=152, cardinality=64, **args)
|
||||
return model
|
||||
|
|
|
@ -1,40 +1,231 @@
|
|||
#copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
|
||||
# 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
|
||||
# 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.
|
||||
# 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 numpy as np
|
||||
import paddle
|
||||
import paddle.fluid as fluid
|
||||
from paddle.fluid.param_attr import ParamAttr
|
||||
from paddle.fluid.layer_helper import LayerHelper
|
||||
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, Linear, Dropout
|
||||
from paddle.fluid.initializer import MSRA
|
||||
import math
|
||||
|
||||
import paddle.fluid as fluid
|
||||
from paddle.fluid.initializer import MSRA
|
||||
from paddle.fluid.param_attr import ParamAttr
|
||||
|
||||
__all__ = [
|
||||
'ShuffleNetV2_x0_25', 'ShuffleNetV2_x0_33', 'ShuffleNetV2_x0_5',
|
||||
'ShuffleNetV2_x1_0', 'ShuffleNetV2_x1_5', 'ShuffleNetV2_x2_0',
|
||||
'ShuffleNetV2'
|
||||
"ShuffleNetV2_x0_25", "ShuffleNetV2_x0_33", "ShuffleNetV2_x0_5",
|
||||
"ShuffleNetV2_x1_0", "ShuffleNetV2_x1_5", "ShuffleNetV2_x2_0",
|
||||
"ShuffleNetV2_swish"
|
||||
]
|
||||
|
||||
|
||||
class ShuffleNetV2():
|
||||
def __init__(self, scale=1.0):
|
||||
self.scale = scale
|
||||
def channel_shuffle(x, groups):
|
||||
batchsize, num_channels, height, width = x.shape[0], x.shape[1], x.shape[
|
||||
2], x.shape[3]
|
||||
channels_per_group = num_channels // groups
|
||||
|
||||
def net(self, input, class_dim=1000):
|
||||
scale = self.scale
|
||||
# reshape
|
||||
x = fluid.layers.reshape(
|
||||
x=x, shape=[batchsize, groups, channels_per_group, height, width])
|
||||
|
||||
x = fluid.layers.transpose(x=x, perm=[0, 2, 1, 3, 4])
|
||||
# flatten
|
||||
x = fluid.layers.reshape(
|
||||
x=x, shape=[batchsize, num_channels, height, width])
|
||||
return x
|
||||
|
||||
|
||||
class ConvBNLayer(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
num_channels,
|
||||
filter_size,
|
||||
num_filters,
|
||||
stride,
|
||||
padding,
|
||||
channels=None,
|
||||
num_groups=1,
|
||||
if_act=True,
|
||||
act='relu',
|
||||
name=None,
|
||||
use_cudnn=True):
|
||||
super(ConvBNLayer, self).__init__()
|
||||
self._if_act = if_act
|
||||
assert act in ['relu', 'swish'], \
|
||||
"supported act are {} but your act is {}".format(
|
||||
['relu', 'swish'], act)
|
||||
self._act = act
|
||||
self._conv = Conv2D(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=stride,
|
||||
padding=padding,
|
||||
groups=num_groups,
|
||||
act=None,
|
||||
use_cudnn=use_cudnn,
|
||||
param_attr=ParamAttr(
|
||||
initializer=MSRA(), name=name + "_weights"),
|
||||
bias_attr=False)
|
||||
|
||||
self._batch_norm = BatchNorm(
|
||||
num_filters,
|
||||
param_attr=ParamAttr(name=name + "_bn_scale"),
|
||||
bias_attr=ParamAttr(name=name + "_bn_offset"),
|
||||
moving_mean_name=name + "_bn_mean",
|
||||
moving_variance_name=name + "_bn_variance")
|
||||
|
||||
def forward(self, inputs, if_act=True):
|
||||
y = self._conv(inputs)
|
||||
y = self._batch_norm(y)
|
||||
if self._if_act:
|
||||
y = fluid.layers.relu(
|
||||
y) if self._act == 'relu' else fluid.layers.swish(y)
|
||||
return y
|
||||
|
||||
|
||||
class InvertedResidualUnit(fluid.dygraph.Layer):
|
||||
def __init__(self,
|
||||
num_channels,
|
||||
num_filters,
|
||||
stride,
|
||||
benchmodel,
|
||||
act='relu',
|
||||
name=None):
|
||||
super(InvertedResidualUnit, self).__init__()
|
||||
assert stride in [1, 2], \
|
||||
"supported stride are {} but your stride is {}".format([
|
||||
1, 2], stride)
|
||||
self.benchmodel = benchmodel
|
||||
oup_inc = num_filters // 2
|
||||
inp = num_channels
|
||||
if benchmodel == 1:
|
||||
self._conv_pw = ConvBNLayer(
|
||||
num_channels=num_channels // 2,
|
||||
num_filters=oup_inc,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
num_groups=1,
|
||||
if_act=True,
|
||||
act=act,
|
||||
name='stage_' + name + '_conv1')
|
||||
self._conv_dw = ConvBNLayer(
|
||||
num_channels=oup_inc,
|
||||
num_filters=oup_inc,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
padding=1,
|
||||
num_groups=oup_inc,
|
||||
if_act=False,
|
||||
act=act,
|
||||
use_cudnn=False,
|
||||
name='stage_' + name + '_conv2')
|
||||
self._conv_linear = ConvBNLayer(
|
||||
num_channels=oup_inc,
|
||||
num_filters=oup_inc,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
num_groups=1,
|
||||
if_act=True,
|
||||
act=act,
|
||||
name='stage_' + name + '_conv3')
|
||||
else:
|
||||
# branch1
|
||||
self._conv_dw_1 = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=inp,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
padding=1,
|
||||
num_groups=inp,
|
||||
if_act=False,
|
||||
act=act,
|
||||
use_cudnn=False,
|
||||
name='stage_' + name + '_conv4')
|
||||
self._conv_linear_1 = ConvBNLayer(
|
||||
num_channels=inp,
|
||||
num_filters=oup_inc,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
num_groups=1,
|
||||
if_act=True,
|
||||
act=act,
|
||||
name='stage_' + name + '_conv5')
|
||||
# branch2
|
||||
self._conv_pw_2 = ConvBNLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=oup_inc,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
num_groups=1,
|
||||
if_act=True,
|
||||
act=act,
|
||||
name='stage_' + name + '_conv1')
|
||||
self._conv_dw_2 = ConvBNLayer(
|
||||
num_channels=oup_inc,
|
||||
num_filters=oup_inc,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
padding=1,
|
||||
num_groups=oup_inc,
|
||||
if_act=False,
|
||||
act=act,
|
||||
use_cudnn=False,
|
||||
name='stage_' + name + '_conv2')
|
||||
self._conv_linear_2 = ConvBNLayer(
|
||||
num_channels=oup_inc,
|
||||
num_filters=oup_inc,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
num_groups=1,
|
||||
if_act=True,
|
||||
act=act,
|
||||
name='stage_' + name + '_conv3')
|
||||
|
||||
def forward(self, inputs):
|
||||
if self.benchmodel == 1:
|
||||
x1, x2 = fluid.layers.split(
|
||||
inputs,
|
||||
num_or_sections=[inputs.shape[1] // 2, inputs.shape[1] // 2],
|
||||
dim=1)
|
||||
x2 = self._conv_pw(x2)
|
||||
x2 = self._conv_dw(x2)
|
||||
x2 = self._conv_linear(x2)
|
||||
out = fluid.layers.concat([x1, x2], axis=1)
|
||||
else:
|
||||
x1 = self._conv_dw_1(inputs)
|
||||
x1 = self._conv_linear_1(x1)
|
||||
|
||||
x2 = self._conv_pw_2(inputs)
|
||||
x2 = self._conv_dw_2(x2)
|
||||
x2 = self._conv_linear_2(x2)
|
||||
out = fluid.layers.concat([x1, x2], axis=1)
|
||||
|
||||
return channel_shuffle(out, 2)
|
||||
|
||||
|
||||
class ShuffleNet(fluid.dygraph.Layer):
|
||||
def __init__(self, class_dim=1000, scale=1.0, act='relu'):
|
||||
super(ShuffleNet, self).__init__()
|
||||
self.scale = scale
|
||||
self.class_dim = class_dim
|
||||
stage_repeats = [4, 8, 4]
|
||||
|
||||
if scale == 0.25:
|
||||
|
@ -52,256 +243,113 @@ class ShuffleNetV2():
|
|||
else:
|
||||
raise NotImplementedError("This scale size:[" + str(scale) +
|
||||
"] is not implemented!")
|
||||
#conv1
|
||||
|
||||
input_channel = stage_out_channels[1]
|
||||
conv1 = self.conv_bn_layer(
|
||||
input=input,
|
||||
# 1. conv1
|
||||
self._conv1 = ConvBNLayer(
|
||||
num_channels=3,
|
||||
num_filters=stage_out_channels[1],
|
||||
filter_size=3,
|
||||
num_filters=input_channel,
|
||||
padding=1,
|
||||
stride=2,
|
||||
padding=1,
|
||||
if_act=True,
|
||||
act=act,
|
||||
name='stage1_conv')
|
||||
pool1 = fluid.layers.pool2d(
|
||||
input=conv1,
|
||||
pool_size=3,
|
||||
pool_stride=2,
|
||||
pool_padding=1,
|
||||
pool_type='max')
|
||||
conv = pool1
|
||||
# bottleneck sequences
|
||||
self._max_pool = Pool2D(
|
||||
pool_type='max', pool_size=3, pool_stride=2, pool_padding=1)
|
||||
|
||||
# 2. bottleneck sequences
|
||||
self._block_list = []
|
||||
i = 1
|
||||
in_c = int(32 * scale)
|
||||
for idxstage in range(len(stage_repeats)):
|
||||
numrepeat = stage_repeats[idxstage]
|
||||
output_channel = stage_out_channels[idxstage + 2]
|
||||
for i in range(numrepeat):
|
||||
if i == 0:
|
||||
conv = self.inverted_residual_unit(
|
||||
input=conv,
|
||||
num_filters=output_channel,
|
||||
stride=2,
|
||||
benchmodel=2,
|
||||
name=str(idxstage + 2) + '_' + str(i + 1))
|
||||
block = self.add_sublayer(
|
||||
str(idxstage + 2) + '_' + str(i + 1),
|
||||
InvertedResidualUnit(
|
||||
num_channels=stage_out_channels[idxstage + 1],
|
||||
num_filters=output_channel,
|
||||
stride=2,
|
||||
benchmodel=2,
|
||||
act=act,
|
||||
name=str(idxstage + 2) + '_' + str(i + 1)))
|
||||
self._block_list.append(block)
|
||||
else:
|
||||
conv = self.inverted_residual_unit(
|
||||
input=conv,
|
||||
num_filters=output_channel,
|
||||
stride=1,
|
||||
benchmodel=1,
|
||||
name=str(idxstage + 2) + '_' + str(i + 1))
|
||||
block = self.add_sublayer(
|
||||
str(idxstage + 2) + '_' + str(i + 1),
|
||||
InvertedResidualUnit(
|
||||
num_channels=output_channel,
|
||||
num_filters=output_channel,
|
||||
stride=1,
|
||||
benchmodel=1,
|
||||
act=act,
|
||||
name=str(idxstage + 2) + '_' + str(i + 1)))
|
||||
self._block_list.append(block)
|
||||
|
||||
conv_last = self.conv_bn_layer(
|
||||
input=conv,
|
||||
filter_size=1,
|
||||
# 3. last_conv
|
||||
self._last_conv = ConvBNLayer(
|
||||
num_channels=stage_out_channels[-2],
|
||||
num_filters=stage_out_channels[-1],
|
||||
padding=0,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
if_act=True,
|
||||
act=act,
|
||||
name='conv5')
|
||||
pool_last = fluid.layers.pool2d(
|
||||
input=conv_last,
|
||||
pool_size=7,
|
||||
pool_stride=1,
|
||||
pool_padding=0,
|
||||
pool_type='avg')
|
||||
|
||||
output = fluid.layers.fc(input=pool_last,
|
||||
size=class_dim,
|
||||
param_attr=ParamAttr(
|
||||
initializer=MSRA(), name='fc6_weights'),
|
||||
bias_attr=ParamAttr(name='fc6_offset'))
|
||||
return output
|
||||
# 4. pool
|
||||
self._pool2d_avg = Pool2D(pool_type='avg', global_pooling=True)
|
||||
self._out_c = stage_out_channels[-1]
|
||||
# 5. fc
|
||||
self._fc = Linear(
|
||||
stage_out_channels[-1],
|
||||
class_dim,
|
||||
param_attr=ParamAttr(name='fc6_weights'),
|
||||
bias_attr=ParamAttr(name='fc6_offset'))
|
||||
|
||||
def conv_bn_layer(self,
|
||||
input,
|
||||
filter_size,
|
||||
num_filters,
|
||||
stride,
|
||||
padding,
|
||||
num_groups=1,
|
||||
use_cudnn=True,
|
||||
if_act=True,
|
||||
name=None):
|
||||
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(
|
||||
initializer=MSRA(), name=name + '_weights'),
|
||||
bias_attr=False)
|
||||
out = int((input.shape[2] - 1) / float(stride) + 1)
|
||||
bn_name = name + '_bn'
|
||||
if if_act:
|
||||
return fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
act='relu',
|
||||
param_attr=ParamAttr(name=bn_name + "_scale"),
|
||||
bias_attr=ParamAttr(name=bn_name + "_offset"),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
else:
|
||||
return fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
param_attr=ParamAttr(name=bn_name + "_scale"),
|
||||
bias_attr=ParamAttr(name=bn_name + "_offset"),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
|
||||
def channel_shuffle(self, x, groups):
|
||||
batchsize, num_channels, height, width = x.shape[0], x.shape[
|
||||
1], x.shape[2], x.shape[3]
|
||||
channels_per_group = num_channels // groups
|
||||
|
||||
# reshape
|
||||
x = fluid.layers.reshape(
|
||||
x=x, shape=[batchsize, groups, channels_per_group, height, width])
|
||||
|
||||
x = fluid.layers.transpose(x=x, perm=[0, 2, 1, 3, 4])
|
||||
|
||||
# flatten
|
||||
x = fluid.layers.reshape(
|
||||
x=x, shape=[batchsize, num_channels, height, width])
|
||||
|
||||
return x
|
||||
|
||||
def inverted_residual_unit(self,
|
||||
input,
|
||||
num_filters,
|
||||
stride,
|
||||
benchmodel,
|
||||
name=None):
|
||||
assert stride in [1, 2], \
|
||||
"supported stride are {} but your stride is {}".format([1,2], stride)
|
||||
|
||||
oup_inc = num_filters // 2
|
||||
inp = input.shape[1]
|
||||
|
||||
if benchmodel == 1:
|
||||
x1, x2 = fluid.layers.split(
|
||||
input,
|
||||
num_or_sections=[input.shape[1] // 2, input.shape[1] // 2],
|
||||
dim=1)
|
||||
|
||||
conv_pw = self.conv_bn_layer(
|
||||
input=x2,
|
||||
num_filters=oup_inc,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
num_groups=1,
|
||||
if_act=True,
|
||||
name='stage_' + name + '_conv1')
|
||||
|
||||
conv_dw = self.conv_bn_layer(
|
||||
input=conv_pw,
|
||||
num_filters=oup_inc,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
padding=1,
|
||||
num_groups=oup_inc,
|
||||
if_act=False,
|
||||
use_cudnn=False,
|
||||
name='stage_' + name + '_conv2')
|
||||
|
||||
conv_linear = self.conv_bn_layer(
|
||||
input=conv_dw,
|
||||
num_filters=oup_inc,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
num_groups=1,
|
||||
if_act=True,
|
||||
name='stage_' + name + '_conv3')
|
||||
|
||||
out = fluid.layers.concat([x1, conv_linear], axis=1)
|
||||
|
||||
else:
|
||||
#branch1
|
||||
conv_dw_1 = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=inp,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
padding=1,
|
||||
num_groups=inp,
|
||||
if_act=False,
|
||||
use_cudnn=False,
|
||||
name='stage_' + name + '_conv4')
|
||||
|
||||
conv_linear_1 = self.conv_bn_layer(
|
||||
input=conv_dw_1,
|
||||
num_filters=oup_inc,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
num_groups=1,
|
||||
if_act=True,
|
||||
name='stage_' + name + '_conv5')
|
||||
|
||||
#branch2
|
||||
conv_pw_2 = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=oup_inc,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
num_groups=1,
|
||||
if_act=True,
|
||||
name='stage_' + name + '_conv1')
|
||||
|
||||
conv_dw_2 = self.conv_bn_layer(
|
||||
input=conv_pw_2,
|
||||
num_filters=oup_inc,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
padding=1,
|
||||
num_groups=oup_inc,
|
||||
if_act=False,
|
||||
use_cudnn=False,
|
||||
name='stage_' + name + '_conv2')
|
||||
|
||||
conv_linear_2 = self.conv_bn_layer(
|
||||
input=conv_dw_2,
|
||||
num_filters=oup_inc,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
num_groups=1,
|
||||
if_act=True,
|
||||
name='stage_' + name + '_conv3')
|
||||
out = fluid.layers.concat([conv_linear_1, conv_linear_2], axis=1)
|
||||
|
||||
return self.channel_shuffle(out, 2)
|
||||
def forward(self, inputs):
|
||||
y = self._conv1(inputs)
|
||||
y = self._max_pool(y)
|
||||
for inv in self._block_list:
|
||||
y = inv(y)
|
||||
y = self._last_conv(y)
|
||||
y = self._pool2d_avg(y)
|
||||
y = fluid.layers.reshape(y, shape=[-1, self._out_c])
|
||||
y = self._fc(y)
|
||||
return y
|
||||
|
||||
|
||||
def ShuffleNetV2_x0_25():
|
||||
model = ShuffleNetV2(scale=0.25)
|
||||
def ShuffleNetV2_x0_25(**args):
|
||||
model = ShuffleNetV2(scale=0.25, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ShuffleNetV2_x0_33():
|
||||
model = ShuffleNetV2(scale=0.33)
|
||||
def ShuffleNetV2_x0_33(**args):
|
||||
model = ShuffleNet(scale=0.33, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ShuffleNetV2_x0_5():
|
||||
model = ShuffleNetV2(scale=0.5)
|
||||
def ShuffleNetV2_x0_5(**args):
|
||||
model = ShuffleNet(scale=0.5, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ShuffleNetV2_x1_0():
|
||||
model = ShuffleNetV2(scale=1.0)
|
||||
def ShuffleNetV2(**args):
|
||||
model = ShuffleNet(scale=1.0, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ShuffleNetV2_x1_5():
|
||||
model = ShuffleNetV2(scale=1.5)
|
||||
def ShuffleNetV2_x1_5(**args):
|
||||
model = ShuffleNet(scale=1.5, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ShuffleNetV2_x2_0():
|
||||
model = ShuffleNetV2(scale=2.0)
|
||||
def ShuffleNetV2_x2_0(**args):
|
||||
model = ShuffleNet(scale=2.0, **args)
|
||||
return model
|
||||
|
||||
|
||||
def ShuffleNetV2_swish(**args):
|
||||
model = ShuffleNet(scale=1.0, act='swish', **args)
|
||||
return model
|
||||
|
|
|
@ -1,293 +0,0 @@
|
|||
#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 math
|
||||
|
||||
import paddle.fluid as fluid
|
||||
from paddle.fluid.initializer import MSRA
|
||||
from paddle.fluid.param_attr import ParamAttr
|
||||
|
||||
__all__ = [
|
||||
'ShuffleNetV2_x0_5_swish', 'ShuffleNetV2_x1_0_swish',
|
||||
'ShuffleNetV2_x1_5_swish', 'ShuffleNetV2_x2_0_swish', 'ShuffleNetV2_swish'
|
||||
]
|
||||
|
||||
|
||||
class ShuffleNetV2_swish():
|
||||
def __init__(self, scale=1.0):
|
||||
self.scale = scale
|
||||
|
||||
def net(self, input, class_dim=1000):
|
||||
scale = self.scale
|
||||
stage_repeats = [4, 8, 4]
|
||||
|
||||
if scale == 0.5:
|
||||
stage_out_channels = [-1, 24, 48, 96, 192, 1024]
|
||||
elif scale == 1.0:
|
||||
stage_out_channels = [-1, 24, 116, 232, 464, 1024]
|
||||
elif scale == 1.5:
|
||||
stage_out_channels = [-1, 24, 176, 352, 704, 1024]
|
||||
elif scale == 2.0:
|
||||
stage_out_channels = [-1, 24, 224, 488, 976, 2048]
|
||||
else:
|
||||
raise ValueError("""{} groups is not supported for
|
||||
1x1 Grouped Convolutions""".format(num_groups))
|
||||
|
||||
#conv1
|
||||
|
||||
input_channel = stage_out_channels[1]
|
||||
conv1 = self.conv_bn_layer(
|
||||
input=input,
|
||||
filter_size=3,
|
||||
num_filters=input_channel,
|
||||
padding=1,
|
||||
stride=2,
|
||||
name='stage1_conv')
|
||||
pool1 = fluid.layers.pool2d(
|
||||
input=conv1,
|
||||
pool_size=3,
|
||||
pool_stride=2,
|
||||
pool_padding=1,
|
||||
pool_type='max')
|
||||
conv = pool1
|
||||
# bottleneck sequences
|
||||
for idxstage in range(len(stage_repeats)):
|
||||
numrepeat = stage_repeats[idxstage]
|
||||
output_channel = stage_out_channels[idxstage + 2]
|
||||
for i in range(numrepeat):
|
||||
if i == 0:
|
||||
conv = self.inverted_residual_unit(
|
||||
input=conv,
|
||||
num_filters=output_channel,
|
||||
stride=2,
|
||||
benchmodel=2,
|
||||
name=str(idxstage + 2) + '_' + str(i + 1))
|
||||
else:
|
||||
conv = self.inverted_residual_unit(
|
||||
input=conv,
|
||||
num_filters=output_channel,
|
||||
stride=1,
|
||||
benchmodel=1,
|
||||
name=str(idxstage + 2) + '_' + str(i + 1))
|
||||
|
||||
conv_last = self.conv_bn_layer(
|
||||
input=conv,
|
||||
filter_size=1,
|
||||
num_filters=stage_out_channels[-1],
|
||||
padding=0,
|
||||
stride=1,
|
||||
name='conv5')
|
||||
pool_last = fluid.layers.pool2d(
|
||||
input=conv_last,
|
||||
pool_size=7,
|
||||
pool_stride=1,
|
||||
pool_padding=0,
|
||||
pool_type='avg')
|
||||
|
||||
output = fluid.layers.fc(input=pool_last,
|
||||
size=class_dim,
|
||||
param_attr=ParamAttr(
|
||||
initializer=MSRA(), name='fc6_weights'),
|
||||
bias_attr=ParamAttr(name='fc6_offset'))
|
||||
return output
|
||||
|
||||
def conv_bn_layer(self,
|
||||
input,
|
||||
filter_size,
|
||||
num_filters,
|
||||
stride,
|
||||
padding,
|
||||
num_groups=1,
|
||||
use_cudnn=True,
|
||||
if_act=True,
|
||||
name=None):
|
||||
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(
|
||||
initializer=MSRA(), name=name + '_weights'),
|
||||
bias_attr=False)
|
||||
out = int((input.shape[2] - 1) / float(stride) + 1)
|
||||
bn_name = name + '_bn'
|
||||
if if_act:
|
||||
return fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
act='swish',
|
||||
param_attr=ParamAttr(name=bn_name + "_scale"),
|
||||
bias_attr=ParamAttr(name=bn_name + "_offset"),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
else:
|
||||
return fluid.layers.batch_norm(
|
||||
input=conv,
|
||||
param_attr=ParamAttr(name=bn_name + "_scale"),
|
||||
bias_attr=ParamAttr(name=bn_name + "_offset"),
|
||||
moving_mean_name=bn_name + '_mean',
|
||||
moving_variance_name=bn_name + '_variance')
|
||||
|
||||
def channel_shuffle(self, x, groups):
|
||||
batchsize, num_channels, height, width = x.shape[0], x.shape[
|
||||
1], x.shape[2], x.shape[3]
|
||||
channels_per_group = num_channels // groups
|
||||
|
||||
# reshape
|
||||
x = fluid.layers.reshape(
|
||||
x=x, shape=[batchsize, groups, channels_per_group, height, width])
|
||||
|
||||
x = fluid.layers.transpose(x=x, perm=[0, 2, 1, 3, 4])
|
||||
|
||||
# flatten
|
||||
x = fluid.layers.reshape(
|
||||
x=x, shape=[batchsize, num_channels, height, width])
|
||||
|
||||
return x
|
||||
|
||||
def inverted_residual_unit(self,
|
||||
input,
|
||||
num_filters,
|
||||
stride,
|
||||
benchmodel,
|
||||
name=None):
|
||||
assert stride in [1, 2], \
|
||||
"supported stride are {} but your stride is {}".format([1,2], stride)
|
||||
|
||||
oup_inc = num_filters // 2
|
||||
inp = input.shape[1]
|
||||
|
||||
if benchmodel == 1:
|
||||
x1, x2 = fluid.layers.split(
|
||||
input,
|
||||
num_or_sections=[input.shape[1] // 2, input.shape[1] // 2],
|
||||
dim=1)
|
||||
|
||||
conv_pw = self.conv_bn_layer(
|
||||
input=x2,
|
||||
num_filters=oup_inc,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
num_groups=1,
|
||||
if_act=True,
|
||||
name='stage_' + name + '_conv1')
|
||||
|
||||
conv_dw = self.conv_bn_layer(
|
||||
input=conv_pw,
|
||||
num_filters=oup_inc,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
padding=1,
|
||||
num_groups=oup_inc,
|
||||
if_act=False,
|
||||
use_cudnn=False,
|
||||
name='stage_' + name + '_conv2')
|
||||
|
||||
conv_linear = self.conv_bn_layer(
|
||||
input=conv_dw,
|
||||
num_filters=oup_inc,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
num_groups=1,
|
||||
if_act=True,
|
||||
name='stage_' + name + '_conv3')
|
||||
|
||||
out = fluid.layers.concat([x1, conv_linear], axis=1)
|
||||
|
||||
else:
|
||||
#branch1
|
||||
conv_dw_1 = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=inp,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
padding=1,
|
||||
num_groups=inp,
|
||||
if_act=False,
|
||||
use_cudnn=False,
|
||||
name='stage_' + name + '_conv4')
|
||||
|
||||
conv_linear_1 = self.conv_bn_layer(
|
||||
input=conv_dw_1,
|
||||
num_filters=oup_inc,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
num_groups=1,
|
||||
if_act=True,
|
||||
name='stage_' + name + '_conv5')
|
||||
|
||||
#branch2
|
||||
conv_pw_2 = self.conv_bn_layer(
|
||||
input=input,
|
||||
num_filters=oup_inc,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
num_groups=1,
|
||||
if_act=True,
|
||||
name='stage_' + name + '_conv1')
|
||||
|
||||
conv_dw_2 = self.conv_bn_layer(
|
||||
input=conv_pw_2,
|
||||
num_filters=oup_inc,
|
||||
filter_size=3,
|
||||
stride=stride,
|
||||
padding=1,
|
||||
num_groups=oup_inc,
|
||||
if_act=False,
|
||||
use_cudnn=False,
|
||||
name='stage_' + name + '_conv2')
|
||||
|
||||
conv_linear_2 = self.conv_bn_layer(
|
||||
input=conv_dw_2,
|
||||
num_filters=oup_inc,
|
||||
filter_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
num_groups=1,
|
||||
if_act=True,
|
||||
name='stage_' + name + '_conv3')
|
||||
out = fluid.layers.concat([conv_linear_1, conv_linear_2], axis=1)
|
||||
|
||||
return self.channel_shuffle(out, 2)
|
||||
|
||||
|
||||
def ShuffleNetV2_x0_5_swish():
|
||||
model = ShuffleNetV2_swish(scale=0.5)
|
||||
return model
|
||||
|
||||
|
||||
def ShuffleNetV2_x1_0_swish():
|
||||
model = ShuffleNetV2_swish(scale=1.0)
|
||||
return model
|
||||
|
||||
|
||||
def ShuffleNetV2_x1_5_swish():
|
||||
model = ShuffleNetV2_swish(scale=1.5)
|
||||
return model
|
||||
|
||||
|
||||
def ShuffleNetV2_x2_0_swish():
|
||||
model = ShuffleNetV2_swish(scale=2.0)
|
||||
return model
|
Loading…
Reference in New Issue