# Copyright (c) OpenMMLab. All rights reserved. from typing import List, Tuple, Union import torch import torch.nn as nn import torch.nn.functional as F from mmcv.cnn import Conv2d, ConvModule from .multi_scale_deform_attn import MultiScaleDeformableAttention from mmengine.model import (BaseModule, ModuleList, caffe2_xavier_init, normal_init, xavier_init) from torch import Tensor from mmdet.models.layers.transformer.detr_layers import (DetrTransformerEncoder, DetrTransformerEncoderLayer) from mmdet.utils import ConfigType, OptMultiConfig from mmdet.models.task_modules.prior_generators import MlvlPointGenerator from mmdet.models.layers.positional_encoding import SinePositionalEncoding from mmcv.cnn import build_norm_layer from mmcv.cnn.bricks.transformer import FFN try: from fairscale.nn.checkpoint import checkpoint_wrapper except Exception: checkpoint_wrapper = None def get_embedding_weight(model, size): vocab_size = size indices = torch.arange(vocab_size).cuda().to(torch.int64) embeddings = model(indices) return embeddings # @MODELS.register_module() class MSDeformAttnPixelDecoder(BaseModule): """Pixel decoder with multi-scale deformable attention. Args: in_channels (list[int] | tuple[int]): Number of channels in the input feature maps. strides (list[int] | tuple[int]): Output strides of feature from backbone. feat_channels (int): Number of channels for feature. out_channels (int): Number of channels for output. num_outs (int): Number of output scales. norm_cfg (:obj:`ConfigDict` or dict): Config for normalization. Defaults to dict(type='GN', num_groups=32). act_cfg (:obj:`ConfigDict` or dict): Config for activation. Defaults to dict(type='ReLU'). encoder (:obj:`ConfigDict` or dict): Config for transformer encoder. Defaults to None. positional_encoding (:obj:`ConfigDict` or dict): Config for transformer encoder position encoding. Defaults to dict(num_feats=128, normalize=True). init_cfg (:obj:`ConfigDict` or dict or list[:obj:`ConfigDict` or \ dict], optional): Initialization config dict. Defaults to None. """ def __init__(self, in_channels: Union[List[int], Tuple[int]] = [256, 512, 1024, 2048], strides: Union[List[int], Tuple[int]] = [4, 8, 16, 32], feat_channels: int = 256, out_channels: int = 256, num_outs: int = 3, norm_cfg: ConfigType = dict(type='GN', num_groups=32), act_cfg: ConfigType = dict(type='ReLU'), encoder: ConfigType = None, positional_encoding: ConfigType = dict( num_feats=128, normalize=True), init_cfg: OptMultiConfig = None) -> None: super().__init__(init_cfg=init_cfg) self.strides = strides self.num_input_levels = len(in_channels) self.num_encoder_levels = \ encoder.layer_cfg.self_attn_cfg.num_levels assert self.num_encoder_levels >= 1, \ 'num_levels in attn_cfgs must be at least one' input_conv_list = [] # from top to down (low to high resolution) for i in range(self.num_input_levels - 1, self.num_input_levels - self.num_encoder_levels - 1, -1): input_conv = ConvModule( in_channels[i], feat_channels, kernel_size=1, norm_cfg=norm_cfg, act_cfg=None, bias=True) input_conv_list.append(input_conv) self.input_convs = ModuleList(input_conv_list) self.encoder = Mask2FormerTransformerEncoder(**encoder) self.postional_encoding = SinePositionalEncoding(**positional_encoding) # high resolution to low resolution self.level_encoding = nn.Embedding(self.num_encoder_levels, feat_channels) # fpn-like structure self.lateral_convs = ModuleList() self.output_convs = ModuleList() self.use_bias = norm_cfg is None # from top to down (low to high resolution) # fpn for the rest features that didn't pass in encoder for i in range(self.num_input_levels - self.num_encoder_levels - 1, -1, -1): lateral_conv = ConvModule( in_channels[i], feat_channels, kernel_size=1, bias=self.use_bias, norm_cfg=norm_cfg, act_cfg=None) output_conv = ConvModule( feat_channels, feat_channels, kernel_size=3, stride=1, padding=1, bias=self.use_bias, norm_cfg=norm_cfg, act_cfg=act_cfg) self.lateral_convs.append(lateral_conv) self.output_convs.append(output_conv) self.mask_feature = Conv2d( feat_channels, out_channels, kernel_size=1, stride=1, padding=0) self.num_outs = num_outs self.point_generator = MlvlPointGenerator(strides) def init_weights(self) -> None: """Initialize weights.""" for i in range(0, self.num_encoder_levels): xavier_init( self.input_convs[i].conv, gain=1, bias=0, distribution='uniform') for i in range(0, self.num_input_levels - self.num_encoder_levels): caffe2_xavier_init(self.lateral_convs[i].conv, bias=0) caffe2_xavier_init(self.output_convs[i].conv, bias=0) caffe2_xavier_init(self.mask_feature, bias=0) normal_init(self.level_encoding, mean=0, std=1) for p in self.encoder.parameters(): if p.dim() > 1: nn.init.xavier_normal_(p) # init_weights defined in MultiScaleDeformableAttention for m in self.encoder.layers.modules(): if isinstance(m, MultiScaleDeformableAttention): m.init_weights() def forward(self, feats: List[Tensor]) -> Tuple[Tensor, Tensor]: """ Args: feats (list[Tensor]): Feature maps of each level. Each has shape of (batch_size, c, h, w). Returns: tuple: A tuple containing the following: - mask_feature (Tensor): shape (batch_size, c, h, w). - multi_scale_features (list[Tensor]): Multi scale \ features, each in shape (batch_size, c, h, w). """ # generate padding mask for each level, for each image batch_size = feats[0].shape[0] encoder_input_list = [] padding_mask_list = [] level_positional_encoding_list = [] spatial_shapes = [] reference_points_list = [] for i in range(self.num_encoder_levels): level_idx = self.num_input_levels - i - 1 feat = feats[level_idx] feat_projected = self.input_convs[i](feat) feat_hw = torch._shape_as_tensor(feat)[2:].to(feat.device) # no padding padding_mask_resized = feat.new_zeros( (batch_size, ) + feat.shape[-2:], dtype=torch.bool) pos_embed = self.postional_encoding(padding_mask_resized) # level_embed = self.level_encoding.weight[i] level_embed = get_embedding_weight(self.level_encoding, self.num_encoder_levels)[i] level_pos_embed = level_embed.view(1, -1, 1, 1) + pos_embed # (h_i * w_i, 2) reference_points = self.point_generator.single_level_grid_priors( feat.shape[-2:], level_idx, device=feat.device) # normalize feat_wh = feat_hw.unsqueeze(0).flip(dims=[0, 1]) factor = feat_wh * self.strides[level_idx] reference_points = reference_points / factor # shape (batch_size, c, h_i, w_i) -> (h_i * w_i, batch_size, c) feat_projected = feat_projected.flatten(2).permute(0, 2, 1) level_pos_embed = level_pos_embed.flatten(2).permute(0, 2, 1) padding_mask_resized = padding_mask_resized.flatten(1) encoder_input_list.append(feat_projected) padding_mask_list.append(padding_mask_resized) level_positional_encoding_list.append(level_pos_embed) spatial_shapes.append(feat_hw) reference_points_list.append(reference_points) # shape (batch_size, total_num_queries), # total_num_queries=sum([., h_i * w_i,.]) padding_masks = torch.cat(padding_mask_list, dim=1) # shape (total_num_queries, batch_size, c) encoder_inputs = torch.cat(encoder_input_list, dim=1) level_positional_encodings = torch.cat( level_positional_encoding_list, dim=1) # shape (num_encoder_levels, 2), from low # resolution to high resolution num_queries_per_level = [e[0] * e[1] for e in spatial_shapes] spatial_shapes = torch.cat(spatial_shapes).view(-1, 2) # shape (0, h_0*w_0, h_0*w_0+h_1*w_1, ...) level_start_index = torch.cat((spatial_shapes.new_zeros( (1, )), spatial_shapes.prod(1).cumsum(0)[:-1])) reference_points = torch.cat(reference_points_list, dim=0) reference_points = reference_points[None, :, None].repeat( batch_size, 1, self.num_encoder_levels, 1) valid_radios = reference_points.new_ones( (batch_size, self.num_encoder_levels, 2)) # shape (num_total_queries, batch_size, c) memory = self.encoder( query=encoder_inputs.to(torch.bfloat16), query_pos=level_positional_encodings.to(torch.bfloat16), key_padding_mask=padding_masks, spatial_shapes=spatial_shapes, reference_points=reference_points.to(torch.bfloat16), level_start_index=level_start_index, valid_ratios=valid_radios) # (batch_size, c, num_total_queries) memory = memory.permute(0, 2, 1) # from low resolution to high resolution outs = torch.split(memory, num_queries_per_level, dim=-1) outs = [ x.reshape(batch_size, -1, spatial_shapes[i][0], spatial_shapes[i][1]) for i, x in enumerate(outs) ] for i in range(self.num_input_levels - self.num_encoder_levels - 1, -1, -1): x = feats[i] cur_feat = self.lateral_convs[i](x) y = cur_feat + F.interpolate( outs[-1], size=cur_feat.shape[-2:], mode='bilinear', align_corners=False) y = self.output_convs[i](y) outs.append(y) multi_scale_features = outs[:self.num_outs] mask_feature = self.mask_feature(outs[-1]) return mask_feature, multi_scale_features class DeformableDetrTransformerEncoderLayer(DetrTransformerEncoderLayer): """Encoder layer of Deformable DETR.""" def _init_layers(self) -> None: """Initialize self_attn, ffn, and norms.""" self.self_attn = MultiScaleDeformableAttention(**self.self_attn_cfg) self.embed_dims = self.self_attn.embed_dims self.ffn = FFN(**self.ffn_cfg) norms_list = [ build_norm_layer(self.norm_cfg, self.embed_dims)[1] for _ in range(2) ] self.norms = ModuleList(norms_list) class DeformableDetrTransformerEncoder(DetrTransformerEncoder): """Transformer encoder of Deformable DETR.""" def _init_layers(self) -> None: """Initialize encoder layers.""" self.layers = ModuleList([ DeformableDetrTransformerEncoderLayer(**self.layer_cfg) for _ in range(self.num_layers) ]) self.embed_dims = self.layers[0].embed_dims def forward(self, query: Tensor, query_pos: Tensor, key_padding_mask: Tensor, spatial_shapes: Tensor, level_start_index: Tensor, valid_ratios: Tensor, **kwargs) -> Tensor: """Forward function of Transformer encoder. Args: query (Tensor): The input query, has shape (bs, num_queries, dim). query_pos (Tensor): The positional encoding for query, has shape (bs, num_queries, dim). key_padding_mask (Tensor): The `key_padding_mask` of `self_attn` input. ByteTensor, has shape (bs, num_queries). spatial_shapes (Tensor): Spatial shapes of features in all levels, has shape (num_levels, 2), last dimension represents (h, w). level_start_index (Tensor): The start index of each level. A tensor has shape (num_levels, ) and can be represented as [0, h_0*w_0, h_0*w_0+h_1*w_1, ...]. valid_ratios (Tensor): The ratios of the valid width and the valid height relative to the width and the height of features in all levels, has shape (bs, num_levels, 2). Returns: Tensor: Output queries of Transformer encoder, which is also called 'encoder output embeddings' or 'memory', has shape (bs, num_queries, dim) """ reference_points = self.get_encoder_reference_points( spatial_shapes, valid_ratios, device=query.device) for layer in self.layers: query = layer( query=query, query_pos=query_pos, key_padding_mask=key_padding_mask, spatial_shapes=spatial_shapes, level_start_index=level_start_index, valid_ratios=valid_ratios, reference_points=reference_points, **kwargs) return query @staticmethod def get_encoder_reference_points( spatial_shapes: Tensor, valid_ratios: Tensor, device: Union[torch.device, str]) -> Tensor: """Get the reference points used in encoder. Args: spatial_shapes (Tensor): Spatial shapes of features in all levels, has shape (num_levels, 2), last dimension represents (h, w). valid_ratios (Tensor): The ratios of the valid width and the valid height relative to the width and the height of features in all levels, has shape (bs, num_levels, 2). device (obj:`device` or str): The device acquired by the `reference_points`. Returns: Tensor: Reference points used in decoder, has shape (bs, length, num_levels, 2). """ reference_points_list = [] for lvl, (H, W) in enumerate(spatial_shapes): ref_y, ref_x = torch.meshgrid( torch.linspace( 0.5, H - 0.5, H, dtype=torch.float32, device=device), torch.linspace( 0.5, W - 0.5, W, dtype=torch.float32, device=device)) ref_y = ref_y.reshape(-1)[None] / ( valid_ratios[:, None, lvl, 1] * H) ref_x = ref_x.reshape(-1)[None] / ( valid_ratios[:, None, lvl, 0] * W) ref = torch.stack((ref_x, ref_y), -1) reference_points_list.append(ref) reference_points = torch.cat(reference_points_list, 1) # [bs, sum(hw), num_level, 2] reference_points = reference_points[:, :, None] * valid_ratios[:, None] return reference_points class Mask2FormerTransformerEncoder(DeformableDetrTransformerEncoder): """Encoder in PixelDecoder of Mask2Former.""" def forward(self, query: Tensor, query_pos: Tensor, key_padding_mask: Tensor, spatial_shapes: Tensor, level_start_index: Tensor, valid_ratios: Tensor, reference_points: Tensor, **kwargs) -> Tensor: """Forward function of Transformer encoder. Args: query (Tensor): The input query, has shape (bs, num_queries, dim). query_pos (Tensor): The positional encoding for query, has shape (bs, num_queries, dim). If not None, it will be added to the `query` before forward function. Defaults to None. key_padding_mask (Tensor): The `key_padding_mask` of `self_attn` input. ByteTensor, has shape (bs, num_queries). spatial_shapes (Tensor): Spatial shapes of features in all levels, has shape (num_levels, 2), last dimension represents (h, w). level_start_index (Tensor): The start index of each level. A tensor has shape (num_levels, ) and can be represented as [0, h_0*w_0, h_0*w_0+h_1*w_1, ...]. valid_ratios (Tensor): The ratios of the valid width and the valid height relative to the width and the height of features in all levels, has shape (bs, num_levels, 2). reference_points (Tensor): The initial reference, has shape (bs, num_queries, 2) with the last dimension arranged as (cx, cy). Returns: Tensor: Output queries of Transformer encoder, which is also called 'encoder output embeddings' or 'memory', has shape (bs, num_queries, dim) """ for layer in self.layers: query = layer( query=query, query_pos=query_pos, key_padding_mask=key_padding_mask, spatial_shapes=spatial_shapes, level_start_index=level_start_index, valid_ratios=valid_ratios, reference_points=reference_points, **kwargs) return query