aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arm_compute/core/Types.h23
-rw-r--r--arm_compute/core/Utils.h9
-rw-r--r--src/core/CL/kernels/CLActivationLayerKernel.cpp4
-rw-r--r--src/core/Utils.cpp34
-rw-r--r--src/runtime/CL/functions/CLPoolingLayer.cpp2
-rw-r--r--tests/validation/Helpers.cpp2
-rw-r--r--tests/validation/UNIT/Utils.cpp14
7 files changed, 74 insertions, 14 deletions
diff --git a/arm_compute/core/Types.h b/arm_compute/core/Types.h
index 36ec38ff68..c77f1d4157 100644
--- a/arm_compute/core/Types.h
+++ b/arm_compute/core/Types.h
@@ -102,6 +102,17 @@ constexpr float SCALE_PYRAMID_HALF = 0.5f;
/* Constant value used to indicate a ORB scaled pyramid */
constexpr float SCALE_PYRAMID_ORB = 8.408964152537146130583778358414e-01;
+/** Rounding method */
+enum class RoundingPolicy
+{
+ TO_ZERO, /**< Truncates the least significand values that are lost in operations. */
+ TO_NEAREST_UP, /**< Rounds to nearest value; half rounds away from zero */
+ TO_NEAREST_EVEN, /**< Rounds to nearest value; half rounds to nearest even */
+};
+
+//forward declare round function
+int round(float, RoundingPolicy);
+
/** Quantization settings (used for QASYMM8 data type) */
struct QuantizationInfo
{
@@ -129,10 +140,10 @@ struct QuantizationInfo
int offset; /**< offset */
/** Quantizes a value using the scale/offset in this QuantizationInfo */
- uint8_t quantize(float value) const
+ uint8_t quantize(float value, RoundingPolicy rounding_policy) const
{
ARM_COMPUTE_ERROR_ON_MSG(scale == 0, "QuantizationInfo::quantize: scale == 0");
- int quantized = static_cast<int>(value / scale + offset);
+ int quantized = arm_compute::round(value / scale, rounding_policy) + offset;
quantized = std::max(0, std::min(quantized, 255));
return quantized;
}
@@ -296,14 +307,6 @@ enum class ThresholdType
RANGE /**< Threshold with two values*/
};
-/** Rounding method */
-enum class RoundingPolicy
-{
- TO_ZERO, /**< Truncates the least significand values that are lost in operations. */
- TO_NEAREST_UP, /**< Rounds to nearest value; half rounds up */
- TO_NEAREST_EVEN /**< Rounds to nearest value; half rounds to nearest even */
-};
-
/** Termination criteria */
enum class Termination
{
diff --git a/arm_compute/core/Utils.h b/arm_compute/core/Utils.h
index af9cf23548..9397d507f8 100644
--- a/arm_compute/core/Utils.h
+++ b/arm_compute/core/Utils.h
@@ -62,6 +62,15 @@ constexpr auto DIV_CEIL(S val, T m) -> decltype((val + m - 1) / m)
return (val + m - 1) / m;
}
+/** Return a rounded value of x. Rounding is done according to the rounding_policy.
+ *
+ * @param[in] x Float value to be rounded.
+ * @param[in] rounding_policy Policy determining how rounding is done.
+ *
+ * @return Rounded value of the argument x.
+ */
+int round(float x, RoundingPolicy rounding_policy);
+
/** Returns the arm_compute library build information
*
* Contains the version number and the build options used to build the library
diff --git a/src/core/CL/kernels/CLActivationLayerKernel.cpp b/src/core/CL/kernels/CLActivationLayerKernel.cpp
index 0f7003a38c..8172aafca9 100644
--- a/src/core/CL/kernels/CLActivationLayerKernel.cpp
+++ b/src/core/CL/kernels/CLActivationLayerKernel.cpp
@@ -131,8 +131,8 @@ void CLActivationLayerKernel::configure(ICLTensor *input, ICLTensor *output, Act
}
else
{
- a_const_int = input->info()->quantization_info().quantize(a_const);
- b_const_int = input->info()->quantization_info().quantize(b_const);
+ a_const_int = input->info()->quantization_info().quantize(a_const, RoundingPolicy::TO_NEAREST_UP);
+ b_const_int = input->info()->quantization_info().quantize(b_const, RoundingPolicy::TO_NEAREST_UP);
}
}
diff --git a/src/core/Utils.cpp b/src/core/Utils.cpp
index af864f57f7..af50bbbaf7 100644
--- a/src/core/Utils.cpp
+++ b/src/core/Utils.cpp
@@ -21,10 +21,13 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
#include "arm_compute/core/Utils.h"
#include "arm_compute/core/FixedPoint.h"
+#include "support/ToolchainSupport.h"
+
#include <algorithm>
#include <cmath>
#include <cstdint>
@@ -387,3 +390,34 @@ int arm_compute::max_consecutive_elements_display_width(std::ostream &s, DataTyp
}
return 0;
}
+
+int arm_compute::round(float x, RoundingPolicy rounding_policy)
+{
+ using namespace std;
+ int rounded = 0;
+ switch(rounding_policy)
+ {
+ case RoundingPolicy::TO_ZERO:
+ {
+ rounded = static_cast<int>(x);
+ break;
+ }
+ case RoundingPolicy::TO_NEAREST_UP:
+ {
+ rounded = static_cast<int>(support::cpp11::round(x));
+ break;
+ }
+ case RoundingPolicy::TO_NEAREST_EVEN:
+ {
+ ARM_COMPUTE_ERROR("TO_NEAREST_EVEN rounding policy is not supported.");
+ break;
+ }
+ default:
+ {
+ ARM_COMPUTE_ERROR("Unsupported rounding policy.");
+ break;
+ }
+ }
+
+ return rounded;
+}
diff --git a/src/runtime/CL/functions/CLPoolingLayer.cpp b/src/runtime/CL/functions/CLPoolingLayer.cpp
index ac360fbb3d..20564f6c9d 100644
--- a/src/runtime/CL/functions/CLPoolingLayer.cpp
+++ b/src/runtime/CL/functions/CLPoolingLayer.cpp
@@ -46,7 +46,7 @@ void CLPoolingLayer::configure(ICLTensor *input, ICLTensor *output, const Poolin
uint32_t border_value = 0;
if(is_data_type_quantized_asymmetric(input->info()->data_type()) && !pool_info.exclude_padding())
{
- border_value = static_cast<uint32_t>(input->info()->quantization_info().quantize(0));
+ border_value = static_cast<uint32_t>(input->info()->quantization_info().quantize(0.f, RoundingPolicy::TO_NEAREST_UP));
}
_border_handler.configure(input, _kernel->border_size(), border_mode, PixelValue(border_value));
diff --git a/tests/validation/Helpers.cpp b/tests/validation/Helpers.cpp
index 3ef5fc1cc5..313b059a8c 100644
--- a/tests/validation/Helpers.cpp
+++ b/tests/validation/Helpers.cpp
@@ -129,7 +129,7 @@ SimpleTensor<uint8_t> convert_to_asymmetric(const SimpleTensor<float> &src, cons
SimpleTensor<uint8_t> dst{ src.shape(), DataType::QASYMM8, 1, 0, quantization_info };
for(int i = 0; i < src.num_elements(); ++i)
{
- dst[i] = quantization_info.quantize(src[i]);
+ dst[i] = quantization_info.quantize(src[i], RoundingPolicy::TO_NEAREST_UP);
}
return dst;
}
diff --git a/tests/validation/UNIT/Utils.cpp b/tests/validation/UNIT/Utils.cpp
index 96f9997d5b..b73edb1fb8 100644
--- a/tests/validation/UNIT/Utils.cpp
+++ b/tests/validation/UNIT/Utils.cpp
@@ -60,6 +60,20 @@ DATA_TEST_CASE(Index2Coord, framework::DatasetMode::ALL, zip(zip(framework::data
ARM_COMPUTE_EXPECT(compare_dimensions(coordinate, ref_coordinate), framework::LogLevel::ERRORS);
}
+DATA_TEST_CASE(RoundFloatToZero, framework::DatasetMode::ALL, zip(framework::dataset::make("FloatIn", { 1.f, 1.2f, 1.5f, 2.5f, 2.9f, -3.f, -3.5f, -3.8f, -4.3f, -4.5f }),
+ framework::dataset::make("FloatOut", { 1.f, 1.f, 1.f, 2.f, 2.f, -3.f, -3.f, -3.f, -4.f, -4.f })),
+ value, result)
+{
+ ARM_COMPUTE_EXPECT(round(value, RoundingPolicy::TO_ZERO) == result, framework::LogLevel::ERRORS);
+}
+
+DATA_TEST_CASE(RoundFloatToNearestUp, framework::DatasetMode::ALL, zip(framework::dataset::make("FloatIn", { 1.f, 1.2f, 1.5f, 2.5f, 2.9f, -3.f, -3.5f, -3.8f, -4.3f, -4.5f }),
+ framework::dataset::make("FloatOut", { 1.f, 1.f, 2.f, 3.f, 3.f, -3.f, -4.f, -4.f, -4.f, -5.f })),
+ value, result)
+{
+ ARM_COMPUTE_EXPECT(round(value, RoundingPolicy::TO_NEAREST_UP) == result, framework::LogLevel::ERRORS);
+}
+
//FIXME: Negative tests only work in debug mode
#if 0
DISABLED_DATA_TEST_CASE(Index2CoordFail, framework::DatasetMode::ALL, zip(framework::dataset::make("Shape", { TensorShape{}, TensorShape{ 2U }, TensorShape{ 2U } }), framework::dataset::make("Index", { 0, -1, 2 })),