resnet.py 14.1 KB
Newer Older
L
LielinJiang 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
#
# 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 division
from __future__ import print_function

L
LielinJiang 已提交
18 19
import paddle
import paddle.nn as nn
L
LielinJiang 已提交
20

21
from paddle.utils.download import get_weights_path_from_url
L
LielinJiang 已提交
22

23
__all__ = []
L
LielinJiang 已提交
24 25 26

model_urls = {
    'resnet18': ('https://paddle-hapi.bj.bcebos.com/models/resnet18.pdparams',
L
LielinJiang 已提交
27
                 'cf548f46534aa3560945be4b95cd11c4'),
L
LielinJiang 已提交
28
    'resnet34': ('https://paddle-hapi.bj.bcebos.com/models/resnet34.pdparams',
L
LielinJiang 已提交
29
                 '8d2275cf8706028345f78ac0e1d31969'),
L
LielinJiang 已提交
30
    'resnet50': ('https://paddle-hapi.bj.bcebos.com/models/resnet50.pdparams',
L
LielinJiang 已提交
31
                 'ca6f485ee1ab0492d38f323885b0ad80'),
L
LielinJiang 已提交
32
    'resnet101': ('https://paddle-hapi.bj.bcebos.com/models/resnet101.pdparams',
L
LielinJiang 已提交
33
                  '02f35f034ca3858e1e54d4036443c92d'),
L
LielinJiang 已提交
34
    'resnet152': ('https://paddle-hapi.bj.bcebos.com/models/resnet152.pdparams',
L
LielinJiang 已提交
35
                  '7ad16a2f1e7333859ff986138630fd7a'),
36 37 38 39 40 41
    'wide_resnet50_2':
    ('https://paddle-hapi.bj.bcebos.com/models/wide_resnet50_2.pdparams',
     '0282f804d73debdab289bd9fea3fa6dc'),
    'wide_resnet101_2':
    ('https://paddle-hapi.bj.bcebos.com/models/wide_resnet101_2.pdparams',
     'd4360a2d23657f059216f5d5a1a9ac93'),
L
LielinJiang 已提交
42 43 44
}


L
LielinJiang 已提交
45 46 47
class BasicBlock(nn.Layer):
    expansion = 1

L
LielinJiang 已提交
48
    def __init__(self,
L
LielinJiang 已提交
49 50
                 inplanes,
                 planes,
L
LielinJiang 已提交
51
                 stride=1,
L
LielinJiang 已提交
52
                 downsample=None,
L
LielinJiang 已提交
53
                 groups=1,
L
LielinJiang 已提交
54 55 56
                 base_width=64,
                 dilation=1,
                 norm_layer=None):
L
LielinJiang 已提交
57
        super(BasicBlock, self).__init__()
L
LielinJiang 已提交
58
        if norm_layer is None:
C
cnn 已提交
59
            norm_layer = nn.BatchNorm2D
L
LielinJiang 已提交
60

L
LielinJiang 已提交
61 62 63
        if dilation > 1:
            raise NotImplementedError(
                "Dilation > 1 not supported in BasicBlock")
L
LielinJiang 已提交
64

C
cnn 已提交
65
        self.conv1 = nn.Conv2D(
L
LielinJiang 已提交
66 67 68
            inplanes, planes, 3, padding=1, stride=stride, bias_attr=False)
        self.bn1 = norm_layer(planes)
        self.relu = nn.ReLU()
C
cnn 已提交
69
        self.conv2 = nn.Conv2D(planes, planes, 3, padding=1, bias_attr=False)
L
LielinJiang 已提交
70 71 72
        self.bn2 = norm_layer(planes)
        self.downsample = downsample
        self.stride = stride
L
LielinJiang 已提交
73

L
LielinJiang 已提交
74 75
    def forward(self, x):
        identity = x
L
LielinJiang 已提交
76

L
LielinJiang 已提交
77 78 79
        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)
L
LielinJiang 已提交
80

L
LielinJiang 已提交
81 82
        out = self.conv2(out)
        out = self.bn2(out)
L
LielinJiang 已提交
83

L
LielinJiang 已提交
84 85
        if self.downsample is not None:
            identity = self.downsample(x)
L
LielinJiang 已提交
86

L
LielinJiang 已提交
87 88
        out += identity
        out = self.relu(out)
L
LielinJiang 已提交
89

L
LielinJiang 已提交
90
        return out
L
LielinJiang 已提交
91

L
LielinJiang 已提交
92 93

class BottleneckBlock(nn.Layer):
L
LielinJiang 已提交
94 95 96

    expansion = 4

