resnet.py 8.0 KB
Newer Older
F
FDInSky 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
import numpy as np
import paddle.fluid as fluid
from paddle.fluid.dygraph import Layer
from paddle.fluid.dygraph import Conv2D, Pool2D, BatchNorm
from paddle.fluid.param_attr import ParamAttr
from paddle.fluid.initializer import Constant
from ppdet.core.workspace import register, serializable


class ConvBNLayer(Layer):
    def __init__(self,
                 name_scope,
                 ch_in,
                 ch_out,
                 filter_size,
                 stride,
                 padding,
                 act='relu',
19
                 lr=1.0):
F
FDInSky 已提交
20 21
        super(ConvBNLayer, self).__init__()

22
        self.conv = Conv2D(
F
FDInSky 已提交
23 24 25 26 27 28 29 30
            num_channels=ch_in,
            num_filters=ch_out,
            filter_size=filter_size,
            stride=stride,
            padding=padding,
            groups=1,
            act=act,
            param_attr=ParamAttr(
31
                name=name_scope + "_weights", learning_rate=lr),
F
FDInSky 已提交
32 33 34 35 36
            bias_attr=ParamAttr(name=name_scope + "_bias"))
        if name_scope == "conv1":
            bn_name = "bn_" + name_scope
        else:
            bn_name = "bn" + name_scope[3:]
37
        self.bn = BatchNorm(
F
FDInSky 已提交
38 39 40
            num_channels=ch_out,
            act=act,
            param_attr=ParamAttr(name=bn_name + '_scale'),
41
            bias_attr=ParamAttr(name=bn_name + '_offset'),
F
FDInSky 已提交
42
            moving_mean_name=bn_name + '_mean',
43
            moving_variance_name=bn_name + '_variance')
F
FDInSky 已提交
44 45

    def forward(self, inputs):
46 47
        out = self.conv(inputs)
        out = self.bn(out)
F
FDInSky 已提交
48 49 50 51 52 53 54 55 56 57 58
        return out


class ConvAffineLayer(Layer):
    def __init__(self,
                 name_scope,
                 ch_in,
                 ch_out,
                 filter_size,
                 stride,
                 padding,
59
                 lr=1.0,
F
FDInSky 已提交
60 61 62
                 act='relu'):
        super(ConvAffineLayer, self).__init__()

63
        self.conv = Conv2D(
F
FDInSky 已提交
64 65 66 67 68 69 70
            num_channels=ch_in,
            num_filters=ch_out,
            filter_size=filter_size,
            stride=stride,
            padding=padding,
            act=None,
            param_attr=ParamAttr(
71
                name=name_scope + "_weights", learning_rate=lr),
F
FDInSky 已提交
72 73 74 75 76
            bias_attr=False)
        if name_scope == "conv1":
            bn_name = "bn_" + name_scope
        else:
            bn_name = "bn" + name_scope[3:]
77
        self.scale = fluid.layers.create_parameter(
F
FDInSky 已提交
78 79 80 81 82
            shape=[ch_out],
            dtype='float32',
            attr=ParamAttr(
                name=bn_name + '_scale', learning_rate=0.),
            default_initializer=Constant(1.))
83 84

        self.offset = fluid.layers.create_parameter(
F
FDInSky 已提交
85 86 87
            shape=[ch_out],
            dtype='float32',
            attr=ParamAttr(
88
                name=bn_name + '_offset', learning_rate=0.),
F
FDInSky 已提交
89 90 91 92 93
            default_initializer=Constant(0.))

        self.act = act

    def forward(self, inputs):
94
        out = self.conv(inputs)
F
FDInSky 已提交
95
        out = fluid.layers.affine_channel(
96
            out, scale=self.scale, bias=self.offset)
F
FDInSky 已提交
97
        if self.act == 'relu':
98
            out = fluid.layers.relu(out)
F
FDInSky 已提交
99 100 101 102 103 104 105 106 107 108
        return out


class BottleNeck(Layer):
    def __init__(self,
                 name_scope,
                 ch_in,
                 ch_out,
                 stride,
                 shortcut=True,
109 110
                 lr=1.0,
                 norm_type='bn'):
F
FDInSky 已提交
111
        super(BottleNeck, self).__init__()
112 113 114 115 116 117 118 119
        self.name_scope = name_scope
        if norm_type == 'bn':
            atom_block = ConvBNLayer
        elif norm_type == 'affine':
            atom_block = ConvAffineLayer
        else:
            atom_block = None
        assert atom_block != None, 'NormType only support BatchNorm and Affine!'
F
FDInSky 已提交
120 121 122

        self.shortcut = shortcut
        if not shortcut:
123
            self.branch1 = atom_block(
F
FDInSky 已提交
124 125 126 127 128 129 130
                name_scope + "_branch1",
                ch_in=ch_in,
                ch_out=ch_out * 4,
                filter_size=1,
                stride=stride,
                padding=0,
                act=None,
131
                lr=lr)
F
FDInSky 已提交
132

133
        self.branch2a = atom_block(
F
FDInSky 已提交
134 135 136 137 138 139
            name_scope + "_branch2a",
            ch_in=ch_in,
            ch_out=ch_out,
            filter_size=1,
            stride=stride,
            padding=0,
140
            lr=lr)
