test_ssd_head.py 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. # Copyright (c) OpenMMLab. All rights reserved.
  2. from math import ceil
  3. from unittest import TestCase
  4. import torch
  5. from mmengine import Config
  6. from mmengine.structures import InstanceData
  7. from mmdet import * # noqa
  8. from mmdet.models.dense_heads import SSDHead
  9. class TestSSDHead(TestCase):
  10. def test_ssd_head_loss(self):
  11. """Tests ssd head loss when truth is empty and non-empty."""
  12. s = 300
  13. img_metas = [{
  14. 'img_shape': (s, s, 3),
  15. 'pad_shape': (s, s, 3),
  16. 'scale_factor': 1,
  17. }]
  18. cfg = Config(
  19. dict(
  20. assigner=dict(
  21. type='MaxIoUAssigner',
  22. pos_iou_thr=0.5,
  23. neg_iou_thr=0.5,
  24. min_pos_iou=0.,
  25. ignore_iof_thr=-1,
  26. gt_max_assign_all=False),
  27. sampler=dict(type='PseudoSampler'),
  28. smoothl1_beta=1.,
  29. allowed_border=-1,
  30. pos_weight=-1,
  31. neg_pos_ratio=3,
  32. debug=False))
  33. ssd_head = SSDHead(
  34. num_classes=4,
  35. in_channels=(1, 1, 1, 1, 1, 1),
  36. stacked_convs=1,
  37. feat_channels=1,
  38. use_depthwise=True,
  39. anchor_generator=dict(
  40. type='SSDAnchorGenerator',
  41. scale_major=False,
  42. input_size=s,
  43. basesize_ratio_range=(0.15, 0.9),
  44. strides=[8, 16, 32, 64, 100, 300],
  45. ratios=[[2], [2, 3], [2, 3], [2, 3], [2], [2]]),
  46. train_cfg=cfg)
  47. # SSD head expects a multiple levels of features per image
  48. feats = (
  49. torch.rand(1, 1, ceil(s / stride[0]), ceil(s / stride[0]))
  50. for stride in ssd_head.prior_generator.strides)
  51. cls_scores, bbox_preds = ssd_head.forward(feats)
  52. # Test that empty ground truth encourages the network to
  53. # predict background
  54. gt_instances = InstanceData()
  55. gt_instances.bboxes = torch.empty((0, 4))
  56. gt_instances.labels = torch.LongTensor([])
  57. empty_gt_losses = ssd_head.loss_by_feat(cls_scores, bbox_preds,
  58. [gt_instances], img_metas)
  59. # When there is no truth, cls_loss and box_loss should all be zero.
  60. empty_cls_loss = sum(empty_gt_losses['loss_cls'])
  61. empty_box_loss = sum(empty_gt_losses['loss_bbox'])
  62. self.assertEqual(
  63. empty_cls_loss.item(), 0,
  64. 'there should be no cls loss when there are no true boxes')
  65. self.assertEqual(
  66. empty_box_loss.item(), 0,
  67. 'there should be no box loss when there are no true boxes')
  68. # When truth is non-empty then both cls and box loss
  69. # should be nonzero for random inputs
  70. gt_instances = InstanceData()
  71. gt_instances.bboxes = torch.Tensor(
  72. [[23.6667, 23.8757, 238.6326, 151.8874]])
  73. gt_instances.labels = torch.LongTensor([2])
  74. one_gt_losses = ssd_head.loss_by_feat(cls_scores, bbox_preds,
  75. [gt_instances], img_metas)
  76. onegt_cls_loss = sum(one_gt_losses['loss_cls'])
  77. onegt_box_loss = sum(one_gt_losses['loss_bbox'])
  78. self.assertGreater(onegt_cls_loss.item(), 0,
  79. 'cls loss should be non-zero')
  80. self.assertGreater(onegt_box_loss.item(), 0,
  81. 'box loss should be non-zero')