pspnet.py 3.9 KB
Newer Older
P
pengmian 已提交
1
# coding: utf8
W
wuyefeilin 已提交
2
# Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserve.
P
pengmian 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15
#
# 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.

P
pengmian 已提交
16 17 18
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
P
pengmian 已提交
19

P
pengmian 已提交
20 21 22
import paddle.fluid as fluid
from paddle.fluid.param_attr import ParamAttr
from models.libs.model_libs import scope, name_scope
P
pengmian 已提交
23
from models.libs.model_libs import avg_pool, conv, bn
P
pengmian 已提交
24 25 26
from models.backbone.resnet import ResNet as resnet_backbone
from utils.config import cfg

W
wuyefeilin 已提交
27

P
pengmian 已提交
28
def get_logit_interp(input, num_classes, out_shape, name="logit"):
P
pengmian 已提交
29
    # 根据类别数决定最后一层卷积输出, 并插值回原始尺寸
P
pengmian 已提交
30 31 32 33 34 35 36
    param_attr = fluid.ParamAttr(
        name=name + 'weights',
        regularizer=fluid.regularizer.L2DecayRegularizer(
            regularization_coeff=0.0),
        initializer=fluid.initializer.TruncatedNormal(loc=0.0, scale=0.01))

    with scope(name):
W
wuyefeilin 已提交
37 38 39 40 41 42 43
        logit = conv(
            input,
            num_classes,
            filter_size=1,
            param_attr=param_attr,
            bias_attr=True,
            name=name + '_conv')
P
pengmian 已提交
44
        logit_interp = fluid.layers.resize_bilinear(
W
wuyefeilin 已提交
45
            logit, out_shape=out_shape, name=name + '_interp')
P
pengmian 已提交
46 47 48 49
    return logit_interp


def psp_module(input, out_features):
P
pengmian 已提交
50 51 52 53
    # Pyramid Scene Parsing 金字塔池化模块
    # 输入:backbone输出的特征
    # 输出:对输入进行不同尺度pooling, 卷积操作后插值回原始尺寸,并concat
    #       最后进行一个卷积及BN操作
W
wuyefeilin 已提交
54

P
pengmian 已提交
55
    cat_layers = []
W
wuyefeilin 已提交
56
    sizes = (1, 2, 3, 6)
P
pengmian 已提交
57
    for size in sizes:
P
pengmian 已提交
58
        psp_name = "psp" + str(size)
P
pengmian 已提交
59
        with scope(psp_name):
W
wuyefeilin 已提交
60 61 62 63 64 65 66 67 68 69 70
            pool = fluid.layers.adaptive_pool2d(
                input,
                pool_size=[size, size],
                pool_type='avg',
                name=psp_name + '_adapool')
            data = conv(
                pool,
                out_features,
                filter_size=1,
                bias_attr=True,
                name=psp_name + '_conv')
P
pengmian 已提交
71
            data_bn = bn(data, act='relu')
W
wuyefeilin 已提交
72 73
            interp = fluid.layers.resize_bilinear(
                data_bn, out_shape=input.shape[2:], name=psp_name + '_interp')
P
pengmian 已提交
74 75 76
        cat_layers.append(interp)
    cat_layers = [input] + cat_layers[::-1]
    cat = fluid.layers.concat(cat_layers, axis=1, name='psp_cat')
P
pengmian 已提交
77

P
pengmian 已提交
78
    psp_end_name = "psp_end"
P
pengmian 已提交
79
    with scope(psp_end_name):
W
wuyefeilin 已提交
80 81 82 83 84 85 86
        data = conv(
            cat,
            out_features,
            filter_size=3,
            padding=1,
            bias_attr=True,
            name=psp_end_name)
P
pengmian 已提交
87 88 89 90
        out = bn(data, act='relu')

    return out

W
wuyefeilin 已提交
91

P
pengmian 已提交
92
def resnet(input):
P
pengmian 已提交
93 94 95
    # PSPNET backbone: resnet, 默认resnet50
    # end_points: resnet终止层数
    # dilation_dict: resnet block数及对应的膨胀卷积尺度
P
pengmian 已提交
96
    scale = cfg.MODEL.PSPNET.DEPTH_MULTIPLIER
P
pengmian 已提交
97 98
    layers = cfg.MODEL.PSPNET.LAYERS
    end_points = layers - 1
W
wuyefeilin 已提交
99
    dilation_dict = {2: 2, 3: 4}
P
pengmian 已提交
100
    model = resnet_backbone(layers, scale, stem='pspnet')
W
wuyefeilin 已提交
101 102
    data, _ = model.net(
        input, end_points=end_points, dilation_dict=dilation_dict)
P
pengmian 已提交
103 104 105

    return data

W
wuyefeilin 已提交
106

P
pengmian 已提交
107
def pspnet(input, num_classes):
P
pengmian 已提交
108
    # Backbone: ResNet
P
pengmian 已提交
109
    res = resnet(input)
P
pengmian 已提交
110
    # PSP模块
P
pengmian 已提交
111
    psp = psp_module(res, 512)
P
pengmian 已提交
112 113 114
    dropout = fluid.layers.dropout(psp, dropout_prob=0.1, name="dropout")
    # 根据类别数决定最后一层卷积输出, 并插值回原始尺寸
    logit = get_logit_interp(dropout, num_classes, input.shape[2:])
P
pengmian 已提交
115
    return logit