inception_v3.py 20.3 KB
Newer Older
F
Felix 已提交
1
# copyright (c) 2021 PaddlePaddle Authors. All Rights Reserve.
F
Felix 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14
#
# 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.

F
Felix 已提交
15
from __future__ import absolute_import, division, print_function
F
Felix 已提交
16 17 18 19 20 21 22 23 24 25

import paddle
from paddle import ParamAttr
import paddle.nn as nn
from paddle.nn import Conv2D, BatchNorm, Linear, Dropout
from paddle.nn import AdaptiveAvgPool2D, MaxPool2D, AvgPool2D
from paddle.nn.initializer import Uniform
import math

from ppcls.arch.backbone.base.theseus_layer import TheseusLayer
F
Felix 已提交
26
from ppcls.utils.save_load import load_dygraph_pretrain, load_dygraph_pretrain_from_url
F
Felix 已提交
27 28


F
Felix 已提交
29 30 31 32 33 34
MODEL_URLS = {
    "InceptionV3": "https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/InceptionV3_pretrained.pdparams",
}


__all__ = MODEL_URLS.keys()
F
Felix 已提交
35

F
Felix 已提交
36 37 38 39 40
'''
InceptionV3 config: dict.
    key: inception blocks of InceptionV3.
    values: conv num in different blocks.
'''
F
Felix 已提交
41
NET_CONFIG = {
F
Felix 已提交
42
    'inception_a':[[192, 256, 288], [32, 64, 64]], 
F
Felix 已提交
43 44 45 46 47 48 49 50 51 52 53 54 55 56
    'inception_b':[288],   
    'inception_c':[[768, 768, 768, 768], [128, 160, 160, 192]],
    'inception_d':[768],   
    'inception_e':[1280,2048]
}

class ConvBNLayer(TheseusLayer):
    def __init__(self,
                 num_channels,
                 num_filters,
                 filter_size,
                 stride=1,
                 padding=0,
                 groups=1,
F
Felix 已提交
57
                 act="relu"):
F
Felix 已提交
58
        super(ConvBNLayer, self).__init__()
F
Felix 已提交
59
        self.act = act
F
Felix 已提交
60 61 62 63 64 65 66 67 68
        self.conv = Conv2D(
            in_channels=num_channels,
            out_channels=num_filters,
            kernel_size=filter_size,
            stride=stride,
            padding=padding,
            groups=groups,
            bias_attr=False)
        self.batch_norm = BatchNorm(
F
Felix 已提交
69 70
            num_filters)
        self.relu = nn.ReLU()
F
Felix 已提交
71

F
Felix 已提交
72 73 74 75 76 77
    def forward(self, x):
        x = self.conv(x)
        x = self.batch_norm(x)
        if self.act:
            x = self.relu(x)
        return x
F
Felix 已提交
78 79 80 81 82 83 84 85

class InceptionStem(TheseusLayer):
    def __init__(self):
        super(InceptionStem, self).__init__()
        self.conv_1a_3x3 = ConvBNLayer(num_channels=3,
                                       num_filters=32,
                                       filter_size=3,
                                       stride=2,
F
Felix 已提交
86
                                       act="relu")
F
Felix 已提交
87 88 89 90
        self.conv_2a_3x3 = ConvBNLayer(num_channels=32,
                                       num_filters=32,
                                       filter_size=3,
                                       stride=1,
F
Felix 已提交
91
                                       act="relu")
F
Felix 已提交
92 93 94 95
        self.conv_2b_3x3 = ConvBNLayer(num_channels=32,
                                       num_filters=64,
                                       filter_size=3,
                                       padding=1,
F
Felix 已提交
96
                                       act="relu")
F
Felix 已提交
97 98 99 100 101

        self.maxpool = MaxPool2D(kernel_size=3, stride=2, padding=0)
        self.conv_3b_1x1 = ConvBNLayer(num_channels=64,
                                       num_filters=80,
                                       filter_size=1,
F
Felix 已提交
102
                                       act="relu")        
