# -*- coding:utf-8 -*- # @author :adolf import torch.nn.functional as F from torch import nn, Tensor """ out_channels=96时,和现有的fpn相比,这个fpn精度差不多,但是模型尺寸会大500k """ class FeaturePyramidNetwork(nn.Module): def __init__(self, in_channels, out_channels=256): super(FeaturePyramidNetwork, self).__init__() self.inner_blocks = nn.ModuleList() self.layer_blocks = nn.ModuleList() self.out_channels = out_channels for in_channels in in_channels: if in_channels == 0: raise ValueError("in_channels=0 is currently not supported") inner_block_module = nn.Conv2d(in_channels, out_channels, 1) layer_block_module = nn.Conv2d(out_channels, out_channels, 3, padding=1) self.inner_blocks.append(inner_block_module) self.layer_blocks.append(layer_block_module) # initialize parameters now to avoid modifying the initialization of top_blocks for m in self.children(): if isinstance(m, nn.Conv2d): nn.init.kaiming_uniform_(m.weight, a=1) nn.init.constant_(m.bias, 0) def get_result_from_inner_blocks(self, x, idx): num_blocks = 0 for m in self.inner_blocks: num_blocks += 1 if idx < 0: idx += num_blocks i = 0 out = x for module in self.inner_blocks: if i == idx: out = module(x) i += 1 return out def get_result_from_layer_blocks(self, x, idx): num_blocks = 0 for m in self.layer_blocks: num_blocks += 1 if idx < 0: idx += num_blocks i = 0 out = x for module in self.layer_blocks: if i == idx: out = module(x) i += 1 return out def forward(self, x): # unpack OrderedDict into two lists for easier handling # names = list(x.keys()) # x = list(x.values()) last_inner = self.get_result_from_inner_blocks(x[-1], -1) results = [] results.append(self.get_result_from_layer_blocks(last_inner, -1)) for idx in range(len(x) - 2, -1, -1): inner_lateral = self.get_result_from_inner_blocks(x[idx], idx) feat_shape = inner_lateral.shape[-2:] inner_top_down = F.interpolate(last_inner, size=feat_shape, mode="nearest") last_inner = inner_lateral + inner_top_down results.insert(0, self.get_result_from_layer_blocks(last_inner, idx)) # make it back an OrderedDict # out = OrderedDict([(k, v) for k, v in zip(names, results)]) out = results[0] return out class ExtraFPNBlock(nn.Module): def forward(self, results, x, names): pass class LastLevelMaxPool(ExtraFPNBlock): def forward(self, x, y, names): names.append("pool") x.append(F.max_pool2d(x[-1], 1, 2, 0)) return x, names class LastLevelP6P7(ExtraFPNBlock): def __init__(self, in_channels, out_channels): super(LastLevelP6P7, self).__init__() self.p6 = nn.Conv2d(in_channels, out_channels, 3, 2, 1) self.p7 = nn.Conv2d(out_channels, out_channels, 3, 2, 1) for module in [self.p6, self.p7]: nn.init.kaiming_uniform_(module.weight, a=1) nn.init.constant_(module.bias, 0) self.use_P5 = in_channels == out_channels def forward(self, p, c, names): p5, c5 = p[-1], c[-1] x = p5 if self.use_P5 else c5 p6 = self.p6(x) p7 = self.p7(F.relu(p6)) p.extend([p6, p7]) names.extend(["p6", "p7"]) return p, names