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 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 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 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 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 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 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 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 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 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 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 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