Caffe2 - C++ API
A deep learning, cross platform ML framework
int8_utils.h
1 #ifndef CAFFE2_INT8_UTILS_H_
2 #define CAFFE2_INT8_UTILS_H_
3 
4 #include <gemmlowp/public/gemmlowp.h>
5 
6 #include "caffe2/utils/threadpool/ThreadPool.h"
7 #include "caffe2/utils/threadpool/WorkersPool.h"
8 
9 namespace caffe2 {
10 
11 /*
12  * Initialized QNNPACK (only once).
13  * Throws if initialization failed.
14  */
15 void initQNNPACK();
16 
17 namespace int8 {
18 
19 /*
20  * Code here is partially derived from gemmlowp library
21  * (https://github.com/google/gemmlowp)
22  */
23 
24 // Copyright 2015 The Gemmlowp Authors. All Rights Reserved.
25 //
26 // Licensed under the Apache License, Version 2.0 (the "License");
27 // you may not use this file except in compliance with the License.
28 // You may obtain a copy of the License at
29 //
30 // http://www.apache.org/licenses/LICENSE-2.0
31 //
32 // Unless required by applicable law or agreed to in writing, software
33 // distributed under the License is distributed on an "AS IS" BASIS,
34 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
35 // See the License for the specific language governing permissions and
36 // limitations under the License.
37 
38 inline int32_t MultiplyByQuantizedMultiplierSmallerThanOne(
39  int32_t x,
40  int32_t quantized_multiplier,
41  int right_shift) {
42  using gemmlowp::RoundingDivideByPOT;
43  using gemmlowp::SaturatingRoundingDoublingHighMul;
44  return RoundingDivideByPOT(
45  SaturatingRoundingDoublingHighMul(x, quantized_multiplier), right_shift);
46 }
47 
48 #if defined(__ANDROID__) && !defined(__NDK_MAJOR__)
49 template <class T>
50 inline float Round(const float x) {
51  return ::nearbyintf(x);
52 }
53 inline double Round(const double x) {
54  return ::nearbyint(x);
55 }
56 #else
57 template <class T>
58 inline T Round(const T x) {
59  return std::nearbyint(x);
60 }
61 #endif
62 
63 inline uint8_t QuantizeUint8(float scale, int32_t zero_point, float value) {
64  const int32_t qmin = std::numeric_limits<uint8_t>::min();
65  const int32_t qmax = std::numeric_limits<uint8_t>::max();
66 
67  auto r = zero_point + static_cast<int32_t>(Round(value / scale));
68  r = std::max(r, qmin);
69  r = std::min(r, qmax);
70  return static_cast<uint8_t>(r);
71 }
72 
73 inline void QuantizeMultiplierSmallerThanOne(
74  double double_multiplier,
75  int32_t* quantized_multiplier,
76  int* right_shift) {
77  CHECK(double_multiplier >= 0.);
78  CHECK(double_multiplier < 1.);
79  if (double_multiplier == 0.) {
80  *quantized_multiplier = 0;
81  *right_shift = 0;
82  return;
83  }
84  CHECK(double_multiplier > 0.);
85  const double q = std::frexp(double_multiplier, right_shift);
86  *right_shift *= -1;
87 
88  auto q_fixed = static_cast<int64_t>(Round(q * (1ll << 31)));
89  CHECK(q_fixed <= (1ll << 31));
90  if (q_fixed == (1ll << 31)) {
91  q_fixed /= 2;
92  --*right_shift;
93  }
94  CHECK_GE(*right_shift, 0);
95  CHECK_LE(q_fixed, std::numeric_limits<int32_t>::max());
96  *quantized_multiplier = static_cast<int32_t>(q_fixed);
97 }
98 
99 inline void QuantizeMultiplierGreaterThanOne(
100  double double_multiplier,
101  int32_t* quantized_multiplier,
102  int* left_shift) {
103  CHECK(double_multiplier > 1.);
104  const double q = std::frexp(double_multiplier, left_shift);
105  auto q_fixed = static_cast<int64_t>(Round(q * (1ll << 31)));
106  CHECK(q_fixed <= (1ll << 31));
107  if (q_fixed == (1ll << 31)) {
108  q_fixed /= 2;
109  ++*left_shift;
110  }
111  CHECK_GE(*left_shift, 0);
112  CHECK_LE(q_fixed, std::numeric_limits<int32_t>::max());
113  *quantized_multiplier = static_cast<int32_t>(q_fixed);
114 }
115 
116 inline int32_t MultiplyByQuantizedMultiplierGreaterThanOne(
117  int32_t x,
118  int32_t quantized_multiplier,
119  int left_shift) {
120  using gemmlowp::SaturatingRoundingDoublingHighMul;
121  return SaturatingRoundingDoublingHighMul(
122  x * (1 << left_shift), quantized_multiplier);
123 }
124 
125 inline int CalculateInputRadius(int input_integer_bits, int input_left_shift) {
126  const double max_input_rescaled = 1.0 * ((1 << input_integer_bits) - 1) *
127  (1ll << (31 - input_integer_bits)) / (1ll << input_left_shift);
128  // Tighten bound using floor. Suppose that we could use the exact value.
129  // After scaling the difference, the result would be at the maximum. Thus we
130  // must ensure that our value has lower magnitude.
131  return static_cast<int>(std::floor(max_input_rescaled));
132 }
133 
134 enum class Activation : uint8_t { NONE = 0, RELU = 1 };
135 
136 inline std::pair<uint8_t, uint8_t>
137 activationLimits(float scale, int32_t zero_point, Activation Ac) {
138  switch (Ac) {
139  case Activation::NONE:
140  return {std::numeric_limits<uint8_t>::min(),
141  std::numeric_limits<uint8_t>::max()};
142  case Activation::RELU:
143  return {QuantizeUint8(scale, zero_point, 0.0),
144  std::numeric_limits<uint8_t>::max()};
145  default:
146 #ifdef _MSC_VER
147  __assume(0);
148 #else
149  __builtin_unreachable();
150 #endif
151  }
152 }
153 
154 } // namespace int8
155 } // namespace caffe2
156 
157 #endif // CAFFE2_INT8_UTILS_H_
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
Definition: blob.h:13