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

951 lines
44 KiB

6 years ago
  1. # Copyright 2017 The TensorFlow Authors. All Rights Reserved.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. # ==============================================================================
  15. """Tests for tensorflow_models.object_detection.metrics.coco_evaluation."""
  16. from __future__ import absolute_import
  17. from __future__ import division
  18. from __future__ import print_function
  19. import numpy as np
  20. import tensorflow as tf
  21. from object_detection.core import standard_fields
  22. from object_detection.metrics import coco_evaluation
  23. def _get_categories_list():
  24. return [{
  25. 'id': 1,
  26. 'name': 'person'
  27. }, {
  28. 'id': 2,
  29. 'name': 'dog'
  30. }, {
  31. 'id': 3,
  32. 'name': 'cat'
  33. }]
  34. class CocoDetectionEvaluationTest(tf.test.TestCase):
  35. def testGetOneMAPWithMatchingGroundtruthAndDetections(self):
  36. """Tests that mAP is calculated correctly on GT and Detections."""
  37. coco_evaluator = coco_evaluation.CocoDetectionEvaluator(
  38. _get_categories_list())
  39. coco_evaluator.add_single_ground_truth_image_info(
  40. image_id='image1',
  41. groundtruth_dict={
  42. standard_fields.InputDataFields.groundtruth_boxes:
  43. np.array([[100., 100., 200., 200.]]),
  44. standard_fields.InputDataFields.groundtruth_classes: np.array([1])
  45. })
  46. coco_evaluator.add_single_detected_image_info(
  47. image_id='image1',
  48. detections_dict={
  49. standard_fields.DetectionResultFields.detection_boxes:
  50. np.array([[100., 100., 200., 200.]]),
  51. standard_fields.DetectionResultFields.detection_scores:
  52. np.array([.8]),
  53. standard_fields.DetectionResultFields.detection_classes:
  54. np.array([1])
  55. })
  56. coco_evaluator.add_single_ground_truth_image_info(
  57. image_id='image2',
  58. groundtruth_dict={
  59. standard_fields.InputDataFields.groundtruth_boxes:
  60. np.array([[50., 50., 100., 100.]]),
  61. standard_fields.InputDataFields.groundtruth_classes: np.array([1])
  62. })
  63. coco_evaluator.add_single_detected_image_info(
  64. image_id='image2',
  65. detections_dict={
  66. standard_fields.DetectionResultFields.detection_boxes:
  67. np.array([[50., 50., 100., 100.]]),
  68. standard_fields.DetectionResultFields.detection_scores:
  69. np.array([.8]),
  70. standard_fields.DetectionResultFields.detection_classes:
  71. np.array([1])
  72. })
  73. coco_evaluator.add_single_ground_truth_image_info(
  74. image_id='image3',
  75. groundtruth_dict={
  76. standard_fields.InputDataFields.groundtruth_boxes:
  77. np.array([[25., 25., 50., 50.]]),
  78. standard_fields.InputDataFields.groundtruth_classes: np.array([1])
  79. })
  80. coco_evaluator.add_single_detected_image_info(
  81. image_id='image3',
  82. detections_dict={
  83. standard_fields.DetectionResultFields.detection_boxes:
  84. np.array([[25., 25., 50., 50.]]),
  85. standard_fields.DetectionResultFields.detection_scores:
  86. np.array([.8]),
  87. standard_fields.DetectionResultFields.detection_classes:
  88. np.array([1])
  89. })
  90. metrics = coco_evaluator.evaluate()
  91. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP'], 1.0)
  92. def testGetOneMAPWithMatchingGroundtruthAndDetectionsSkipCrowd(self):
  93. """Tests computing mAP with is_crowd GT boxes skipped."""
  94. coco_evaluator = coco_evaluation.CocoDetectionEvaluator(
  95. _get_categories_list())
  96. coco_evaluator.add_single_ground_truth_image_info(
  97. image_id='image1',
  98. groundtruth_dict={
  99. standard_fields.InputDataFields.groundtruth_boxes:
  100. np.array([[100., 100., 200., 200.], [99., 99., 200., 200.]]),
  101. standard_fields.InputDataFields.groundtruth_classes:
  102. np.array([1, 2]),
  103. standard_fields.InputDataFields.groundtruth_is_crowd:
  104. np.array([0, 1])
  105. })
  106. coco_evaluator.add_single_detected_image_info(
  107. image_id='image1',
  108. detections_dict={
  109. standard_fields.DetectionResultFields.detection_boxes:
  110. np.array([[100., 100., 200., 200.]]),
  111. standard_fields.DetectionResultFields.detection_scores:
  112. np.array([.8]),
  113. standard_fields.DetectionResultFields.detection_classes:
  114. np.array([1])
  115. })
  116. metrics = coco_evaluator.evaluate()
  117. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP'], 1.0)
  118. def testGetOneMAPWithMatchingGroundtruthAndDetectionsEmptyCrowd(self):
  119. """Tests computing mAP with empty is_crowd array passed in."""
  120. coco_evaluator = coco_evaluation.CocoDetectionEvaluator(
  121. _get_categories_list())
  122. coco_evaluator.add_single_ground_truth_image_info(
  123. image_id='image1',
  124. groundtruth_dict={
  125. standard_fields.InputDataFields.groundtruth_boxes:
  126. np.array([[100., 100., 200., 200.]]),
  127. standard_fields.InputDataFields.groundtruth_classes:
  128. np.array([1]),
  129. standard_fields.InputDataFields.groundtruth_is_crowd:
  130. np.array([])
  131. })
  132. coco_evaluator.add_single_detected_image_info(
  133. image_id='image1',
  134. detections_dict={
  135. standard_fields.DetectionResultFields.detection_boxes:
  136. np.array([[100., 100., 200., 200.]]),
  137. standard_fields.DetectionResultFields.detection_scores:
  138. np.array([.8]),
  139. standard_fields.DetectionResultFields.detection_classes:
  140. np.array([1])
  141. })
  142. metrics = coco_evaluator.evaluate()
  143. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP'], 1.0)
  144. def testRejectionOnDuplicateGroundtruth(self):
  145. """Tests that groundtruth cannot be added more than once for an image."""
  146. coco_evaluator = coco_evaluation.CocoDetectionEvaluator(
  147. _get_categories_list())
  148. # Add groundtruth
  149. image_key1 = 'img1'
  150. groundtruth_boxes1 = np.array([[0, 0, 1, 1], [0, 0, 2, 2], [0, 0, 3, 3]],
  151. dtype=float)
  152. groundtruth_class_labels1 = np.array([1, 3, 1], dtype=int)
  153. coco_evaluator.add_single_ground_truth_image_info(image_key1, {
  154. standard_fields.InputDataFields.groundtruth_boxes:
  155. groundtruth_boxes1,
  156. standard_fields.InputDataFields.groundtruth_classes:
  157. groundtruth_class_labels1
  158. })
  159. groundtruth_lists_len = len(coco_evaluator._groundtruth_list)
  160. # Add groundtruth with the same image id.
  161. coco_evaluator.add_single_ground_truth_image_info(image_key1, {
  162. standard_fields.InputDataFields.groundtruth_boxes:
  163. groundtruth_boxes1,
  164. standard_fields.InputDataFields.groundtruth_classes:
  165. groundtruth_class_labels1
  166. })
  167. self.assertEqual(groundtruth_lists_len,
  168. len(coco_evaluator._groundtruth_list))
  169. def testRejectionOnDuplicateDetections(self):
  170. """Tests that detections cannot be added more than once for an image."""
  171. coco_evaluator = coco_evaluation.CocoDetectionEvaluator(
  172. _get_categories_list())
  173. # Add groundtruth
  174. coco_evaluator.add_single_ground_truth_image_info(
  175. image_id='image1',
  176. groundtruth_dict={
  177. standard_fields.InputDataFields.groundtruth_boxes:
  178. np.array([[99., 100., 200., 200.]]),
  179. standard_fields.InputDataFields.groundtruth_classes: np.array([1])
  180. })
  181. coco_evaluator.add_single_detected_image_info(
  182. image_id='image1',
  183. detections_dict={
  184. standard_fields.DetectionResultFields.detection_boxes:
  185. np.array([[100., 100., 200., 200.]]),
  186. standard_fields.DetectionResultFields.detection_scores:
  187. np.array([.8]),
  188. standard_fields.DetectionResultFields.detection_classes:
  189. np.array([1])
  190. })
  191. detections_lists_len = len(coco_evaluator._detection_boxes_list)
  192. coco_evaluator.add_single_detected_image_info(
  193. image_id='image1', # Note that this image id was previously added.
  194. detections_dict={
  195. standard_fields.DetectionResultFields.detection_boxes:
  196. np.array([[100., 100., 200., 200.]]),
  197. standard_fields.DetectionResultFields.detection_scores:
  198. np.array([.8]),
  199. standard_fields.DetectionResultFields.detection_classes:
  200. np.array([1])
  201. })
  202. self.assertEqual(detections_lists_len,
  203. len(coco_evaluator._detection_boxes_list))
  204. def testExceptionRaisedWithMissingGroundtruth(self):
  205. """Tests that exception is raised for detection with missing groundtruth."""
  206. coco_evaluator = coco_evaluation.CocoDetectionEvaluator(
  207. _get_categories_list())
  208. with self.assertRaises(ValueError):
  209. coco_evaluator.add_single_detected_image_info(
  210. image_id='image1',
  211. detections_dict={
  212. standard_fields.DetectionResultFields.detection_boxes:
  213. np.array([[100., 100., 200., 200.]]),
  214. standard_fields.DetectionResultFields.detection_scores:
  215. np.array([.8]),
  216. standard_fields.DetectionResultFields.detection_classes:
  217. np.array([1])
  218. })
  219. class CocoEvaluationPyFuncTest(tf.test.TestCase):
  220. def testGetOneMAPWithMatchingGroundtruthAndDetections(self):
  221. coco_evaluator = coco_evaluation.CocoDetectionEvaluator(
  222. _get_categories_list())
  223. image_id = tf.placeholder(tf.string, shape=())
  224. groundtruth_boxes = tf.placeholder(tf.float32, shape=(None, 4))
  225. groundtruth_classes = tf.placeholder(tf.float32, shape=(None))
  226. detection_boxes = tf.placeholder(tf.float32, shape=(None, 4))
  227. detection_scores = tf.placeholder(tf.float32, shape=(None))
  228. detection_classes = tf.placeholder(tf.float32, shape=(None))
  229. input_data_fields = standard_fields.InputDataFields
  230. detection_fields = standard_fields.DetectionResultFields
  231. eval_dict = {
  232. input_data_fields.key: image_id,
  233. input_data_fields.groundtruth_boxes: groundtruth_boxes,
  234. input_data_fields.groundtruth_classes: groundtruth_classes,
  235. detection_fields.detection_boxes: detection_boxes,
  236. detection_fields.detection_scores: detection_scores,
  237. detection_fields.detection_classes: detection_classes
  238. }
  239. eval_metric_ops = coco_evaluator.get_estimator_eval_metric_ops(eval_dict)
  240. _, update_op = eval_metric_ops['DetectionBoxes_Precision/mAP']
  241. with self.test_session() as sess:
  242. sess.run(update_op,
  243. feed_dict={
  244. image_id: 'image1',
  245. groundtruth_boxes: np.array([[100., 100., 200., 200.]]),
  246. groundtruth_classes: np.array([1]),
  247. detection_boxes: np.array([[100., 100., 200., 200.]]),
  248. detection_scores: np.array([.8]),
  249. detection_classes: np.array([1])
  250. })
  251. sess.run(update_op,
  252. feed_dict={
  253. image_id: 'image2',
  254. groundtruth_boxes: np.array([[50., 50., 100., 100.]]),
  255. groundtruth_classes: np.array([3]),
  256. detection_boxes: np.array([[50., 50., 100., 100.]]),
  257. detection_scores: np.array([.7]),
  258. detection_classes: np.array([3])
  259. })
  260. sess.run(update_op,
  261. feed_dict={
  262. image_id: 'image3',
  263. groundtruth_boxes: np.array([[25., 25., 50., 50.]]),
  264. groundtruth_classes: np.array([2]),
  265. detection_boxes: np.array([[25., 25., 50., 50.]]),
  266. detection_scores: np.array([.9]),
  267. detection_classes: np.array([2])
  268. })
  269. metrics = {}
  270. for key, (value_op, _) in eval_metric_ops.iteritems():
  271. metrics[key] = value_op
  272. metrics = sess.run(metrics)
  273. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP'], 1.0)
  274. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP@.50IOU'], 1.0)
  275. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP@.75IOU'], 1.0)
  276. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP (large)'], 1.0)
  277. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP (medium)'],
  278. 1.0)
  279. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP (small)'], 1.0)
  280. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@1'], 1.0)
  281. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@10'], 1.0)
  282. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100'], 1.0)
  283. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100 (large)'], 1.0)
  284. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100 (medium)'],
  285. 1.0)
  286. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100 (small)'], 1.0)
  287. self.assertFalse(coco_evaluator._groundtruth_list)
  288. self.assertFalse(coco_evaluator._detection_boxes_list)
  289. self.assertFalse(coco_evaluator._image_ids)
  290. def testGetOneMAPWithMatchingGroundtruthAndDetectionsIsAnnotated(self):
  291. coco_evaluator = coco_evaluation.CocoDetectionEvaluator(
  292. _get_categories_list())
  293. image_id = tf.placeholder(tf.string, shape=())
  294. groundtruth_boxes = tf.placeholder(tf.float32, shape=(None, 4))
  295. groundtruth_classes = tf.placeholder(tf.float32, shape=(None))
  296. is_annotated = tf.placeholder(tf.bool, shape=())
  297. detection_boxes = tf.placeholder(tf.float32, shape=(None, 4))
  298. detection_scores = tf.placeholder(tf.float32, shape=(None))
  299. detection_classes = tf.placeholder(tf.float32, shape=(None))
  300. input_data_fields = standard_fields.InputDataFields
  301. detection_fields = standard_fields.DetectionResultFields
  302. eval_dict = {
  303. input_data_fields.key: image_id,
  304. input_data_fields.groundtruth_boxes: groundtruth_boxes,
  305. input_data_fields.groundtruth_classes: groundtruth_classes,
  306. 'is_annotated': is_annotated,
  307. detection_fields.detection_boxes: detection_boxes,
  308. detection_fields.detection_scores: detection_scores,
  309. detection_fields.detection_classes: detection_classes
  310. }
  311. eval_metric_ops = coco_evaluator.get_estimator_eval_metric_ops(eval_dict)
  312. _, update_op = eval_metric_ops['DetectionBoxes_Precision/mAP']
  313. with self.test_session() as sess:
  314. sess.run(update_op,
  315. feed_dict={
  316. image_id: 'image1',
  317. groundtruth_boxes: np.array([[100., 100., 200., 200.]]),
  318. groundtruth_classes: np.array([1]),
  319. is_annotated: True,
  320. detection_boxes: np.array([[100., 100., 200., 200.]]),
  321. detection_scores: np.array([.8]),
  322. detection_classes: np.array([1])
  323. })
  324. sess.run(update_op,
  325. feed_dict={
  326. image_id: 'image2',
  327. groundtruth_boxes: np.array([[50., 50., 100., 100.]]),
  328. groundtruth_classes: np.array([3]),
  329. is_annotated: True,
  330. detection_boxes: np.array([[50., 50., 100., 100.]]),
  331. detection_scores: np.array([.7]),
  332. detection_classes: np.array([3])
  333. })
  334. sess.run(update_op,
  335. feed_dict={
  336. image_id: 'image3',
  337. groundtruth_boxes: np.array([[25., 25., 50., 50.]]),
  338. groundtruth_classes: np.array([2]),
  339. is_annotated: True,
  340. detection_boxes: np.array([[25., 25., 50., 50.]]),
  341. detection_scores: np.array([.9]),
  342. detection_classes: np.array([2])
  343. })
  344. sess.run(update_op,
  345. feed_dict={
  346. image_id: 'image4',
  347. groundtruth_boxes: np.zeros((0, 4)),
  348. groundtruth_classes: np.zeros((0)),
  349. is_annotated: False, # Note that this image isn't annotated.
  350. detection_boxes: np.array([[25., 25., 50., 50.],
  351. [25., 25., 70., 50.],
  352. [25., 25., 80., 50.],
  353. [25., 25., 90., 50.]]),
  354. detection_scores: np.array([0.6, 0.7, 0.8, 0.9]),
  355. detection_classes: np.array([1, 2, 2, 3])
  356. })
  357. metrics = {}
  358. for key, (value_op, _) in eval_metric_ops.iteritems():
  359. metrics[key] = value_op
  360. metrics = sess.run(metrics)
  361. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP'], 1.0)
  362. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP@.50IOU'], 1.0)
  363. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP@.75IOU'], 1.0)
  364. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP (large)'], 1.0)
  365. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP (medium)'],
  366. 1.0)
  367. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP (small)'], 1.0)
  368. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@1'], 1.0)
  369. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@10'], 1.0)
  370. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100'], 1.0)
  371. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100 (large)'], 1.0)
  372. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100 (medium)'],
  373. 1.0)
  374. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100 (small)'], 1.0)
  375. self.assertFalse(coco_evaluator._groundtruth_list)
  376. self.assertFalse(coco_evaluator._detection_boxes_list)
  377. self.assertFalse(coco_evaluator._image_ids)
  378. def testGetOneMAPWithMatchingGroundtruthAndDetectionsPadded(self):
  379. coco_evaluator = coco_evaluation.CocoDetectionEvaluator(
  380. _get_categories_list())
  381. image_id = tf.placeholder(tf.string, shape=())
  382. groundtruth_boxes = tf.placeholder(tf.float32, shape=(None, 4))
  383. groundtruth_classes = tf.placeholder(tf.float32, shape=(None))
  384. detection_boxes = tf.placeholder(tf.float32, shape=(None, 4))
  385. detection_scores = tf.placeholder(tf.float32, shape=(None))
  386. detection_classes = tf.placeholder(tf.float32, shape=(None))
  387. input_data_fields = standard_fields.InputDataFields
  388. detection_fields = standard_fields.DetectionResultFields
  389. eval_dict = {
  390. input_data_fields.key: image_id,
  391. input_data_fields.groundtruth_boxes: groundtruth_boxes,
  392. input_data_fields.groundtruth_classes: groundtruth_classes,
  393. detection_fields.detection_boxes: detection_boxes,
  394. detection_fields.detection_scores: detection_scores,
  395. detection_fields.detection_classes: detection_classes
  396. }
  397. eval_metric_ops = coco_evaluator.get_estimator_eval_metric_ops(eval_dict)
  398. _, update_op = eval_metric_ops['DetectionBoxes_Precision/mAP']
  399. with self.test_session() as sess:
  400. sess.run(
  401. update_op,
  402. feed_dict={
  403. image_id:
  404. 'image1',
  405. groundtruth_boxes:
  406. np.array([[100., 100., 200., 200.], [-1, -1, -1, -1]]),
  407. groundtruth_classes:
  408. np.array([1, -1]),
  409. detection_boxes:
  410. np.array([[100., 100., 200., 200.], [0., 0., 0., 0.]]),
  411. detection_scores:
  412. np.array([.8, 0.]),
  413. detection_classes:
  414. np.array([1, -1])
  415. })
  416. sess.run(
  417. update_op,
  418. feed_dict={
  419. image_id:
  420. 'image2',
  421. groundtruth_boxes:
  422. np.array([[50., 50., 100., 100.], [-1, -1, -1, -1]]),
  423. groundtruth_classes:
  424. np.array([3, -1]),
  425. detection_boxes:
  426. np.array([[50., 50., 100., 100.], [0., 0., 0., 0.]]),
  427. detection_scores:
  428. np.array([.7, 0.]),
  429. detection_classes:
  430. np.array([3, -1])
  431. })
  432. sess.run(
  433. update_op,
  434. feed_dict={
  435. image_id:
  436. 'image3',
  437. groundtruth_boxes:
  438. np.array([[25., 25., 50., 50.], [10., 10., 15., 15.]]),
  439. groundtruth_classes:
  440. np.array([2, 2]),
  441. detection_boxes:
  442. np.array([[25., 25., 50., 50.], [10., 10., 15., 15.]]),
  443. detection_scores:
  444. np.array([.95, .9]),
  445. detection_classes:
  446. np.array([2, 2])
  447. })
  448. metrics = {}
  449. for key, (value_op, _) in eval_metric_ops.iteritems():
  450. metrics[key] = value_op
  451. metrics = sess.run(metrics)
  452. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP'], 1.0)
  453. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP@.50IOU'], 1.0)
  454. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP@.75IOU'], 1.0)
  455. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP (large)'], 1.0)
  456. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP (medium)'],
  457. 1.0)
  458. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP (small)'], 1.0)
  459. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@1'], 0.83333331)
  460. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@10'], 1.0)
  461. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100'], 1.0)
  462. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100 (large)'], 1.0)
  463. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100 (medium)'],
  464. 1.0)
  465. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100 (small)'], 1.0)
  466. self.assertFalse(coco_evaluator._groundtruth_list)
  467. self.assertFalse(coco_evaluator._detection_boxes_list)
  468. self.assertFalse(coco_evaluator._image_ids)
  469. def testGetOneMAPWithMatchingGroundtruthAndDetectionsBatched(self):
  470. coco_evaluator = coco_evaluation.CocoDetectionEvaluator(
  471. _get_categories_list())
  472. batch_size = 3
  473. image_id = tf.placeholder(tf.string, shape=(batch_size))
  474. groundtruth_boxes = tf.placeholder(tf.float32, shape=(batch_size, None, 4))
  475. groundtruth_classes = tf.placeholder(tf.float32, shape=(batch_size, None))
  476. detection_boxes = tf.placeholder(tf.float32, shape=(batch_size, None, 4))
  477. detection_scores = tf.placeholder(tf.float32, shape=(batch_size, None))
  478. detection_classes = tf.placeholder(tf.float32, shape=(batch_size, None))
  479. input_data_fields = standard_fields.InputDataFields
  480. detection_fields = standard_fields.DetectionResultFields
  481. eval_dict = {
  482. input_data_fields.key: image_id,
  483. input_data_fields.groundtruth_boxes: groundtruth_boxes,
  484. input_data_fields.groundtruth_classes: groundtruth_classes,
  485. detection_fields.detection_boxes: detection_boxes,
  486. detection_fields.detection_scores: detection_scores,
  487. detection_fields.detection_classes: detection_classes
  488. }
  489. eval_metric_ops = coco_evaluator.get_estimator_eval_metric_ops(eval_dict)
  490. _, update_op = eval_metric_ops['DetectionBoxes_Precision/mAP']
  491. with self.test_session() as sess:
  492. sess.run(update_op,
  493. feed_dict={
  494. image_id: ['image1', 'image2', 'image3'],
  495. groundtruth_boxes: np.array([[[100., 100., 200., 200.]],
  496. [[50., 50., 100., 100.]],
  497. [[25., 25., 50., 50.]]]),
  498. groundtruth_classes: np.array([[1], [3], [2]]),
  499. detection_boxes: np.array([[[100., 100., 200., 200.]],
  500. [[50., 50., 100., 100.]],
  501. [[25., 25., 50., 50.]]]),
  502. detection_scores: np.array([[.8], [.7], [.9]]),
  503. detection_classes: np.array([[1], [3], [2]])
  504. })
  505. metrics = {}
  506. for key, (value_op, _) in eval_metric_ops.iteritems():
  507. metrics[key] = value_op
  508. metrics = sess.run(metrics)
  509. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP'], 1.0)
  510. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP@.50IOU'], 1.0)
  511. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP@.75IOU'], 1.0)
  512. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP (large)'], 1.0)
  513. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP (medium)'],
  514. 1.0)
  515. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP (small)'], 1.0)
  516. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@1'], 1.0)
  517. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@10'], 1.0)
  518. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100'], 1.0)
  519. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100 (large)'], 1.0)
  520. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100 (medium)'],
  521. 1.0)
  522. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100 (small)'], 1.0)
  523. self.assertFalse(coco_evaluator._groundtruth_list)
  524. self.assertFalse(coco_evaluator._detection_boxes_list)
  525. self.assertFalse(coco_evaluator._image_ids)
  526. def testGetOneMAPWithMatchingGroundtruthAndDetectionsPaddedBatches(self):
  527. coco_evaluator = coco_evaluation.CocoDetectionEvaluator(
  528. _get_categories_list())
  529. batch_size = 3
  530. image_id = tf.placeholder(tf.string, shape=(batch_size))
  531. groundtruth_boxes = tf.placeholder(tf.float32, shape=(batch_size, None, 4))
  532. groundtruth_classes = tf.placeholder(tf.float32, shape=(batch_size, None))
  533. num_gt_boxes_per_image = tf.placeholder(tf.int32, shape=(None))
  534. detection_boxes = tf.placeholder(tf.float32, shape=(batch_size, None, 4))
  535. detection_scores = tf.placeholder(tf.float32, shape=(batch_size, None))
  536. detection_classes = tf.placeholder(tf.float32, shape=(batch_size, None))
  537. num_det_boxes_per_image = tf.placeholder(tf.int32, shape=(None))
  538. input_data_fields = standard_fields.InputDataFields
  539. detection_fields = standard_fields.DetectionResultFields
  540. eval_dict = {
  541. input_data_fields.key: image_id,
  542. input_data_fields.groundtruth_boxes: groundtruth_boxes,
  543. input_data_fields.groundtruth_classes: groundtruth_classes,
  544. detection_fields.detection_boxes: detection_boxes,
  545. detection_fields.detection_scores: detection_scores,
  546. detection_fields.detection_classes: detection_classes,
  547. 'num_groundtruth_boxes_per_image': num_gt_boxes_per_image,
  548. 'num_det_boxes_per_image': num_det_boxes_per_image
  549. }
  550. eval_metric_ops = coco_evaluator.get_estimator_eval_metric_ops(eval_dict)
  551. _, update_op = eval_metric_ops['DetectionBoxes_Precision/mAP']
  552. with self.test_session() as sess:
  553. sess.run(
  554. update_op,
  555. feed_dict={
  556. image_id: ['image1', 'image2', 'image3'],
  557. groundtruth_boxes:
  558. np.array([[[100., 100., 200., 200.], [-1, -1, -1, -1]],
  559. [[50., 50., 100., 100.], [-1, -1, -1, -1]],
  560. [[25., 25., 50., 50.], [10., 10., 15., 15.]]]),
  561. groundtruth_classes:
  562. np.array([[1, -1], [3, -1], [2, 2]]),
  563. num_gt_boxes_per_image:
  564. np.array([1, 1, 2]),
  565. detection_boxes:
  566. np.array([[[100., 100., 200., 200.],
  567. [0., 0., 0., 0.],
  568. [0., 0., 0., 0.]],
  569. [[50., 50., 100., 100.],
  570. [0., 0., 0., 0.],
  571. [0., 0., 0., 0.]],
  572. [[25., 25., 50., 50.],
  573. [10., 10., 15., 15.],
  574. [10., 10., 15., 15.]]]),
  575. detection_scores:
  576. np.array([[.8, 0., 0.], [.7, 0., 0.], [.95, .9, 0.9]]),
  577. detection_classes:
  578. np.array([[1, -1, -1], [3, -1, -1], [2, 2, 2]]),
  579. num_det_boxes_per_image:
  580. np.array([1, 1, 3]),
  581. })
  582. # Check the number of bounding boxes added.
  583. self.assertEqual(len(coco_evaluator._groundtruth_list), 4)
  584. self.assertEqual(len(coco_evaluator._detection_boxes_list), 5)
  585. metrics = {}
  586. for key, (value_op, _) in eval_metric_ops.iteritems():
  587. metrics[key] = value_op
  588. metrics = sess.run(metrics)
  589. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP'], 1.0)
  590. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP@.50IOU'], 1.0)
  591. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP@.75IOU'], 1.0)
  592. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP (large)'], 1.0)
  593. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP (medium)'],
  594. 1.0)
  595. self.assertAlmostEqual(metrics['DetectionBoxes_Precision/mAP (small)'], 1.0)
  596. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@1'], 0.83333331)
  597. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@10'], 1.0)
  598. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100'], 1.0)
  599. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100 (large)'], 1.0)
  600. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100 (medium)'],
  601. 1.0)
  602. self.assertAlmostEqual(metrics['DetectionBoxes_Recall/AR@100 (small)'], 1.0)
  603. self.assertFalse(coco_evaluator._groundtruth_list)
  604. self.assertFalse(coco_evaluator._detection_boxes_list)
  605. self.assertFalse(coco_evaluator._image_ids)
  606. class CocoMaskEvaluationTest(tf.test.TestCase):
  607. def testGetOneMAPWithMatchingGroundtruthAndDetections(self):
  608. coco_evaluator = coco_evaluation.CocoMaskEvaluator(_get_categories_list())
  609. coco_evaluator.add_single_ground_truth_image_info(
  610. image_id='image1',
  611. groundtruth_dict={
  612. standard_fields.InputDataFields.groundtruth_boxes:
  613. np.array([[100., 100., 200., 200.]]),
  614. standard_fields.InputDataFields.groundtruth_classes: np.array([1]),
  615. standard_fields.InputDataFields.groundtruth_instance_masks:
  616. np.pad(np.ones([1, 100, 100], dtype=np.uint8),
  617. ((0, 0), (10, 10), (10, 10)), mode='constant')
  618. })
  619. coco_evaluator.add_single_detected_image_info(
  620. image_id='image1',
  621. detections_dict={
  622. standard_fields.DetectionResultFields.detection_boxes:
  623. np.array([[100., 100., 200., 200.]]),
  624. standard_fields.DetectionResultFields.detection_scores:
  625. np.array([.8]),
  626. standard_fields.DetectionResultFields.detection_classes:
  627. np.array([1]),
  628. standard_fields.DetectionResultFields.detection_masks:
  629. np.pad(np.ones([1, 100, 100], dtype=np.uint8),
  630. ((0, 0), (10, 10), (10, 10)), mode='constant')
  631. })
  632. coco_evaluator.add_single_ground_truth_image_info(
  633. image_id='image2',
  634. groundtruth_dict={
  635. standard_fields.InputDataFields.groundtruth_boxes:
  636. np.array([[50., 50., 100., 100.]]),
  637. standard_fields.InputDataFields.groundtruth_classes: np.array([1]),
  638. standard_fields.InputDataFields.groundtruth_instance_masks:
  639. np.pad(np.ones([1, 50, 50], dtype=np.uint8),
  640. ((0, 0), (10, 10), (10, 10)), mode='constant')
  641. })
  642. coco_evaluator.add_single_detected_image_info(
  643. image_id='image2',
  644. detections_dict={
  645. standard_fields.DetectionResultFields.detection_boxes:
  646. np.array([[50., 50., 100., 100.]]),
  647. standard_fields.DetectionResultFields.detection_scores:
  648. np.array([.8]),
  649. standard_fields.DetectionResultFields.detection_classes:
  650. np.array([1]),
  651. standard_fields.DetectionResultFields.detection_masks:
  652. np.pad(np.ones([1, 50, 50], dtype=np.uint8),
  653. ((0, 0), (10, 10), (10, 10)), mode='constant')
  654. })
  655. coco_evaluator.add_single_ground_truth_image_info(
  656. image_id='image3',
  657. groundtruth_dict={
  658. standard_fields.InputDataFields.groundtruth_boxes:
  659. np.array([[25., 25., 50., 50.]]),
  660. standard_fields.InputDataFields.groundtruth_classes: np.array([1]),
  661. standard_fields.InputDataFields.groundtruth_instance_masks:
  662. np.pad(np.ones([1, 25, 25], dtype=np.uint8),
  663. ((0, 0), (10, 10), (10, 10)), mode='constant')
  664. })
  665. coco_evaluator.add_single_detected_image_info(
  666. image_id='image3',
  667. detections_dict={
  668. standard_fields.DetectionResultFields.detection_boxes:
  669. np.array([[25., 25., 50., 50.]]),
  670. standard_fields.DetectionResultFields.detection_scores:
  671. np.array([.8]),
  672. standard_fields.DetectionResultFields.detection_classes:
  673. np.array([1]),
  674. standard_fields.DetectionResultFields.detection_masks:
  675. np.pad(np.ones([1, 25, 25], dtype=np.uint8),
  676. ((0, 0), (10, 10), (10, 10)), mode='constant')
  677. })
  678. metrics = coco_evaluator.evaluate()
  679. self.assertAlmostEqual(metrics['DetectionMasks_Precision/mAP'], 1.0)
  680. coco_evaluator.clear()
  681. self.assertFalse(coco_evaluator._image_id_to_mask_shape_map)
  682. self.assertFalse(coco_evaluator._image_ids_with_detections)
  683. self.assertFalse(coco_evaluator._groundtruth_list)
  684. self.assertFalse(coco_evaluator._detection_masks_list)
  685. class CocoMaskEvaluationPyFuncTest(tf.test.TestCase):
  686. def testGetOneMAPWithMatchingGroundtruthAndDetections(self):
  687. coco_evaluator = coco_evaluation.CocoMaskEvaluator(_get_categories_list())
  688. image_id = tf.placeholder(tf.string, shape=())
  689. groundtruth_boxes = tf.placeholder(tf.float32, shape=(None, 4))
  690. groundtruth_classes = tf.placeholder(tf.float32, shape=(None))
  691. groundtruth_masks = tf.placeholder(tf.uint8, shape=(None, None, None))
  692. detection_scores = tf.placeholder(tf.float32, shape=(None))
  693. detection_classes = tf.placeholder(tf.float32, shape=(None))
  694. detection_masks = tf.placeholder(tf.uint8, shape=(None, None, None))
  695. input_data_fields = standard_fields.InputDataFields
  696. detection_fields = standard_fields.DetectionResultFields
  697. eval_dict = {
  698. input_data_fields.key: image_id,
  699. input_data_fields.groundtruth_boxes: groundtruth_boxes,
  700. input_data_fields.groundtruth_classes: groundtruth_classes,
  701. input_data_fields.groundtruth_instance_masks: groundtruth_masks,
  702. detection_fields.detection_scores: detection_scores,
  703. detection_fields.detection_classes: detection_classes,
  704. detection_fields.detection_masks: detection_masks,
  705. }
  706. eval_metric_ops = coco_evaluator.get_estimator_eval_metric_ops(eval_dict)
  707. _, update_op = eval_metric_ops['DetectionMasks_Precision/mAP']
  708. with self.test_session() as sess:
  709. sess.run(
  710. update_op,
  711. feed_dict={
  712. image_id:
  713. 'image1',
  714. groundtruth_boxes:
  715. np.array([[100., 100., 200., 200.], [50., 50., 100., 100.]]),
  716. groundtruth_classes:
  717. np.array([1, 2]),
  718. groundtruth_masks:
  719. np.stack([
  720. np.pad(
  721. np.ones([100, 100], dtype=np.uint8), ((10, 10),
  722. (10, 10)),
  723. mode='constant'),
  724. np.pad(
  725. np.ones([50, 50], dtype=np.uint8), ((0, 70), (0, 70)),
  726. mode='constant')
  727. ]),
  728. detection_scores:
  729. np.array([.9, .8]),
  730. detection_classes:
  731. np.array([2, 1]),
  732. detection_masks:
  733. np.stack([
  734. np.pad(
  735. np.ones([50, 50], dtype=np.uint8), ((0, 70), (0, 70)),
  736. mode='constant'),
  737. np.pad(
  738. np.ones([100, 100], dtype=np.uint8), ((10, 10),
  739. (10, 10)),
  740. mode='constant'),
  741. ])
  742. })
  743. sess.run(update_op,
  744. feed_dict={
  745. image_id: 'image2',
  746. groundtruth_boxes: np.array([[50., 50., 100., 100.]]),
  747. groundtruth_classes: np.array([1]),
  748. groundtruth_masks: np.pad(np.ones([1, 50, 50],
  749. dtype=np.uint8),
  750. ((0, 0), (10, 10), (10, 10)),
  751. mode='constant'),
  752. detection_scores: np.array([.8]),
  753. detection_classes: np.array([1]),
  754. detection_masks: np.pad(np.ones([1, 50, 50], dtype=np.uint8),
  755. ((0, 0), (10, 10), (10, 10)),
  756. mode='constant')
  757. })
  758. sess.run(update_op,
  759. feed_dict={
  760. image_id: 'image3',
  761. groundtruth_boxes: np.array([[25., 25., 50., 50.]]),
  762. groundtruth_classes: np.array([1]),
  763. groundtruth_masks: np.pad(np.ones([1, 25, 25],
  764. dtype=np.uint8),
  765. ((0, 0), (10, 10), (10, 10)),
  766. mode='constant'),
  767. detection_scores: np.array([.8]),
  768. detection_classes: np.array([1]),
  769. detection_masks: np.pad(np.ones([1, 25, 25],
  770. dtype=np.uint8),
  771. ((0, 0), (10, 10), (10, 10)),
  772. mode='constant')
  773. })
  774. metrics = {}
  775. for key, (value_op, _) in eval_metric_ops.iteritems():
  776. metrics[key] = value_op
  777. metrics = sess.run(metrics)
  778. self.assertAlmostEqual(metrics['DetectionMasks_Precision/mAP'], 1.0)
  779. self.assertAlmostEqual(metrics['DetectionMasks_Precision/mAP@.50IOU'], 1.0)
  780. self.assertAlmostEqual(metrics['DetectionMasks_Precision/mAP@.75IOU'], 1.0)
  781. self.assertAlmostEqual(metrics['DetectionMasks_Precision/mAP (large)'], 1.0)
  782. self.assertAlmostEqual(metrics['DetectionMasks_Precision/mAP (medium)'],
  783. 1.0)
  784. self.assertAlmostEqual(metrics['DetectionMasks_Precision/mAP (small)'], 1.0)
  785. self.assertAlmostEqual(metrics['DetectionMasks_Recall/AR@1'], 1.0)
  786. self.assertAlmostEqual(metrics['DetectionMasks_Recall/AR@10'], 1.0)
  787. self.assertAlmostEqual(metrics['DetectionMasks_Recall/AR@100'], 1.0)
  788. self.assertAlmostEqual(metrics['DetectionMasks_Recall/AR@100 (large)'], 1.0)
  789. self.assertAlmostEqual(metrics['DetectionMasks_Recall/AR@100 (medium)'],
  790. 1.0)
  791. self.assertAlmostEqual(metrics['DetectionMasks_Recall/AR@100 (small)'], 1.0)
  792. self.assertFalse(coco_evaluator._groundtruth_list)
  793. self.assertFalse(coco_evaluator._image_ids_with_detections)
  794. self.assertFalse(coco_evaluator._image_id_to_mask_shape_map)
  795. self.assertFalse(coco_evaluator._detection_masks_list)
  796. def testGetOneMAPWithMatchingGroundtruthAndDetectionsBatched(self):
  797. coco_evaluator = coco_evaluation.CocoMaskEvaluator(_get_categories_list())
  798. batch_size = 3
  799. image_id = tf.placeholder(tf.string, shape=(batch_size))
  800. groundtruth_boxes = tf.placeholder(tf.float32, shape=(batch_size, None, 4))
  801. groundtruth_classes = tf.placeholder(tf.float32, shape=(batch_size, None))
  802. groundtruth_masks = tf.placeholder(
  803. tf.uint8, shape=(batch_size, None, None, None))
  804. detection_scores = tf.placeholder(tf.float32, shape=(batch_size, None))
  805. detection_classes = tf.placeholder(tf.float32, shape=(batch_size, None))
  806. detection_masks = tf.placeholder(
  807. tf.uint8, shape=(batch_size, None, None, None))
  808. input_data_fields = standard_fields.InputDataFields
  809. detection_fields = standard_fields.DetectionResultFields
  810. eval_dict = {
  811. input_data_fields.key: image_id,
  812. input_data_fields.groundtruth_boxes: groundtruth_boxes,
  813. input_data_fields.groundtruth_classes: groundtruth_classes,
  814. input_data_fields.groundtruth_instance_masks: groundtruth_masks,
  815. detection_fields.detection_scores: detection_scores,
  816. detection_fields.detection_classes: detection_classes,
  817. detection_fields.detection_masks: detection_masks,
  818. }
  819. eval_metric_ops = coco_evaluator.get_estimator_eval_metric_ops(eval_dict)
  820. _, update_op = eval_metric_ops['DetectionMasks_Precision/mAP']
  821. with self.test_session() as sess:
  822. sess.run(
  823. update_op,
  824. feed_dict={
  825. image_id: ['image1', 'image2', 'image3'],
  826. groundtruth_boxes:
  827. np.array([[[100., 100., 200., 200.]],
  828. [[50., 50., 100., 100.]],
  829. [[25., 25., 50., 50.]]]),
  830. groundtruth_classes:
  831. np.array([[1], [1], [1]]),
  832. groundtruth_masks:
  833. np.stack([
  834. np.pad(
  835. np.ones([1, 100, 100], dtype=np.uint8),
  836. ((0, 0), (0, 0), (0, 0)),
  837. mode='constant'),
  838. np.pad(
  839. np.ones([1, 50, 50], dtype=np.uint8),
  840. ((0, 0), (25, 25), (25, 25)),
  841. mode='constant'),
  842. np.pad(
  843. np.ones([1, 25, 25], dtype=np.uint8),
  844. ((0, 0), (37, 38), (37, 38)),
  845. mode='constant')
  846. ],
  847. axis=0),
  848. detection_scores:
  849. np.array([[.8], [.8], [.8]]),
  850. detection_classes:
  851. np.array([[1], [1], [1]]),
  852. detection_masks:
  853. np.stack([
  854. np.pad(
  855. np.ones([1, 100, 100], dtype=np.uint8),
  856. ((0, 0), (0, 0), (0, 0)),
  857. mode='constant'),
  858. np.pad(
  859. np.ones([1, 50, 50], dtype=np.uint8),
  860. ((0, 0), (25, 25), (25, 25)),
  861. mode='constant'),
  862. np.pad(
  863. np.ones([1, 25, 25], dtype=np.uint8),
  864. ((0, 0), (37, 38), (37, 38)),
  865. mode='constant')
  866. ],
  867. axis=0)
  868. })
  869. metrics = {}
  870. for key, (value_op, _) in eval_metric_ops.iteritems():
  871. metrics[key] = value_op
  872. metrics = sess.run(metrics)
  873. self.assertAlmostEqual(metrics['DetectionMasks_Precision/mAP'], 1.0)
  874. self.assertAlmostEqual(metrics['DetectionMasks_Precision/mAP@.50IOU'], 1.0)
  875. self.assertAlmostEqual(metrics['DetectionMasks_Precision/mAP@.75IOU'], 1.0)
  876. self.assertAlmostEqual(metrics['DetectionMasks_Precision/mAP (large)'], 1.0)
  877. self.assertAlmostEqual(metrics['DetectionMasks_Precision/mAP (medium)'],
  878. 1.0)
  879. self.assertAlmostEqual(metrics['DetectionMasks_Precision/mAP (small)'], 1.0)
  880. self.assertAlmostEqual(metrics['DetectionMasks_Recall/AR@1'], 1.0)
  881. self.assertAlmostEqual(metrics['DetectionMasks_Recall/AR@10'], 1.0)
  882. self.assertAlmostEqual(metrics['DetectionMasks_Recall/AR@100'], 1.0)
  883. self.assertAlmostEqual(metrics['DetectionMasks_Recall/AR@100 (large)'], 1.0)
  884. self.assertAlmostEqual(metrics['DetectionMasks_Recall/AR@100 (medium)'],
  885. 1.0)
  886. self.assertAlmostEqual(metrics['DetectionMasks_Recall/AR@100 (small)'], 1.0)
  887. self.assertFalse(coco_evaluator._groundtruth_list)
  888. self.assertFalse(coco_evaluator._image_ids_with_detections)
  889. self.assertFalse(coco_evaluator._image_id_to_mask_shape_map)
  890. self.assertFalse(coco_evaluator._detection_masks_list)
  891. if __name__ == '__main__':
  892. tf.test.main()