diff --git a/onnxruntime/contrib_ops/cpu/range.cc b/onnxruntime/contrib_ops/cpu/range.cc deleted file mode 100644 index fffe378aac..0000000000 --- a/onnxruntime/contrib_ops/cpu/range.cc +++ /dev/null @@ -1,90 +0,0 @@ -#include "range.h" -#include "onnx/defs/schema.h" - -#include - -namespace onnxruntime { -namespace contrib { - -template -static Status ComputeRange(OpKernelContext* ctx) { - auto& start_tensor = *ctx->Input(0); - auto& limit_tensor = *ctx->Input(1); - auto delta_tensor_ptr = ctx->Input(2); - - if (!start_tensor.Shape().IsScalar()) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "start in Range operator should be scalar like tensor, yet got shape:", - start_tensor.Shape()); - } - if (!limit_tensor.Shape().IsScalar()) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "limit in Range operator should be scalar like tensor, yet got shape:", - limit_tensor.Shape()); - } - if (delta_tensor_ptr != nullptr && !delta_tensor_ptr->Shape().IsScalar()) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "delta in Range operator should be scalar like tensor, yet got shape:", - delta_tensor_ptr->Shape()); - } - - T start = *start_tensor.template Data(); - T limit = *limit_tensor.template Data(); - T delta = (delta_tensor_ptr == nullptr) ? T{1} : *(delta_tensor_ptr->template Data()); - - if (delta == T{0}) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "delta in Range operator can not be zero!"); - } - int64_t n = static_cast(ceil((1.0 * (limit - start)) / delta)); - if (n <= 0) n = 0; - TensorShape shape = {n}; - T* y = ctx->Output(0, shape)->template MutableData(); - for (int64_t i = 0; i < n; ++i) { - *y++ = start; - start += delta; - } - - return Status::OK(); -} - -Status Range::Compute(OpKernelContext* ctx) const { - auto input_tensor = ctx->Input(0); - if (input_tensor == nullptr) return Status(common::ONNXRUNTIME, common::FAIL, "input count mismatch"); - auto data_type = input_tensor->DataType(); - if (data_type == DataTypeImpl::GetType()) { - return ComputeRange(ctx); - } - else if (data_type == DataTypeImpl::GetType()) { - return ComputeRange(ctx); - } - else if (data_type == DataTypeImpl::GetType()) { - return ComputeRange(ctx); - } - else if (data_type == DataTypeImpl::GetType()) { - return ComputeRange(ctx); - } - else if (data_type == DataTypeImpl::GetType()) { - return ComputeRange(ctx); - } - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "Unsupportted tensor data type:", - data_type); -} - -/* Range operator */ -ONNX_OPERATOR_KERNEL_EX( - Range, //name - kMSDomain, - 1, - kCpuExecutionProvider, - KernelDefBuilder().TypeConstraint("T", { - DataTypeImpl::GetTensorType(), - DataTypeImpl::GetTensorType(), - DataTypeImpl::GetTensorType(), - DataTypeImpl::GetTensorType(), - DataTypeImpl::GetTensorType()}), - Range); - - -} // namespace contrib -} // namespace onnxruntime diff --git a/onnxruntime/core/providers/cpu/cpu_execution_provider.cc b/onnxruntime/core/providers/cpu/cpu_execution_provider.cc index fc27c28979..0bcc81ee32 100644 --- a/onnxruntime/core/providers/cpu/cpu_execution_provider.cc +++ b/onnxruntime/core/providers/cpu/cpu_execution_provider.cc @@ -394,6 +394,7 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Ge class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, GatherElements); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Pad); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, GatherND); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Range); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Unique); void RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) { @@ -1011,6 +1012,7 @@ void RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo}; for (auto& function_table_entry : function_table) { diff --git a/onnxruntime/core/providers/cpu/generator/range.cc b/onnxruntime/core/providers/cpu/generator/range.cc new file mode 100644 index 0000000000..60719c5e19 --- /dev/null +++ b/onnxruntime/core/providers/cpu/generator/range.cc @@ -0,0 +1,103 @@ +#include "range.h" + +#include + +namespace onnxruntime { + +// Register a kernel for kMsDomain (contrib op) Range +#ifndef DISABLE_CONTRIB_OPS + +namespace contrib { +// TODO: Remove this contrib kernel registration and the schema from the appropriate places +// once Keras Mask RCNN is shipped with all ONNX domain ops + +// Currently this kernel is required to support Keras Mask-RCNN +ONNX_OPERATOR_KERNEL_EX( + Range, //name + kMSDomain, + 1, + kCpuExecutionProvider, + KernelDefBuilder().TypeConstraint("T", {DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType()}), + Range); + +} // namespace contrib + +#endif + +ONNX_CPU_OPERATOR_KERNEL( + Range, + 11, + KernelDefBuilder().TypeConstraint("T", {DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType()}), + Range); + +template +static Status ComputeRange(OpKernelContext* ctx) { + const auto& start_tensor = *ctx->Input(0); + const auto& limit_tensor = *ctx->Input(1); + const auto* delta_tensor_ptr = ctx->Input(2); + + if (!start_tensor.Shape().IsScalar()) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "start in Range operator should be scalar like tensor, yet got shape:", + start_tensor.Shape()); + } + if (!limit_tensor.Shape().IsScalar()) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "limit in Range operator should be scalar like tensor, yet got shape:", + limit_tensor.Shape()); + } + if (delta_tensor_ptr != nullptr && !delta_tensor_ptr->Shape().IsScalar()) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "delta in Range operator should be scalar like tensor, yet got shape:", + delta_tensor_ptr->Shape()); + } + + T start = *start_tensor.template Data(); + T limit = *limit_tensor.template Data(); + T delta = (delta_tensor_ptr == nullptr) ? T{1} : *(delta_tensor_ptr->template Data()); + + if (delta == T{0}) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "delta in Range operator can not be zero!"); + } + int64_t n = static_cast(ceil((1.0 * (limit - start)) / delta)); + if (n <= 0) + n = 0; + TensorShape shape = {n}; + T* y = ctx->Output(0, shape)->template MutableData(); + for (int64_t i = 0; i < n; ++i) { + *y++ = start; + start += delta; + } + + return Status::OK(); +} + +Status Range::Compute(OpKernelContext* ctx) const { + const auto* input_tensor = ctx->Input(0); + if (input_tensor == nullptr) return Status(common::ONNXRUNTIME, common::FAIL, "input count mismatch"); + auto data_type = input_tensor->DataType(); + if (data_type == DataTypeImpl::GetType()) { + return ComputeRange(ctx); + } else if (data_type == DataTypeImpl::GetType()) { + return ComputeRange(ctx); + } else if (data_type == DataTypeImpl::GetType()) { + return ComputeRange(ctx); + } else if (data_type == DataTypeImpl::GetType()) { + return ComputeRange(ctx); + } else if (data_type == DataTypeImpl::GetType()) { + return ComputeRange(ctx); + } + + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Range op: Unsupported tensor data type:", data_type); +} + +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cpu/range.h b/onnxruntime/core/providers/cpu/generator/range.h similarity index 90% rename from onnxruntime/contrib_ops/cpu/range.h rename to onnxruntime/core/providers/cpu/generator/range.h index 5d7ef25238..678eb961f7 100644 --- a/onnxruntime/contrib_ops/cpu/range.h +++ b/onnxruntime/core/providers/cpu/generator/range.h @@ -8,7 +8,6 @@ #include "core/framework/tensor.h" namespace onnxruntime { -namespace contrib { class Range : public OpKernel { public: @@ -17,5 +16,4 @@ class Range : public OpKernel { Status Compute(OpKernelContext* context) const override; }; -} // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/test/contrib_ops/range_test.cc b/onnxruntime/test/contrib_ops/range_test.cc deleted file mode 100644 index 32c892e945..0000000000 --- a/onnxruntime/test/contrib_ops/range_test.cc +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "gtest/gtest.h" -#include "test/providers/provider_test_utils.h" - -namespace onnxruntime { -namespace test { - -TEST(RangeTest, PositiveInt32DeltaDefault) { - OpTester test("Range", 1, onnxruntime::kMSDomain); - std::vector start = {0}; - std::vector limit = {5}; - std::vector expected_output = {0, 1, 2, 3, 4}; - - test.AddInput("start", {1}, start); - test.AddInput("limit", {1}, limit); - test.AddOutput("Y", {5LL}, expected_output); - test.Run(); -} - -TEST(RangeTest, PositiveInt32Delta_0) { - OpTester test("Range", 1, onnxruntime::kMSDomain); - std::vector start = {0}; - std::vector limit = {10}; - std::vector delta = {2}; - std::vector expected_output = {0, 2, 4, 6, 8}; - - test.AddInput("start", {1}, start); - test.AddInput("limit", {1}, limit); - test.AddInput("delta", {1}, delta); - test.AddOutput("Y", {5LL}, expected_output); - test.Run(); -} - -TEST(RangeTest, PositiveInt32Delta_1) { - OpTester test("Range", 1, onnxruntime::kMSDomain); - std::vector start = {0}; - std::vector limit = {9}; - std::vector delta = {2}; - std::vector expected_output = {0, 2, 4, 6, 8}; - - test.AddInput("start", {1}, start); - test.AddInput("limit", {1}, limit); - test.AddInput("delta", {1}, delta); - test.AddOutput("Y", {5LL}, expected_output); - test.Run(); -} - -TEST(RangeTest, PositiveInt32Delta_2) { - OpTester test("Range", 1, onnxruntime::kMSDomain); - std::vector start = {1}; - std::vector limit = {2}; - std::vector delta = {2}; - std::vector expected_output = {1}; - - test.AddInput("start", {1}, start); - test.AddInput("limit", {1}, limit); - test.AddInput("delta", {1}, delta); - test.AddOutput("Y", {1LL}, expected_output); - test.Run(); -} - -TEST(RangeTest, Int32ScalarNegativeDelta_0) { - OpTester test("Range", 1, onnxruntime::kMSDomain); - std::vector start = {2}; - std::vector limit = {-9}; - std::vector delta = {-2}; - std::vector expected_output = {2, 0, -2, -4, -6, -8}; - - test.AddInput("start", {}, start); - test.AddInput("limit", {}, limit); - test.AddInput("delta", {}, delta); - test.AddOutput("Y", {6LL}, expected_output); - test.Run(); -} - - -TEST(RangeTest, Int32ScalarNegativeDelta_1) { - OpTester test("Range", 1, onnxruntime::kMSDomain); - std::vector start = {2}; - std::vector limit = {9}; - std::vector delta = {-2}; - std::vector expected_output = {}; - - test.AddInput("start", {}, start); - test.AddInput("limit", {}, limit); - test.AddInput("delta", {}, delta); - test.AddOutput("Y", {0}, expected_output); - test.Run(); -} - -TEST(RangeTest, ScalarFloatNegativeDelta) { - OpTester test("Range", 1, onnxruntime::kMSDomain); - std::vector start = {2.0f}; - std::vector limit = {-8.1f}; - std::vector delta = {-2.0f}; - std::vector expected_output = {2.0f, 0.0f, -2.0f, -4.0f, -6.0f, -8.0f}; - - test.AddInput("start", {}, start); - test.AddInput("limit", {}, limit); - test.AddInput("delta", {}, delta); - test.AddOutput("Y", {6LL}, expected_output); - test.Run(); -} - -TEST(RangeTest, SameStartAndLimit) { - OpTester test("Range", 1, onnxruntime::kMSDomain); - std::vector start = {2.0f}; - std::vector limit = {2.0f}; - std::vector expected_output = {}; - - test.AddInput("start", {}, start); - test.AddInput("limit", {}, limit); - test.AddOutput("Y", {0}, expected_output); - test.Run(); -} - -TEST(RangeTest, AlmostSameStartAndLimitHighDelta) { - OpTester test("Range", 1, onnxruntime::kMSDomain); - std::vector start = {2.0f}; - std::vector limit = {2.01f}; - std::vector delta = {1000000.0f}; - std::vector expected_output = {2.0f}; - - test.AddInput("start", {}, start); - test.AddInput("limit", {}, limit); - test.AddInput("delta", {}, delta); - test.AddOutput("Y", {1}, expected_output); - test.Run(); -} -} // namespace test -} // namespace onnxruntime diff --git a/onnxruntime/test/onnx/main.cc b/onnxruntime/test/onnx/main.cc index 18ac64e5f6..6c5fbae387 100644 --- a/onnxruntime/test/onnx/main.cc +++ b/onnxruntime/test/onnx/main.cc @@ -394,10 +394,6 @@ int real_main(int argc, char* argv[], Ort::Env& env) { {"top_k_negative_axis", "TopK(11) not implemented yet"}, {"unique_not_sorted_without_axis", "Expected data for 'Y' is incorrect and in sorted order."}, {"cumsum_1d_reverse_exclusive", "only failing linux GPU CI. Likely build error."}, - {"range_float_type_positive_delta", "not implemented yet"}, - {"range_float_type_positive_delta_expanded", "not implemented yet"}, - {"range_int32_type_negative_delta", "not implemented yet"}, - {"range_int32_type_negative_delta_expanded", "not implemented yet"}, {"det_2d", "not implemented yet"}, {"det_nd", "not implemented yet"}, {"resize_downsample_scales_cubic_A_n0p5_exclude_outside", "not implemented yet"}, @@ -500,6 +496,8 @@ int real_main(int argc, char* argv[], Ort::Env& env) { broken_tests.insert({"tf_mobilenet_v1_1.0_224", "result mismatch"}); broken_tests.insert({"mobilenetv2-1.0", "result mismatch"}); broken_tests.insert({"candy", "result mismatch"}); + broken_tests.insert({"range_float_type_positive_delta_expanded", "get unknown exception from MKLDNN EP"}); + broken_tests.insert({"range_int32_type_negative_delta_expanded", "get unknown exception from MKLDNN EP"}); #endif #ifdef USE_OPENVINO diff --git a/onnxruntime/test/providers/cpu/generator/range_test.cc b/onnxruntime/test/providers/cpu/generator/range_test.cc new file mode 100644 index 0000000000..1768e1edbc --- /dev/null +++ b/onnxruntime/test/providers/cpu/generator/range_test.cc @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "gtest/gtest.h" +#include "test/providers/provider_test_utils.h" + +namespace onnxruntime { +namespace test { + +template +static void RunTest( + T start, + T limit, + T delta, + const std::vector& output_dims, + const std::vector& output) { + // ONNX domain opset-11 + OpTester test1("Range", 11); + test1.AddInput("start", {}, {start}); + test1.AddInput("limit", {}, {limit}); + test1.AddInput("delta", {}, {delta}); + test1.AddOutput("output", output_dims, output); + // NGraph does not yet support opset-11 and builds break on this test, hence exclude the EP + test1.Run(OpTester::ExpectResult::kExpectSuccess, "", {kNGraphExecutionProvider}); + +#ifndef DISABLE_CONTRIB_OPS + + // MSFT domain opset-1 (contrib op) + OpTester test2("Range", 1, kMSDomain); + test2.AddInput("start", {}, {start}); + test2.AddInput("limit", {}, {limit}); + + if (delta != T{1}) // only contrib schema allows optional 'delta' input + test2.AddInput("delta", {}, {delta}); + + test2.AddOutput("output", output_dims, output); + test2.Run(); + +#endif +} // namespace test + +TEST(RangeTest, Int32_DeltaDefault) { + RunTest(0, 5, 1, {5}, {0, 1, 2, 3, 4}); +} + +TEST(RangeTest, Int64_DeltaDefault) { + RunTest(0, 5, 1, {5}, {0, 1, 2, 3, 4}); +} + +TEST(RangeTest, Float_DeltaDefault) { + RunTest(0.f, 5.f, 1.f, {5}, {0.f, 1.f, 2.f, 3.f, 4.f}); +} + +TEST(RangeTest, Double_DeltaDefault) { + RunTest(0., 5., 1., {5}, {0., 1., 2., 3., 4.}); +} + +TEST(RangeTest, Int32_Delta_NonDefault) { + RunTest(0, 10, 2, {5}, {0, 2, 4, 6, 8}); +} + +TEST(RangeTest, Int64_Delta_NonDefault_0) { + RunTest(0, 9, 2, {5}, {0, 2, 4, 6, 8}); +} + +TEST(RangeTest, Int64_Delta_NonDefault_1) { + RunTest(1, 2, 2, {1}, {1}); +} + +TEST(RangeTest, Int32_NegativeDelta_0) { + RunTest(2, -9, -2, {6}, {2, 0, -2, -4, -6, -8}); +} + +TEST(RangeTest, Int32_NegativeDelta_1) { + RunTest(2, 9, -2, {0}, {}); +} + +TEST(RangeTest, Float_NegativeDelta_0) { + RunTest(2.0f, -8.1f, -2.0f, {6}, {2.0f, 0.0f, -2.0f, -4.0f, -6.0f, -8.0f}); +} + +TEST(RangeTest, Float_SameStartAndLimit) { + RunTest(2.0f, 2.0f, 1, {0}, {}); +} + +TEST(RangeTest, AlmostSameStartAndLimitHighDelta) { + RunTest(2.0f, 2.01f, 1000000.0f, {1}, {2.0f}); +} + +} // namespace test +} // namespace onnxruntime