F
Felix 已提交
103 104 105
        self.conv_4a_3x3 = ConvBNLayer(num_channels=80,
                                       num_filters=192,
                                       filter_size=3,
F
Felix 已提交
106
                                       act="relu")
F
Felix 已提交
107
    def forward(self, x):
F
Felix 已提交
108 109 110 111 112 113 114 115
        x = self.conv_1a_3x3(x)
        x = self.conv_2a_3x3(x)
        x = self.conv_2b_3x3(x)
        x = self.maxpool(x)
        x = self.conv_3b_1x1(x)
        x = self.conv_4a_3x3(x)
        x = self.maxpool(x)
        return x
F
Felix 已提交
116 117 118

                         
class InceptionA(TheseusLayer):
F
Felix 已提交
119
    def __init__(self, num_channels, pool_features):
F
Felix 已提交
120 121 122 123
        super(InceptionA, self).__init__()
        self.branch1x1 = ConvBNLayer(num_channels=num_channels,
                                     num_filters=64,
                                     filter_size=1,
F
Felix 已提交
124
                                     act="relu") 
F
Felix 已提交
125 126 127
        self.branch5x5_1 = ConvBNLayer(num_channels=num_channels,
                                       num_filters=48, 
                                       filter_size=1, 
F
Felix 已提交
128
                                       act="relu")
F
Felix 已提交
129 130 131 132
        self.branch5x5_2 = ConvBNLayer(num_channels=48, 
                                       num_filters=64, 
                                       filter_size=5, 
                                       padding=2, 
F
Felix 已提交
133
                                       act="relu")
F
Felix 已提交
134 135 136 137

        self.branch3x3dbl_1 = ConvBNLayer(num_channels=num_channels,
                                       num_filters=64, 
                                       filter_size=1, 
F
Felix 已提交
138
                                       act="relu")
F
Felix 已提交
139 140 141 142
        self.branch3x3dbl_2 = ConvBNLayer(num_channels=64,
                                       num_filters=96, 
                                       filter_size=3, 
                                       padding=1,
F
Felix 已提交
143
                                       act="relu")
F
Felix 已提交
144 145 146 147
        self.branch3x3dbl_3 = ConvBNLayer(num_channels=96,
                               num_filters=96, 
                               filter_size=3, 
                               padding=1,
F
Felix 已提交
148
                               act="relu")
F
Felix 已提交
149 150 151 152
        self.branch_pool = AvgPool2D(kernel_size=3, stride=1, padding=1, exclusive=False)
        self.branch_pool_conv = ConvBNLayer(num_channels=num_channels,
                               num_filters=pool_features, 
                               filter_size=1, 
F
Felix 已提交
153
                               act="relu")
F
Felix 已提交
154 155 156 157 158 159 160 161 162 163 164 165

    def forward(self, x):
        branch1x1 = self.branch1x1(x)
        branch5x5 = self.branch5x5_1(x)
        branch5x5 = self.branch5x5_2(branch5x5)

        branch3x3dbl = self.branch3x3dbl_1(x)
        branch3x3dbl = self.branch3x3dbl_2(branch3x3dbl)
        branch3x3dbl = self.branch3x3dbl_3(branch3x3dbl)

        branch_pool = self.branch_pool(x)
        branch_pool = self.branch_pool_conv(branch_pool)
F
Felix 已提交
166 167
        x = paddle.concat([branch1x1, branch5x5, branch3x3dbl, branch_pool], axis=1)
        return x
F
Felix 已提交
168 169 170

    
class InceptionB(TheseusLayer):
F
Felix 已提交
171
    def __init__(self, num_channels):
F
Felix 已提交
172 173 174 175 176
        super(InceptionB, self).__init__()
        self.branch3x3 = ConvBNLayer(num_channels=num_channels,
                                     num_filters=384,
                                     filter_size=3,
                                     stride=2,
F
Felix 已提交
177
                                     act="relu") 
F
Felix 已提交
178 179 180
        self.branch3x3dbl_1 = ConvBNLayer(num_channels=num_channels, 
                                       num_filters=64, 
                                       filter_size=1, 
F
Felix 已提交
181
                                       act="relu")
