//  [python]
def forward_single(self, x, idx, eval=False, upsampled_size=None):
        ins_feat = x
        cate_feat = x
        # ins branch
        # concat coord
        x_range = torch.linspace(-1, 1, ins_feat.shape[-1], device=ins_feat.device)
        y_range = torch.linspace(-1, 1, ins_feat.shape[-2], device=ins_feat.device)
        y, x = torch.meshgrid(y_range, x_range)
        y = y.expand([ins_feat.shape[0], 1, -1, -1])
        x = x.expand([ins_feat.shape[0], 1, -1, -1])
        coord_feat = torch.cat([x, y], 1)
        ins_feat = torch.cat([ins_feat, coord_feat], 1)

        for i, ins_layer in enumerate(self.ins_convs):
            ins_feat = ins_layer(ins_feat)

        ins_feat = t.upsample(ins_feat, scale_factor=2, mode='bilinear')
        ins_pred = self.solo_ins_list[idx](ins_feat)

        if self.s2_maskactivation is not None:
            if self.s2_maskactivation == 'sigmoid':
                ins_pred = F.sigmoid(ins_pred)
            elif self.s2_maskactivation == 'relu':
                ins_pred = F.relu(ins_pred)
            else:
                raise NotImplementedError
        # cate branch
        for i, cate_layer in enumerate(self.cate_convs):
            if i == self.cate_down_pos:
                cls_num_grid = self.cls_grid_number[idx]
                cate_feat = t.upsample(cate_feat, size=cls_num_grid, mode='bilinear')
            cate_feat = cate_layer(cate_feat)

        ##add predicting conv weight
        if self.learned_weight_activation==None:
            learned_upsample_weight = self.learned_weights(cate_feat)
        elif self.learned_weight_activation=='tanh':
            learned_upsample_weight = torch.tanh(self.learned_weights(cate_feat))
        else:
            raise ValueError
        ##add spatial index
        l = idx
        shifts_x = torch.arange(
            0, self.cls_grid_number[l], step=1,
            dtype=torch.float32, device=cate_feat.device
        )
        shifts_y = torch.arange(
            0, self.cls_grid_number[l], step=1,
            dtype=torch.float32, device=cate_feat.device
        )
        shift_y, shift_x = torch.meshgrid(shifts_y, shifts_x)
        # locations_HW = torch.stack([shift_x, shift_y],dim=2)## transposed index
        locations_HW = torch.stack([shift_y, shift_x], dim=2)  ## correct index
        locations_HW *= ((self.mask_grid_number[l] - 1) / (self.cls_grid_number[l] - 1))
        locations_map_to_HW = locations_HW.view(-1, 2)

        if self.nearest_neighbour == 4 or self.nearest_neighbour == 5 or self.nearest_neighbour == 1 or self.nearest_neighbour == 0:
            if any([clsg == maskg for i, (clsg, maskg) in enumerate(zip(self.cls_grid_number, self.mask_grid_number))]) or self.interpolation_mode == 5:  # if equal, get the near 5 points

                ## find nearest center
                neareast_center = locations_map_to_HW.round()

                ## generating nearest neighbour offsets
                shifts_x = torch.arange(
                    -1, 2, step=1,
                    dtype=torch.float32, device=cate_feat.device
                )
                shifts_y = torch.arange(
                    -1, 2, step=1,
                    dtype=torch.float32, device=cate_feat.device
                )
                shift_y, shift_x = torch.meshgrid(shifts_y, shifts_x)
                locations_offset = torch.stack([shift_y, shift_x], dim=2)
                locations_offset = torch.stack([locations_offset[0, 1],
                                                locations_offset[1, 0],
                                                locations_offset[1, 1],
                                                locations_offset[1, 2],
                                                locations_offset[2, 1]])
                spatial_index_this_lvl = neareast_center.unsqueeze(1) + locations_offset.unsqueeze(0)
                spatial_index_this_lvl = spatial_index_this_lvl.clamp(0, self.mask_grid_number[l] - 1).long()

            else:  # mask_grid_number less than cls grid number
                right_top_inds = torch.stack([locations_map_to_HW[:, 0].floor(), locations_map_to_HW[:, 1].ceil()],
                                             dim=1).long()
                right_bottom_inds = locations_map_to_HW.ceil().long()
                left_top_inds = torch.stack([locations_map_to_HW[:, 0].ceil(), locations_map_to_HW[:, 1].floor()],
                                            dim=1).long()
                left_bottom_inds = locations_map_to_HW.floor().long()

                spatial_index_this_lvl = torch.stack(
                    [right_top_inds, right_bottom_inds, left_top_inds, left_bottom_inds], dim=1)

        elif self.nearest_neighbour == 9:
            ## find nearest center
            neareast_center = locations_map_to_HW.round()
            ## generating nearest neighbour offsets
            shifts_x = torch.arange(
                -1, 2, step=1,
                dtype=torch.float32, device=cate_feat.device
            )
            shifts_y = torch.arange(
                -1, 2, step=1,
                dtype=torch.float32, device=cate_feat.device
            )
            shift_y, shift_x = torch.meshgrid(shifts_y, shifts_x)
            locations_offset = torch.stack([shift_y, shift_x], dim=2).view(9, 2)
            spatial_index_this_lvl = neareast_center.unsqueeze(1) + locations_offset.unsqueeze(0)
            spatial_index_this_lvl = spatial_index_this_lvl.clamp(0, self.mask_grid_number[
                l] - 1).long()  ## clamp for boundary points

        cate_pred = self.solo_cate(cate_feat)
        if eval:
            # ins_pred = F.interpolate(ins_pred.sigmoid(), size=upsampled_size, mode='bilinear')
            cate_pred = points_nms(cate_pred.sigmoid(), kernel=2).permute(0, 2, 3, 1)
        return ins_pred, cate_pred, spatial_index_this_lvl, learned_upsample_weight