Add int16x8 support for RESIZE_NEAREST_NEIGHBOR operator

This commit is contained in:
Thibaut Goetghebuer-Planchon 2020-07-17 09:38:52 +01:00
parent 00c6f88dd1
commit 860898de6f
10 changed files with 102 additions and 4 deletions

View File

@ -331,6 +331,8 @@ ResizeNearestNeighborOpTest/ResizeNearestNeighborOpTest.+AlignCorners.*/0,30
ResizeNearestNeighborOpTest/ResizeNearestNeighborOpTest.+HalfPixelCenters.*/0,30
// Only models with constant size tensor are accelerated
ResizeNearestNeighborOpTest/ResizeNearestNeighborOpTest/.+/0,29
// 16-bit tests are not supported
-ResizeNearestNeighborOpTest/.*Int16.*
# select_test
-SelectOpTest/SelectBool

View File

@ -91,6 +91,17 @@ TEST(ResizeNearestNeighborReference, Test2x2To3x3) {
output_shape, output_data);
}
TEST(ResizeNearestNeighborReference, Test2x2To3x3Int16) {
RuntimeShape input_shape = {1, 2, 2, 1};
std::vector<int16_t> input_data = {1, 2, 3, 4};
std::vector<int32> output_size_data = {3, 3};
RuntimeShape output_shape = {1, 3, 3, 1};
std::vector<int16_t> output_data = {1, 1, 2, 1, 1, 2, 3, 3, 4};
TestReferenceResizeNearestNeighbor(input_shape, input_data, output_size_data,
output_shape, output_data);
}
TEST(ResizeNearestNeighborReference, Test2x2To3x3_AlignCorners) {
RuntimeShape input_shape = {1, 2, 2, 1};
std::vector<uint8> input_data = {1, 2, 3, 4};

View File

@ -123,7 +123,7 @@ BuiltinOpResolver::BuiltinOpResolver() {
AddBuiltin(BuiltinOperator_RESIZE_NEAREST_NEIGHBOR,
Register_RESIZE_NEAREST_NEIGHBOR(),
/* min_version = */ 1,
/* max_version = */ 3);
/* max_version = */ 4);
AddBuiltin(BuiltinOperator_SKIP_GRAM, Register_SKIP_GRAM());
AddBuiltin(BuiltinOperator_SPACE_TO_DEPTH, Register_SPACE_TO_DEPTH(),
/* min_version = */ 1,

View File

@ -121,6 +121,11 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
op_params, GetTensorShape(input), GetTensorData<int8_t>(input),
GetTensorShape(size), GetTensorData<int32>(size),
GetTensorShape(output), GetTensorData<int8_t>(output));
} else if (output->type == kTfLiteInt16) {
reference_ops::ResizeNearestNeighbor(
op_params, GetTensorShape(input), GetTensorData<int16_t>(input),
GetTensorShape(size), GetTensorData<int32>(size),
GetTensorShape(output), GetTensorData<int16_t>(output));
} else {
TF_LITE_KERNEL_LOG(context,
"Output type is %s, requires float, uint8 or int8.",

View File

@ -106,6 +106,14 @@ TEST_P(ResizeNearestNeighborOpTest, HorizontalResizeInt8) {
EXPECT_THAT(m.GetOutput<int8_t>(),
ElementsAreArray(ArrayFloatNear({-3, -3, 6})));
}
TEST_P(ResizeNearestNeighborOpTest, HorizontalResizeInt16) {
ResizeNearestNeighborOpModel m({TensorType_INT16, {1, 1, 2, 1}}, {1, 3},
GetParam());
m.SetInput<int16_t>({-3, 6});
m.Invoke();
EXPECT_THAT(m.GetOutput<int16_t>(),
ElementsAreArray(ArrayFloatNear({-3, -3, 6})));
}
TEST_P(ResizeNearestNeighborOpTest, VerticalResize) {
ResizeNearestNeighborOpModel m({TensorType_FLOAT32, {1, 2, 1, 1}}, {3, 1},
GetParam());
@ -130,6 +138,14 @@ TEST_P(ResizeNearestNeighborOpTest, VerticalResizeInt8) {
EXPECT_THAT(m.GetOutput<int8_t>(),
ElementsAreArray(ArrayFloatNear({3, 3, -9})));
}
TEST_P(ResizeNearestNeighborOpTest, VerticalResizeInt16) {
ResizeNearestNeighborOpModel m({TensorType_INT16, {1, 2, 1, 1}}, {3, 1},
GetParam());
m.SetInput<int16_t>({3, -9});
m.Invoke();
EXPECT_THAT(m.GetOutput<int16_t>(),
ElementsAreArray(ArrayFloatNear({3, 3, -9})));
}
TEST_P(ResizeNearestNeighborOpTest, TwoDimensionalResize) {
ResizeNearestNeighborOpModel m({TensorType_FLOAT32, {1, 2, 2, 1}}, {3, 3},
GetParam());
@ -172,6 +188,20 @@ TEST_P(ResizeNearestNeighborOpTest, TwoDimensionalResizeInt8) {
9, 9, 12, //
})));
}
TEST_P(ResizeNearestNeighborOpTest, TwoDimensionalResizeInt16) {
ResizeNearestNeighborOpModel m({TensorType_INT16, {1, 2, 2, 1}}, {3, 3},
GetParam());
m.SetInput<int16_t>({
3, -6, //
9, 12 //
});
m.Invoke();
EXPECT_THAT(m.GetOutput<int16_t>(), ElementsAreArray(ArrayFloatNear({
3, 3, -6, //
3, 3, -6, //
9, 9, 12, //
})));
}
TEST_P(ResizeNearestNeighborOpTest, TwoDimensionalResizeWithTwoBatches) {
ResizeNearestNeighborOpModel m({TensorType_FLOAT32, {2, 2, 2, 1}}, {3, 3},
GetParam());
@ -284,6 +314,25 @@ TEST_P(ResizeNearestNeighborOpTest, TwoDimensionalResizeWithTwoBatchesInt8) {
12, 12, 16, //
})));
}
TEST_P(ResizeNearestNeighborOpTest, TwoDimensionalResizeWithTwoBatchesInt16) {
ResizeNearestNeighborOpModel m({TensorType_INT16, {2, 2, 2, 1}}, {3, 3},
GetParam());
m.SetInput<int16_t>({
3, 6, //
9, -12, //
-4, 10, //
12, 16 //
});
m.Invoke();
EXPECT_THAT(m.GetOutput<int16_t>(), ElementsAreArray(ArrayFloatNear({
3, 3, 6, //
3, 3, 6, //
9, 9, -12, //
-4, -4, 10, //
-4, -4, 10, //
12, 12, 16, //
})));
}
TEST_P(ResizeNearestNeighborOpTest, ThreeDimensionalResizeUInt8) {
ResizeNearestNeighborOpModel m({TensorType_UINT8, {1, 2, 2, 2}}, {3, 3},
GetParam());
@ -342,6 +391,20 @@ TEST_P(ResizeNearestNeighborOpTest, ThreeDimensionalResizeInt8) {
10, 12, 10, 12, -14, 16, //
})));
}
TEST_P(ResizeNearestNeighborOpTest, ThreeDimensionalResizeInt16) {
ResizeNearestNeighborOpModel m({TensorType_INT16, {1, 2, 2, 2}}, {3, 3},
GetParam());
m.SetInput<int16_t>({
3, 4, -6, 10, //
10, 12, -14, 16, //
});
m.Invoke();
EXPECT_THAT(m.GetOutput<int16_t>(), ElementsAreArray(ArrayFloatNear({
3, 4, 3, 4, -6, 10, //
3, 4, 3, 4, -6, 10, //
10, 12, 10, 12, -14, 16, //
})));
}
INSTANTIATE_TEST_SUITE_P(ResizeNearestNeighborOpTest,
ResizeNearestNeighborOpTest,
testing::Values(TestType::kConst, TestType::kDynamic));