F
Felix 已提交
182 183 184 185
        self.branch3x3dbl_2 = ConvBNLayer(num_channels=64, 
                                       num_filters=96, 
                                       filter_size=3, 
                                       padding=1,
F
Felix 已提交
186
                                       act="relu")
F
Felix 已提交
187 188 189 190
        self.branch3x3dbl_3 = ConvBNLayer(num_channels=96, 
                                       num_filters=96, 
                                       filter_size=3,
                                       stride=2,
F
Felix 已提交
191
                                       act="relu")
F
Felix 已提交
192 193 194 195 196 197 198 199 200 201 202
        self.branch_pool = MaxPool2D(kernel_size=3, stride=2)
        
    def forward(self, x):
        branch3x3 = self.branch3x3(x)

        branch3x3dbl = self.branch3x3dbl_1(x)
        branch3x3dbl = self.branch3x3dbl_2(branch3x3dbl)
        branch3x3dbl = self.branch3x3dbl_3(branch3x3dbl)

        branch_pool = self.branch_pool(x)

F
Felix 已提交
203
        x = paddle.concat([branch3x3, branch3x3dbl, branch_pool], axis=1)
F
Felix 已提交
204

F
Felix 已提交
205
        return x
F
Felix 已提交
206 207

class InceptionC(TheseusLayer):
F
Felix 已提交
208
    def __init__(self, num_channels, channels_7x7):
F
Felix 已提交
209 210 211 212
        super(InceptionC, self).__init__()
        self.branch1x1 = ConvBNLayer(num_channels=num_channels, 
                                       num_filters=192, 
                                       filter_size=1, 
F
Felix 已提交
213
                                       act="relu")
F
Felix 已提交
214 215


F
Felix 已提交
216 217 218 219
        self.branch7x7_1 = ConvBNLayer(num_channels=num_channels, 
                                       num_filters=channels_7x7, 
                                       filter_size=1, 
                                       stride=1,
F
Felix 已提交
220
                                       act="relu")
F
Felix 已提交
221 222 223 224 225
        self.branch7x7_2 = ConvBNLayer(num_channels=channels_7x7,
                                       num_filters=channels_7x7, 
                                       filter_size=(1, 7), 
                                       stride=1,
                                       padding=(0, 3),
F
Felix 已提交
226
                                       act="relu")
F
Felix 已提交
227 228 229 230 231
        self.branch7x7_3 = ConvBNLayer(num_channels=channels_7x7,
                                       num_filters=192, 
                                       filter_size=(7, 1), 
                                       stride=1,
                                       padding=(3, 0),
F
Felix 已提交
232
                                       act="relu")
F
Felix 已提交
233 234 235 236
        
        self.branch7x7dbl_1 = ConvBNLayer(num_channels=num_channels, 
                                       num_filters=channels_7x7, 
                                       filter_size=1, 
F
Felix 已提交
237
                                       act="relu")
F
Felix 已提交
238 239 240 241
        self.branch7x7dbl_2 = ConvBNLayer(num_channels=channels_7x7,  
                                       num_filters=channels_7x7, 
                                       filter_size=(7, 1), 
                                       padding = (3, 0),
F
Felix 已提交
242
                                       act="relu")
F
Felix 已提交
243 244 245 246
        self.branch7x7dbl_3 = ConvBNLayer(num_channels=channels_7x7, 
                                       num_filters=channels_7x7, 
                                       filter_size=(1, 7), 
                                       padding = (0, 3),
F
Felix 已提交
247
                                       act="relu")
F
Felix 已提交
248 249 250 251
        self.branch7x7dbl_4 = ConvBNLayer(num_channels=channels_7x7,  
                                       num_filters=channels_7x7, 
                                       filter_size=(7, 1), 
                                       padding = (3, 0),
F
Felix 已提交
252
                                       act="relu")
