darknet.py 5.3 KB
Newer Older
W
wangxinxin08 已提交
1 2 3 4
import paddle
import paddle.nn as nn
import paddle.nn.functional as F
from paddle import ParamAttr
5 6 7 8 9 10
from paddle.fluid.regularizer import L2Decay
from ppdet.core.workspace import register, serializable

__all__ = ['DarkNet', 'ConvBNLayer']


W
wangxinxin08 已提交
11
class ConvBNLayer(nn.Layer):
12 13 14 15 16 17 18
    def __init__(self,
                 ch_in,
                 ch_out,
                 filter_size=3,
                 stride=1,
                 groups=1,
                 padding=0,
W
wangguanzhong 已提交
19 20
                 act="leaky",
                 name=None):
21 22
        super(ConvBNLayer, self).__init__()

W
wangguanzhong 已提交
23
        self.conv = nn.Conv2D(
W
wangxinxin08 已提交
24 25 26
            in_channels=ch_in,
            out_channels=ch_out,
            kernel_size=filter_size,
27 28 29
            stride=stride,
            padding=padding,
            groups=groups,
W
wangxinxin08 已提交
30 31
            weight_attr=ParamAttr(name=name + '.conv.weights'),
            bias_attr=False)
W
wangguanzhong 已提交
32
        bn_name = name + '.bn'
W
wangxinxin08 已提交
33 34 35
        self.batch_norm = nn.BatchNorm2d(
            ch_out,
            weight_attr=ParamAttr(
W
wangguanzhong 已提交
36
                name=bn_name + '.scale', regularizer=L2Decay(0.)),
37
            bias_attr=ParamAttr(
W
wangxinxin08 已提交
38
                name=bn_name + '.offset', regularizer=L2Decay(0.)))
39 40 41 42 43 44 45

        self.act = act

    def forward(self, inputs):
        out = self.conv(inputs)
        out = self.batch_norm(out)
        if self.act == 'leaky':
W
wangxinxin08 已提交
46
            out = F.leaky_relu(out, 0.1)
47 48 49
        return out


W
wangxinxin08 已提交
50
class DownSample(nn.Layer):
W
wangguanzhong 已提交
51 52 53 54 55 56 57
    def __init__(self,
                 ch_in,
                 ch_out,
                 filter_size=3,
                 stride=2,
                 padding=1,
                 name=None):
58 59 60 61 62 63 64 65

        super(DownSample, self).__init__()

        self.conv_bn_layer = ConvBNLayer(
            ch_in=ch_in,
            ch_out=ch_out,
            filter_size=filter_size,
            stride=stride,
W
wangguanzhong 已提交
66 67
            padding=padding,
            name=name)
68 69 70 71 72 73 74
        self.ch_out = ch_out

    def forward(self, inputs):
        out = self.conv_bn_layer(inputs)
        return out


W
wangxinxin08 已提交
75
class BasicBlock(nn.Layer):
W
wangguanzhong 已提交
76
    def __init__(self, ch_in, ch_out, name=None):
77 78 79
        super(BasicBlock, self).__init__()

        self.conv1 = ConvBNLayer(
W
wangguanzhong 已提交
80 81 82 83 84 85
            ch_in=ch_in,
            ch_out=ch_out,
            filter_size=1,
            stride=1,
            padding=0,
            name=name + '.0')
86
        self.conv2 = ConvBNLayer(
W
wangguanzhong 已提交
87 88 89 90 91 92
            ch_in=ch_out,
            ch_out=ch_out * 2,
            filter_size=3,
            stride=1,
            padding=1,
            name=name + '.1')
93 94 95 96

    def forward(self, inputs):
        conv1 = self.conv1(inputs)
        conv2 = self.conv2(conv1)
W
wangxinxin08 已提交
97
        out = paddle.add(x=inputs, y=conv2)
98 99 100
        return out


W
wangxinxin08 已提交
101
class Blocks(nn.Layer):
W
wangguanzhong 已提交
102
    def __init__(self, ch_in, ch_out, count, name=None):
103 104
        super(Blocks, self).__init__()

W
wangguanzhong 已提交
105
        self.basicblock0 = BasicBlock(ch_in, ch_out, name=name + '.0')
106 107
        self.res_out_list = []
        for i in range(1, count):
W
wangguanzhong 已提交
108 109 110 111
            block_name = '{}.{}'.format(name, i)
            res_out = self.add_sublayer(
                block_name, BasicBlock(
                    ch_out * 2, ch_out, name=block_name))
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
            self.res_out_list.append(res_out)
        self.ch_out = ch_out

    def forward(self, inputs):
        y = self.basicblock0(inputs)
        for basic_block_i in self.res_out_list:
            y = basic_block_i(y)
        return y


DarkNet_cfg = {53: ([1, 2, 8, 8, 4])}


@register
@serializable
W
wangxinxin08 已提交
127
class DarkNet(nn.Layer):
W
wangguanzhong 已提交
128 129 130 131 132
    def __init__(self,
                 depth=53,
                 freeze_at=-1,
                 return_idx=[2, 3, 4],
                 num_stages=5):
133 134
        super(DarkNet, self).__init__()
        self.depth = depth
W
wangguanzhong 已提交
135 136 137 138
        self.freeze_at = freeze_at
        self.return_idx = return_idx
        self.num_stages = num_stages
        self.stages = DarkNet_cfg[self.depth][0:num_stages]
139 140

        self.conv0 = ConvBNLayer(
W
wangguanzhong 已提交
141 142 143 144 145 146
            ch_in=3,
            ch_out=32,
            filter_size=3,
            stride=1,
            padding=1,
            name='yolo_input')
147

W
wangguanzhong 已提交
148 149
        self.downsample0 = DownSample(
            ch_in=32, ch_out=32 * 2, name='yolo_input.downsample')
150

W
wangguanzhong 已提交
151
        self.darknet_conv_block_list = []
152 153 154
        self.downsample_list = []
        ch_in = [64, 128, 256, 512, 1024]
        for i, stage in enumerate(self.stages):
W
wangguanzhong 已提交
155 156 157 158 159 160 161
            name = 'stage.{}'.format(i)
            conv_block = self.add_sublayer(
                name, Blocks(
                    int(ch_in[i]), 32 * (2**i), stage, name=name))
            self.darknet_conv_block_list.append(conv_block)
        for i in range(num_stages - 1):
            down_name = 'stage.{}.downsample'.format(i)
162
            downsample = self.add_sublayer(
W
wangguanzhong 已提交
163
                down_name,
164
                DownSample(
W
wangguanzhong 已提交
165 166 167
                    ch_in=32 * (2**(i + 1)),
                    ch_out=32 * (2**(i + 2)),
                    name=down_name))
168 169 170 171 172 173 174 175
            self.downsample_list.append(downsample)

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

        out = self.conv0(x)
        out = self.downsample0(out)
        blocks = []
W
wangguanzhong 已提交
176
        for i, conv_block_i in enumerate(self.darknet_conv_block_list):
177
            out = conv_block_i(out)
W
wangguanzhong 已提交
178 179 180 181 182
            if i == self.freeze_at:
                out.stop_gradient = True
            if i in self.return_idx:
                blocks.append(out)
            if i < self.num_stages - 1:
183
                out = self.downsample_list[i](out)
W
wangguanzhong 已提交
184
        return blocks