View File

@ -145,6 +145,7 @@ std::string GetMinimumRuntimeVersionForModel(const Model& model) {
{{OperatorType::kResizeNearestNeighbor, 1}, "1.13.1"},
{{OperatorType::kResizeNearestNeighbor, 2}, "1.14.0"},
{{OperatorType::kResizeNearestNeighbor, 3}, kPendingReleaseOpVersion},
{{OperatorType::kResizeNearestNeighbor, 4}, kPendingReleaseOpVersion},
{{OperatorType::kSqueeze, 1}, "1.6.0"},
{{OperatorType::kSplit, 1}, "1.5.0"},
{{OperatorType::kSplit, 2}, "1.14.0"},

View File

@ -868,13 +868,18 @@ OperatorProperty GetOperatorProperty(const ModelT* model, int subgraph_index,
property.version = 1;
break;
case BuiltinOperator_RESIZE_BILINEAR:
case BuiltinOperator_RESIZE_NEAREST_NEIGHBOR:
property.inputs = {{0, {}}};
property.outputs = {{0, {}}};
property.restrict_same_input_output_scale = true;
property.version = 2;
property.quantizable_int16 = false;
break;
case BuiltinOperator_RESIZE_NEAREST_NEIGHBOR:
property.inputs = {{0, {}}};
property.outputs = {{0, {}}};
property.restrict_same_input_output_scale = true;
property.version = 2;
break;
case BuiltinOperator_SHAPE:
property.inputs = {{0, {}}};
// Shape has no quantizable output.

View File

@ -396,8 +396,10 @@ int GetBuiltinOperatorVersion(const OpSignature& op_sig) {
}
return 1;
case BuiltinOperator_RESIZE_NEAREST_NEIGHBOR:
if (op_sig.options.resize.half_pixel_centers ||
op_sig.options.resize.align_corners) {
if (op_sig.input_types.at(0) == TensorType_INT16) {
return 4;
} else if (op_sig.options.resize.half_pixel_centers ||
op_sig.options.resize.align_corners) {
return 3;
} else if (op_sig.input_types.at(0) == TensorType_INT8) {
return 2;

View File

@ -697,5 +697,13 @@ TEST(OpVersionTest, VersioningResizeNearestNeighborTest) {
fake_op_sig.options.resize.align_corners = true;
EXPECT_EQ(GetBuiltinOperatorVersion(fake_op_sig), 3);
// int16 input is version 4.
fake_op_sig = {
.op = BuiltinOperator_RESIZE_NEAREST_NEIGHBOR,
.input_types = std::vector<TensorType>{TensorType_INT16, TensorType_INT32},
.output_types = std::vector<TensorType>{TensorType_INT16},
};
EXPECT_EQ(GetBuiltinOperatorVersion(fake_op_sig), 4);
}
} // namespace tflite

View File

@ -186,6 +186,7 @@ std::string FindMinimumRuntimeVersionForOp(tflite::BuiltinOperator op_code,
{{BuiltinOperator_RESIZE_NEAREST_NEIGHBOR, 1}, "1.13.1"},
{{BuiltinOperator_RESIZE_NEAREST_NEIGHBOR, 2}, "1.14.0"},
{{BuiltinOperator_RESIZE_NEAREST_NEIGHBOR, 3}, "2.3.0"},
{{BuiltinOperator_RESIZE_NEAREST_NEIGHBOR, 4}, kPendingReleaseVersion},
{{BuiltinOperator_RNN, 1}, "1.5.0"},
{{BuiltinOperator_RNN, 2}, "1.14.0"},
{{BuiltinOperator_RNN, 3}, "2.3.0"},