F
Felix 已提交
253 254 255 256
        self.branch7x7dbl_5 = ConvBNLayer(num_channels=channels_7x7, 
                                       num_filters=192, 
                                       filter_size=(1, 7), 
                                       padding = (0, 3),
F
Felix 已提交
257
                                       act="relu")
F
Felix 已提交
258 259 260 261 262
       
        self.branch_pool = AvgPool2D(kernel_size=3, stride=1, padding=1, exclusive=False)
        self.branch_pool_conv = ConvBNLayer(num_channels=num_channels,
                                       num_filters=192, 
                                       filter_size=1, 
F
Felix 已提交
263
                                       act="relu")
F
Felix 已提交
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
        
    def forward(self, x):
        branch1x1 = self.branch1x1(x)

        branch7x7 = self.branch7x7_1(x)
        branch7x7 = self.branch7x7_2(branch7x7)
        branch7x7 = self.branch7x7_3(branch7x7)

        branch7x7dbl = self.branch7x7dbl_1(x)
        branch7x7dbl = self.branch7x7dbl_2(branch7x7dbl)
        branch7x7dbl = self.branch7x7dbl_3(branch7x7dbl)
        branch7x7dbl = self.branch7x7dbl_4(branch7x7dbl)
        branch7x7dbl = self.branch7x7dbl_5(branch7x7dbl)

        branch_pool = self.branch_pool(x)
        branch_pool = self.branch_pool_conv(branch_pool)

F
Felix 已提交
281
        x = paddle.concat([branch1x1, branch7x7, branch7x7dbl, branch_pool], axis=1)
F
Felix 已提交
282
        
F
Felix 已提交
283
        return x
F
Felix 已提交
284 285
    
class InceptionD(TheseusLayer):
F
Felix 已提交
286
    def __init__(self, num_channels):
F
Felix 已提交
287 288 289 290
        super(InceptionD, self).__init__()
        self.branch3x3_1 = ConvBNLayer(num_channels=num_channels, 
                                       num_filters=192, 
                                       filter_size=1, 
F
Felix 已提交
291
                                       act="relu")
F
Felix 已提交
292 293 294 295
        self.branch3x3_2 = ConvBNLayer(num_channels=192, 
                                       num_filters=320, 
                                       filter_size=3, 
                                       stride=2,
F
Felix 已提交
296
                                       act="relu")
F
Felix 已提交
297 298 299
        self.branch7x7x3_1 = ConvBNLayer(num_channels=num_channels, 
                                       num_filters=192, 
                                       filter_size=1, 
F
Felix 已提交
300
                                       act="relu")
F
Felix 已提交
301 302 303 304
        self.branch7x7x3_2 = ConvBNLayer(num_channels=192,
                                       num_filters=192, 
                                       filter_size=(1, 7), 
                                       padding=(0, 3),
F
Felix 已提交
305
                                       act="relu")
F
Felix 已提交
306 307 308 309
        self.branch7x7x3_3 = ConvBNLayer(num_channels=192, 
                                       num_filters=192, 
                                       filter_size=(7, 1), 
                                       padding=(3, 0),
F
Felix 已提交
310
                                       act="relu")
F
Felix 已提交
311 312 313 314
        self.branch7x7x3_4 = ConvBNLayer(num_channels=192,  
                                       num_filters=192, 
                                       filter_size=3, 
                                       stride=2,
F
Felix 已提交
315
                                       act="relu")
F
Felix 已提交
316 317 318 319 320 321 322 323 324 325 326 327 328
        self.branch_pool = MaxPool2D(kernel_size=3, stride=2)

    def forward(self, x):
        branch3x3 = self.branch3x3_1(x)
        branch3x3 = self.branch3x3_2(branch3x3)

        branch7x7x3 = self.branch7x7x3_1(x)
        branch7x7x3 = self.branch7x7x3_2(branch7x7x3)
        branch7x7x3 = self.branch7x7x3_3(branch7x7x3)
        branch7x7x3 = self.branch7x7x3_4(branch7x7x3)

        branch_pool = self.branch_pool(x)
        
F
Felix 已提交
329 330
        x = paddle.concat([branch3x3, branch7x7x3, branch_pool], axis=1)
        return x
