bifpn问题

https://github.com/Michael-Jing/EfficientDet-pytorch/blob/master/efficientdet_pytorch/BiFPN.py

这里面的参数不可导,

训练集有map,但是测试集map全是0,

经过验证,不是bifpn的问题。

bifpn 动态参数和静态参数

改成可求导的参数后,准确率反而下降了。

后来用的就是这个:

https://github.com/toandaominh1997/EfficientDet.Pytorch/blob/cd75ddb5d7f1ade0f16914b70d564b9cf82ea917/models/efficientdet.py

import torch
from torch.nn.init import xavier_uniform

import torch.nn as nn
import torch.nn.functional as F

from conv_module import ConvModule

eps = 0.0001


class ConvBlock(nn.Module):
    def __init__(self, in_ch, out_ch, k, act=True):
        super().__init__()
        self.conv = nn.Conv2d(in_ch, out_ch, k, padding=k // 2)
        self.act = act
        if self.act:
            self.bn = nn.BatchNorm2d(out_ch)

    def forward(self, x):
        x = self.conv(x)
        if self.act:
            x = self.bn(x)
            return F.relu6(x)
        else:
            return x
class BiFPN_2(nn.Module):
    def __init__(self, n_inputs, out_channels):
        super().__init__()
        self.n_inputs = n_inputs

        self.intermediate_fusion_weights = nn.Parameter(
            torch.ones(self.n_inputs-2, 2, dtype=torch.float32))
        self.output_fusion_weights = nn.Parameter(
            torch.ones(self.n_inputs, 3, dtype=torch.float32))

        self.intermediate_convs = nn.ModuleList([])
        for _ in range(self.n_inputs-2):
            self.intermediate_convs.append(ConvBlock(
                in_ch=out_channels, out_ch=out_channels, k=3))
        self.output_convs = nn.ModuleList([])
        for _ in range(self.n_inputs):
            self.output_convs.append(ConvBlock(
                in_ch=out_channels, out_ch=out_channels, k=3))

    @staticmethod
    def fast_fuse(xs, ws):
        "Output has shape of first x"
        target_sz = xs[0].shape[-1]
        output = torch.zeros_like(xs[0])
        for i, x in enumerate(xs):
            if x.shape[-1] != target_sz:
                if x.shape[-1] == target_sz//2:
                    x = F.interpolate(x, scale_factor=2, mode='nearest')
                elif x.shape[-1] == target_sz*2:
                    x = F.avg_pool2d(x, 2)
                else:
                    assert False
            output += ws[i] * x
        output /= ws.sum() + 1e-4
        return output

    def forward(self, *xs):
        assert len(xs) == self.n_inputs
        ifws = F.relu(self.intermediate_fusion_weights)
        intermediates = []
        for i in range(self.n_inputs-2):
            small = xs[-1] if i == 0 else intermediates[-1]
            same = xs[self.n_inputs-i-2]
            fused = self.fast_fuse([same, small], ifws[i])
            intermediates.append(self.intermediate_convs[i](fused))
        ofws = F.relu(self.output_fusion_weights)
        outputs = []
        for i in range(self.n_inputs):
            if i == 0:
                fuse_inps = [xs[0], intermediates[-1]]
            elif i > 0 and i < self.n_inputs - 1:
                fuse_inps = [xs[i], intermediates[-i], outputs[-1]]
            elif i == self.n_inputs - 1:
                fuse_inps = [xs[i], outputs[-1]]
            fused = self.fast_fuse(fuse_inps, ofws[i])
            outputs.append(self.output_convs[i](fused))
        return outputs
class BIFPN(nn.Module):

    def __init__(self,
                 in_channels,
                 out_channels,
                 num_outs,
                 start_level = 0,
                 end_level = -1,
                 stack = 1,
                 add_extra_convs = False,
                 extra_convs_on_inputs = True,
                 relu_before_extra_convs = False,
                 no_norm_on_lateral = False,
                 conv_cfg = None,
                 norm_cfg = None,
                 activation = None):
        super(BIFPN, self).__init__()
        assert isinstance(in_channels, list)
        self.in_channels = in_channels
        self.out_channels = out_channels
        self.num_ins = len(in_channels)
        self.num_outs = num_outs
        self.activation = activation
        self.relu_before_extra_convs = relu_before_extra_convs
        self.no_norm_on_lateral = no_norm_on_lateral
        self.fp16_enabled = False
        self.stack = stack

        if end_level == -1:
            self.backbone_end_level = self.num_ins
            assert num_outs >= self.num_ins - start_level
        else:
            # if end_level < inputs, no extra level is allowed
            self.backbone_end_level = end_level
            assert end_level <= len(in_channels)
            assert num_outs == end_level - start_level
        self.start_level = start_level
        self.end_level = end_level
        self.add_extra_convs = add_extra_convs
        self.extra_convs_on_inputs = extra_convs_on_inputs

        self.lateral_convs = nn.ModuleList()
        self.fpn_convs = nn.ModuleList()
        self.stack_bifpn_convs = nn.ModuleList()

        for i in range(self.start_level, self.backbone_end_level):
            l_conv = ConvModule(
                in_channels[i],
                out_channels,
                1,
                conv_cfg = conv_cfg,
                norm_cfg = norm_cfg if not self.no_norm_on_lateral else None,
                activation = self.activation,
                inplace = False)
            self.lateral_convs.append(l_conv)

        for ii in range(stack):
            self.stack_bifpn_convs.append(BiFPNModule(channels = out_channels,
                                                      levels = self.backbone_end_level - self.start_level,
                                                      conv_cfg = conv_cfg,
                                                      norm_cfg = norm_cfg,
                                                      activation = activation))
        # add extra conv layers (e.g., RetinaNet)
        extra_levels = num_outs - self.backbone_end_level + self.start_level
        if add_extra_convs and extra_levels >= 1:
            for i in range(extra_levels):
                if i == 0 and self.extra_convs_on_inputs:
                    in_channels = self.in_channels[self.backbone_end_level - 1]
                else:
                    in_channels = out_channels
                extra_fpn_conv = ConvModule(
                    in_channels,
                    out_channels,
                    3,
                    stride = 2,
                    padding = 1,
                    conv_cfg = conv_cfg,
                    norm_cfg = norm_cfg,
                    activation = self.activation,
                    inplace = False)
                self.fpn_convs.append(extra_fpn_conv)

    # default init_weights for conv(msra) and norm in ConvModule
    def init_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                xavier_uniform(m)

    def forward(self, inputs):
        assert len(inputs) == len(self.in_channels)

        # build laterals
        laterals = [
            lateral_conv(inputs[i + self.start_level])
            for i, lateral_conv in enumerate(self.lateral_convs)
        ]
        # part 1: build top-down and down-top path with stack
        used_backbone_levels = len(laterals)
        for bifpn_module in self.stack_bifpn_convs:
            laterals = bifpn_module(laterals)
        outs = laterals
        # part 2: add extra levels
        if self.num_outs > len(outs):
            # use max pool to get more levels on top of outputs
            # (e.g., Faster R-CNN, Mask R-CNN)
            if not self.add_extra_convs:
                for i in range(self.num_outs - used_backbone_levels):
                    outs.append(F.max_pool2d(outs[-1], 1, stride = 2))
            # add conv layers on top of original feature maps (RetinaNet)
            else:
                if self.extra_convs_on_inputs:
                    orig = inputs[self.backbone_end_level - 1]
                    outs.append(self.fpn_convs[0](orig))
                else:
                    outs.append(self.fpn_convs[0](outs[-1]))
                for i in range(1, self.num_outs - used_backbone_levels):
                    if self.relu_before_extra_convs:
                        outs.append(self.fpn_convs[i](F.relu(outs[-1])))
                    else:
                        outs.append(self.fpn_convs[i](outs[-1]))
        return tuple(outs)

class BiFPNModule(nn.Module):

    def __init__(self,
                 channels,
                 levels,
                 init = 0.5,
                 conv_cfg = None,
                 norm_cfg = None,
                 activation = None):
        super(BiFPNModule, self).__init__()
        self.activation = activation
        self.levels = levels
        self.bifpn_convs = nn.ModuleList()
        # weighted
        self.w1 = nn.Parameter(torch.Tensor(2, levels).fill_(init))
        self.relu1 = nn.ReLU()
        self.w2 = nn.Parameter(torch.Tensor(3, levels - 2).fill_(init))
        self.relu2 = nn.ReLU()
        for jj in range(2):
            for i in range(self.levels - 1):# 1,2,3
                fpn_conv = nn.Sequential(
                    ConvModule(
                        channels,
                        channels,
                        3,
                        padding = 1,
                        groups = channels,
                        conv_cfg = conv_cfg,
                        norm_cfg = norm_cfg,
                        activation = self.activation,
                        inplace = False),
                    ConvModule(
                        channels,
                        channels,
                        1,
                        conv_cfg = conv_cfg,
                        norm_cfg = norm_cfg,
                        activation = self.activation,
                        inplace = False))
                self.bifpn_convs.append(fpn_conv)

    # default init_weights for conv(msra) and norm in ConvModule
    def init_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                xavier_uniform(m)

    def forward(self, inputs):
        # for item in inputs:print(item.shape)
        assert len(inputs) == self.levels
        # build top-down and down-top path with stack
        levels = self.levels
        # w relu
        w1 = self.relu1(self.w1)
        w1 /= torch.sum(w1, dim = 0) + eps# normalize
        w2 = self.relu2(self.w2)
        w2 /= torch.sum(w2, dim = 0) + eps
        # build top-down
        kk = 0
        pathtd = inputs
        inputs_clone = []
        for in_tensor in inputs:
            inputs_clone.append(in_tensor.clone())
        for i in range(levels - 1, 0, -1):
            pathtd[i - 1] = w1[0, kk] * pathtd[i - 1] + w1[1, kk] * F.interpolate(
                pathtd[i], scale_factor = 2, mode = 'nearest')
            pathtd[i - 1] = self.bifpn_convs[kk](pathtd[i - 1])
            kk = kk + 1
        jj = kk
        # build down-top
        for i in range(0, levels - 2, 1):
            pathtd[i + 1] = w2[0, i] * pathtd[i + 1] + w2[1, i] * F.max_pool2d(pathtd[i], kernel_size = 2) + w2[2, i] * \
                            inputs_clone[i + 1]
            pathtd[i + 1] = self.bifpn_convs[jj](pathtd[i + 1])
            jj = jj + 1

        pathtd[levels - 1] = w1[0, kk] * pathtd[levels - 1] + w1[1, kk] * F.max_pool2d(pathtd[levels - 2],
                                                                                       kernel_size = 2)
        pathtd[levels - 1] = self.bifpn_convs[jj](pathtd[levels - 1])
        return pathtd

if __name__ == '__main__':
    W_bifpn=3
    D_bifpn=88
    in_channels_stage2=24
    in_channels_list = [
        in_channels_stage2 * 2,
        in_channels_stage2 * 4,
        in_channels_stage2 * 8,
    ]

    neck = BIFPN(in_channels=in_channels_list,
                      out_channels=W_bifpn,
                      stack=D_bifpn,
                      num_outs=5)

网上又出了另一版本的:

https://blog.csdn.net/qq_43152949/article/details/103474572

发布了2608 篇原创文章 · 获赞 920 · 访问量 506万+

猜你喜欢

转载自blog.csdn.net/jacke121/article/details/103668625