import paddle import paddle.fluid as fluid from paddle.fluid.param_attr import ParamAttr from paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, Linear __all__ = ["ResNeXt101_32x8d_wsl", "ResNeXt101_wsl_32x16d_wsl", "ResNeXt101_wsl_32x32d_wsl", "ResNeXt101_wsl_32x48d_wsl"] class ConvBNLayer(fluid.dygraph.Layer): def __init__(self, input_channels, output_channels, filter_size, stride=1, groups=1, act=None, name=None): super(ConvBNLayer, self).__init__() if "downsample" in name: conv_name = name + ".0" else: conv_name = name self._conv = Conv2D(num_channels=input_channels, num_filters=output_channels, filter_size=filter_size, stride=stride, padding=(filter_size-1)//2, groups=groups, act=None, param_attr=ParamAttr(name=conv_name + ".weight"), bias_attr=False) if "downsample" in name: bn_name = name[:9] + "downsample.1" else: if "conv1" == name: bn_name = "bn" + name[-1] else: bn_name = (name[:10] if name[7:9].isdigit() else name[:9]) + "bn" + name[-1] self._bn = BatchNorm(num_channels=output_channels, act=act, param_attr=ParamAttr(name=bn_name + ".weight"), bias_attr=ParamAttr(name=bn_name + ".bias"), moving_mean_name=bn_name + ".running_mean", moving_variance_name=bn_name + ".running_var") def forward(self, inputs): x = self._conv(inputs) x = self._bn(x) return x class ShortCut(fluid.dygraph.Layer): def __init__(self, input_channels, output_channels, stride, name=None): super(ShortCut, self).__init__() self.input_channels = input_channels self.output_channels = output_channels self.stride = stride if input_channels!=output_channels or stride!=1: self._conv = ConvBNLayer( input_channels, output_channels, filter_size=1, stride=stride, name=name) def forward(self, inputs): if self.input_channels!= self.output_channels or self.stride!=1: return self._conv(inputs) return inputs class BottleneckBlock(fluid.dygraph.Layer): def __init__(self, input_channels, output_channels, stride, cardinality, width, name): super(BottleneckBlock, self).__init__() self._conv0 = ConvBNLayer( input_channels, output_channels, filter_size=1, act="relu", name=name + ".conv1") self._conv1 = ConvBNLayer( output_channels, output_channels, filter_size=3, act="relu", stride=stride, groups=cardinality, name=name + ".conv2") self._conv2 = ConvBNLayer( output_channels, output_channels//(width//8), filter_size=1, act=None, name=name + ".conv3") self._short = ShortCut( input_channels, output_channels//(width//8), stride=stride, name=name + ".downsample") def forward(self, inputs): x = self._conv0(inputs) x = self._conv1(x) x = self._conv2(x) y = self._short(inputs) return fluid.layers.elementwise_add(x, y, act="relu") class ResNeXt101WSL(fluid.dygraph.Layer): def __init__(self, layers=101, cardinality=32, width=48, class_dim=1000): super(ResNeXt101WSL, self).__init__() self.class_dim = class_dim self.layers = layers self.cardinality = cardinality self.width = width self.scale = width//8 self.depth = [3, 4, 23, 3] self.base_width = cardinality * width num_filters = [self.base_width*i for i in [1,2,4,8]] #[256, 512, 1024, 2048] self._conv_stem = ConvBNLayer( 3, 64, 7, stride=2, act="relu", name="conv1") self._pool = Pool2D(pool_size=3, pool_stride=2, pool_padding=1, pool_type="max") self._conv1_0 = BottleneckBlock( 64, num_filters[0], stride=1, cardinality=self.cardinality, width=self.width, name="layer1.0") self._conv1_1 = BottleneckBlock( num_filters[0]//(width//8), num_filters[0], stride=1, cardinality=self.cardinality, width=self.width, name="layer1.1") self._conv1_2 = BottleneckBlock( num_filters[0]//(width//8), num_filters[0], stride=1, cardinality=self.cardinality, width=self.width, name="layer1.2") self._conv2_0 = BottleneckBlock( num_filters[0]//(width//8), num_filters[1], stride=2, cardinality=self.cardinality, width=self.width, name="layer2.0") self._conv2_1 = BottleneckBlock( num_filters[1]//(width//8), num_filters[1], stride=1, cardinality=self.cardinality, width=self.width, name="layer2.1") self._conv2_2 = BottleneckBlock( num_filters[1]//(width//8), num_filters[1], stride=1, cardinality=self.cardinality, width=self.width, name="layer2.2") self._conv2_3 = BottleneckBlock( num_filters[1]//(width//8), num_filters[1], stride=1, cardinality=self.cardinality, width=self.width, name="layer2.3") self._conv3_0 = BottleneckBlock( num_filters[1]//(width//8), num_filters[2], stride=2, cardinality=self.cardinality, width=self.width, name="layer3.0") self._conv3_1 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.1") self._conv3_2 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.2") self._conv3_3 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.3") self._conv3_4 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.4") self._conv3_5 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.5") self._conv3_6 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.6") self._conv3_7 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.7") self._conv3_8 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.8") self._conv3_9 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.9") self._conv3_10 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.10") self._conv3_11 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.11") self._conv3_12 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.12") self._conv3_13 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.13") self._conv3_14 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.14") self._conv3_15 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.15") self._conv3_16 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.16") self._conv3_17 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.17") self._conv3_18 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.18") self._conv3_19 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.19") self._conv3_20 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.20") self._conv3_21 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.21") self._conv3_22 = BottleneckBlock( num_filters[2]//(width//8), num_filters[2], stride=1, cardinality=self.cardinality, width=self.width, name="layer3.22") self._conv4_0 = BottleneckBlock( num_filters[2]//(width//8), num_filters[3], stride=2, cardinality=self.cardinality, width=self.width, name="layer4.0") self._conv4_1 = BottleneckBlock( num_filters[3]//(width//8), num_filters[3], stride=1, cardinality=self.cardinality, width=self.width, name="layer4.1") self._conv4_2 = BottleneckBlock( num_filters[3]//(width//8), num_filters[3], stride=1, cardinality=self.cardinality, width=self.width, name="layer4.2") self._avg_pool = Pool2D(pool_type="avg", global_pooling=True) self._out = Linear(input_dim=num_filters[3]//(width//8), output_dim=class_dim, param_attr=ParamAttr(name="fc.weight"), bias_attr=ParamAttr(name="fc.bias")) def forward(self, inputs): x = self._conv_stem(inputs) x = self._pool(x) x = self._conv1_0(x) x = self._conv1_1(x) x = self._conv1_2(x) x = self._conv2_0(x) x = self._conv2_1(x) x = self._conv2_2(x) x = self._conv2_3(x) x = self._conv3_0(x) x = self._conv3_1(x) x = self._conv3_2(x) x = self._conv3_3(x) x = self._conv3_4(x) x = self._conv3_5(x) x = self._conv3_6(x) x = self._conv3_7(x) x = self._conv3_8(x) x = self._conv3_9(x) x = self._conv3_10(x) x = self._conv3_11(x) x = self._conv3_12(x) x = self._conv3_13(x) x = self._conv3_14(x) x = self._conv3_15(x) x = self._conv3_16(x) x = self._conv3_17(x) x = self._conv3_18(x) x = self._conv3_19(x) x = self._conv3_20(x) x = self._conv3_21(x) x = self._conv3_22(x) x = self._conv4_0(x) x = self._conv4_1(x) x = self._conv4_2(x) x = self._avg_pool(x) x = fluid.layers.squeeze(x, axes=[2, 3]) x = self._out(x) return x def ResNeXt101_32x8d_wsl(**args): model = ResNeXt101WSL(cardinality=32, width=8, **args) return model def ResNeXt101_32x16d_wsl(**args): model = ResNeXt101WSL(cardinality=32, width=16, **args) return model def ResNeXt101_32x32d_wsl(**args): model = ResNeXt101WSL(cardinality=32, width=32, **args) return model def ResNeXt101_32x48d_wsl(**args): model = ResNeXt101WSL(cardinality=32, width=48, **args) return model