From a983509ed391cfd94f571b6f72cba0211cb4fbee Mon Sep 17 00:00:00 2001 From: Matthieu Darbois Date: Thu, 28 May 2020 00:05:13 +0200 Subject: [PATCH] Pad: Add support for all datatypes in opset-11 spec (#4021) * Pad: Add support for all datatypes in opset-11 spec Pad opset-11 implementation supports: int32, int64, float & double Per specification, Pad opset-11 also supports: uint8, uint16, uint32, uint64, int8, int16 & float16 This commit add support for those types to get full coverage of Pad opset-11 operator. * Pad: Remove 16-bit datatypes support These types are unused at the moment and binary size is impacted. Remove support for those type to lower binary size. --- .../providers/cpu/cpu_execution_provider.cc | 10 +- onnxruntime/core/providers/cpu/tensor/pad.cc | 126 +++- onnxruntime/core/providers/cpu/tensor/pad.h | 8 - .../test/providers/cpu/tensor/pad_test.cc | 693 +++++++++--------- 4 files changed, 440 insertions(+), 397 deletions(-) diff --git a/onnxruntime/core/providers/cpu/cpu_execution_provider.cc b/onnxruntime/core/providers/cpu/cpu_execution_provider.cc index 65e9680d01..79fc1d098d 100644 --- a/onnxruntime/core/providers/cpu/cpu_execution_provider.cc +++ b/onnxruntime/core/providers/cpu/cpu_execution_provider.cc @@ -386,10 +386,7 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Ga class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, uint8_t, BitShift); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, uint32_t, BitShift); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, uint64_t, BitShift); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, float, Pad); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, double, Pad); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, int32_t, Pad); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, int64_t, Pad); +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); @@ -1014,10 +1011,7 @@ Status RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, diff --git a/onnxruntime/core/providers/cpu/tensor/pad.cc b/onnxruntime/core/providers/cpu/tensor/pad.cc index 72a1f5e4ea..2e082d5210 100644 --- a/onnxruntime/core/providers/cpu/tensor/pad.cc +++ b/onnxruntime/core/providers/cpu/tensor/pad.cc @@ -7,6 +7,7 @@ #ifdef _MSC_VER #pragma warning(disable : 4996) #endif +#include "core/util/math.h" #include "core/providers/cpu/tensor/pad.h" #include "core/providers/cpu/tensor/utils.h" @@ -26,7 +27,7 @@ ONNX_OPERATOR_KERNEL_EX(Pad, 1, kCpuExecutionProvider, KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), - onnxruntime::Pad); + onnxruntime::Pad); } // namespace contrib @@ -36,36 +37,26 @@ ONNX_OPERATOR_KERNEL_EX(Pad, ONNX_CPU_OPERATOR_VERSIONED_KERNEL( Pad, 2, 10, - KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), - Pad); + KernelDefBuilder().TypeConstraint("T", {DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType()}), + Pad); // The interface for the 'Pad' op was changed in opset-11 // 'pads' and 'value' (attributes previously) became inputs in this version // The core logic remains the same -ONNX_CPU_OPERATOR_TYPED_KERNEL( +ONNX_CPU_OPERATOR_KERNEL( Pad, 11, - float, - KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), Pad); - -ONNX_CPU_OPERATOR_TYPED_KERNEL( - Pad, - 11, - double, - KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), Pad); - -ONNX_CPU_OPERATOR_TYPED_KERNEL( - Pad, - 11, - int32_t, - KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), Pad); - -ONNX_CPU_OPERATOR_TYPED_KERNEL( - Pad, - 11, - int64_t, - KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), Pad); + KernelDefBuilder().TypeConstraint("T", {DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType()}), + Pad); // This is the general padding method to n-dimensionally do edge or reflection padding (based on the inputDelta values) template @@ -144,7 +135,7 @@ static Status PadInputWithDimValueOfZero(OpKernelContext* ctx, // we need to add pads if mode is constant, otherwise the output has one or more dim values of 0 so is empty if (mode == Mode::Constant) { // we add pads with the default value to all dims including those with a value of 0 - auto* output = output_tensor.template MutableData(); + auto* output = reinterpret_cast(output_tensor.MutableDataRaw()); std::fill_n(output, output_shape.Size(), value); } @@ -192,7 +183,7 @@ static void ReshapePads(const std::vector& src_pad, size_t src_dim_coun } template -Status PadCpuImpl(OpKernelContext* ctx, +static Status PadImpl(OpKernelContext* ctx, const std::vector& pads, const std::vector& slices, const Mode& mode, @@ -247,7 +238,7 @@ Status PadCpuImpl(OpKernelContext* ctx, // output_shape need to keep original. TensorShape output_shape(output_dims); auto& output_tensor = *ctx->Output(0, output_shape); - auto* output = output_tensor.template MutableData(); + auto* output = reinterpret_cast(output_tensor.MutableDataRaw()); TensorPitches output_pitches(reshaped_output_dims); size_t alignSkip = 0; // Amount to skip to align to where the next input tensor data needs to be written @@ -356,11 +347,42 @@ Status PadCpuImpl(OpKernelContext* ctx, return Status::OK(); } -template -Status Pad::Compute(OpKernelContext* ctx) const { +union PadValue +{ + uint64_t u64; + uint32_t u32; + uint8_t u8; + double f64; + float f32; +}; + +static PadValue PadValueFromFloat(float value, MLDataType data_type) { + PadValue result; + if (data_type == DataTypeImpl::GetType()) { + result.f32 = value; + } + else if (data_type == DataTypeImpl::GetType()) { + result.f64 = value; + } + else { + ORT_THROW("Unsupported input data type of ", data_type); + } + return result; +} + +Status Pad::Compute(OpKernelContext* ctx) const { + const Tensor& input_tensor = *ctx->Input(0); + MLDataType data_type = input_tensor.DataType(); + const auto element_size = data_type->Size(); + std::vector pads; + std::vector slices; + const std::vector* pads_to_use; + const std::vector* slices_to_use; + PadValue value; + Status status; + // kOnnxDomain Pad opset >= 11 (Or) kMsDomain opset == 1 if (is_dynamic_) { - const Tensor& input_tensor = *ctx->Input(0); size_t data_rank = input_tensor.Shape().NumDimensions(); const Tensor& pads_tensor = *ctx->Input(1); @@ -375,14 +397,13 @@ Status Pad::Compute(OpKernelContext* ctx) const { ORT_ENFORCE(pads_size == 2 * data_rank, "Pads tensor size should be equal to twice the input dimension count "); - std::vector pads; pads.reserve(2 * data_rank); for (size_t i = 0; i < pads_size; ++i) { pads.push_back(pads_tensor_raw_data[i]); } // Separate out any negative pads into the slices array - std::vector slices(pads.size(), 0); + slices = std::vector(pads.size(), 0); for (size_t index = 0; index < pads.size(); index++) { if (pads[index] < 0) { slices[index] = pads[index]; @@ -390,21 +411,50 @@ Status Pad::Compute(OpKernelContext* ctx) const { } } - T value = static_cast(0); + value.u64 = 0U; const Tensor* value_tensor = ctx->Input(2); if (nullptr != value_tensor) { - ORT_ENFORCE(value_tensor->IsDataType() && + ORT_ENFORCE(value_tensor->DataType() == data_type && value_tensor->Shape().Size() == 1, "Value tensor should be a 1D tensor of size 1 with the same type as that of the input tensor"); - value = value_tensor->template Data()[0]; + const void* value_data = value_tensor->DataRaw(); + switch (element_size) { + case sizeof(uint32_t): + value.u32 = reinterpret_cast(value_data)[0]; + break; + case sizeof(uint64_t): + value.u64 = reinterpret_cast(value_data)[0]; + break; + case sizeof(uint8_t): + value.u8 = reinterpret_cast(value_data)[0]; + break; + default: + ORT_THROW("Unsupported input data type of ", data_type); + } } - - return PadCpuImpl(ctx, pads, slices, mode_, value); + pads_to_use = &pads; + slices_to_use = &slices; } else { // kOnnxDomain Pad opset < 11 // In the earlier opset versions of Pad, the type for 'value' attribute was always float, // irrespective of the data type of the actual input to be padded - return PadCpuImpl(ctx, pads_, slices_, mode_, static_cast(value_)); + value = PadValueFromFloat(value_, data_type); + pads_to_use = &pads_; + slices_to_use = &slices_; } + switch (element_size) { + case sizeof(uint32_t): + status = PadImpl(ctx, *pads_to_use, *slices_to_use, mode_, value.u32); + break; + case sizeof(uint64_t): + status = PadImpl(ctx, *pads_to_use, *slices_to_use, mode_, value.u64); + break; + case sizeof(uint8_t): + status = PadImpl(ctx, *pads_to_use, *slices_to_use, mode_, value.u8); + break; + default: + ORT_THROW("Unsupported input data type of ", data_type); + } + return status; } }; // namespace onnxruntime diff --git a/onnxruntime/core/providers/cpu/tensor/pad.h b/onnxruntime/core/providers/cpu/tensor/pad.h index 8663e205d9..13d18257a5 100644 --- a/onnxruntime/core/providers/cpu/tensor/pad.h +++ b/onnxruntime/core/providers/cpu/tensor/pad.h @@ -71,18 +71,10 @@ class PadBase { bool is_dynamic_ = false; }; -template struct Pad final : public OpKernel, public PadBase { explicit Pad(const OpKernelInfo& info) : OpKernel(info), PadBase(info) {} Status Compute(OpKernelContext* context) const override; }; -template -Status PadCpuImpl(OpKernelContext* ctx, - const std::vector& pads, - const std::vector& slices, - const Mode& mode, - T value); - } // namespace onnxruntime diff --git a/onnxruntime/test/providers/cpu/tensor/pad_test.cc b/onnxruntime/test/providers/cpu/tensor/pad_test.cc index 5192f93833..19df1aaf0c 100644 --- a/onnxruntime/test/providers/cpu/tensor/pad_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/pad_test.cc @@ -7,9 +7,8 @@ namespace onnxruntime { namespace test { -// There is support for int32, int64, float, and double types for opset-11 Pad alone in ORT -template -static void RunOpset11TypedTest( +template +static void RunOnnxOpsetTypedTest( const std::vector& input_dims, const std::vector& input, const std::vector& pads, @@ -19,50 +18,106 @@ static void RunOpset11TypedTest( std::string mode = "constant", OpTester::ExpectResult expect = OpTester::ExpectResult::kExpectSuccess, const std::string& error_msg = "") { - // ONNX domain opset-11 - OpTester test("Pad", 11); + // ONNX domain opset + OpTester test("Pad", opset); if (mode != "constant") test.AddAttribute("mode", mode); test.AddInput("data", input_dims, input); - test.AddInput("pads", {static_cast(pads.size())}, pads); - test.AddInput("value", {1}, {value}); + if (opset >= 11) { + test.AddInput("pads", {static_cast(pads.size())}, pads); + test.AddInput("value", {1}, {value}); + } + else { + test.AddAttribute("pads", pads); + test.AddAttribute("value", static_cast(value)); + } test.AddOutput("output", output_dims, output); - // NGraph and TensorRT do not yet support opset-11 and builds break on this test, hence exclude the EP - test.Run(expect, error_msg, {kNGraphExecutionProvider, kTensorrtExecutionProvider}); + if (opset >= 11) { + // NGraph and TensorRT do not yet support opset-11 and builds break on this test, hence exclude the EP + test.Run(expect, error_msg, {kNGraphExecutionProvider, kTensorrtExecutionProvider}); + } + else { +#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) + test.Run(expect, error_msg, {kOpenVINOExecutionProvider}); +#else + test.Run(expect, error_msg); +#endif + } } -// There is only support for float type for opset-10 and MSDomain kernel in ORT +template static void RunAllOpsetAllDomainPadTests( + const std::vector& input_dims, + const std::vector& input, + const std::vector& pads, + T value, + const std::vector& output_dims, + const std::vector& output, + std::string mode = "constant", + OpTester::ExpectResult expect = OpTester::ExpectResult::kExpectSuccess, + const std::string& error_msg = "") { + // ONNX domain opset-11 is the only one to support all data types + RunOnnxOpsetTypedTest(input_dims, + input, + pads, + value, + output_dims, + output, + mode, expect, error_msg); +} +template<> +void RunAllOpsetAllDomainPadTests<>( + const std::vector& input_dims, + const std::vector& input, + const std::vector& pads, + double value, + const std::vector& output_dims, + const std::vector& output, + std::string mode, + OpTester::ExpectResult expect, + const std::string& error_msg) { + // ONNX domain supports double type + RunOnnxOpsetTypedTest(input_dims, + input, + pads, + value, + output_dims, + output, + mode, expect, error_msg); + RunOnnxOpsetTypedTest(input_dims, + input, + pads, + value, + output_dims, + output, + mode, expect, error_msg); +} +// There is only support for float type for MSDomain kernel in ORT +template<> +void RunAllOpsetAllDomainPadTests<>( const std::vector& input_dims, const std::vector& input, const std::vector& pads, float value, const std::vector& output_dims, const std::vector& output, - std::string mode = "constant", - OpTester::ExpectResult expect = OpTester::ExpectResult::kExpectSuccess, - const std::string& error_msg = "") { - // ONNX domain opset-10 - OpTester test1("Pad", 10); - test1.AddInput("data", input_dims, input); - if (mode != "constant") test1.AddAttribute("mode", mode); - test1.AddAttribute("pads", pads); - test1.AddAttribute("value", value); - test1.AddOutput("output", output_dims, output); -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) - test1.Run(expect, error_msg, {kOpenVINOExecutionProvider}); -#else - test1.Run(expect, error_msg); -#endif - - // ONNX domain opset-11 - RunOpset11TypedTest(input_dims, - input, - pads, - value, - output_dims, - output, - mode, expect, error_msg); + std::string mode, + OpTester::ExpectResult expect, + const std::string& error_msg) { + RunOnnxOpsetTypedTest(input_dims, + input, + pads, + value, + output_dims, + output, + mode, expect, error_msg); + RunOnnxOpsetTypedTest(input_dims, + input, + pads, + value, + output_dims, + output, + mode, expect, error_msg); #ifndef DISABLE_CONTRIB_OPS @@ -82,280 +137,229 @@ static void RunAllOpsetAllDomainPadTests( // Some of the tests can't run on TensorrtExecutionProvider because only constant mode and value 0 of "Pad" node is supported. // Those tests will fallback to other EP. -TEST(TensorOpTest, Pad_Spec_Example) { - RunAllOpsetAllDomainPadTests({3, 2}, - {1.0f, 1.2f, 2.3f, 3.4f, 4.5f, 5.7f}, - {0, 2, 0, 0}, - 0.f, - {3, 4}, - {0.0f, 0.0f, 1.0f, 1.2f, 0.0f, 0.0f, 2.3f, 3.4f, 0.0f, 0.0f, 4.5f, 5.7f}); +using PadTypes = ::testing::Types; + +template +class PadOpTest : public ::testing::Test { +}; +TYPED_TEST_SUITE(PadOpTest, PadTypes); + +TYPED_TEST(PadOpTest, Pad_Spec_Example) { + using T = TypeParam; + RunAllOpsetAllDomainPadTests({3, 2}, + {T(1), T(2), T(3), T(4), T(5), T(6)}, + {0, 2, 0, 0}, + T(0), + {3, 4}, + {T(0), T(0), T(1), T(2), T(0), T(0), T(3), T(4), T(0), T(0), T(5), T(6)}); } -TEST(TensorOpTest, Pad_Constant_1D_int) { - std::vector X = {1, 2, 3, 4, 5, 6}; - int32_t value = 1234; - std::vector Y = {1234, 1234, 1, 2, 1234, 1234, 3, 4, 1234, 1234, 5, 6}; - RunOpset11TypedTest({3, 2}, - X, - {0, 2, 0, 0}, - value, - {3, 4}, - Y); +TYPED_TEST(PadOpTest, Pad_Constant_1D) { + using T = TypeParam; + RunAllOpsetAllDomainPadTests({2}, + {T(1), T(2)}, + {1, 2}, + T(123), + {5}, + {T(123), T(1), T(2), T(123), T(123)}); } -TEST(TensorOpTest, Pad_Constant_1D_long) { - std::vector X = {1, 2, 3, 4, 5, 6}; - int64_t value = 1234; - std::vector Y = {1234, 1234, 1, 2, 1234, 1234, 3, 4, 1234, 1234, 5, 6}; - RunOpset11TypedTest({3, 2}, - X, - {0, 2, 0, 0}, - value, - {3, 4}, - Y); +TYPED_TEST(PadOpTest, Pad_Constant_1D_Zero) { + using T = TypeParam; + RunAllOpsetAllDomainPadTests({2}, + {T(1), T(2)}, + {0, 0}, + T(123), + {2}, + {T(1), T(2)}); } -TEST(TensorOpTest, Pad_Constant_1D_double) { - std::vector X = {1., 2., 3., 4., 5., 6.}; - double value = 0.; - std::vector Y = {0., 0., 1., 2., 0., 0., 3., 4., 0., 0., 5., 6.}; - RunOpset11TypedTest({3, 2}, - X, - {0, 2, 0, 0}, - value, - {3, 4}, - Y); +TYPED_TEST(PadOpTest, Pad_Reflect_1D) { + using T = TypeParam; + RunAllOpsetAllDomainPadTests({3, 2}, + {T(1), T(2), T(3), T(4), T(5), T(6)}, + {0, 1, 0, 1}, + T(0), + {3, 4}, + {T(2), T(1), T(2), T(1), T(4), T(3), T(4), T(3), T(6), T(5), T(6), T(5)}, + "reflect"); } -TEST(TensorOpTest, Pad_Constant_1D) { - RunAllOpsetAllDomainPadTests({2}, - {1.0f, 2.0f}, - {1, 2}, - 1234.f, - {5}, - {1234.0f, 1.0f, 2.0f, 1234.0f, 1234.0f}); +TYPED_TEST(PadOpTest, Pad_Edge_1D) { + using T = TypeParam; + RunAllOpsetAllDomainPadTests({3, 2}, + {T(1), T(2), T(3), T(4), T(5), T(6)}, + {0, 2, 0, 1}, + T(0), + {3, 5}, + {T(1), T(1), T(1), T(2), T(2), T(3), T(3), T(3), T(4), T(4), T(5), T(5), T(5), T(6), T(6)}, + "edge"); } -TEST(TensorOpTest, Pad_Constant_1D_Zero) { - RunAllOpsetAllDomainPadTests({2}, - {1.0f, 2.0f}, - {0, 0}, - 1234.f, - {2}, - {1.0f, 2.0f}); +TYPED_TEST(PadOpTest, Pad_Constant_2D) { + using T = TypeParam; + RunAllOpsetAllDomainPadTests({2, 2}, + {T(11), T(21), + T(12), T(22)}, + {1, 2, 1, 2}, + T(123), + {4, 6}, + {T(123), T(123), T(123), T(123), T(123), T(123), + T(123), T(123), T(11), T(21), T(123), T(123), + T(123), T(123), T(12), T(22), T(123), T(123), + T(123), T(123), T(123), T(123), T(123), T(123)}); } -TEST(TensorOpTest, Pad_Constant_2D) { - RunAllOpsetAllDomainPadTests({2, 2}, - {11.0f, 21.0f, - 12.0f, 22.0f}, - {1, 2, 1, 2}, - 1234.f, - {4, 6}, - {1234.0f, 1234.0f, 1234.0f, 1234.0f, 1234.0f, 1234.0f, - 1234.0f, 1234.0f, 11.0f, 21.0f, 1234.0f, 1234.0f, - 1234.0f, 1234.0f, 12.0f, 22.0f, 1234.0f, 1234.0f, - 1234.0f, 1234.0f, 1234.0f, 1234.0f, 1234.0f, 1234.0f}); +TYPED_TEST(PadOpTest, Pad_Constant_2D_negative_pads_1) { + using T = TypeParam; + RunAllOpsetAllDomainPadTests({2, 3}, + {T(11), T(21), T(31), + T(12), T(22), T(32)}, + {1, 2, 1, -1}, + T(123), + {4, 4}, + {T(123), T(123), T(123), T(123), + T(123), T(123), T(11), T(21), + T(123), T(123), T(12), T(22), + T(123), T(123), T(123), T(123)}); } -TEST(TensorOpTest, Pad_Constant_2D_negative_pads_1) { - RunAllOpsetAllDomainPadTests({2, 3}, - {11.0f, 21.0f, 31.0f, - 12.0f, 22.0f, 32.0f}, - {1, 2, 1, -1}, - 1234.f, - {4, 4}, - {1234.0f, 1234.0f, 1234.0f, 1234.0f, - 1234.0f, 1234.0f, 11.0f, 21.0f, - 1234.0f, 1234.0f, 12.0f, 22.0f, - 1234.0f, 1234.0f, 1234.0f, 1234.0f}); +TYPED_TEST(PadOpTest, Pad_Constant_2D_negative_pads_2) { + using T = TypeParam; + RunAllOpsetAllDomainPadTests({2, 3}, + {T(11), T(21), T(31), + T(12), T(22), T(32)}, + {-1, 0, 0, 0}, + T(123), + {1, 3}, + {T(12), T(22), T(32)}); } -TEST(TensorOpTest, Pad_Constant_2D_negative_pads_2) { - RunAllOpsetAllDomainPadTests({2, 3}, - {11.0f, 21.0f, 31.0f, - 12.0f, 22.0f, 32.0f}, - {-1, 0, 0, 0}, - 1234.f, - {1, 3}, - {12.0f, 22.0f, 32.0f}); +TYPED_TEST(PadOpTest, Pad_Constant_3D_negative_pads) { + using T = TypeParam; + RunAllOpsetAllDomainPadTests({1, 1, 3}, + {T(0), T(1), T(2)}, + {0, 0, -1, 0, 0, -1}, + T(0), + {1, 1, 1}, + {T(1)}); } -TEST(TensorOpTest, Pad_Constant_3D_negative_pads) { - RunAllOpsetAllDomainPadTests({1, 1, 3}, - {0.f, 1.0f, 2.f}, - {0, 0, -1, 0, 0, -1}, - 0.f, - {1, 1, 1}, - {1.f}); -} - -TEST(TensorOpTest, Pad_Constant_4D_negative_pads) { +TYPED_TEST(PadOpTest, Pad_Constant_4D_negative_pads) { + using T = TypeParam; // input_vals contains values from 0 to 99 (inclusive) - std::vector input_vals; + std::vector input_vals; input_vals.reserve(100); for (int i = 0; i < 100; ++i) { - input_vals.push_back(static_cast(i)); + input_vals.push_back(T(i)); } // holder for output_vals (expected) - std::vector output_vals; + std::vector output_vals; output_vals.reserve(21); - float seed = 13; + int seed = 13; for (int i = 0; i < 7; ++i) { for (int j = 0; j < 3; ++j) { - output_vals.push_back(static_cast(seed + j)); + output_vals.push_back(T(seed + j)); } seed += 10; } // run tests - RunAllOpsetAllDomainPadTests({1, 1, 10, 10}, - input_vals, - {0, 0, -1, -3, 0, 0, -2, -4}, - 0.f, - {1, 1, 7, 3}, - output_vals); + RunAllOpsetAllDomainPadTests({1, 1, 10, 10}, + input_vals, + {0, 0, -1, -3, 0, 0, -2, -4}, + T(0), + {1, 1, 7, 3}, + output_vals); } -TEST(TensorOpTest, Pad_3D_complex) { - RunAllOpsetAllDomainPadTests({2, 2, 2}, - {111.0f, 112.0f, - 121.0f, 122.0f, +TYPED_TEST(PadOpTest, Pad_3D_complex) { + using T = TypeParam; + RunAllOpsetAllDomainPadTests({2, 2, 2}, + {T(11), T(12), + T(21), T(22), - 211.0f, 212.0f, - 221.0f, 222.0f}, - {1, 0, 0, -1, 0, 0}, - 0.f, - {2, 2, 2}, - {0.0f, 0.0f, - 0.0f, 0.0f, + T(111), T(112), + T(121), T(122)}, + {1, 0, 0, -1, 0, 0}, + T(0), + {2, 2, 2}, + {T(0), T(0), + T(0), T(0), - 111.0f, 112.0f, - 121.0f, 122.0f}); + T(11), T(12), + T(21), T(22)}); } -TEST(TensorOpTest, Pad_Edge_2D) { - RunAllOpsetAllDomainPadTests({2, 3}, - {11.0f, 21.0f, 31.0f, - 12.0f, 22.0f, 32.0f}, - {2, 2, 2, 2}, - 0.f, - {6, 7}, - {11.0f, 11.0f, 11.0f, 21.0f, 31.0f, 31.0f, 31.0f, - 11.0f, 11.0f, 11.0f, 21.0f, 31.0f, 31.0f, 31.0f, - 11.0f, 11.0f, 11.0f, 21.0f, 31.0f, 31.0f, 31.0f, - 12.0f, 12.0f, 12.0f, 22.0f, 32.0f, 32.0f, 32.0f, - 12.0f, 12.0f, 12.0f, 22.0f, 32.0f, 32.0f, 32.0f, - 12.0f, 12.0f, 12.0f, 22.0f, 32.0f, 32.0f, 32.0f}, - "edge"); +TYPED_TEST(PadOpTest, Pad_Edge_2D) { + using T = TypeParam; + RunAllOpsetAllDomainPadTests({2, 3}, + {T(11), T(21), T(31), + T(12), T(22), T(32)}, + {2, 2, 2, 2}, + T(0), + {6, 7}, + {T(11), T(11), T(11), T(21), T(31), T(31), T(31), + T(11), T(11), T(11), T(21), T(31), T(31), T(31), + T(11), T(11), T(11), T(21), T(31), T(31), T(31), + T(12), T(12), T(12), T(22), T(32), T(32), T(32), + T(12), T(12), T(12), T(22), T(32), T(32), T(32), + T(12), T(12), T(12), T(22), T(32), T(32), T(32)}, + "edge"); } -TEST(TensorOpTest, Pad_Edge_3D) { - RunAllOpsetAllDomainPadTests({1, 2, 3}, - {11.0f, 21.0f, 31.0f, - 12.0f, 22.0f, 32.0f}, - {1, 2, 2, 1, 2, 2}, - 0.f, - {3, 6, 7}, - {11.0f, 11.0f, 11.0f, 21.0f, 31.0f, 31.0f, 31.0f, - 11.0f, 11.0f, 11.0f, 21.0f, 31.0f, 31.0f, 31.0f, - 11.0f, 11.0f, 11.0f, 21.0f, 31.0f, 31.0f, 31.0f, - 12.0f, 12.0f, 12.0f, 22.0f, 32.0f, 32.0f, 32.0f, - 12.0f, 12.0f, 12.0f, 22.0f, 32.0f, 32.0f, 32.0f, - 12.0f, 12.0f, 12.0f, 22.0f, 32.0f, 32.0f, 32.0f, +TYPED_TEST(PadOpTest, Pad_Edge_3D) { + using T = TypeParam; + RunAllOpsetAllDomainPadTests({1, 2, 3}, + {T(11), T(21), T(31), + T(12), T(22), T(32)}, + {1, 2, 2, 1, 2, 2}, + T(0), + {3, 6, 7}, + {T(11), T(11), T(11), T(21), T(31), T(31), T(31), + T(11), T(11), T(11), T(21), T(31), T(31), T(31), + T(11), T(11), T(11), T(21), T(31), T(31), T(31), + T(12), T(12), T(12), T(22), T(32), T(32), T(32), + T(12), T(12), T(12), T(22), T(32), T(32), T(32), + T(12), T(12), T(12), T(22), T(32), T(32), T(32), - 11.0f, 11.0f, 11.0f, 21.0f, 31.0f, 31.0f, 31.0f, - 11.0f, 11.0f, 11.0f, 21.0f, 31.0f, 31.0f, 31.0f, - 11.0f, 11.0f, 11.0f, 21.0f, 31.0f, 31.0f, 31.0f, - 12.0f, 12.0f, 12.0f, 22.0f, 32.0f, 32.0f, 32.0f, - 12.0f, 12.0f, 12.0f, 22.0f, 32.0f, 32.0f, 32.0f, - 12.0f, 12.0f, 12.0f, 22.0f, 32.0f, 32.0f, 32.0f, + T(11), T(11), T(11), T(21), T(31), T(31), T(31), + T(11), T(11), T(11), T(21), T(31), T(31), T(31), + T(11), T(11), T(11), T(21), T(31), T(31), T(31), + T(12), T(12), T(12), T(22), T(32), T(32), T(32), + T(12), T(12), T(12), T(22), T(32), T(32), T(32), + T(12), T(12), T(12), T(22), T(32), T(32), T(32), - 11.0f, 11.0f, 11.0f, 21.0f, 31.0f, 31.0f, 31.0f, - 11.0f, 11.0f, 11.0f, 21.0f, 31.0f, 31.0f, 31.0f, - 11.0f, 11.0f, 11.0f, 21.0f, 31.0f, 31.0f, 31.0f, - 12.0f, 12.0f, 12.0f, 22.0f, 32.0f, 32.0f, 32.0f, - 12.0f, 12.0f, 12.0f, 22.0f, 32.0f, 32.0f, 32.0f, - 12.0f, 12.0f, 12.0f, 22.0f, 32.0f, 32.0f, 32.0f}, - "edge"); + T(11), T(11), T(11), T(21), T(31), T(31), T(31), + T(11), T(11), T(11), T(21), T(31), T(31), T(31), + T(11), T(11), T(11), T(21), T(31), T(31), T(31), + T(12), T(12), T(12), T(22), T(32), T(32), T(32), + T(12), T(12), T(12), T(22), T(32), T(32), T(32), + T(12), T(12), T(12), T(22), T(32), T(32), T(32)}, + "edge"); } -TEST(TensorOpTest, Pad_Reflect_2D) { - RunAllOpsetAllDomainPadTests({3, 3}, - {11.0f, 21.0f, 31.0f, - 12.0f, 22.0f, 32.0f, - 13.0f, 23.0f, 33.0f}, - {2, 2, 2, 2}, - 0.f, - {7, 7}, - {33.0f, 23.0f, 13.0f, 23.0f, 33.0f, 23.0f, 13.0f, - 32.0f, 22.0f, 12.0f, 22.0f, 32.0f, 22.0f, 12.0f, - 31.0f, 21.0f, 11.0f, 21.0f, 31.0f, 21.0f, 11.0f, - 32.0f, 22.0f, 12.0f, 22.0f, 32.0f, 22.0f, 12.0f, - 33.0f, 23.0f, 13.0f, 23.0f, 33.0f, 23.0f, 13.0f, - 32.0f, 22.0f, 12.0f, 22.0f, 32.0f, 22.0f, 12.0f, - 31.0f, 21.0f, 11.0f, 21.0f, 31.0f, 21.0f, 11.0f}, - "reflect"); +TYPED_TEST(PadOpTest, Pad_Reflect_2D) { + using T = TypeParam; + RunAllOpsetAllDomainPadTests({3, 3}, + {T(11), T(21), T(31), + T(12), T(22), T(32), + T(13), T(23), T(33)}, + {2, 2, 2, 2}, + T(0), + {7, 7}, + {T(33), T(23), T(13), T(23), T(33), T(23), T(13), + T(32), T(22), T(12), T(22), T(32), T(22), T(12), + T(31), T(21), T(11), T(21), T(31), T(21), T(11), + T(32), T(22), T(12), T(22), T(32), T(22), T(12), + T(33), T(23), T(13), T(23), T(33), T(23), T(13), + T(32), T(22), T(12), T(22), T(32), T(22), T(12), + T(31), T(21), T(11), T(21), T(31), T(21), T(11)}, + "reflect"); } -TEST(TensorOpTest, Pad_Constant_2D_int) { - std::vector X = {11, 21, 31, - 12, 22, 32}; - int32_t value = 0; - std::vector Y = {11, 11, 11, 21, 31, 31, 31, - 11, 11, 11, 21, 31, 31, 31, - 11, 11, 11, 21, 31, 31, 31, - 12, 12, 12, 22, 32, 32, 32, - 12, 12, 12, 22, 32, 32, 32, - 12, 12, 12, 22, 32, 32, 32}; - RunOpset11TypedTest({2, 3}, - X, - {2, 2, 2, 2}, - value, - {6, 7}, - Y, - "edge"); -} - -TEST(TensorOpTest, Pad_Constant_2D_long) { - std::vector X = {11, 21, 31, - 12, 22, 32}; - int64_t value = 0; - std::vector Y = {11, 11, 11, 21, 31, 31, 31, - 11, 11, 11, 21, 31, 31, 31, - 11, 11, 11, 21, 31, 31, 31, - 12, 12, 12, 22, 32, 32, 32, - 12, 12, 12, 22, 32, 32, 32, - 12, 12, 12, 22, 32, 32, 32}; - RunOpset11TypedTest({2, 3}, - X, - {2, 2, 2, 2}, - value, - {6, 7}, - Y, - "edge"); -} - -TEST(TensorOpTest, Pad_Constant_2D_double) { - std::vector X = {11., 21., 31., - 12., 22., 32.}; - double value = 0.; - std::vector Y = {11., 11., 11., 21., 31., 31., 31., - 11., 11., 11., 21., 31., 31., 31., - 11., 11., 11., 21., 31., 31., 31., - 12., 12., 12., 22., 32., 32., 32., - 12., 12., 12., 22., 32., 32., 32., - 12., 12., 12., 22., 32., 32., 32.}; - RunOpset11TypedTest({2, 3}, - X, - {2, 2, 2, 2}, - value, - {6, 7}, - Y, - "edge"); -} /* Example numpy for testing behavior @@ -396,101 +400,104 @@ edge */ // test handling of input with a 0 for a dimension -TEST(TensorOpTest, Pad_Constant_DimWithZeroInput) { - RunAllOpsetAllDomainPadTests({0}, // 1D - {}, - {1, 1}, - 0.1f, - {2}, - {0.1f, 0.1f}); +TYPED_TEST(PadOpTest, Pad_Constant_DimWithZeroInput) { + using T = TypeParam; + RunAllOpsetAllDomainPadTests({0}, // 1D + {}, + {1, 1}, + T(1), + {2}, + {T(1), T(1)}); - RunAllOpsetAllDomainPadTests({0}, // 1D empty pads - {}, - {0, 0}, - 0.1f, - {0}, - {}); + RunAllOpsetAllDomainPadTests({0}, // 1D empty pads + {}, + {0, 0}, + T(1), + {0}, + {}); - RunAllOpsetAllDomainPadTests({0}, // 1D offsetting pads - {}, - {-1, 1}, - 0.1f, - {0}, - {}); + RunAllOpsetAllDomainPadTests({0}, // 1D offsetting pads + {}, + {-1, 1}, + T(1), + {0}, + {}); - RunAllOpsetAllDomainPadTests({2, 0}, // 2D - {}, - {1, 1, 1, 1}, - 0.1f, - {4, 2}, - {0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f}); + RunAllOpsetAllDomainPadTests({2, 0}, // 2D + {}, + {1, 1, 1, 1}, + T(1), + {4, 2}, + {T(1), T(1), T(1), T(1), T(1), T(1), T(1), T(1)}); - RunAllOpsetAllDomainPadTests({0, 2}, - {}, - {1, 1, 1, 1}, - 0.1f, - {2, 4}, - {0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f}); + RunAllOpsetAllDomainPadTests({0, 2}, + {}, + {1, 1, 1, 1}, + T(1), + {2, 4}, + {T(1), T(1), T(1), T(1), T(1), T(1), T(1), T(1)}); - RunAllOpsetAllDomainPadTests({0, 2}, - {}, - {1, 0, 1, 0}, // empty pads for dim 1 - 0.1f, - {2, 2}, - {0.1f, 0.1f, 0.1f, 0.1f}); + RunAllOpsetAllDomainPadTests({0, 2}, + {}, + {1, 0, 1, 0}, // empty pads for dim 1 + T(1), + {2, 2}, + {T(1), T(1), T(1), T(1)}); - RunAllOpsetAllDomainPadTests({2, 0, 2}, // 3D - {}, - {0, 1, 0, 0, 1, 0}, - 0.1f, - {2, 2, 2}, - {0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f}); + RunAllOpsetAllDomainPadTests({2, 0, 2}, // 3D + {}, + {0, 1, 0, 0, 1, 0}, + T(1), + {2, 2, 2}, + {T(1), T(1), T(1), T(1), T(1), T(1), T(1), T(1)}); } -TEST(TensorOpTest, Pad_Edge_DimWithZeroInput) { - RunAllOpsetAllDomainPadTests({0}, // 1D - {}, - {1, 1}, - 0.1f, - {0}, - {}, - "edge"); +TYPED_TEST(PadOpTest, Pad_Edge_DimWithZeroInput) { + using T = TypeParam; + RunAllOpsetAllDomainPadTests({0}, // 1D + {}, + {1, 1}, + T(1), + {0}, + {}, + "edge"); - RunAllOpsetAllDomainPadTests({2, 0}, // 2D - {}, - {1, 1, 1, 1}, // ignore pad for dims with value of 0 as there's no edge value to pad with - 0.1f, - {4, 0}, - {}, - "edge"); + RunAllOpsetAllDomainPadTests({2, 0}, // 2D + {}, + {1, 1, 1, 1}, // ignore pad for dims with value of 0 as there's no edge value to pad with + T(1), + {4, 0}, + {}, + "edge"); - RunAllOpsetAllDomainPadTests({2, 2, 0}, // 3D - {}, - {0, 1, 1, 0, 1, 1}, - 0.1f, - {2, 4, 0}, - {}, - "edge"); + RunAllOpsetAllDomainPadTests({2, 2, 0}, // 3D + {}, + {0, 1, 1, 0, 1, 1}, + T(1), + {2, 4, 0}, + {}, + "edge"); } -TEST(TensorOpTest, Pad_Reflect_DimWithZeroInput) { - RunAllOpsetAllDomainPadTests({2, 0}, // 2D - {}, - {1, 0, 1, 0}, // allowed if it doesn't pad the empty dim - 0.1f, - {4, 0}, - {}, - "reflect"); +TYPED_TEST(PadOpTest, Pad_Reflect_DimWithZeroInput) { + using T = TypeParam; + RunAllOpsetAllDomainPadTests({2, 0}, // 2D + {}, + {1, 0, 1, 0}, // allowed if it doesn't pad the empty dim + T(1), + {4, 0}, + {}, + "reflect"); - RunAllOpsetAllDomainPadTests({0, 2, 1}, // 3D - {}, - {1, 1, 1, 1, 1, 1}, // not allowed if it pads the empty dim - 0.1f, - {0, 4, 2}, - {}, - "reflect", - OpTester::ExpectResult::kExpectFailure, - "Cannot use 'reflect' mode to pad dimension with a value of 0. Input shape:{0,2,1}"); + RunAllOpsetAllDomainPadTests({0, 2, 1}, // 3D + {}, + {1, 1, 1, 1, 1, 1}, // not allowed if it pads the empty dim + T(1), + {0, 4, 2}, + {}, + "reflect", + OpTester::ExpectResult::kExpectFailure, + "Cannot use 'reflect' mode to pad dimension with a value of 0. Input shape:{0,2,1}"); } } // namespace test