You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_assigner.py 16 kB

2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. # Copyright (c) OpenMMLab. All rights reserved.
  2. """Tests the Assigner objects.
  3. CommandLine:
  4. pytest tests/test_utils/test_assigner.py
  5. xdoctest tests/test_utils/test_assigner.py zero
  6. """
  7. import torch
  8. from mmdet.core.bbox.assigners import (ApproxMaxIoUAssigner,
  9. CenterRegionAssigner, HungarianAssigner,
  10. MaxIoUAssigner, PointAssigner,
  11. UniformAssigner)
  12. def test_max_iou_assigner():
  13. self = MaxIoUAssigner(
  14. pos_iou_thr=0.5,
  15. neg_iou_thr=0.5,
  16. )
  17. bboxes = torch.FloatTensor([
  18. [0, 0, 10, 10],
  19. [10, 10, 20, 20],
  20. [5, 5, 15, 15],
  21. [32, 32, 38, 42],
  22. ])
  23. gt_bboxes = torch.FloatTensor([
  24. [0, 0, 10, 9],
  25. [0, 10, 10, 19],
  26. ])
  27. gt_labels = torch.LongTensor([2, 3])
  28. assign_result = self.assign(bboxes, gt_bboxes, gt_labels=gt_labels)
  29. assert len(assign_result.gt_inds) == 4
  30. assert len(assign_result.labels) == 4
  31. expected_gt_inds = torch.LongTensor([1, 0, 2, 0])
  32. assert torch.all(assign_result.gt_inds == expected_gt_inds)
  33. def test_max_iou_assigner_with_ignore():
  34. self = MaxIoUAssigner(
  35. pos_iou_thr=0.5,
  36. neg_iou_thr=0.5,
  37. ignore_iof_thr=0.5,
  38. ignore_wrt_candidates=False,
  39. )
  40. bboxes = torch.FloatTensor([
  41. [0, 0, 10, 10],
  42. [10, 10, 20, 20],
  43. [5, 5, 15, 15],
  44. [30, 32, 40, 42],
  45. ])
  46. gt_bboxes = torch.FloatTensor([
  47. [0, 0, 10, 9],
  48. [0, 10, 10, 19],
  49. ])
  50. gt_bboxes_ignore = torch.Tensor([
  51. [30, 30, 40, 40],
  52. ])
  53. assign_result = self.assign(
  54. bboxes, gt_bboxes, gt_bboxes_ignore=gt_bboxes_ignore)
  55. expected_gt_inds = torch.LongTensor([1, 0, 2, -1])
  56. assert torch.all(assign_result.gt_inds == expected_gt_inds)
  57. def test_max_iou_assigner_with_empty_gt():
  58. """Test corner case where an image might have no true detections."""
  59. self = MaxIoUAssigner(
  60. pos_iou_thr=0.5,
  61. neg_iou_thr=0.5,
  62. )
  63. bboxes = torch.FloatTensor([
  64. [0, 0, 10, 10],
  65. [10, 10, 20, 20],
  66. [5, 5, 15, 15],
  67. [32, 32, 38, 42],
  68. ])
  69. gt_bboxes = torch.empty(0, 4)
  70. assign_result = self.assign(bboxes, gt_bboxes)
  71. expected_gt_inds = torch.LongTensor([0, 0, 0, 0])
  72. assert torch.all(assign_result.gt_inds == expected_gt_inds)
  73. def test_max_iou_assigner_with_empty_boxes():
  74. """Test corner case where a network might predict no boxes."""
  75. self = MaxIoUAssigner(
  76. pos_iou_thr=0.5,
  77. neg_iou_thr=0.5,
  78. )
  79. bboxes = torch.empty((0, 4))
  80. gt_bboxes = torch.FloatTensor([
  81. [0, 0, 10, 9],
  82. [0, 10, 10, 19],
  83. ])
  84. gt_labels = torch.LongTensor([2, 3])
  85. # Test with gt_labels
  86. assign_result = self.assign(bboxes, gt_bboxes, gt_labels=gt_labels)
  87. assert len(assign_result.gt_inds) == 0
  88. assert tuple(assign_result.labels.shape) == (0, )
  89. # Test without gt_labels
  90. assign_result = self.assign(bboxes, gt_bboxes, gt_labels=None)
  91. assert len(assign_result.gt_inds) == 0
  92. assert assign_result.labels is None
  93. def test_max_iou_assigner_with_empty_boxes_and_ignore():
  94. """Test corner case where a network might predict no boxes and
  95. ignore_iof_thr is on."""
  96. self = MaxIoUAssigner(
  97. pos_iou_thr=0.5,
  98. neg_iou_thr=0.5,
  99. ignore_iof_thr=0.5,
  100. )
  101. bboxes = torch.empty((0, 4))
  102. gt_bboxes = torch.FloatTensor([
  103. [0, 0, 10, 9],
  104. [0, 10, 10, 19],
  105. ])
  106. gt_bboxes_ignore = torch.Tensor([
  107. [30, 30, 40, 40],
  108. ])
  109. gt_labels = torch.LongTensor([2, 3])
  110. # Test with gt_labels
  111. assign_result = self.assign(
  112. bboxes,
  113. gt_bboxes,
  114. gt_labels=gt_labels,
  115. gt_bboxes_ignore=gt_bboxes_ignore)
  116. assert len(assign_result.gt_inds) == 0
  117. assert tuple(assign_result.labels.shape) == (0, )
  118. # Test without gt_labels
  119. assign_result = self.assign(
  120. bboxes, gt_bboxes, gt_labels=None, gt_bboxes_ignore=gt_bboxes_ignore)
  121. assert len(assign_result.gt_inds) == 0
  122. assert assign_result.labels is None
  123. def test_max_iou_assigner_with_empty_boxes_and_gt():
  124. """Test corner case where a network might predict no boxes and no gt."""
  125. self = MaxIoUAssigner(
  126. pos_iou_thr=0.5,
  127. neg_iou_thr=0.5,
  128. )
  129. bboxes = torch.empty((0, 4))
  130. gt_bboxes = torch.empty((0, 4))
  131. assign_result = self.assign(bboxes, gt_bboxes)
  132. assert len(assign_result.gt_inds) == 0
  133. def test_point_assigner():
  134. self = PointAssigner()
  135. points = torch.FloatTensor([ # [x, y, stride]
  136. [0, 0, 1],
  137. [10, 10, 1],
  138. [5, 5, 1],
  139. [32, 32, 1],
  140. ])
  141. gt_bboxes = torch.FloatTensor([
  142. [0, 0, 10, 9],
  143. [0, 10, 10, 19],
  144. ])
  145. assign_result = self.assign(points, gt_bboxes)
  146. expected_gt_inds = torch.LongTensor([1, 2, 1, 0])
  147. assert torch.all(assign_result.gt_inds == expected_gt_inds)
  148. def test_point_assigner_with_empty_gt():
  149. """Test corner case where an image might have no true detections."""
  150. self = PointAssigner()
  151. points = torch.FloatTensor([ # [x, y, stride]
  152. [0, 0, 1],
  153. [10, 10, 1],
  154. [5, 5, 1],
  155. [32, 32, 1],
  156. ])
  157. gt_bboxes = torch.FloatTensor([])
  158. assign_result = self.assign(points, gt_bboxes)
  159. expected_gt_inds = torch.LongTensor([0, 0, 0, 0])
  160. assert torch.all(assign_result.gt_inds == expected_gt_inds)
  161. def test_point_assigner_with_empty_boxes_and_gt():
  162. """Test corner case where an image might predict no points and no gt."""
  163. self = PointAssigner()
  164. points = torch.FloatTensor([])
  165. gt_bboxes = torch.FloatTensor([])
  166. assign_result = self.assign(points, gt_bboxes)
  167. assert len(assign_result.gt_inds) == 0
  168. def test_approx_iou_assigner():
  169. self = ApproxMaxIoUAssigner(
  170. pos_iou_thr=0.5,
  171. neg_iou_thr=0.5,
  172. )
  173. bboxes = torch.FloatTensor([
  174. [0, 0, 10, 10],
  175. [10, 10, 20, 20],
  176. [5, 5, 15, 15],
  177. [32, 32, 38, 42],
  178. ])
  179. gt_bboxes = torch.FloatTensor([
  180. [0, 0, 10, 9],
  181. [0, 10, 10, 19],
  182. ])
  183. approxs_per_octave = 1
  184. approxs = bboxes
  185. squares = bboxes
  186. assign_result = self.assign(approxs, squares, approxs_per_octave,
  187. gt_bboxes)
  188. expected_gt_inds = torch.LongTensor([1, 0, 2, 0])
  189. assert torch.all(assign_result.gt_inds == expected_gt_inds)
  190. def test_approx_iou_assigner_with_empty_gt():
  191. """Test corner case where an image might have no true detections."""
  192. self = ApproxMaxIoUAssigner(
  193. pos_iou_thr=0.5,
  194. neg_iou_thr=0.5,
  195. )
  196. bboxes = torch.FloatTensor([
  197. [0, 0, 10, 10],
  198. [10, 10, 20, 20],
  199. [5, 5, 15, 15],
  200. [32, 32, 38, 42],
  201. ])
  202. gt_bboxes = torch.FloatTensor([])
  203. approxs_per_octave = 1
  204. approxs = bboxes
  205. squares = bboxes
  206. assign_result = self.assign(approxs, squares, approxs_per_octave,
  207. gt_bboxes)
  208. expected_gt_inds = torch.LongTensor([0, 0, 0, 0])
  209. assert torch.all(assign_result.gt_inds == expected_gt_inds)
  210. def test_approx_iou_assigner_with_empty_boxes():
  211. """Test corner case where an network might predict no boxes."""
  212. self = ApproxMaxIoUAssigner(
  213. pos_iou_thr=0.5,
  214. neg_iou_thr=0.5,
  215. )
  216. bboxes = torch.empty((0, 4))
  217. gt_bboxes = torch.FloatTensor([
  218. [0, 0, 10, 9],
  219. [0, 10, 10, 19],
  220. ])
  221. approxs_per_octave = 1
  222. approxs = bboxes
  223. squares = bboxes
  224. assign_result = self.assign(approxs, squares, approxs_per_octave,
  225. gt_bboxes)
  226. assert len(assign_result.gt_inds) == 0
  227. def test_approx_iou_assigner_with_empty_boxes_and_gt():
  228. """Test corner case where an network might predict no boxes and no gt."""
  229. self = ApproxMaxIoUAssigner(
  230. pos_iou_thr=0.5,
  231. neg_iou_thr=0.5,
  232. )
  233. bboxes = torch.empty((0, 4))
  234. gt_bboxes = torch.empty((0, 4))
  235. approxs_per_octave = 1
  236. approxs = bboxes
  237. squares = bboxes
  238. assign_result = self.assign(approxs, squares, approxs_per_octave,
  239. gt_bboxes)
  240. assert len(assign_result.gt_inds) == 0
  241. def test_random_assign_result():
  242. """Test random instantiation of assign result to catch corner cases."""
  243. from mmdet.core.bbox.assigners.assign_result import AssignResult
  244. AssignResult.random()
  245. AssignResult.random(num_gts=0, num_preds=0)
  246. AssignResult.random(num_gts=0, num_preds=3)
  247. AssignResult.random(num_gts=3, num_preds=3)
  248. AssignResult.random(num_gts=0, num_preds=3)
  249. AssignResult.random(num_gts=7, num_preds=7)
  250. AssignResult.random(num_gts=7, num_preds=64)
  251. AssignResult.random(num_gts=24, num_preds=3)
  252. def test_center_region_assigner():
  253. self = CenterRegionAssigner(pos_scale=0.3, neg_scale=1)
  254. bboxes = torch.FloatTensor([[0, 0, 10, 10], [10, 10, 20, 20], [8, 8, 9,
  255. 9]])
  256. gt_bboxes = torch.FloatTensor([
  257. [0, 0, 11, 11], # match bboxes[0]
  258. [10, 10, 20, 20], # match bboxes[1]
  259. [4.5, 4.5, 5.5, 5.5], # match bboxes[0] but area is too small
  260. [0, 0, 10, 10], # match bboxes[1] and has a smaller area than gt[0]
  261. ])
  262. gt_labels = torch.LongTensor([2, 3, 4, 5])
  263. assign_result = self.assign(bboxes, gt_bboxes, gt_labels=gt_labels)
  264. assert len(assign_result.gt_inds) == 3
  265. assert len(assign_result.labels) == 3
  266. expected_gt_inds = torch.LongTensor([4, 2, 0])
  267. assert torch.all(assign_result.gt_inds == expected_gt_inds)
  268. shadowed_labels = assign_result.get_extra_property('shadowed_labels')
  269. # [8, 8, 9, 9] in the shadowed region of [0, 0, 11, 11] (label: 2)
  270. assert torch.any(shadowed_labels == torch.LongTensor([[2, 2]]))
  271. # [8, 8, 9, 9] in the shadowed region of [0, 0, 10, 10] (label: 5)
  272. assert torch.any(shadowed_labels == torch.LongTensor([[2, 5]]))
  273. # [0, 0, 10, 10] is already assigned to [4.5, 4.5, 5.5, 5.5].
  274. # Therefore, [0, 0, 11, 11] (label: 2) is shadowed
  275. assert torch.any(shadowed_labels == torch.LongTensor([[0, 2]]))
  276. def test_center_region_assigner_with_ignore():
  277. self = CenterRegionAssigner(
  278. pos_scale=0.5,
  279. neg_scale=1,
  280. )
  281. bboxes = torch.FloatTensor([
  282. [0, 0, 10, 10],
  283. [10, 10, 20, 20],
  284. ])
  285. gt_bboxes = torch.FloatTensor([
  286. [0, 0, 10, 10], # match bboxes[0]
  287. [10, 10, 20, 20], # match bboxes[1]
  288. ])
  289. gt_bboxes_ignore = torch.FloatTensor([
  290. [0, 0, 10, 10], # match bboxes[0]
  291. ])
  292. gt_labels = torch.LongTensor([1, 2])
  293. assign_result = self.assign(
  294. bboxes,
  295. gt_bboxes,
  296. gt_bboxes_ignore=gt_bboxes_ignore,
  297. gt_labels=gt_labels)
  298. assert len(assign_result.gt_inds) == 2
  299. assert len(assign_result.labels) == 2
  300. expected_gt_inds = torch.LongTensor([-1, 2])
  301. assert torch.all(assign_result.gt_inds == expected_gt_inds)
  302. def test_center_region_assigner_with_empty_bboxes():
  303. self = CenterRegionAssigner(
  304. pos_scale=0.5,
  305. neg_scale=1,
  306. )
  307. bboxes = torch.empty((0, 4)).float()
  308. gt_bboxes = torch.FloatTensor([
  309. [0, 0, 10, 10], # match bboxes[0]
  310. [10, 10, 20, 20], # match bboxes[1]
  311. ])
  312. gt_labels = torch.LongTensor([1, 2])
  313. assign_result = self.assign(bboxes, gt_bboxes, gt_labels=gt_labels)
  314. assert assign_result.gt_inds is None or assign_result.gt_inds.numel() == 0
  315. assert assign_result.labels is None or assign_result.labels.numel() == 0
  316. def test_center_region_assigner_with_empty_gts():
  317. self = CenterRegionAssigner(
  318. pos_scale=0.5,
  319. neg_scale=1,
  320. )
  321. bboxes = torch.FloatTensor([
  322. [0, 0, 10, 10],
  323. [10, 10, 20, 20],
  324. ])
  325. gt_bboxes = torch.empty((0, 4)).float()
  326. gt_labels = torch.empty((0, )).long()
  327. assign_result = self.assign(bboxes, gt_bboxes, gt_labels=gt_labels)
  328. assert len(assign_result.gt_inds) == 2
  329. expected_gt_inds = torch.LongTensor([0, 0])
  330. assert torch.all(assign_result.gt_inds == expected_gt_inds)
  331. def test_hungarian_match_assigner():
  332. self = HungarianAssigner()
  333. assert self.iou_cost.iou_mode == 'giou'
  334. # test no gt bboxes
  335. bbox_pred = torch.rand((10, 4))
  336. cls_pred = torch.rand((10, 81))
  337. gt_bboxes = torch.empty((0, 4)).float()
  338. gt_labels = torch.empty((0, )).long()
  339. img_meta = dict(img_shape=(10, 8, 3))
  340. assign_result = self.assign(bbox_pred, cls_pred, gt_bboxes, gt_labels,
  341. img_meta)
  342. assert torch.all(assign_result.gt_inds == 0)
  343. assert torch.all(assign_result.labels == -1)
  344. # test with gt bboxes
  345. gt_bboxes = torch.FloatTensor([[0, 0, 5, 7], [3, 5, 7, 8]])
  346. gt_labels = torch.LongTensor([1, 20])
  347. assign_result = self.assign(bbox_pred, cls_pred, gt_bboxes, gt_labels,
  348. img_meta)
  349. assert torch.all(assign_result.gt_inds > -1)
  350. assert (assign_result.gt_inds > 0).sum() == gt_bboxes.size(0)
  351. assert (assign_result.labels > -1).sum() == gt_bboxes.size(0)
  352. # test iou mode
  353. self = HungarianAssigner(
  354. iou_cost=dict(type='IoUCost', iou_mode='iou', weight=1.0))
  355. assert self.iou_cost.iou_mode == 'iou'
  356. assign_result = self.assign(bbox_pred, cls_pred, gt_bboxes, gt_labels,
  357. img_meta)
  358. assert torch.all(assign_result.gt_inds > -1)
  359. assert (assign_result.gt_inds > 0).sum() == gt_bboxes.size(0)
  360. assert (assign_result.labels > -1).sum() == gt_bboxes.size(0)
  361. # test focal loss mode
  362. self = HungarianAssigner(
  363. iou_cost=dict(type='IoUCost', iou_mode='giou', weight=1.0),
  364. cls_cost=dict(type='FocalLossCost', weight=1.))
  365. assert self.iou_cost.iou_mode == 'giou'
  366. assign_result = self.assign(bbox_pred, cls_pred, gt_bboxes, gt_labels,
  367. img_meta)
  368. assert torch.all(assign_result.gt_inds > -1)
  369. assert (assign_result.gt_inds > 0).sum() == gt_bboxes.size(0)
  370. assert (assign_result.labels > -1).sum() == gt_bboxes.size(0)
  371. def test_uniform_assigner():
  372. self = UniformAssigner(0.15, 0.7, 1)
  373. pred_bbox = torch.FloatTensor([
  374. [1, 1, 12, 8],
  375. [4, 4, 20, 20],
  376. [1, 5, 15, 15],
  377. [30, 5, 32, 42],
  378. ])
  379. anchor = torch.FloatTensor([
  380. [0, 0, 10, 10],
  381. [10, 10, 20, 20],
  382. [5, 5, 15, 15],
  383. [32, 32, 38, 42],
  384. ])
  385. gt_bboxes = torch.FloatTensor([
  386. [0, 0, 10, 9],
  387. [0, 10, 10, 19],
  388. ])
  389. gt_labels = torch.LongTensor([2, 3])
  390. assign_result = self.assign(
  391. pred_bbox, anchor, gt_bboxes, gt_labels=gt_labels)
  392. assert len(assign_result.gt_inds) == 4
  393. assert len(assign_result.labels) == 4
  394. expected_gt_inds = torch.LongTensor([-1, 0, 2, 0])
  395. assert torch.all(assign_result.gt_inds == expected_gt_inds)
  396. def test_uniform_assigner_with_empty_gt():
  397. """Test corner case where an image might have no true detections."""
  398. self = UniformAssigner(0.15, 0.7, 1)
  399. pred_bbox = torch.FloatTensor([
  400. [1, 1, 12, 8],
  401. [4, 4, 20, 20],
  402. [1, 5, 15, 15],
  403. [30, 5, 32, 42],
  404. ])
  405. anchor = torch.FloatTensor([
  406. [0, 0, 10, 10],
  407. [10, 10, 20, 20],
  408. [5, 5, 15, 15],
  409. [32, 32, 38, 42],
  410. ])
  411. gt_bboxes = torch.empty(0, 4)
  412. assign_result = self.assign(pred_bbox, anchor, gt_bboxes)
  413. expected_gt_inds = torch.LongTensor([0, 0, 0, 0])
  414. assert torch.all(assign_result.gt_inds == expected_gt_inds)
  415. def test_uniform_assigner_with_empty_boxes():
  416. """Test corner case where a network might predict no boxes."""
  417. self = UniformAssigner(0.15, 0.7, 1)
  418. pred_bbox = torch.empty((0, 4))
  419. anchor = torch.empty((0, 4))
  420. gt_bboxes = torch.FloatTensor([
  421. [0, 0, 10, 9],
  422. [0, 10, 10, 19],
  423. ])
  424. gt_labels = torch.LongTensor([2, 3])
  425. # Test with gt_labels
  426. assign_result = self.assign(
  427. pred_bbox, anchor, gt_bboxes, gt_labels=gt_labels)
  428. assert len(assign_result.gt_inds) == 0
  429. assert tuple(assign_result.labels.shape) == (0, )
  430. # Test without gt_labels
  431. assign_result = self.assign(pred_bbox, anchor, gt_bboxes, gt_labels=None)
  432. assert len(assign_result.gt_inds) == 0

No Description

Contributors (1)