diff --git a/onnxruntime/core/providers/cpu/math/element_wise_ops.cc b/onnxruntime/core/providers/cpu/math/element_wise_ops.cc index a4fdd02126..2c0cbf99be 100644 --- a/onnxruntime/core/providers/cpu/math/element_wise_ops.cc +++ b/onnxruntime/core/providers/cpu/math/element_wise_ops.cc @@ -569,10 +569,80 @@ struct Min_8::ComputeImpl { } }; +template +static Status MinMaxMLFloat16(const OpKernel& inst, OpKernelContext* context) { + const auto typed_allocator = [](const TensorAllocator& tensor_allocator, const TensorShape& shape) { + return tensor_allocator.Allocate(shape); + }; + + ProcessBroadcastSpanFuncs funcs{ + [](BroadcastHelper& per_iter_bh) { + auto num_elements = per_iter_bh.NumOutputElements(); + + const auto* input_1 = reinterpret_cast(per_iter_bh.EigenInput1().data()); + ConstEigenVectorArrayMap input_1_vec_map(input_1, num_elements); + + auto* output = reinterpret_cast(per_iter_bh.OutputEigen().data()); + EigenVectorArrayMap output_vec_map(output, num_elements); + + if (is_min) { + output_vec_map = input_1_vec_map.min(static_cast(per_iter_bh.ScalarInput0())); + } else { + output_vec_map = input_1_vec_map.max(static_cast(per_iter_bh.ScalarInput0())); + } + }, + [](BroadcastHelper& per_iter_bh) { + auto num_elements = per_iter_bh.NumOutputElements(); + + const auto* input_0 = reinterpret_cast(per_iter_bh.EigenInput0().data()); + ConstEigenVectorArrayMap input_0_vec_map(input_0, num_elements); + + auto* output = reinterpret_cast(per_iter_bh.OutputEigen().data()); + EigenVectorArrayMap output_vec_map(output, num_elements); + + if (is_min) { + output_vec_map = input_0_vec_map.min(static_cast(per_iter_bh.ScalarInput1())); + } else { + output_vec_map = input_0_vec_map.max(static_cast(per_iter_bh.ScalarInput1())); + } + }, + [](BroadcastHelper& per_iter_bh) { + auto num_elements = per_iter_bh.NumOutputElements(); + + const auto* input_0 = reinterpret_cast(per_iter_bh.EigenInput0().data()); + ConstEigenVectorArrayMap input_0_vec_map(input_0, num_elements); + + const auto* input_1 = reinterpret_cast(per_iter_bh.EigenInput1().data()); + ConstEigenVectorArrayMap input_1_vec_map(input_1, num_elements); + + auto* output = reinterpret_cast(per_iter_bh.OutputEigen().data()); + EigenVectorArrayMap output_vec_map(output, num_elements); + + if (is_min) { + output_vec_map = input_0_vec_map.min(input_1_vec_map); + } else { + output_vec_map = input_0_vec_map.max(input_1_vec_map); + } + }}; + + int input_count = inst.Node().InputArgCount().front(); + UntypedBroadcastVariadic(input_count, *context, typed_allocator, funcs); + + return Status::OK(); +} + Status Min_8::Compute(OpKernelContext* context) const { - utils::MLTypeCallDispatcherRet - t_disp(context->Input(0)->GetElementType()); - return t_disp.Invoke(*this, context); + auto dt_type = context->Input(0)->GetElementType(); + + switch (dt_type) { + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: + return MinMaxMLFloat16(*this, context); + break; + default: + utils::MLTypeCallDispatcherRet + t_disp(dt_type); + return t_disp.Invoke(*this, context); + } } template <> @@ -622,9 +692,17 @@ struct Max_8::ComputeImpl { }; Status Max_8::Compute(OpKernelContext* context) const { - utils::MLTypeCallDispatcherRet - t_disp(context->Input(0)->GetElementType()); - return t_disp.Invoke(*this, context); + auto dt_type = context->Input(0)->GetElementType(); + + switch (dt_type) { + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: + return MinMaxMLFloat16(*this, context); + break; + default: + utils::MLTypeCallDispatcherRet + t_disp(dt_type); + return t_disp.Invoke(*this, context); + } } Status Not::Compute(OpKernelContext* context) const { diff --git a/onnxruntime/test/providers/cpu/math/element_wise_ops_test.cc b/onnxruntime/test/providers/cpu/math/element_wise_ops_test.cc index 86ed5c40b3..c373ed45a0 100644 --- a/onnxruntime/test/providers/cpu/math/element_wise_ops_test.cc +++ b/onnxruntime/test/providers/cpu/math/element_wise_ops_test.cc @@ -1241,6 +1241,44 @@ TEST(MathOpTest, Min_12_UInt64) { test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); //TensorRT: Input batch size is inconsistent } +TEST(MathOpTest, Min_12_MLFLoat16) { + OpTester test("Min", 12); + test.AddInput("data_0", {1, 3}, + MakeMLFloat16({1.f, 1.f, 1.f})); + test.AddInput("data_1", {1, 3}, + MakeMLFloat16({2.f, -1.f, -2.f})); + test.AddInput("data_2", {1, 3}, + MakeMLFloat16({3.f, 2.f, -3.f})); + test.AddOutput("min", {1, 3}, + MakeMLFloat16({1.f, -1.f, -3.f})); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); //TensorRT: Input batch size is inconsistent +} + +TEST(MathOpTest, Min_12_MLFLoat16_Scalar0) { + OpTester test("Min", 12); + test.AddInput("data_0", {}, + MakeMLFloat16({-10.f})); + test.AddInput("data_1", {1, 3}, + MakeMLFloat16({2.f, -1.f, -2.f})); + test.AddInput("data_2", {1, 3}, + MakeMLFloat16({3.f, 2.f, -3.f})); + test.AddOutput("min", {1, 3}, + MakeMLFloat16({-10.f, -10.f, -10.f})); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); //TensorRT: Input batch size is inconsistent +} + +TEST(MathOpTest, Min_12_MLFLoat16_Scalar1) { + OpTester test("Min", 12); + test.AddInput("data_0", {1, 3}, + MakeMLFloat16({2.f, 3.f, 4.f})); + test.AddInput("data_1", {}, + MakeMLFloat16({-10.f})); + test.AddInput("data_2", {1, 3}, + MakeMLFloat16({3.f, 2.f, -3.f})); + test.AddOutput("min", {1, 3}, + MakeMLFloat16({-10.f, -10.f, -10.f})); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); //TensorRT: Input batch size is inconsistent +} TEST(MathOpTest, Max_6) { OpTester test("Max", 6); std::vector dims{3, 3}; @@ -1418,6 +1456,45 @@ TEST(MathOpTest, Max_12_UInt64) { test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); //TensorRT: Input batch size is inconsistent } +TEST(MathOpTest, Max_12_MLFLoat16) { + OpTester test("Max", 12); + test.AddInput("data_0", {1, 3}, + MakeMLFloat16({-1.f, -1.f, -1.f})); + test.AddInput("data_1", {1, 3}, + MakeMLFloat16({-2.f, -1.f, -2.f})); + test.AddInput("data_2", {1, 3}, + MakeMLFloat16({-3.f, -2.f, -3.f})); + test.AddOutput("max", {1, 3}, + MakeMLFloat16({-1.f, -1.f, -1.f})); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); //TensorRT: Input batch size is inconsistent +} + +TEST(MathOpTest, Max_12_MLFLoat16_Scalar0) { + OpTester test("Max", 12); + test.AddInput("data_0", {}, + MakeMLFloat16({-1.f})); + test.AddInput("data_1", {1, 3}, + MakeMLFloat16({-11.f, -12.f, -22.f})); + test.AddInput("data_2", {1, 3}, + MakeMLFloat16({-10.f, -11.f, -13.f})); + test.AddOutput("max", {1, 3}, + MakeMLFloat16({-1.f, -1.f, -1.f})); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); //TensorRT: Input batch size is inconsistent +} + +TEST(MathOpTest, Max_12_MLFLoat16_Scalar1) { + OpTester test("Max", 12); + test.AddInput("data_0", {1, 3}, + MakeMLFloat16({-1.f, -2.f, -3.f})); + test.AddInput("data_1", {}, + MakeMLFloat16({2.f})); + test.AddInput("data_2", {1, 3}, + MakeMLFloat16({-2.f, -3.f, -4.f})); + test.AddOutput("max", {1, 3}, + MakeMLFloat16({2.f, 2.f, 2.f})); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); //TensorRT: Input batch size is inconsistent +} + TEST(MathOpTest, Not) { OpTester test("Not"); std::vector dims{2};