F
Felix 已提交
331 332
    
class InceptionE(TheseusLayer):
F
Felix 已提交
333
    def __init__(self, num_channels):
F
Felix 已提交
334 335 336 337
        super(InceptionE, self).__init__()
        self.branch1x1 = ConvBNLayer(num_channels=num_channels,
                                       num_filters=320, 
                                       filter_size=1, 
F
Felix 已提交
338
                                       act="relu")
F
Felix 已提交
339 340 341
        self.branch3x3_1 = ConvBNLayer(num_channels=num_channels,
                                       num_filters=384, 
                                       filter_size=1, 
F
Felix 已提交
342
                                       act="relu")
F
Felix 已提交
343 344 345 346
        self.branch3x3_2a = ConvBNLayer(num_channels=384, 
                                       num_filters=384, 
                                       filter_size=(1, 3), 
                                       padding=(0, 1),
F
Felix 已提交
347
                                       act="relu")
F
Felix 已提交
348 349 350 351
        self.branch3x3_2b = ConvBNLayer(num_channels=384, 
                                       num_filters=384, 
                                       filter_size=(3, 1), 
                                       padding=(1, 0),
F
Felix 已提交
352
                                       act="relu")
F
Felix 已提交
353 354 355 356
        
        self.branch3x3dbl_1 = ConvBNLayer(num_channels=num_channels, 
                                       num_filters=448, 
                                       filter_size=1, 
F
Felix 已提交
357
                                       act="relu")
F
Felix 已提交
358 359 360 361
        self.branch3x3dbl_2 = ConvBNLayer(num_channels=448, 
                                       num_filters=384, 
                                       filter_size=3, 
                                       padding=1,
F
Felix 已提交
362
                                       act="relu")
F
Felix 已提交
363 364 365 366
        self.branch3x3dbl_3a = ConvBNLayer(num_channels=384,
                                       num_filters=384, 
                                       filter_size=(1, 3), 
                                       padding=(0, 1),
F
Felix 已提交
367
                                       act="relu")
F
Felix 已提交
368 369 370 371
        self.branch3x3dbl_3b = ConvBNLayer(num_channels=384,
                                       num_filters=384, 
                                       filter_size=(3, 1), 
                                       padding=(1, 0),
F
Felix 已提交
372
                                       act="relu")
F
Felix 已提交
373 374 375 376
        self.branch_pool = AvgPool2D(kernel_size=3, stride=1, padding=1, exclusive=False)
        self.branch_pool_conv = ConvBNLayer(num_channels=num_channels, 
                                       num_filters=192, 
                                       filter_size=1, 
F
Felix 已提交
377
                                       act="relu")
F
Felix 已提交
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
    def forward(self, x):
        branch1x1 = self.branch1x1(x)

        branch3x3 = self.branch3x3_1(x)
        branch3x3 = [
            self.branch3x3_2a(branch3x3),
            self.branch3x3_2b(branch3x3),
        ]
        branch3x3 = paddle.concat(branch3x3, axis=1)

        branch3x3dbl = self.branch3x3dbl_1(x)
        branch3x3dbl = self.branch3x3dbl_2(branch3x3dbl)
        branch3x3dbl = [
            self.branch3x3dbl_3a(branch3x3dbl),
            self.branch3x3dbl_3b(branch3x3dbl),
        ]
        branch3x3dbl = paddle.concat(branch3x3dbl, axis=1)

        branch_pool = self.branch_pool(x)
        branch_pool = self.branch_pool_conv(branch_pool)

F
Felix 已提交
399 400
        x = paddle.concat([branch1x1, branch3x3, branch3x3dbl, branch_pool], axis=1)
        return x   
F
Felix 已提交
401 402 403


class Inception_V3(TheseusLayer):
F
Felix 已提交
404 405 406 407 408 409 410 411 412
    """
    Inception_V3
    Args:
        config: dict. config of Inception_V3.
        class_num: int=1000. The number of classes.
        pretrained: (True or False) or path of pretrained_model. Whether to load the pretrained model.
    Returns:
        model: nn.Layer. Specific Inception_V3 model depends on args.
    """
