IVGCVSW-2721 Quantize and Dequantize aren't quite right
authorFrancis Murtagh <francis.murtagh@arm.com>
Fri, 22 Feb 2019 16:35:13 +0000 (16:35 +0000)
committerFrancis Murtagh <francis.murtagh@arm.com>
Mon, 25 Feb 2019 09:46:01 +0000 (09:46 +0000)
 * Add check for infinity and negative infinity in quantize()
 * Add assert for NaN value in quantize and dequantize()
 * Add unit tests for infinity and negative infinity

Change-Id: Ie60e1e15b289ccbf99df4a3281f067b82cc9f9bf
Signed-off-by: Francis Murtagh <francis.murtagh@arm.com>
include/armnn/TypesUtils.hpp
src/armnn/test/QuantizerTest.cpp

index c65eefc..e765264 100644 (file)
@@ -189,18 +189,16 @@ inline std::ostream & operator<<(std::ostream & os, const armnn::TensorShape & s
 template<typename QuantizedType>
 inline QuantizedType Quantize(float value, float scale, int32_t offset)
 {
-    // TODO : check we act sensibly for Inf, NaN and -Inf
-    //        see IVGCVSW-1849
     static_assert(IsQuantizedType<QuantizedType>(), "Not an integer type.");
     constexpr QuantizedType max = std::numeric_limits<QuantizedType>::max();
     constexpr QuantizedType min = std::numeric_limits<QuantizedType>::lowest();
     BOOST_ASSERT(scale != 0.f);
-    int quantized = boost::numeric_cast<int>(round(value / scale)) + offset;
-    QuantizedType quantizedBits = quantized <= min
-                                  ? min
-                                  : quantized >= max
-                                    ? max
-                                    : static_cast<QuantizedType>(quantized);
+    BOOST_ASSERT(!std::isnan(value));
+
+    float clampedValue = std::min(std::max(static_cast<float>(round(value/scale) + offset), static_cast<float>(min)),
+                                  static_cast<float>(max));
+    auto quantizedBits = static_cast<QuantizedType>(clampedValue);
+
     return quantizedBits;
 }
 
@@ -215,6 +213,7 @@ inline float Dequantize(QuantizedType value, float scale, int32_t offset)
 {
     static_assert(IsQuantizedType<QuantizedType>(), "Not an integer type.");
     BOOST_ASSERT(scale != 0.f);
+    BOOST_ASSERT(!std::isnan(value));
     float dequantized = boost::numeric_cast<float>(value - offset) * scale;
     return dequantized;
 }
index 548203a..fcce208 100644 (file)
@@ -14,6 +14,7 @@
 #include "../NetworkQuantizerUtils.hpp"
 #include "../OverrideInputRangeVisitor.hpp"
 #include "../RangeTracker.hpp"
+#include "../backends/backendsCommon/test/QuantizeHelper.hpp"
 
 #include <boost/test/unit_test.hpp>
 
@@ -1215,5 +1216,33 @@ BOOST_AUTO_TEST_CASE(QuantizeBatchToSpace)
     VisitLayersTopologically(quantizedNetwork.get(), validator);
 }
 
+std::vector<uint8_t> SetupQuantize(float value)
+{
+    armnn::TensorInfo inputInfo({ 1, 2, 2 }, armnn::DataType::Float32);
+    inputInfo.SetQuantizationScale(1.0f);
+    inputInfo.SetQuantizationOffset(1);
+    std::vector<float> input({
+                                     value, 0.0f,
+                                     0.0f, 1.0f
+                             });
+    const std::vector<float> &inputRef = input;
+
+    auto output = QuantizedVector<uint8_t>(inputInfo.GetQuantizationScale(),
+                                           inputInfo.GetQuantizationOffset(),
+                                           inputRef);
+
+    return output;
+}
+
+BOOST_AUTO_TEST_CASE(QuantizeInf)
+{
+    BOOST_CHECK_EQUAL(SetupQuantize(std::numeric_limits<float>::infinity())[0], 255);
+}
+
+BOOST_AUTO_TEST_CASE(QuantizeNegativeInf)
+{
+    BOOST_CHECK_EQUAL(SetupQuantize(-1 * std::numeric_limits<float>::infinity())[0], 0);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 } // namespace armnn