COMPMID-3241: Fix hidden scale in NEQLSTMLayer
authorSang-Hoon Park <sang-hoon.park@arm.com>
Sat, 18 Apr 2020 00:40:57 +0000 (01:40 +0100)
committerSang-Hoon Park <sang-hoon.park@arm.com>
Mon, 20 Apr 2020 14:53:23 +0000 (14:53 +0000)
- Fix wrong data types in LSTMParams
- Add logic to ignore epsilon for quantization multiplier computation
- Ignore epsilon for hidden gate scale computation

Change-Id: Ia0b2f523b1c2ad325f3523439a8eea051d81958c
Signed-off-by: Sang-Hoon Park <sang-hoon.park@arm.com>
Reviewed-on: https://review.mlplatform.org/c/ml/ComputeLibrary/+/3058
Reviewed-by: Michele Di Giorgio <michele.digiorgio@arm.com>
Comments-Addressed: Arm Jenkins <bsgcomp@arm.com>
Tested-by: Arm Jenkins <bsgcomp@arm.com>
arm_compute/core/utils/quantization/AsymmHelpers.h
arm_compute/runtime/common/LSTMParams.h
src/core/utils/quantization/AsymmHelpers.cpp
src/runtime/NEON/functions/NEQLSTMLayer.cpp

index a7bbf9b137631e7fc5ec8c25f2371ef52127d6cd..4ef49476b22e583734ca7090fd1474cc1291bff8 100644 (file)
@@ -37,19 +37,21 @@ namespace quantization
  * @param[in]  multiplier       Real multiplier.
  * @param[out] quant_multiplier Integer multiplier.
  * @param[out] shift            bit shift. A negative value indicates a left shift, while a positive value indicates a right shift
+ * @param[in]  ignore_epsilon   When true, ignore pre-defined epsilon value. Defaults to false
  *
  * @return a status
  */
-Status calculate_quantized_multiplier(float multiplier, int32_t *quant_multiplier, int32_t *shift);
+Status calculate_quantized_multiplier(float multiplier, int32_t *quant_multiplier, int32_t *shift, bool ignore_epsilon = false);
 /** Calculate quantized representation of multiplier with value less than one.
  *
  * @param[in]  multiplier       Real multiplier.
  * @param[out] quant_multiplier Integer multiplier.
  * @param[out] right_shift      Right bit shift.
+ * @param[in]  ignore_epsilon   When true, ignore pre-defined epsilon value. Defaults to false
  *
  * @return a status
  */
