| 314 | } |
| 315 | |
| 316 | void Quantize(OpKernelContext* tf_context, const float* input, int count, |
| 317 | float range_min, float range_max, quint8* output) { |
| 318 | #ifdef TENSORFLOW_USE_META |
| 319 | mutex_lock library_lock(GetMutex()); |
| 320 | typedef gemmlowp::meta::Transform1DParams<float, uint8_t, |
| 321 | gemmlowp::meta::Quantize> |
| 322 | Params; |
| 323 | |
| 324 | Params params; |
| 325 | params.input = reinterpret_cast<const float*>(input); |
| 326 | params.output = reinterpret_cast<uint8_t*>(output); |
| 327 | params.kernel.count = count; |
| 328 | params.kernel.range_min = range_min; |
| 329 | params.kernel.range_scale = |
| 330 | CalculateOneOverRangeScale<uint8_t>(range_min, range_max); |
| 331 | |
| 332 | // After adding the range_offset the value is cast from float to uint. |
| 333 | // The float to int/uint cast in NEON uses round toward 0. To keep the |
| 334 | // rounding consistent with Eigen, which uses round toward closest, we can |
| 335 | // add 0.5f and exploit the fact that we only operate on non negative values. |
| 336 | // TODO(maciekc): fix the actual kernel in gemmlowp/meta |
| 337 | params.kernel.range_offset = |
| 338 | static_cast<float>(std::numeric_limits<uint8_t>::lowest()) + 0.5f; |
| 339 | |
| 340 | MultiThreadTransform1D<Params, 16>(tf_context, params); |
| 341 | #else |
| 342 | LOG(FATAL) << "Quantize: Meta fastpath not supported."; |
| 343 | #endif |
| 344 | } |
| 345 | |
| 346 | void QuantizedBiasAdd(OpKernelContext* tf_context, const quint8* input, |
| 347 | int input_count, const quint8* bias, int bias_count, |
no test coverage detected