L
LielinJiang 已提交
97 98 99 100 101 102 103 104 105
    def __init__(self,
                 inplanes,
                 planes,
                 stride=1,
                 downsample=None,
                 groups=1,
                 base_width=64,
                 dilation=1,
                 norm_layer=None):
L
LielinJiang 已提交
106
        super(BottleneckBlock, self).__init__()
L
LielinJiang 已提交
107
        if norm_layer is None:
C
cnn 已提交
108
            norm_layer = nn.BatchNorm2D
L
LielinJiang 已提交
109 110
        width = int(planes * (base_width / 64.)) * groups

C
cnn 已提交
111
        self.conv1 = nn.Conv2D(inplanes, width, 1, bias_attr=False)
L
LielinJiang 已提交
112 113
        self.bn1 = norm_layer(width)

C
cnn 已提交
114
        self.conv2 = nn.Conv2D(
L
LielinJiang 已提交
115 116 117 118
            width,
            width,
            3,
            padding=dilation,
L
LielinJiang 已提交
119
            stride=stride,
L
LielinJiang 已提交
120 121 122 123
            groups=groups,
            dilation=dilation,
            bias_attr=False)
        self.bn2 = norm_layer(width)
L
LielinJiang 已提交
124

C
cnn 已提交
125
        self.conv3 = nn.Conv2D(
L
LielinJiang 已提交
126 127 128 129 130
            width, planes * self.expansion, 1, bias_attr=False)
        self.bn3 = norm_layer(planes * self.expansion)
        self.relu = nn.ReLU()
        self.downsample = downsample
        self.stride = stride
L
LielinJiang 已提交
131

L
LielinJiang 已提交
132 133
    def forward(self, x):
        identity = x
L
LielinJiang 已提交
134

L
LielinJiang 已提交
135 136 137
        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)
L
LielinJiang 已提交
138

L
LielinJiang 已提交
139 140 141
        out = self.conv2(out)
        out = self.bn2(out)
        out = self.relu(out)
L
LielinJiang 已提交
142

L
LielinJiang 已提交
143 144
        out = self.conv3(out)
        out = self.bn3(out)
L
LielinJiang 已提交
145

L
LielinJiang 已提交
146 147
        if self.downsample is not None:
            identity = self.downsample(x)
L
LielinJiang 已提交
148

L
LielinJiang 已提交
149 150
        out += identity
        out = self.relu(out)
L
LielinJiang 已提交
151

L
LielinJiang 已提交
152
        return out
L
LielinJiang 已提交
153

L
LielinJiang 已提交
154 155

class ResNet(nn.Layer):
L
LielinJiang 已提交
156 157 158 159 160 161
    """ResNet model from
    `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_

    Args:
        Block (BasicBlock|BottleneckBlock): block module of model.
        depth (int): layers of resnet, default: 50.
162 163
        width (int): base width of resnet, default: 64.
        num_classes (int): output dim of last fc layer. If num_classes <=0, last fc layer
L
LielinJiang 已提交
164 165 166 167 168 169
                            will not be defined. Default: 1000.
        with_pool (bool): use pool before the last fc layer or not. Default: True.

    Examples:
        .. code-block:: python

170
            import paddle
171 172
            from paddle.vision.models import ResNet
            from paddle.vision.models.resnet import BottleneckBlock, BasicBlock
L
LielinJiang 已提交
173 174 175

            resnet50 = ResNet(BottleneckBlock, 50)

176 177
            wide_resnet50_2 = ResNet(BottleneckBlock, 50, width=64*2)

L
LielinJiang 已提交
178 179
            resnet18 = ResNet(BasicBlock, 18)

180 181 182 183 184
            x = paddle.rand([1, 3, 224, 224])
            out = resnet18(x)

            print(out.shape)

L
LielinJiang 已提交
185 186
    """

187 188 189 190 191 192
    def __init__(self,
                 block,
                 depth=50,
                 width=64,
                 num_classes=1000,
                 with_pool=True):
L
LielinJiang 已提交
193
        super(ResNet, self).__init__()
L
LielinJiang 已提交
194
        layer_cfg = {
L
LielinJiang 已提交
195 196 197 198
            18: [2, 2, 2, 2],
            34: [3, 4, 6, 3],
            50: [3, 4, 6, 3],
            101: [3, 4, 23, 3],
L
LielinJiang 已提交
199
            152: [3, 8, 36, 3]
L
LielinJiang 已提交
200
        }
L
LielinJiang 已提交
201
        layers = layer_cfg[depth]
202 203
        self.groups = 1
        self.base_width = width
