| 164 | } |
| 165 | |
| 166 | void QuantizeTensor(OpKernelContext* ctx, const Tensor& input, |
| 167 | const float input_min_range, const float input_max_range, |
| 168 | Tensor* output, Tensor* output_min_tensor, |
| 169 | Tensor* output_max_tensor) { |
| 170 | OP_REQUIRES(ctx, !(input_max_range < input_min_range), |
| 171 | errors::InvalidArgument( |
| 172 | "input_max_range must be larger than input_min_range.")); |
| 173 | |
| 174 | // When the minimum and maximum ranges are too close together, nudge them |
| 175 | // apart by a small value so that they are slightly different. This helps |
| 176 | // us avoid creating ill-formed buffers where all quantized values map to |
| 177 | // the same float number. These kinds of buffers cause problems for |
| 178 | // downstream ops when they need to do calculations on them. |
| 179 | // We pick the value by making sure that zero is not more than 100x the |
| 180 | // overall range from the maximum, so that the value can be easily |
| 181 | // represented when we promote the quantized value to a higher |
| 182 | // intermediate bit depth, since that's a common requirement. |
| 183 | float min_range = std::min(0.0f, input_min_range); |
| 184 | const float epsilon = std::max(1.0f, std::max(fabsf(input_min_range), |
| 185 | fabsf(input_max_range))) * |
| 186 | ensure_minimum_range_; |
| 187 | float max_range = |
| 188 | std::max(0.0f, std::max(input_max_range, min_range + epsilon)); |
| 189 | |
| 190 | if (mode_ == QUANTIZE_MODE_MIN_FIRST) { |
| 191 | if (meta::IsSupportedAndEnabled() && std::is_same<T, quint8>()) { |
| 192 | TTypes<const float>::Vec input_array = input.flat<float>(); |
| 193 | |
| 194 | meta::Quantize(ctx, input_array.data(), input_array.size(), min_range, |
| 195 | max_range, output->flat<quint8>().data()); |
| 196 | } else { |
| 197 | FloatTensorToQuantizedInPlaceUsingEigen<T>( |
| 198 | ctx->template eigen_device<Device>(), input, min_range, max_range, |
| 199 | output); |
| 200 | } |
| 201 | output_min_tensor->flat<float>()(0) = min_range; |
| 202 | output_max_tensor->flat<float>()(0) = max_range; |
| 203 | } else { |
| 204 | QuantizeSlice(ctx->eigen_device<Device>(), ctx, input.flat<float>(), |
| 205 | input_min_range, input_max_range, |
| 206 | output->template flat<T>(), |
| 207 | &output_min_tensor->flat<float>()(0), |
| 208 | &output_max_tensor->flat<float>()(0)); |
| 209 | } |
| 210 | } |
| 211 | |
| 212 | template <typename ConstVec, typename Vec> |
| 213 | void QuantizeSlice(const Device& d, OpKernelContext* ctx, |
nothing calls this directly
no test coverage detected