• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The Gemmlowp Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <unistd.h>
16 #ifdef __APPLE__
17 #include <sys/time.h>
18 #endif
19 
20 #include <cstdint>
21 #include <cstdlib>
22 #include <ctime>
23 #include <iomanip>
24 #include <iostream>
25 #include <map>
26 #include <memory>
27 #include <vector>
28 
29 #include "single_thread_transform.h"
30 #include "transform_kernels.h"
31 
32 #define EPSILON (0.0001)
33 
34 using namespace gemmlowp::meta;
35 
36 typedef Transform1DParams<std::int32_t, std::uint8_t, Requantize> RequantizeParams;
37 typedef Transform1DParams<float, std::uint8_t, Quantize> QuantizeParams;
38 typedef Transform1DParams<std::uint8_t, float, Dequantize> DequantizeParams;
39 typedef Transform1DParams<std::uint8_t, std::uint8_t, MinMax<std::uint8_t>> MinMaxParams;
40 typedef Transform1DParams<std::uint8_t, std::int32_t, BiasAdd<std::uint8_t>> BiasAddParams;
41 
prepare_data_requantize(int count,std::int32_t * data)42 void prepare_data_requantize(int count, std::int32_t* data) {
43   float scale = 4000000000.0f / static_cast<float>(count - 1);
44   for (int i = 0; i < count; ++i) {
45     float temp = -2000000000.0f + scale * i;
46     data[i] = static_cast<std::int32_t>(temp);
47   }
48 }
49 
prepare_data_quantize(int count,float * data)50 void prepare_data_quantize(int count, float* data) {
51   float scale = 200.0f / static_cast<float>(count - 1);
52   for (int i = 0; i < count; ++i) {
53     data[i] = -100 + scale * i;
54   }
55 }
56 
prepare_data_dequantize(int count,std::uint8_t * data)57 void prepare_data_dequantize(int count, std::uint8_t* data) {
58   for (int i = 0; i < count; ++i) {
59     data[i] = static_cast<std::uint8_t>(i % 256);
60   }
61 }
62 
prepare_data_minmax(int count,std::uint8_t * data)63 void prepare_data_minmax(int count, std::uint8_t* data) {
64   for (int i = 0; i < count; ++i) {
65     data[i] = static_cast<std::uint8_t>(i % 256);
66   }
67 }
68 
prepare_data_biasadd(int count,std::uint8_t * data)69 void prepare_data_biasadd(int count, std::uint8_t* data) {
70   for (int i = 0; i < count; ++i) {
71     data[i] = static_cast<std::uint8_t>(i % 256);
72   }
73 }
74 
verify_requantize(const RequantizeParams & params)75 void verify_requantize(const RequantizeParams& params) {
76   for (int i = 0; i < params.kernel.count; ++i) {
77     std::uint8_t actual = params.output[i];
78     float expected = static_cast<float>(params.input[i]);
79     expected -= params.kernel.input_range_offset;
80     expected *= params.kernel.input_range_scale;
81     expected += params.kernel.input_range_min;
82     expected -= params.kernel.output_range_min;
83     expected *= params.kernel.one_over_output_range_scale;
84     expected += params.kernel.output_range_offset;
85     std::uint8_t expected_uint8 = static_cast<std::uint8_t>(expected);
86 
87     if (actual != expected_uint8) {
88       std::cout << "Wrong: " << i << " : " << actual << " vs. "
89                 << expected_uint8 << std::endl;
90       std::exit(1);
91     }
92   }
93   std::cout << "Requantize: OK" << std::endl;
94 }
95 
verify_quantize(const QuantizeParams & params)96 void verify_quantize(const QuantizeParams& params) {
97   for (int i = 0; i < params.kernel.count; ++i) {
98     std::uint8_t actual = params.output[i];
99     float expected = params.input[i];
100     expected -= params.kernel.range_min;
101     expected *= params.kernel.range_scale;
102     expected += params.kernel.range_offset;
103     std::uint8_t expected_uint8 = static_cast<std::uint8_t>(expected);
104 
105     if (actual != expected_uint8) {
106       std::cout << "Wrong: " << i << " : " << actual << " vs. "
107                 << expected_uint8 << std::endl;
108       std::exit(1);
109     }
110   }
111   std::cout << "Quantize: OK" << std::endl;
112 }
113 
verify_dequantize(const DequantizeParams & params)114 void verify_dequantize(const DequantizeParams& params) {
115   for (int i = 0; i < params.kernel.count; ++i) {
116     float actual = params.output[i];
117     float expected = static_cast<float>(params.input[i]);
118     expected -= params.kernel.range_offset;
119     expected *= params.kernel.range_scale;
120     expected += params.kernel.range_min;
121     if (std::abs(actual - expected) > EPSILON) {
122       std::cout << std::setprecision(9) << "Wrong: " << i << " : " << actual
123                 << " vs. " << expected << std::endl;
124       std::exit(1);
125     }
126   }
127   std::cout << "Dequantize: OK" << std::endl;
128 }
129 
verify_minmax(const MinMaxParams & params)130 void verify_minmax(const MinMaxParams& params) {
131   for (int i = 0; i < params.kernel.count; ++i) {
132     std::uint8_t actual = params.output[i];
133     std::uint8_t expected = params.input[i];
134     expected = std::min(expected, params.kernel.max);
135     expected = std::max(expected, params.kernel.min);
136 
137     if (actual != expected) {
138       std::cout << "Wrong: " << i << " : " << actual << " vs. " << expected
139                 << std::endl;
140       std::exit(1);
141     }
142   }
143   std::cout << "MinMax: OK" << std::endl;
144 }
145 
verify_biasadd(const BiasAddParams & params)146 void verify_biasadd(const BiasAddParams& params) {
147   for (int i = 0; i < params.kernel.rows * params.kernel.count; ++i) {
148     std::int32_t actual = params.output[i];
149     std::uint8_t input = params.input[i];
150     std::uint8_t bias = params.kernel.bias[i % params.kernel.count];
151     float input_float = static_cast<float>(input);
152     input_float -= params.kernel.input_range_offset;
153     input_float *= params.kernel.input_range_scale;
154     input_float += params.kernel.input_range_min;
155     float bias_float = static_cast<float>(bias);
156     bias_float -= params.kernel.bias_range_offset;
157     bias_float *= params.kernel.bias_range_scale;
158     bias_float += params.kernel.bias_range_min;
159     float sum = input_float + bias_float;
160     sum -= params.kernel.output_range_min;
161     sum *= params.kernel.one_over_output_range_scale;
162     sum += params.kernel.output_range_offset;
163     std::int32_t expected = static_cast<std::int32_t>(sum);
164     if (std::abs(actual - expected) > 1024) {
165       std::cout << "Wrong: " << i << " : " << actual << " vs. " << expected
166                 << std::endl;
167       std::exit(1);
168     }
169   }
170   std::cout << "BiasAdd: OK" << std::endl;
171 }
172 
main()173 int main() {
174   std::unique_ptr<std::int32_t[]> array_int32(new std::int32_t[128 * 1024]);
175   std::unique_ptr<std::uint8_t[]> array_uint8(new std::uint8_t[128 * 1024]);
176   std::unique_ptr<std::uint8_t[]> array_uint8_2(new std::uint8_t[128 * 1024]);
177   std::unique_ptr<float[]> array_float(new float[128 * 1024]);
178 
179   {
180     RequantizeParams requantize_params;
181     requantize_params.input = array_int32.get();
182     requantize_params.output = array_uint8.get();
183     requantize_params.kernel.count = 12345;
184     requantize_params.kernel.input_range_min = -100.0f;
185     requantize_params.kernel.input_range_scale =
186         200.0f / ((static_cast<std::int64_t>(1) << 32) - 1);
187     requantize_params.kernel.input_range_offset =
188         static_cast<float>(std::numeric_limits<std::int32_t>::lowest());
189     requantize_params.kernel.output_range_min = -100.f;
190     requantize_params.kernel.one_over_output_range_scale =
191         static_cast<float>((static_cast<std::int64_t>(1) << 8) - 1) / 200.0f;
192     requantize_params.kernel.output_range_offset =
193         static_cast<float>(std::numeric_limits<std::uint8_t>::lowest());
194 
195     prepare_data_requantize(12345, array_int32.get());
196 
197     Transform1D<RequantizeParams, 16>(requantize_params);
198 
199     verify_requantize(requantize_params);
200   }
201 
202   {
203     QuantizeParams quantize_params;
204     quantize_params.input = array_float.get();
205     quantize_params.output = array_uint8.get();
206     quantize_params.kernel.count = 12345;
207     quantize_params.kernel.range_min = -100.0f;
208     quantize_params.kernel.range_scale =
209         static_cast<float>((static_cast<std::int64_t>(1) << 8) - 1) / 200.0f;
210     quantize_params.kernel.range_offset =
211         static_cast<float>(std::numeric_limits<std::uint8_t>::lowest());
212 
213     prepare_data_quantize(12345, array_float.get());
214 
215     Transform1D<QuantizeParams, 16>(quantize_params);
216 
217     verify_quantize(quantize_params);
218   }
219 
220   {
221     DequantizeParams dequantize_params;
222     dequantize_params.input = array_uint8.get();
223     dequantize_params.output = array_float.get();
224     dequantize_params.kernel.count = 12345;
225     dequantize_params.kernel.range_min = -100.0f;
226     dequantize_params.kernel.range_scale =
227         200.0f / ((static_cast<std::int64_t>(1) << 8) - 1);
228     dequantize_params.kernel.range_offset =
229         static_cast<float>(std::numeric_limits<std::uint8_t>::lowest());
230 
231     prepare_data_dequantize(12345, array_uint8.get());
232 
233     Transform1D<DequantizeParams, 16>(dequantize_params);
234 
235     verify_dequantize(dequantize_params);
236   }
237 
238   {
239     MinMaxParams minmax_params;
240     minmax_params.input = array_uint8.get();
241     minmax_params.output = array_uint8_2.get();
242     minmax_params.kernel.count = 12345;
243     minmax_params.kernel.min = 64;
244     minmax_params.kernel.max = 192;
245 
246     prepare_data_minmax(12345, array_uint8.get());
247 
248     Transform1D<MinMaxParams, 16>(minmax_params);
249 
250     verify_minmax(minmax_params);
251   }
252 
253   {
254     BiasAddParams biasadd_params;
255     biasadd_params.input = array_uint8.get();
256     biasadd_params.output = array_int32.get();
257     biasadd_params.kernel.count = 1234;
258     biasadd_params.kernel.rows = 11;
259     biasadd_params.kernel.input_range_min = -100.0f;
260     biasadd_params.kernel.bias_range_min = -100.0f;
261     biasadd_params.kernel.output_range_min = -250.0f;
262     biasadd_params.kernel.input_range_offset =
263         static_cast<float>(std::numeric_limits<std::uint8_t>::lowest());
264     biasadd_params.kernel.bias_range_offset =
265         static_cast<float>(std::numeric_limits<std::uint8_t>::lowest());
266     biasadd_params.kernel.output_range_offset =
267         static_cast<float>(std::numeric_limits<std::int32_t>::lowest());
268     biasadd_params.kernel.input_range_scale =
269         200.0f / ((static_cast<std::int64_t>(1) << 8) - 1);
270     biasadd_params.kernel.bias_range_scale =
271         200.0f / ((static_cast<std::int64_t>(1) << 8) - 1);
272     biasadd_params.kernel.one_over_output_range_scale =
273         static_cast<float>((static_cast<std::int64_t>(1) << 32) - 1) / 500.0f;
274     biasadd_params.kernel.bias = array_uint8_2.get();
275 
276     prepare_data_biasadd(1234 * 11, array_uint8.get());
277     prepare_data_biasadd(1234, array_uint8_2.get());
278 
279     Transform1D<BiasAddParams, 16>(biasadd_params);
280 
281     verify_biasadd(biasadd_params);
282   }
283 
284   return 0;
285 }
286