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.

148 lines
6.5 KiB

6 years ago
  1. # Copyright 2019 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 calibration_builder."""
  16. import numpy as np
  17. from scipy import interpolate
  18. import tensorflow as tf
  19. from object_detection.builders import calibration_builder
  20. from object_detection.protos import calibration_pb2
  21. class CalibrationBuilderTest(tf.test.TestCase):
  22. def test_tf_linear_interp1d_map(self):
  23. """Tests TF linear interpolation mapping to a single number."""
  24. with self.test_session() as sess:
  25. tf_x = tf.constant([0., 0.5, 1.])
  26. tf_y = tf.constant([0.5, 0.5, 0.5])
  27. new_x = tf.constant([0., 0.25, 0.5, 0.75, 1.])
  28. tf_map_outputs = calibration_builder._tf_linear_interp1d(
  29. new_x, tf_x, tf_y)
  30. tf_map_outputs_np = sess.run([tf_map_outputs])
  31. self.assertAllClose(tf_map_outputs_np, [[0.5, 0.5, 0.5, 0.5, 0.5]])
  32. def test_tf_linear_interp1d_interpolate(self):
  33. """Tests TF 1d linear interpolation not mapping to a single number."""
  34. with self.test_session() as sess:
  35. tf_x = tf.constant([0., 0.5, 1.])
  36. tf_y = tf.constant([0.6, 0.7, 1.0])
  37. new_x = tf.constant([0., 0.25, 0.5, 0.75, 1.])
  38. tf_interpolate_outputs = calibration_builder._tf_linear_interp1d(
  39. new_x, tf_x, tf_y)
  40. tf_interpolate_outputs_np = sess.run([tf_interpolate_outputs])
  41. self.assertAllClose(tf_interpolate_outputs_np, [[0.6, 0.65, 0.7, 0.85, 1.]])
  42. @staticmethod
  43. def _get_scipy_interp1d(new_x, x, y):
  44. """Helper performing 1d linear interpolation using SciPy."""
  45. interpolation1d_fn = interpolate.interp1d(x, y)
  46. return interpolation1d_fn(new_x)
  47. def _get_tf_interp1d(self, new_x, x, y):
  48. """Helper performing 1d linear interpolation using Tensorflow."""
  49. with self.test_session() as sess:
  50. tf_interp_outputs = calibration_builder._tf_linear_interp1d(
  51. tf.convert_to_tensor(new_x, dtype=tf.float32),
  52. tf.convert_to_tensor(x, dtype=tf.float32),
  53. tf.convert_to_tensor(y, dtype=tf.float32))
  54. np_tf_interp_outputs = sess.run(tf_interp_outputs)
  55. return np_tf_interp_outputs
  56. def test_tf_linear_interp1d_against_scipy_map(self):
  57. """Tests parity of TF linear interpolation with SciPy for simple mapping."""
  58. length = 10
  59. np_x = np.linspace(0, 1, length)
  60. # Mapping all numbers to 0.5
  61. np_y_map = np.repeat(0.5, length)
  62. # Scipy and TF interpolations
  63. test_data_np = np.linspace(0, 1, length * 10)
  64. scipy_map_outputs = self._get_scipy_interp1d(test_data_np, np_x, np_y_map)
  65. np_tf_map_outputs = self._get_tf_interp1d(test_data_np, np_x, np_y_map)
  66. self.assertAllClose(scipy_map_outputs, np_tf_map_outputs)
  67. def test_tf_linear_interp1d_against_scipy_interpolate(self):
  68. """Tests parity of TF linear interpolation with SciPy."""
  69. length = 10
  70. np_x = np.linspace(0, 1, length)
  71. # Requires interpolation over 0.5 to 1 domain
  72. np_y_interp = np.linspace(0.5, 1, length)
  73. # Scipy interpolation for comparison
  74. test_data_np = np.linspace(0, 1, length * 10)
  75. scipy_interp_outputs = self._get_scipy_interp1d(test_data_np, np_x,
  76. np_y_interp)
  77. np_tf_interp_outputs = self._get_tf_interp1d(test_data_np, np_x,
  78. np_y_interp)
  79. self.assertAllClose(scipy_interp_outputs, np_tf_interp_outputs)
  80. @staticmethod
  81. def _add_function_approximation_to_calibration_proto(calibration_proto,
  82. x_array,
  83. y_array,
  84. class_label):
  85. """Adds a function approximation to calibration proto for a class label."""
  86. # Per-class calibration.
  87. if class_label:
  88. label_function_approximation = (calibration_proto
  89. .label_function_approximations
  90. .label_xy_pairs_map[class_label])
  91. # Class-agnostic calibration.
  92. else:
  93. label_function_approximation = (calibration_proto
  94. .function_approximation
  95. .x_y_pairs)
  96. for x, y in zip(x_array, y_array):
  97. x_y_pair_message = label_function_approximation.x_y_pair.add()
  98. x_y_pair_message.x = x
  99. x_y_pair_message.y = y
  100. def test_class_agnostic_function_approximation(self):
  101. """Ensures that calibration appropriate values, regardless of class."""
  102. # Generate fake calibration proto. For this interpolation, any input on
  103. # [0.0, 0.5] should be divided by 2 and any input on (0.5, 1.0] should have
  104. # 0.25 subtracted from it.
  105. class_agnostic_x = np.asarray([0.0, 0.5, 1.0])
  106. class_agnostic_y = np.asarray([0.0, 0.25, 0.75])
  107. calibration_config = calibration_pb2.CalibrationConfig()
  108. self._add_function_approximation_to_calibration_proto(calibration_config,
  109. class_agnostic_x,
  110. class_agnostic_y,
  111. class_label=None)
  112. od_graph = tf.Graph()
  113. with self.test_session(graph=od_graph) as sess:
  114. calibration_fn = calibration_builder.build(calibration_config)
  115. # batch_size = 2, num_classes = 2, num_anchors = 2.
  116. class_predictions_with_background = tf.constant(
  117. [[[0.1, 0.2, 0.3],
  118. [0.4, 0.5, 0.0]],
  119. [[0.6, 0.7, 0.8],
  120. [0.9, 1.0, 1.0]]], dtype=tf.float32)
  121. # Everything should map to 0.5 if classes are ignored.
  122. calibrated_scores = calibration_fn(class_predictions_with_background)
  123. calibrated_scores_np = sess.run(calibrated_scores)
  124. self.assertAllClose(calibrated_scores_np, [[[0.05, 0.1, 0.15],
  125. [0.2, 0.25, 0.0]],
  126. [[0.35, 0.45, 0.55],
  127. [0.65, 0.75, 0.75]]])
  128. if __name__ == '__main__':
  129. tf.test.main()