Repository: quic/aimet (language: python)

Issue:
Implement cpp lpbq scale calculation



Discussion / hints:

Fix patch:
diff --git a/ModelOptimizations/DlQuantization/src/quantization_utils.cpp b/ModelOptimizations/DlQuantization/src/quantization_utils.cpp
index 8c1f667efd..fee4aa3e4c 100644
--- a/ModelOptimizations/DlQuantization/src/quantization_utils.cpp
+++ b/ModelOptimizations/DlQuantization/src/quantization_utils.cpp
@@ -358,6 +358,22 @@ void concat(const std::vector<std::vector<DTYPE>>& inputs, const std::vector<uin
     }
 }
 
+
+template <typename DTYPE>
+std::tuple<DTYPE, std::vector<int>> quantizeSingleChannelPerBlockScale(std::vector<DTYPE>& scale, int compressed_bw,
+                                                                       int decompressed_bw)
+{
+    typename std::vector<DTYPE>::iterator maxScale;
+    maxScale = std::max_element(scale.begin(), scale.end());
+    DTYPE perChannelScale = *maxScale / pow(2, decompressed_bw - compressed_bw);
+    std::vector<int> perBlockIntScale;
+    for (int i=0; i<scale.size(); i++)
+    {
+        perBlockIntScale.push_back(std::max(1, static_cast<int>(std::round(scale[i] / perChannelScale))));
+    }
+    return std::tuple<DTYPE, std::vector<int>>(perChannelScale, perBlockIntScale);
+}
+
 template void slice(const float* input, const std::vector<uint32_t>& inputDim, int32_t axis,
                     std::vector<std::vector<float>>& outputs, std::vector<uint32_t>& outputDim);
 template void slice(const double* input, const std::vector<uint32_t>& inputDim, int32_t axis,
@@ -372,4 +388,11 @@ template void concat(const std::vector<std::vector<double>>& inputs, const std::
 template void concat(const std::vector<std::vector<unsigned char>>& inputs, const std::vector<uint32_t>& inputDim,
                      int32_t axis, unsigned char* output, std::vector<uint32_t>& outputDim);
 
+template std::tuple<float, std::vector<int>> quantizeSingleChannelPerBlockScale(std::vector<float>& scale,
+                                                                                int compressed_bw,
+                                                                                int decompressed_bw);
+template std::tuple<double, std::vector<int>> quantizeSingleChannelPerBlockScale(std::vector<double>& scale,
+                                                                                 int compressed_bw,
+                                                                                 int decompressed_bw);
+
 }   // End of namespace DlQuantization
\ No newline at end of file
diff --git a/ModelOptimizations/DlQuantization/src/quantization_utils.hpp b/ModelOptimizations/DlQuantization/src/quantization_utils.hpp
index 341c0dfeb7..7c627fccdf 100644
--- a/ModelOptimizations/DlQuantization/src/quantization_utils.hpp
+++ b/ModelOptimizations/DlQuantization/src/quantization_utils.hpp
@@ -73,6 +73,10 @@ template <typename DTYPE>
 void concat(const std::vector<std::vector<DTYPE>>& data, const std::vector<uint32_t>& inputShape, int32_t axis,
             DTYPE* output, std::vector<uint32_t>& outputShape);
 
+template <typename DTYPE>
+std::tuple<DTYPE, std::vector<int>> quantizeSingleChannelPerBlockScale(std::vector<DTYPE>& scale, int compressed_bw,
+                                                                       int decompressed_bw);
+
 }   // End of namespace DlQuantization
 
 #endif   // QUANTIZATION_UTILS_H_
\ No newline at end of file


Test patch:
diff --git a/ModelOptimizations/DlQuantization/test/TestUtilities.cpp b/ModelOptimizations/DlQuantization/test/TestUtilities.cpp
index b8a12dc07e..3d6fc28624 100644
--- a/ModelOptimizations/DlQuantization/test/TestUtilities.cpp
+++ b/ModelOptimizations/DlQuantization/test/TestUtilities.cpp
@@ -39,6 +39,7 @@
 #include "quantization_utils.hpp"
 #include <gtest/gtest.h>
 #include <random>
+#include <cmath>
 
 using namespace DlQuantization;
 
@@ -263,4 +264,39 @@ TEST_F(TestUtilitiesCpu, SANITY_Concat4)
     ASSERT_EQ(outputData.size(), this->data2.size());
     ASSERT_EQ(outputData, this->data2);
     ASSERT_EQ(outputShape, this->shape2);
+}
+
+TEST_F(TestUtilitiesCpu, SANITY_QuantizeSingleChannelPerBlockScale) {
+    std::vector<float> scale;
+    scale.resize(24);
+    std::mt19937 eng;
+    std::uniform_real_distribution<> distrib(0.001, 1);
+    for(auto& d : scale) {
+        d = distrib(eng);
+    }
+    float maxScale = 0.0;
+    for (int i=0; i< 24; i++) {
+        if (maxScale < scale[i])
+        {
+            maxScale = scale[i];
+        }
+    }
+    float perChannelScale;
+    std::vector<int> perBlockIntScale;
+    tie(perChannelScale, perBlockIntScale) = quantizeSingleChannelPerBlockScale(scale, 4, 8);
+
+    ASSERT_EQ(perChannelScale, maxScale / 16);
+    for (int i=0; i<24; i++)
+    {
+        ASSERT_GE(perBlockIntScale[i], 1);
+        ASSERT_LE(perBlockIntScale[i], 16);
+        if (perBlockIntScale[i] == 1)
+        {
+            ASSERT_LE(abs(scale[i] - perBlockIntScale[i]*perChannelScale), perChannelScale);
+        }
+        else
+        {
+            ASSERT_LE(abs(scale[i] - perBlockIntScale[i]*perChannelScale), perChannelScale / 2.0);
+        }
+    }
 }
\ No newline at end of file