PaddleClas/ppcls/modeling/architectures/resnet.py

197 lines
5.6 KiB
Python
Raw Normal View History

2020-06-09 08:24:03 +08:00
# copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
2020-04-09 02:16:30 +08:00
#
2020-06-09 08:24:03 +08:00
# 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
2020-04-09 02:16:30 +08:00
#
# http://www.apache.org/licenses/LICENSE-2.0
#
2020-06-09 08:24:03 +08:00
# 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.
2020-04-09 02:16:30 +08:00
2020-06-09 08:24:03 +08:00
import paddle.fluid as fluid
from paddle.fluid.layer_helper import LayerHelper
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, Linear
2020-04-09 02:16:30 +08:00
import math
__all__ = [
2020-06-09 08:24:03 +08:00
"ResNet18",
"ResNet34",
"ResNet50",
"ResNet101",
"ResNet152",
2020-04-09 02:16:30 +08:00
]
2020-06-09 08:24:03 +08:00
class ConvBNLayer(fluid.dygraph.Layer):
def __init__(self,
num_channels,
num_filters,
filter_size,
stride=1,
groups=1,
act=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,
bias_attr=False)
self._batch_norm = BatchNorm(num_filters, act=act)
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):
super(BottleneckBlock, self).__init__()
self.conv0 = ConvBNLayer(
num_channels=num_channels,
num_filters=num_filters,
filter_size=1,
act='relu')
self.conv1 = ConvBNLayer(
num_channels=num_filters,
num_filters=num_filters,
filter_size=3,
stride=stride,
act='relu')
self.conv2 = ConvBNLayer(
num_channels=num_filters,
num_filters=num_filters * 4,
filter_size=1,
act=None)
if not shortcut:
self.short = ConvBNLayer(
num_channels=num_channels,
num_filters=num_filters * 4,
filter_size=1,
stride=stride)
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)
2020-04-09 02:16:30 +08:00
2020-06-09 08:24:03 +08:00
class ResNet(fluid.dygraph.Layer):
def __init__(self, layers=50, class_dim=1000):
super(ResNet, self).__init__()
self.layers = layers
supported_layers = [50, 101, 152]
2020-04-09 02:16:30 +08:00
assert layers in supported_layers, \
2020-06-09 08:24:03 +08:00
"supported layers are {} but input layer is {}".format(
supported_layers, layers)
2020-04-09 02:16:30 +08:00
2020-06-09 08:24:03 +08:00
if layers == 50:
2020-04-09 02:16:30 +08:00
depth = [3, 4, 6, 3]
elif layers == 101:
depth = [3, 4, 23, 3]
elif layers == 152:
depth = [3, 8, 36, 3]
2020-06-09 08:24:03 +08:00
num_channels = [64, 256, 512, 1024]
2020-04-09 02:16:30 +08:00
num_filters = [64, 128, 256, 512]
2020-06-09 08:24:03 +08:00
self.conv = ConvBNLayer(
num_channels=3,
2020-04-09 02:16:30 +08:00
num_filters=64,
filter_size=7,
stride=2,
2020-06-09 08:24:03 +08:00
act='relu')
self.pool2d_max = Pool2D(
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,
2020-04-09 02:16:30 +08:00
num_filters=num_filters[block],
stride=2 if i == 0 and block != 0 else 1,
2020-06-09 08:24:03 +08:00
shortcut=shortcut))
self.bottleneck_block_list.append(bottleneck_block)
shortcut = True
2020-04-09 02:16:30 +08:00
2020-06-09 08:24:03 +08:00
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
stdv = 1.0 / math.sqrt(2048 * 1.0)
self.out = Linear(
self.pool2d_avg_output,
class_dim,
2020-04-09 02:16:30 +08:00
param_attr=fluid.param_attr.ParamAttr(
2020-06-09 08:24:03 +08:00
initializer=fluid.initializer.Uniform(-stdv, stdv)))
2020-04-09 02:16:30 +08:00
2020-06-09 08:24:03 +08:00
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)
y = self.pool2d_avg(y)
y = fluid.layers.reshape(y, shape=[-1, self.pool2d_avg_output])
y = self.out(y)
return y
2020-04-09 02:16:30 +08:00
2020-06-09 08:24:03 +08:00
def ResNet18(**kwargs):
model = ResNet(layers=18, **kwargs)
2020-04-09 02:16:30 +08:00
return model
2020-06-09 08:24:03 +08:00
def ResNet34(**kwargs):
model = ResNet(layers=34, **kwargs)
2020-04-09 02:16:30 +08:00
return model
2020-06-09 08:24:03 +08:00
def ResNet50(**kwargs):
model = ResNet(layers=50, **kwargs)
2020-04-09 02:16:30 +08:00
return model
2020-06-09 08:24:03 +08:00
def ResNet101(**kwargs):
model = ResNet(layers=101, **kwargs)
2020-04-09 02:16:30 +08:00
return model
2020-06-09 08:24:03 +08:00
def ResNet152(class_dim=1000):
model = ResNet(layers=152, class_dim=class_dim)
2020-04-09 02:16:30 +08:00
return model