single_level.py 4.01 KB
Newer Older
Kai Chen's avatar
Kai Chen committed
1
2
3
4
5
6
from __future__ import division

import torch
import torch.nn as nn

from mmdet import ops
7
from mmdet.core import bbox_assign, bbox_sampling
Kai Chen's avatar
Kai Chen committed
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43


class SingleLevelRoI(nn.Module):
    """Extract RoI features from a single level feature map. Each RoI is
    mapped to a level according to its scale."""

    def __init__(self,
                 roi_layer,
                 out_channels,
                 featmap_strides,
                 finest_scale=56):
        super(SingleLevelRoI, self).__init__()
        self.roi_layers = self.build_roi_layers(roi_layer, featmap_strides)
        self.out_channels = out_channels
        self.featmap_strides = featmap_strides
        self.finest_scale = finest_scale

    @property
    def num_inputs(self):
        return len(self.featmap_strides)

    def init_weights(self):
        pass

    def build_roi_layers(self, layer_cfg, featmap_strides):
        cfg = layer_cfg.copy()
        layer_type = cfg.pop('type')
        assert hasattr(ops, layer_type)
        layer_cls = getattr(ops, layer_type)
        roi_layers = nn.ModuleList(
            [layer_cls(spatial_scale=1 / s, **cfg) for s in featmap_strides])
        return roi_layers

    def map_roi_levels(self, rois, num_levels):
        """Map rois to corresponding feature levels (0-based) by scales.

Kai Chen's avatar
Kai Chen committed
44
45
46
47
        - scale < finest_scale: level 0
        - finest_scale <= scale < finest_scale * 2: level 1
        - finest_scale * 2 <= scale < finest_scale * 4: level 2
        - scale >= finest_scale * 4: level 3
Kai Chen's avatar
Kai Chen committed
48
49
50
51
52
53
54
        """
        scale = torch.sqrt(
            (rois[:, 3] - rois[:, 1] + 1) * (rois[:, 4] - rois[:, 2] + 1))
        target_lvls = torch.floor(torch.log2(scale / self.finest_scale + 1e-6))
        target_lvls = target_lvls.clamp(min=0, max=num_levels - 1).long()
        return target_lvls

Kai Chen's avatar
Kai Chen committed
55
56
    def sample_proposals(self, proposals, gt_bboxes, gt_bboxes_ignore,
                         gt_labels, cfg):
57
58
        proposals = proposals[:, :4]
        assigned_gt_inds, assigned_labels, argmax_overlaps, max_overlaps = \
Kai Chen's avatar
Kai Chen committed
59
60
61
            bbox_assign(proposals, gt_bboxes, gt_bboxes_ignore, gt_labels,
                        cfg.pos_iou_thr, cfg.neg_iou_thr, cfg.min_pos_iou,
                        cfg.crowd_thr)
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

        if cfg.add_gt_as_proposals:
            proposals = torch.cat([gt_bboxes, proposals], dim=0)
            gt_assign_self = torch.arange(
                1,
                len(gt_labels) + 1,
                dtype=torch.long,
                device=proposals.device)
            assigned_gt_inds = torch.cat([gt_assign_self, assigned_gt_inds])
            assigned_labels = torch.cat([gt_labels, assigned_labels])

        pos_inds, neg_inds = bbox_sampling(
            assigned_gt_inds, cfg.roi_batch_size, cfg.pos_fraction,
            cfg.neg_pos_ub, cfg.pos_balance_sampling, max_overlaps,
            cfg.neg_balance_thr)

        pos_proposals = proposals[pos_inds]
        neg_proposals = proposals[neg_inds]
        pos_assigned_gt_inds = assigned_gt_inds[pos_inds] - 1
        pos_gt_bboxes = gt_bboxes[pos_assigned_gt_inds, :]
        pos_gt_labels = assigned_labels[pos_inds]

Kai Chen's avatar
Kai Chen committed
84
85
        return (pos_proposals, neg_proposals, pos_assigned_gt_inds,
                pos_gt_bboxes, pos_gt_labels)
86

Kai Chen's avatar
Kai Chen committed
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
    def forward(self, feats, rois):
        """Extract roi features with the roi layer. If multiple feature levels
        are used, then rois are mapped to corresponding levels according to
        their scales.
        """
        if len(feats) == 1:
            return self.roi_layers[0](feats[0], rois)

        out_size = self.roi_layers[0].out_size
        num_levels = len(feats)
        target_lvls = self.map_roi_levels(rois, num_levels)
        roi_feats = torch.cuda.FloatTensor(rois.size()[0], self.out_channels,
                                           out_size, out_size).fill_(0)
        for i in range(num_levels):
            inds = target_lvls == i
            if inds.any():
                rois_ = rois[inds, :]
                roi_feats_t = self.roi_layers[i](feats[i], rois_)
                roi_feats[inds] += roi_feats_t
        return roi_feats