F
Felix 已提交
413 414 415 416 417
    def __init__(self, 
                 config, 
                 class_num=1000, 
                 pretrained=False,
                 **kwargs):
F
Felix 已提交
418 419 420 421 422 423 424
        super(Inception_V3, self).__init__()

        self.inception_a_list = config['inception_a']
        self.inception_c_list = config['inception_c']
        self.inception_b_list = config['inception_b']
        self.inception_d_list = config['inception_d']
        self.inception_e_list = config ['inception_e']
F
Felix 已提交
425 426
        self.pretrained = pretrained   

F
Felix 已提交
427 428
        self.inception_stem = InceptionStem()

F
Felix 已提交
429
        self.inception_block_list = nn.LayerList()
F
Felix 已提交
430 431
        for i in range(len(self.inception_a_list[0])):
            inception_a = InceptionA(self.inception_a_list[0][i], 
F
Felix 已提交
432
                                     self.inception_a_list[1][i])
F
Felix 已提交
433 434 435
            self.inception_block_list.append(inception_a)

        for i in range(len(self.inception_b_list)):
F
Felix 已提交
436
            inception_b = InceptionB(self.inception_b_list[i])
F
Felix 已提交
437 438 439 440
            self.inception_block_list.append(inception_b)

        for i in range(len(self.inception_c_list[0])):
            inception_c = InceptionC(self.inception_c_list[0][i], 
F
Felix 已提交
441
                                     self.inception_c_list[1][i])
F
Felix 已提交
442 443 444
            self.inception_block_list.append(inception_c)

        for i in range(len(self.inception_d_list)):
F
Felix 已提交
445
            inception_d = InceptionD(self.inception_d_list[i])
F
Felix 已提交
446 447 448
            self.inception_block_list.append(inception_d)

        for i in range(len(self.inception_e_list)):
F
Felix 已提交
449
            inception_e = InceptionE(self.inception_e_list[i])
F
Felix 已提交
450 451 452 453 454 455 456 457 458
            self.inception_block_list.append(inception_e)
 
        self.gap = AdaptiveAvgPool2D(1)
        self.drop = Dropout(p=0.2, mode="downscale_in_infer")
        stdv = 1.0 / math.sqrt(2048 * 1.0)
        self.out = Linear(
            2048,
            class_num,
            weight_attr=ParamAttr(
F
Felix 已提交
459 460
                initializer=Uniform(-stdv, stdv)),
            bias_attr=ParamAttr())
F
Felix 已提交
461 462

    def forward(self, x):
F
Felix 已提交
463
        x = self.inception_stem(x)
F
Felix 已提交
464
        for inception_block in self.inception_block_list:
F
Felix 已提交
465 466 467 468 469 470
           x = inception_block(x)
        x = self.gap(x)
        x = paddle.reshape(x, shape=[-1, 2048])
        x = self.drop(x)
        x = self.out(x)
        return x
F
Felix 已提交
471 472 473 474 475 476 477 478


def InceptionV3(**kwargs):
    """
    InceptionV3
    Args:
        kwargs: 
            class_num: int=1000. Output dim of last fc layer.
F
Felix 已提交
479
            pretrained: bool or str, default: bool=False. Whether to load the pretrained model.
F
Felix 已提交
480 481 482 483
    Returns:
        model: nn.Layer. Specific `InceptionV3` model 
    """
    model = Inception_V3(NET_CONFIG, **kwargs)
F
Felix 已提交
484 485 486 487 488 489 490 491 492
    
    if isinstance(model.pretrained, bool):
        if model.pretrained is True:
            load_dygraph_pretrain_from_url(model, MODEL_URLS["InceptionV3"])
    elif isinstance(model.pretrained, str):
        load_dygraph_pretrain(model, model.pretrained)
    else:
        raise RuntimeError(
            "pretrained type is not available. Please use `string` or `boolean` type")
F
Felix 已提交
493 494
    return model