L
LielinJiang 已提交
204 205
        self.num_classes = num_classes
        self.with_pool = with_pool
C
cnn 已提交
206
        self._norm_layer = nn.BatchNorm2D
L
LielinJiang 已提交
207 208 209

        self.inplanes = 64
        self.dilation = 1
L
LielinJiang 已提交
210

C
cnn 已提交
211
        self.conv1 = nn.Conv2D(
L
LielinJiang 已提交
212 213 214 215 216 217 218 219
            3,
            self.inplanes,
            kernel_size=7,
            stride=2,
            padding=3,
            bias_attr=False)
        self.bn1 = self._norm_layer(self.inplanes)
        self.relu = nn.ReLU()
C
cnn 已提交
220
        self.maxpool = nn.MaxPool2D(kernel_size=3, stride=2, padding=1)
L
LielinJiang 已提交
221 222 223 224
        self.layer1 = self._make_layer(block, 64, layers[0])
        self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
        self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
        self.layer4 = self._make_layer(block, 512, layers[3], stride=2)
L
LielinJiang 已提交
225
        if with_pool:
C
cnn 已提交
226
            self.avgpool = nn.AdaptiveAvgPool2D((1, 1))
L
LielinJiang 已提交
227 228

        if num_classes > 0:
L
LielinJiang 已提交
229 230 231 232 233 234 235 236 237 238 239
            self.fc = nn.Linear(512 * block.expansion, num_classes)

    def _make_layer(self, block, planes, blocks, stride=1, dilate=False):
        norm_layer = self._norm_layer
        downsample = None
        previous_dilation = self.dilation
        if dilate:
            self.dilation *= stride
            stride = 1
        if stride != 1 or self.inplanes != planes * block.expansion:
            downsample = nn.Sequential(
C
cnn 已提交
240
                nn.Conv2D(
L
LielinJiang 已提交
241 242 243 244 245 246 247 248 249
                    self.inplanes,
                    planes * block.expansion,
                    1,
                    stride=stride,
                    bias_attr=False),
                norm_layer(planes * block.expansion), )

        layers = []
        layers.append(
250 251
            block(self.inplanes, planes, stride, downsample, self.groups,
                  self.base_width, previous_dilation, norm_layer))
L
LielinJiang 已提交
252 253
        self.inplanes = planes * block.expansion
        for _ in range(1, blocks):
254 255 256 257 258 259 260
            layers.append(
                block(
                    self.inplanes,
                    planes,
                    groups=self.groups,
                    base_width=self.base_width,
                    norm_layer=norm_layer))
L
LielinJiang 已提交
261 262 263 264 265 266 267 268 269 270 271 272 273

        return nn.Sequential(*layers)

    def forward(self, x):
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.maxpool(x)
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)

L
LielinJiang 已提交
274
        if self.with_pool:
L
LielinJiang 已提交
275 276 277 278
            x = self.avgpool(x)

        if self.num_classes > 0:
            x = paddle.flatten(x, 1)
L
LielinJiang 已提交
279
            x = self.fc(x)
L
LielinJiang 已提交
280

L
LielinJiang 已提交
281 282 283 284 285 286 287 288 289 290
        return x


def _resnet(arch, Block, depth, pretrained, **kwargs):
    model = ResNet(Block, depth, **kwargs)
    if pretrained:
        assert arch in model_urls, "{} model do not have a pretrained model now, you should set pretrained=False".format(
            arch)
        weight_path = get_weights_path_from_url(model_urls[arch][0],
                                                model_urls[arch][1])
291 292

        param = paddle.load(weight_path)
293 294
        model.set_dict(param)

L
LielinJiang 已提交
295 296 297 298
    return model


def resnet18(pretrained=False, **kwargs):
299 300 301
    """ResNet 18-layer model from
    `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_

L
LielinJiang 已提交
302 303 304 305 306 307
    Args:
        pretrained (bool): If True, returns a model pre-trained on ImageNet

    Examples:
        .. code-block:: python

308
            import paddle
309
            from paddle.vision.models import resnet18
L
LielinJiang 已提交
310 311 312 313 314 315

            # build model
            model = resnet18()

            # build model and load imagenet pretrained weight
            # model = resnet18(pretrained=True)
316 317 318 319 320

            x = paddle.rand([1, 3, 224, 224])
            out = model(x)

            print(out.shape)
L
LielinJiang 已提交
321 322 323 324 325
    """
    return _resnet('resnet18', BasicBlock, 18, pretrained, **kwargs)


