Create fully integer ResizeBilinear kernel.
PiperOrigin-RevId: 317110515 Change-Id: I233b89083dda9f9e0150c97a88391a154fb32d50
This commit is contained in:
parent
3cea671a74
commit
06bc84b12e
@ -1645,6 +1645,109 @@ inline void ResizeBilinear(const tflite::ResizeBilinearParams& op_params,
|
||||
}
|
||||
}
|
||||
|
||||
inline void ComputeInterpolationValues(const int32 value, const int32 scale_10,
|
||||
const bool half_pixel_centers,
|
||||
int32 input_size, int32* scaled_value,
|
||||
int32* lower_bound, int32* upper_bound) {
|
||||
if (half_pixel_centers) {
|
||||
*scaled_value = value * scale_10 + scale_10 / 2 - (1 << 9);
|
||||
} else {
|
||||
*scaled_value = value * scale_10;
|
||||
}
|
||||
*lower_bound = std::max(*scaled_value / (1 << 10), 0);
|
||||
*upper_bound = std::min(*scaled_value / (1 << 10) + 1, input_size - 1);
|
||||
}
|
||||
|
||||
// Same as above but takes int8 as input and output.
|
||||
inline void ResizeBilinear(const tflite::ResizeBilinearParams& op_params,
|
||||
const RuntimeShape& unextended_input_shape,
|
||||
const int8_t* input_data,
|
||||
const RuntimeShape& unextended_output_size_shape,
|
||||
const int32* output_size_data,
|
||||
const RuntimeShape& unextended_output_shape,
|
||||
int8_t* output_data) {
|
||||
// If half_pixel_centers is True, align_corners must be False.
|
||||
TFLITE_DCHECK(!op_params.half_pixel_centers || !op_params.align_corners);
|
||||
TFLITE_DCHECK_LE(unextended_input_shape.DimensionsCount(), 4);
|
||||
TFLITE_DCHECK_LE(unextended_output_size_shape.DimensionsCount(), 4);
|
||||
TFLITE_DCHECK_LE(unextended_output_shape.DimensionsCount(), 4);
|
||||
const RuntimeShape input_shape =
|
||||
RuntimeShape::ExtendedShape(4, unextended_input_shape);
|
||||
const RuntimeShape output_size_shape =
|
||||
RuntimeShape::ExtendedShape(4, unextended_output_size_shape);
|
||||
const RuntimeShape output_shape =
|
||||
RuntimeShape::ExtendedShape(4, unextended_output_shape);
|
||||
|
||||
const int32 batches = MatchingDim(input_shape, 0, output_shape, 0);
|
||||
const int32 input_height = input_shape.Dims(1);
|
||||
const int32 input_width = input_shape.Dims(2);
|
||||
const int32 depth = MatchingDim(input_shape, 3, output_shape, 3);
|
||||
|
||||
TFLITE_DCHECK_EQ(output_size_shape.Dims(0), 1);
|
||||
TFLITE_DCHECK_EQ(output_size_shape.Dims(1), 1);
|
||||
TFLITE_DCHECK_EQ(output_size_shape.Dims(2), 1);
|
||||
TFLITE_DCHECK_EQ(output_size_shape.Dims(3), 2);
|
||||
const int32 output_height =
|
||||
output_size_data[Offset(output_size_shape, 0, 0, 0, 0)];
|
||||
const int32 output_width =
|
||||
output_size_data[Offset(output_size_shape, 0, 0, 0, 1)];
|
||||
|
||||
int32 height_scale_10 =
|
||||
((1 << 10) * input_height + output_height / 2) / output_height;
|
||||
int32 width_scale_10 =
|
||||
((1 << 10) * input_width + output_width / 2) / output_width;
|
||||
if (op_params.align_corners && output_height > 1) {
|
||||
height_scale_10 =
|
||||
((1 << 10) * (input_height - 1) + (output_height - 1) / 2) /
|
||||
(output_height - 1);
|
||||
}
|
||||
if (op_params.align_corners && output_width > 1) {
|
||||
width_scale_10 = ((1 << 10) * (input_width - 1) + (output_width - 1) / 2) /
|
||||
(output_width - 1);
|
||||
}
|
||||
|
||||
for (int b = 0; b < batches; ++b) {
|
||||
for (int y = 0; y < output_height; ++y) {
|
||||
int32 input_y, y0, y1;
|
||||
ComputeInterpolationValues(y, height_scale_10,
|
||||
op_params.half_pixel_centers, input_height,
|
||||
&input_y, &y0, &y1);
|
||||
for (int x = 0; x < output_width; ++x) {
|
||||
int32 input_x, x0, x1;
|
||||
ComputeInterpolationValues(x, width_scale_10,
|
||||
op_params.half_pixel_centers, input_width,
|
||||
&input_x, &x0, &x1);
|
||||
for (int c = 0; c < depth; ++c) {
|
||||
const int64_t output_20_ll =
|
||||
static_cast<int64_t>(
|
||||
input_data[Offset(input_shape, b, y0, x0, c)]) *
|
||||
((1 << 10) - (input_y - (1 << 10) * y0)) *
|
||||
((1 << 10) - (input_x - (1 << 10) * x0));
|
||||
const int64_t output_20_lu =
|
||||
static_cast<int64_t>(
|
||||
input_data[Offset(input_shape, b, y1, x0, c)]) *
|
||||
(input_y - (1 << 10) * y0) *
|
||||
((1 << 10) - (input_x - (1 << 10) * x0));
|
||||
const int64_t output_20_rl =
|
||||
static_cast<int64_t>(
|
||||
input_data[Offset(input_shape, b, y0, x1, c)]) *
|
||||
((1 << 10) - (input_y - (1 << 10) * y0)) *
|
||||
(input_x - (1 << 10) * x0);
|
||||
const int64_t output_20_ru =
|
||||
static_cast<int64_t>(
|
||||
input_data[Offset(input_shape, b, y1, x1, c)]) *
|
||||
(input_y - (1 << 10) * y0) * (input_x - (1 << 10) * x0);
|
||||
const int64_t output_20 =
|
||||
output_20_ll + output_20_lu + output_20_rl + output_20_ru;
|
||||
const int8_t interpolation =
|
||||
static_cast<int8_t>((output_20 + (1 << 19)) / (1 << 20));
|
||||
output_data[Offset(output_shape, b, y, x, c)] = interpolation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void SpaceToBatchND(
|
||||
const SpaceToBatchParams& params,
|
||||
|
Loading…
Reference in New Issue
Block a user