Enable Squeeze Opset 13 for NNAPI (#5717)

* Add copy sparse model in minimal CI

* Add squeeze 13 support

* fix small typo

* Add ut for squeeze in NNAPI

* Fix some issue in the UT and code

* Modify based on the master change

* Fix build break
This commit is contained in:
Guoyu Wang 2020-11-17 00:26:06 -08:00 committed by GitHub
parent 7b76b57fc8
commit 1a66dfc0f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 96 additions and 17 deletions

View file

@ -1677,10 +1677,44 @@ Status ConcatOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const
#pragma region op_squeeze
class SqueezeOpBuilder : public BaseOpBuilder {
public:
void AddInitializersToSkip(ModelBuilder& model_builder, const Node& node) const override;
private:
Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node) const override ORT_MUST_USE_RESULT;
static vector<int32_t> GetAxes(ModelBuilder& model_builder, const Node& node);
};
void SqueezeOpBuilder::AddInitializersToSkip(ModelBuilder& model_builder, const Node& node) const {
if (node.SinceVersion() > 12 && node.InputDefs().size() > 1) {
model_builder.AddInitializerToSkip(node.InputDefs()[1]->Name());
}
}
/* static */ vector<int32_t> SqueezeOpBuilder::GetAxes(ModelBuilder& model_builder, const Node& node) {
vector<int32_t> axes;
// Squeeze opset 13 use input as axes
if (node.SinceVersion() > 12) {
// If axes is not supplied, return an empty axes as default to squeeze all
if (node.InputDefs().size() > 1) {
const auto& initializers(model_builder.GetInitializerTensors());
const auto& axes_tensor = *initializers.at(node.InputDefs()[1]->Name());
const int64_t* raw_axes = GetTensorInt64Data(axes_tensor);
const auto size = SafeInt<uint32_t>(axes_tensor.dims()[0]);
axes.resize(size);
for (uint32_t i = 0; i < size; i++) {
// it is unlikely we have a axis value overflow for int32
axes[i] = static_cast<int32_t>(raw_axes[i]);
}
}
} else {
NodeAttrHelper helper(node);
axes = helper.Get("axes", vector<int32_t>());
}
return axes;
}
Status SqueezeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node) const {
auto& shaper(model_builder.GetShaper());
const auto& operand_indices(model_builder.GetOperandIndices());
@ -1693,7 +1727,7 @@ Status SqueezeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, cons
}
NodeAttrHelper helper(node);
vector<int32_t> axes = helper.Get("axes", vector<int32_t>());
vector<int32_t> axes = GetAxes(model_builder, node);
const auto& input_shape(shaper[input]);
auto input_dims = input_shape.size();
for (auto& axis : axes) {

View file

@ -793,13 +793,9 @@ class SqueezeOpSupportChecker : public BaseOpSupportChecker {
int32_t GetMinSupportedSdkVer(const Node& /* node */, const OpSupportCheckParams& /* params */) const override {
return 28;
}
// Squeeze opset 13+ uses input for axes, which is not supported yet
// TODO add support for squeeze opset 13+
int GetMaxSupportedOpSet(const Node& /* node */) const override { return 12; }
};
bool SqueezeOpSupportChecker::IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const Node& node,
bool SqueezeOpSupportChecker::IsOpSupportedImpl(const InitializedTensorSet& initializers, const Node& node,
const OpSupportCheckParams& /* params */) const {
Shape input_shape;
if (!GetShape(*node.InputDefs()[0], input_shape))
@ -812,6 +808,15 @@ bool SqueezeOpSupportChecker::IsOpSupportedImpl(const InitializedTensorSet& /* i
return false;
}
// Squeeze opset 13 use input 1 as axes, if we have input 1 then it need to be an initializer
if (node.SinceVersion() > 12 && node.InputDefs().size() > 1) {
const auto& axes_name = node.InputDefs()[1]->Name();
if (!Contains(initializers, axes_name)) {
LOGS_DEFAULT(VERBOSE) << "Input axes of Squeeze must be known";
return false;
}
}
return true;
}

View file

@ -267,7 +267,7 @@ TEST(OrtModelOnlyTests, SerializeToOrtFormat) {
TEST(OrtModelOnlyTests, SparseInitializerHandling) {
const std::basic_string<ORTCHAR_T> ort_file = ORT_TSTR("sparse_initializer_handling.onnx.ort");
SaveAndCompareModels("testdata/sparse_initializer_handling.onnx", ort_file);
SaveAndCompareModels("testdata/ort_minimal_test_models/sparse_initializer_handling.onnx", ort_file);
SessionOptions so;
so.session_logid = "LoadOrtFormat";

View file

@ -15,7 +15,7 @@ TEST(SqueezeOpTest, Squeeze_1) {
test.AddAttribute("axes", std::vector<int64_t>{0});
test.AddInput<float>("data", {1, 3, 4, 5}, std::vector<float>(60, 1.0f));
test.AddOutput<float>("squeezed", {3, 4, 5}, std::vector<float>(60, 1.0f));
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); //Incorrect precision. Will be re-enabled after it's fixed
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); //Incorrect precision. Will be re-enabled after it's fixed
}
TEST(SqueezeOpTest, Squeeze_Empty_Axes_1) {
@ -23,7 +23,7 @@ TEST(SqueezeOpTest, Squeeze_Empty_Axes_1) {
test.AddInput<float>("data", {1, 1, 4, 1}, std::vector<float>(4, 1.0f));
test.AddOutput<float>("squeezed", {4}, std::vector<float>(4, 1.0f));
// TensorRT doesn't seem to support missing 'axes'
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider});
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider});
}
TEST(SqueezeOpTest, Squeeze_Empty_Axes_2) {
@ -40,7 +40,7 @@ TEST(SqueezeOpTest, Squeeze_1_int32) {
test.AddAttribute("axes", std::vector<int64_t>{0});
test.AddInput<int32_t>("data", {1, 3, 4, 5}, std::vector<int32_t>(60, 1));
test.AddOutput<int32_t>("squeezed", {3, 4, 5}, std::vector<int32_t>(60, 1));
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); //Incorrect precision. Will be re-enabled after it's fixed
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); //Incorrect precision. Will be re-enabled after it's fixed
}
TEST(SqueezeOpTest, Squeeze_string) {
@ -58,7 +58,7 @@ TEST(SqueezeOpTest, Squeeze_2) {
std::vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f});
test.AddOutput<float>("squeezed", {4, 2},
std::vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f});
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); //Incorrect precision. Will be re-enabled after it's fixed
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); //Incorrect precision. Will be re-enabled after it's fixed
}
TEST(SqueezeOpTest, UnsortedAxes) {
@ -69,7 +69,7 @@ TEST(SqueezeOpTest, UnsortedAxes) {
std::vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f});
test.AddOutput<float>("squeezed", {4, 2},
std::vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f});
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); //Incorrect precision. Will be re-enabled after it's fixed
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); //Incorrect precision. Will be re-enabled after it's fixed
}
TEST(SqueezeOpTest, DuplicateAxes) {
@ -80,7 +80,7 @@ TEST(SqueezeOpTest, DuplicateAxes) {
std::vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f});
test.AddOutput<float>("squeezed", {4, 2},
std::vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f});
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); //Incorrect precision. Will be re-enabled after it's fixed
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); //Incorrect precision. Will be re-enabled after it's fixed
}
TEST(SqueezeOpTest, BadAxes) {
@ -105,7 +105,7 @@ TEST(SqueezeOpTest, SqueezeNegAxis_2) {
// nGraph does not support neg axis.
// OpenVINO EP Incorrect precision. Will be re-enabled after its fixed
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kNGraphExecutionProvider, kOpenVINOExecutionProvider});
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kNGraphExecutionProvider, kOpenVINOExecutionProvider});
}
TEST(SqueezeOpTest, Squeeze_2_axes_input) {
@ -117,7 +117,7 @@ TEST(SqueezeOpTest, Squeeze_2_axes_input) {
std::vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f});
// Incorrect precision for OpenVINO EP. Will be re-enabled after it's fixed
// TensorRT and OpenVINO dont support "axes" input in opset 13, re-enable after
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider, kTensorrtExecutionProvider});
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider, kTensorrtExecutionProvider});
}
TEST(SqueezeOpTest, Squeeze_Empty_Axes_opset13) {
@ -125,7 +125,7 @@ TEST(SqueezeOpTest, Squeeze_Empty_Axes_opset13) {
test.AddInput<float>("data", {1, 1, 4, 1}, std::vector<float>(4, 1.0f));
test.AddOutput<float>("squeezed", {4}, std::vector<float>(4, 1.0f));
// TensorRT doesn't seem to support missing 'axes'
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider});
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider});
}
TEST(SqueezeOpTest, SqueezeNegAxis_axes_input) {
@ -133,7 +133,7 @@ TEST(SqueezeOpTest, SqueezeNegAxis_axes_input) {
test.AddInput<float>("data", {1, 4, 1, 1, 2},
std::vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f});
test.AddInput<int64_t>("axes",{3} ,std::vector<int64_t>{0, -3, -2});
test.AddInput<int64_t>("axes", {3}, std::vector<int64_t>{0, -3, -2});
test.AddOutput<float>("squeezed", {4, 2},
std::vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f});
@ -143,5 +143,44 @@ TEST(SqueezeOpTest, SqueezeNegAxis_axes_input) {
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kNGraphExecutionProvider, kOpenVINOExecutionProvider, kTensorrtExecutionProvider});
}
// Add 4d input shape test, since NNAPI supports up to 4d input shape
TEST(SqueezeOpTest, Squeeze_4d_2_axes_input) {
auto run_test = [](bool axes_is_initializer) {
OpTester test("Squeeze", 13);
test.AddInput<float>("data", {1, 4, 1, 2},
std::vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f});
test.AddInput<int64_t>("axes", {2}, std::vector<int64_t>{0, 2}, axes_is_initializer);
test.AddOutput<float>("squeezed", {4, 2},
std::vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f});
// Incorrect precision for OpenVINO EP. Will be re-enabled after it's fixed
// TensorRT and OpenVINO dont support "axes" input in opset 13, re-enable after
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider, kTensorrtExecutionProvider});
};
run_test(false);
run_test(true); // NNAPI EP will need axes as an initializer
}
// Add 4d input shape test, since NNAPI supports up to 4d input shape
TEST(SqueezeOpTest, Squeeze_4d_NegAxis_axes_input) {
auto run_test = [](bool axes_is_initializer) {
OpTester test("Squeeze", 13);
test.AddInput<float>("data", {1, 4, 1, 2},
std::vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f});
test.AddInput<int64_t>("axes", {2}, std::vector<int64_t>{0, -2}, axes_is_initializer);
test.AddOutput<float>("squeezed", {4, 2},
std::vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f});
// nGraph does not support neg axis.
// OpenVINO EP Incorrect precision. Will be re-enabled after its fixed
// TensorRT and OpenVINO dont support "axes" input in opset 13, re-enable after
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kNGraphExecutionProvider, kOpenVINOExecutionProvider, kTensorrtExecutionProvider});
};
run_test(false);
run_test(true); // NNAPI EP will need axes as an initializer
}
} // namespace test
} // namespace onnxruntime

View file

@ -16,6 +16,7 @@ rm -rf /build/Debug
# which will be used as the input of --include_ops_by_model to have ops to be included for the minimal build UT.
mkdir -p /home/onnxruntimedev/.test_data/models_to_include
cp /onnxruntime_src/onnxruntime/test/testdata/ort_github_issue_4031.onnx /home/onnxruntimedev/.test_data/models_to_include
cp /onnxruntime_src/onnxruntime/test/testdata/ort_minimal_test_models/*.onnx /home/onnxruntimedev/.test_data/models_to_include
# Build a minimal build with included ops and models
# then run ORT minimal UTs