F
FDInSky 已提交
141

142
        self.branch2b = atom_block(
F
FDInSky 已提交
143 144 145 146 147 148
            name_scope + "_branch2b",
            ch_in=ch_out,
            ch_out=ch_out,
            filter_size=3,
            stride=1,
            padding=1,
149
            lr=lr)
F
FDInSky 已提交
150

151
        self.branch2c = atom_block(
F
FDInSky 已提交
152 153 154 155 156 157
            name_scope + "_branch2c",
            ch_in=ch_out,
            ch_out=ch_out * 4,
            filter_size=1,
            stride=1,
            padding=0,
158
            lr=lr,
F
FDInSky 已提交
159 160 161 162 163 164
            act=None)

    def forward(self, inputs):
        if self.shortcut:
            short = inputs
        else:
165
            short = self.branch1(inputs)
F
FDInSky 已提交
166

167 168 169
        out = self.branch2a(inputs)
        out = self.branch2b(out)
        out = self.branch2c(out)
F
FDInSky 已提交
170 171

        out = fluid.layers.elementwise_add(
172
            x=short, y=out, act='relu', name=self.name_scope + ".add.output.5")
F
FDInSky 已提交
173 174 175 176 177 178 179 180 181 182 183

        return out


class Blocks(Layer):
    def __init__(self,
                 name_scope,
                 ch_in,
                 ch_out,
                 count,
                 stride,
184 185
                 lr=1.0,
                 norm_type='bn'):
F
FDInSky 已提交
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
        super(Blocks, self).__init__()

        self.blocks = []
        for i in range(count):
            if i == 0:
                name = name_scope + "a"
                self.stride = stride
                self.shortcut = False
            else:
                name = name_scope + chr(ord("a") + i)
                self.stride = 1
                self.shortcut = True

            block = self.add_sublayer(
                name,
                BottleNeck(
                    name,
                    ch_in=ch_in if i == 0 else ch_out * 4,
                    ch_out=ch_out,
                    stride=self.stride,
                    shortcut=self.shortcut,
207 208
                    lr=lr,
                    norm_type=norm_type))
F
FDInSky 已提交
209 210 211 212 213 214 215 216 217 218
            self.blocks.append(block)
            shortcut = True

    def forward(self, inputs):
        res_out = self.blocks[0](inputs)
        for block in self.blocks[1:]:
            res_out = block(res_out)
        return res_out


219 220 221
ResNet_cfg = {'50': [3, 4, 6, 3], '101': [3, 4, 23, 3], '152': [3, 8, 36, 3]}


F
FDInSky 已提交
222 223 224
@register
@serializable
class ResNet(Layer):
225
    def __init__(self, depth=50, norm_type='bn', freeze_at='res2'):
F
FDInSky 已提交
226
        super(ResNet, self).__init__()
227 228 229 230 231 232 233 234 235 236 237 238
        self.depth = depth
        self.norm_type = norm_type
        self.freeze_at = freeze_at

        block_nums = ResNet_cfg[str(self.depth)]
        if self.norm_type == 'bn':
            atom_block = ConvBNLayer
        elif self.norm_type == 'affine':
            atom_block = ConvAffineLayer
        else:
            atom_block = None
        assert atom_block != None, 'NormType only support BatchNorm and Affine!'
F
FDInSky 已提交
239

240 241
        self.conv1 = atom_block(
            'conv1', ch_in=3, ch_out=64, filter_size=7, stride=2, padding=3)
F
FDInSky 已提交
242

243
        self.pool = Pool2D(
F
FDInSky 已提交
244 245 246 247 248 249
            pool_type='max', pool_size=3, pool_stride=2, pool_padding=1)

        self.stage2 = Blocks(
            "res2",
            ch_in=64,
            ch_out=64,
250
            count=block_nums[0],
F
FDInSky 已提交
251
            stride=1,
252
            norm_type=norm_type)
F
FDInSky 已提交
253 254

        self.stage3 = Blocks(
255 256 257 258 259 260
            "res3",
            ch_in=256,
            ch_out=128,
            count=block_nums[1],
            stride=2,
            norm_type=norm_type)
F
FDInSky 已提交
261 262

        self.stage4 = Blocks(
263 264 265 266 267 268
            "res4",
            ch_in=512,
            ch_out=256,
            count=block_nums[2],
            stride=2,
            norm_type=norm_type)
F
FDInSky 已提交
269 270 271 272

    def forward(self, inputs):
        x = inputs['image']

273 274 275
        conv1 = self.conv1(x)

        pool1 = self.pool(conv1)
F
FDInSky 已提交
276

277
        res2 = self.stage2(pool1)
F
FDInSky 已提交
278 279 280 281 282

        res3 = self.stage3(res2)

        res4 = self.stage4(res3)

283 284 285 286 287 288 289
        outs = {
            'res2': res2,
            'res3': res3,
            'res4': res4,
            'res_norm_type': self.norm_type
        }
        outs[self.freeze_at].stop_gradient = True
F
FDInSky 已提交
290
        return outs