docstr: Tests mask head loss when truth is empty and non-empty.
docstr_tok: ["Tests","mask","head","loss","when","truth","is","empty","and","non-empty","."]
code: def test_solov2_head_loss(self):
      """Tests mask head loss when truth is empty and non-empty."""
      s = 256
      img_metas = [
          {
              "img_shape": (s, s, 3),
              "ori_shape": (s, s, 3),
              "scale_factor": 1,
              "batch_input_shape": (s, s, 3),
          }
      ]
  
      mask_feature_head = _fake_mask_feature_head()
  
      mask_head = SOLOV2Head(
          num_classes=4,
          in_channels=1,
          mask_feature_head=mask_feature_head,
      )
  
      # SOLO head expects a multiple levels of features per image
      feats = []
      for i in range(len(mask_head.strides)):
          feats.append(
              torch.rand(1, 1, s // (2 ** (i + 2)), s // (2 ** (i + 2)))
          )
      feats = tuple(feats)
  
      mask_outs = mask_head.forward(feats)
  
      # Test that empty ground truth encourages the network to
      # predict background
      gt_instances = InstanceData()
      gt_instances.bboxes = torch.empty(0, 4)
      gt_instances.labels = torch.LongTensor([])
      gt_instances.masks = _rand_masks(
          0, gt_instances.bboxes.numpy(), s, s
      )
  
      empty_gt_losses = mask_head.loss_by_feat(
          *mask_outs,
          batch_gt_instances=[gt_instances],
          batch_img_metas=img_metas,
      )
      # When there is no truth, the cls loss should be nonzero but
      # there should be no box loss.
      empty_cls_loss = empty_gt_losses["loss_cls"]
      empty_mask_loss = empty_gt_losses["loss_mask"]
      self.assertGreater(
          empty_cls_loss.item(), 0, "cls loss should be non-zero"
      )
      self.assertEqual(
          empty_mask_loss.item(),
          0,
          "there should be no mask loss when there are no true mask",
      )
  
      # When truth is non-empty then both cls and box loss
      # should be nonzero for random inputs
      gt_instances = InstanceData()
      gt_instances.bboxes = torch.Tensor(
          [[23.6667, 23.8757, 238.6326, 151.8874]]
      )
      gt_instances.labels = torch.LongTensor([2])
      gt_instances.masks = _rand_masks(
          1, gt_instances.bboxes.numpy(), s, s
      )
  
      one_gt_losses = mask_head.loss_by_feat(
          *mask_outs,
          batch_gt_instances=[gt_instances],
          batch_img_metas=img_metas,
      )
      onegt_cls_loss = one_gt_losses["loss_cls"]
      onegt_mask_loss = one_gt_losses["loss_mask"]
      self.assertGreater(
          onegt_cls_loss.item(), 0, "cls loss should be non-zero"
      )
      self.assertGreater(
          onegt_mask_loss.item(), 0, "mask loss should be non-zero"
      )
  
file_path: mmdetection/tests/test_models/test_dense_heads/test_solov2_head.py
imports: from unittest import TestCase
  import numpy
  import torch
  from mmengine.config import ConfigDict
  from mmengine.structures import InstanceData
  from mmdet import *
  from mmdet.models.dense_heads import SOLOV2Head
  from mmdet.structures.mask import BitmapMasks
label_desc: Use image node_id 1 for calling the TestSOLOv2Head obj's underlying member method code with example usage: obj.test_solov2_head_loss() without return types