-Status calculate_quantized_multiplier_less_than_one(float multiplier, int32_t *quant_multiplier, int32_t *right_shift);
+Status calculate_quantized_multiplier_less_than_one(float multiplier, int32_t *quant_multiplier, int32_t *right_shift, bool ignore_epsilon = false);
 /** Calculate quantized representation of multiplier having value greater than one.
  *
  * @param[in]  multiplier           Real multiplier.
index e21ddd7af1f54a6d2d7312fbede195202438081d..5e4a76afaec89528432d4b9e93f139f24defe469 100644 (file)
@@ -58,8 +58,8 @@ public:
           _forget_intermediate_scale(0.0f),
           _cell_intermediate_scale(0.0f),
           _output_intermediate_scale(0.0f),
-          _hidden_state_zero(0.0f),
-          _hidden_state_scale(0),
+          _hidden_state_zero(0),
+          _hidden_state_scale(0.0f),
           _has_peephole_opt(false),
           _has_projection(false),
           _has_cifg_opt(true),
@@ -333,8 +333,8 @@ private:
     float    _forget_intermediate_scale;
     float    _cell_intermediate_scale;
     float    _output_intermediate_scale;
-    float    _hidden_state_zero;
-    int32_t  _hidden_state_scale;
+    int32_t  _hidden_state_zero;
+    float    _hidden_state_scale;
     bool     _has_peephole_opt;
     bool     _has_projection;
     bool     _has_cifg_opt;
index f923518ca40f4c9fe2e168dabae95cca13bca34e..8e0e92c7ab7748c0c4cc1a54ee02157ad5011a5f 100644 (file)
@@ -36,7 +36,7 @@ namespace quantization
 constexpr int64_t fixed_point_one_Q0 = (1LL << 31);
 constexpr float   epsilon            = 0.00001f;
 
-Status calculate_quantized_multiplier(float multiplier, int32_t *quant_multiplier, int32_t *shift)
+Status calculate_quantized_multiplier(float multiplier, int32_t *quant_multiplier, int32_t *shift, bool ignore_epsilon)
 {
     if(multiplier >= 1.f)
     {
@@ -46,19 +46,22 @@ Status calculate_quantized_multiplier(float multiplier, int32_t *quant_multiplie
     }
     else
     {
-        return calculate_quantized_multiplier_less_than_one(multiplier, quant_multiplier, shift);
+        return calculate_quantized_multiplier_less_than_one(multiplier, quant_multiplier, shift, ignore_epsilon);
     }
 }
 
 Status calculate_quantized_multiplier_less_than_one(float    multiplier,
                                                     int32_t *quant_multiplier,
-                                                    int32_t *right_shift)
+                                                    int32_t *right_shift,
+                                                    bool     ignore_epsilon)
 {
+    const float internal_epsilon = ignore_epsilon ? 0.0f : epsilon;
+
     ARM_COMPUTE_RETURN_ERROR_ON(quant_multiplier == nullptr);
     ARM_COMPUTE_RETURN_ERROR_ON(right_shift == nullptr);
-    ARM_COMPUTE_RETURN_ERROR_ON(multiplier < -epsilon);
-    ARM_COMPUTE_RETURN_ERROR_ON(multiplier > 1.0f + epsilon);
-    if(std::fabs(0.0f - multiplier) < epsilon)
+    ARM_COMPUTE_RETURN_ERROR_ON(multiplier < -internal_epsilon);
+    ARM_COMPUTE_RETURN_ERROR_ON(multiplier > 1.0f + internal_epsilon);
+    if(std::fabs(0.0f - multiplier) < internal_epsilon)
     {
         *quant_multiplier = 0;
         *right_shift      = 0;
@@ -75,6 +78,13 @@ Status calculate_quantized_multiplier_less_than_one(float    multiplier,
         q_fixed /= 2;
         --*right_shift;
     }
+
+    if(ignore_epsilon && *right_shift > 31)
+    {
+        *right_shift = 0;
+        q_fixed      = 0;
+    }
+
     ARM_COMPUTE_RETURN_ERROR_ON(*right_shift < 0);
     ARM_COMPUTE_RETURN_ERROR_ON(q_fixed > std::numeric_limits<int32_t>::max());
     *quant_multiplier = static_cast<int32_t>(q_fixed);
index 3aa77b28ce6064469196fd693f180f208507e61c..b02fab227bfedeb81e6e640480dc6cbd8082d174 100644 (file)
@@ -341,7 +341,7 @@ void NEQLSTMLayer::configure(const ITensor *input,
     _output_gate.allocator()->allocate();
     _input_gate.allocator()->allocate();
     const float hidden_state_scale = std::pow(2, -15) / lstm_params.hidden_state_scale() * std::pow(2, -15);
-    quantization::calculate_quantized_multiplier(hidden_state_scale, &gemmlowp_info.gemmlowp_multiplier, &gemmlowp_info.gemmlowp_shift);
+    quantization::calculate_quantized_multiplier(hidden_state_scale, &gemmlowp_info.gemmlowp_multiplier, &gemmlowp_info.gemmlowp_shift, /* ignore_epsilon */ true);
     gemmlowp_info.gemmlowp_offset  = lstm_params.hidden_state_zero();
     gemmlowp_info.output_data_type = output_state_in->info()->data_type();
     _hidden_outstage.configure(&_hidden_mul_res, nullptr, output_state_out, gemmlowp_info);
@@ -622,7 +622,7 @@ Status NEQLSTMLayer::validate(const ITensorInfo *input,
     const TensorInfo hidden_mul_res(TensorShape(num_units, batch_size), 1, DataType::S32);
     ARM_COMPUTE_RETURN_ON_ERROR(NEPixelWiseMultiplicationKernel::validate(&output_gate_info, &input_gate_info, &hidden_mul_res, 1.f, ConvertPolicy::SATURATE, RoundingPolicy::TO_ZERO));
     const float hidden_state_scale = std::pow(2, -15) / lstm_params.hidden_state_scale() * std::pow(2, -15);
-    ARM_COMPUTE_RETURN_ON_ERROR(quantization::calculate_quantized_multiplier(hidden_state_scale, &gemmlowp_info.gemmlowp_multiplier, &gemmlowp_info.gemmlowp_shift));
+    ARM_COMPUTE_RETURN_ON_ERROR(quantization::calculate_quantized_multiplier(hidden_state_scale, &gemmlowp_info.gemmlowp_multiplier, &gemmlowp_info.gemmlowp_shift, /* ignore_epsilon */ true));
     gemmlowp_info.gemmlowp_offset = lstm_params.hidden_state_zero();
     ARM_COMPUTE_RETURN_ON_ERROR(NEGEMMLowpOutputStage::validate(&hidden_mul_res, nullptr, output_state_out, gemmlowp_info));