def resnet34(pretrained=False, **kwargs):
326 327 328
    """ResNet 34-layer model from
    `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_

L
LielinJiang 已提交
329 330
    Args:
        pretrained (bool): If True, returns a model pre-trained on ImageNet
331

L
LielinJiang 已提交
332 333 334
    Examples:
        .. code-block:: python

335
            import paddle
336
            from paddle.vision.models import resnet34
L
LielinJiang 已提交
337 338 339 340 341 342

            # build model
            model = resnet34()

            # build model and load imagenet pretrained weight
            # model = resnet34(pretrained=True)
343 344 345 346 347

            x = paddle.rand([1, 3, 224, 224])
            out = model(x)

            print(out.shape)
L
LielinJiang 已提交
348 349 350 351 352
    """
    return _resnet('resnet34', BasicBlock, 34, pretrained, **kwargs)


def resnet50(pretrained=False, **kwargs):
353 354 355
    """ResNet 50-layer model from
    `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_

L
LielinJiang 已提交
356 357 358 359 360 361
    Args:
        pretrained (bool): If True, returns a model pre-trained on ImageNet

    Examples:
        .. code-block:: python

362
            import paddle
363
            from paddle.vision.models import resnet50
L
LielinJiang 已提交
364 365 366 367 368 369

            # build model
            model = resnet50()

            # build model and load imagenet pretrained weight
            # model = resnet50(pretrained=True)
370 371 372 373 374

            x = paddle.rand([1, 3, 224, 224])
            out = model(x)

            print(out.shape)
L
LielinJiang 已提交
375 376 377 378 379
    """
    return _resnet('resnet50', BottleneckBlock, 50, pretrained, **kwargs)


def resnet101(pretrained=False, **kwargs):
380 381 382
    """ResNet 101-layer model from
    `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_

L
LielinJiang 已提交
383 384 385 386 387 388
    Args:
        pretrained (bool): If True, returns a model pre-trained on ImageNet

    Examples:
        .. code-block:: python

389
            import paddle
390
            from paddle.vision.models import resnet101
L
LielinJiang 已提交
391 392 393 394 395 396

            # build model
            model = resnet101()

            # build model and load imagenet pretrained weight
            # model = resnet101(pretrained=True)
397 398 399 400 401

            x = paddle.rand([1, 3, 224, 224])
            out = model(x)

            print(out.shape)
L
LielinJiang 已提交
402 403 404 405 406
    """
    return _resnet('resnet101', BottleneckBlock, 101, pretrained, **kwargs)


def resnet152(pretrained=False, **kwargs):
407 408 409
    """ResNet 152-layer model from
    `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_

L
LielinJiang 已提交
410 411 412 413 414 415
    Args:
        pretrained (bool): If True, returns a model pre-trained on ImageNet

    Examples:
        .. code-block:: python

416
            import paddle
417
            from paddle.vision.models import resnet152
L
LielinJiang 已提交
418 419 420 421 422 423

            # build model
            model = resnet152()

            # build model and load imagenet pretrained weight
            # model = resnet152(pretrained=True)
424 425 426 427 428

            x = paddle.rand([1, 3, 224, 224])
            out = model(x)

            print(out.shape)
L
LielinJiang 已提交
429 430
    """
    return _resnet('resnet152', BottleneckBlock, 152, pretrained, **kwargs)
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487


def wide_resnet50_2(pretrained=False, **kwargs):
    """Wide ResNet-50-2 model from
    `"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_.

    Args:
        pretrained (bool): If True, returns a model pre-trained on ImageNet

    Examples:
        .. code-block:: python

            import paddle
            from paddle.vision.models import wide_resnet50_2

            # build model
            model = wide_resnet50_2()

            # build model and load imagenet pretrained weight
            # model = wide_resnet50_2(pretrained=True)

            x = paddle.rand([1, 3, 224, 224])
            out = model(x)

            print(out.shape)
    """
    kwargs['width'] = 64 * 2
    return _resnet('wide_resnet50_2', BottleneckBlock, 50, pretrained, **kwargs)


def wide_resnet101_2(pretrained=False, **kwargs):
    """Wide ResNet-101-2 model from
    `"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_.

    Args:
        pretrained (bool): If True, returns a model pre-trained on ImageNet

    Examples:
        .. code-block:: python

            import paddle
            from paddle.vision.models import wide_resnet101_2

            # build model
            model = wide_resnet101_2()

            # build model and load imagenet pretrained weight
            # model = wide_resnet101_2(pretrained=True)

            x = paddle.rand([1, 3, 224, 224])
            out = model(x)

            print(out.shape)
    """
    kwargs['width'] = 64 * 2
    return _resnet('wide_resnet101_2', BottleneckBlock, 101, pretrained,
                   **kwargs)