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.
This commit is contained in:
Matthieu Darbois 2020-05-28 00:05:13 +02:00 committed by GitHub
parent 930c6a59da
commit a983509ed3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 440 additions and 397 deletions

View file

@ -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<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, uint8_t, BitShift)>,
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, uint32_t, BitShift)>,
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, uint64_t, BitShift)>,
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, float, Pad)>,
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, double, Pad)>,
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, int32_t, Pad)>,
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, int64_t, Pad)>,
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Pad)>,
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, GatherND)>,
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Range)>,
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Unique)>,

View file

@ -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<float>()),
onnxruntime::Pad<float>);
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<float>()),
Pad<float>);
KernelDefBuilder().TypeConstraint("T", {DataTypeImpl::GetTensorType<float>(),
DataTypeImpl::GetTensorType<double>()}),
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<float>()), Pad<float>);
ONNX_CPU_OPERATOR_TYPED_KERNEL(
Pad,
11,
double,
KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType<double>()), Pad<double>);
ONNX_CPU_OPERATOR_TYPED_KERNEL(
Pad,
11,
int32_t,
KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType<int32_t>()), Pad<int32_t>);
ONNX_CPU_OPERATOR_TYPED_KERNEL(
Pad,
11,
int64_t,
KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType<int64_t>()), Pad<int64_t>);
KernelDefBuilder().TypeConstraint("T", {DataTypeImpl::GetTensorType<float>(),
DataTypeImpl::GetTensorType<double>(),
DataTypeImpl::GetTensorType<int32_t>(),
DataTypeImpl::GetTensorType<int64_t>(),
DataTypeImpl::GetTensorType<uint32_t>(),
DataTypeImpl::GetTensorType<uint64_t>(),
DataTypeImpl::GetTensorType<int8_t>(),
DataTypeImpl::GetTensorType<uint8_t>()}),
Pad);
// This is the general padding method to n-dimensionally do edge or reflection padding (based on the inputDelta values)
template <typename T>
@ -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<T>();
auto* output = reinterpret_cast<T*>(output_tensor.MutableDataRaw());
std::fill_n(output, output_shape.Size(), value);
}
@ -192,7 +183,7 @@ static void ReshapePads(const std::vector<int64_t>& src_pad, size_t src_dim_coun
}
template <typename T>
Status PadCpuImpl(OpKernelContext* ctx,
static Status PadImpl(OpKernelContext* ctx,
const std::vector<int64_t>& pads,
const std::vector<int64_t>& 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<T>();
auto* output = reinterpret_cast<T*>(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 <typename T>
Status Pad<T>::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<float>()) {
result.f32 = value;
}
else if (data_type == DataTypeImpl::GetType<double>()) {
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<Tensor>(0);
MLDataType data_type = input_tensor.DataType();
const auto element_size = data_type->Size();
std::vector<int64_t> pads;
std::vector<int64_t> slices;
const std::vector<int64_t>* pads_to_use;
const std::vector<int64_t>* slices_to_use;
PadValue value;
Status status;
// kOnnxDomain Pad opset >= 11 (Or) kMsDomain opset == 1
if (is_dynamic_) {
const Tensor& input_tensor = *ctx->Input<Tensor>(0);
size_t data_rank = input_tensor.Shape().NumDimensions();
const Tensor& pads_tensor = *ctx->Input<Tensor>(1);
@ -375,14 +397,13 @@ Status Pad<T>::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<int64_t> 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<int64_t> slices(pads.size(), 0);
slices = std::vector<int64_t>(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<T>::Compute(OpKernelContext* ctx) const {
}
}
T value = static_cast<T>(0);
value.u64 = 0U;
const Tensor* value_tensor = ctx->Input<Tensor>(2);
if (nullptr != value_tensor) {
ORT_ENFORCE(value_tensor->IsDataType<T>() &&
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<T>()[0];
const void* value_data = value_tensor->DataRaw();
switch (element_size) {
case sizeof(uint32_t):
value.u32 = reinterpret_cast<const uint32_t*>(value_data)[0];
break;
case sizeof(uint64_t):
value.u64 = reinterpret_cast<const uint64_t*>(value_data)[0];
break;
case sizeof(uint8_t):
value.u8 = reinterpret_cast<const uint8_t*>(value_data)[0];
break;
default:
ORT_THROW("Unsupported input data type of ", data_type);
}
}
return PadCpuImpl<T>(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<T>(ctx, pads_, slices_, mode_, static_cast<T>(value_));
value = PadValueFromFloat(value_, data_type);
pads_to_use = &pads_;
slices_to_use = &slices_;
}
switch (element_size) {
case sizeof(uint32_t):
status = PadImpl<uint32_t>(ctx, *pads_to_use, *slices_to_use, mode_, value.u32);
break;
case sizeof(uint64_t):
status = PadImpl<uint64_t>(ctx, *pads_to_use, *slices_to_use, mode_, value.u64);
break;
case sizeof(uint8_t):
status = PadImpl<uint8_t>(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

View file

@ -71,18 +71,10 @@ class PadBase {
bool is_dynamic_ = false;
};
template <typename T>
struct Pad final : public OpKernel, public PadBase {
explicit Pad(const OpKernelInfo& info) : OpKernel(info), PadBase(info) {}
Status Compute(OpKernelContext* context) const override;
};
template <typename T>
Status PadCpuImpl(OpKernelContext* ctx,
const std::vector<int64_t>& pads,
const std::vector<int64_t>& slices,
const Mode& mode,
T value);
} // namespace onnxruntime

View file

@ -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 <typename T>
static void RunOpset11TypedTest(
template <typename T, int opset>
static void RunOnnxOpsetTypedTest(
const std::vector<int64_t>& input_dims,
const std::vector<T>& input,
const std::vector<int64_t>& 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<T>("data", input_dims, input);
test.AddInput<int64_t>("pads", {static_cast<int64_t>(pads.size())}, pads);
test.AddInput<T>("value", {1}, {value});
if (opset >= 11) {
test.AddInput<int64_t>("pads", {static_cast<int64_t>(pads.size())}, pads);
test.AddInput<T>("value", {1}, {value});
}
else {
test.AddAttribute("pads", pads);
test.AddAttribute("value", static_cast<float>(value));
}
test.AddOutput<T>("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 <typename T>
static void RunAllOpsetAllDomainPadTests(
const std::vector<int64_t>& input_dims,
const std::vector<T>& input,
const std::vector<int64_t>& pads,
T value,
const std::vector<int64_t>& output_dims,
const std::vector<T>& 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<T, 11>(input_dims,
input,
pads,
value,
output_dims,
output,
mode, expect, error_msg);
}
template<>
void RunAllOpsetAllDomainPadTests<>(
const std::vector<int64_t>& input_dims,
const std::vector<double>& input,
const std::vector<int64_t>& pads,
double value,
const std::vector<int64_t>& output_dims,
const std::vector<double>& output,
std::string mode,
OpTester::ExpectResult expect,
const std::string& error_msg) {
// ONNX domain supports double type
RunOnnxOpsetTypedTest<double, 10>(input_dims,
input,
pads,
value,
output_dims,
output,
mode, expect, error_msg);
RunOnnxOpsetTypedTest<double, 11>(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<int64_t>& input_dims,
const std::vector<float>& input,
const std::vector<int64_t>& pads,
float value,
const std::vector<int64_t>& output_dims,
const std::vector<float>& 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<float>("data", input_dims, input);
if (mode != "constant") test1.AddAttribute("mode", mode);
test1.AddAttribute("pads", pads);
test1.AddAttribute("value", value);
test1.AddOutput<float>("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<float>(input_dims,
input,
pads,
value,
output_dims,
output,
mode, expect, error_msg);
std::string mode,
OpTester::ExpectResult expect,
const std::string& error_msg) {
RunOnnxOpsetTypedTest<float, 10>(input_dims,
input,
pads,
value,
output_dims,
output,
mode, expect, error_msg);
RunOnnxOpsetTypedTest<float, 11>(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<float, double, int8_t, int32_t, int64_t, uint8_t, uint32_t, uint64_t>;
template <typename T>
class PadOpTest : public ::testing::Test {
};
TYPED_TEST_SUITE(PadOpTest, PadTypes);
TYPED_TEST(PadOpTest, Pad_Spec_Example) {
using T = TypeParam;
RunAllOpsetAllDomainPadTests<T>({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<int32_t> X = {1, 2, 3, 4, 5, 6};
int32_t value = 1234;
std::vector<int32_t> 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<T>({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<int64_t> X = {1, 2, 3, 4, 5, 6};
int64_t value = 1234;
std::vector<int64_t> 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<T>({2},
{T(1), T(2)},
{0, 0},
T(123),
{2},
{T(1), T(2)});
}
TEST(TensorOpTest, Pad_Constant_1D_double) {
std::vector<double> X = {1., 2., 3., 4., 5., 6.};
double value = 0.;
std::vector<double> 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<T>({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<T>({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<T>({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<T>({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<T>({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<T>({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<float> input_vals;
std::vector<T> input_vals;
input_vals.reserve(100);
for (int i = 0; i < 100; ++i) {
input_vals.push_back(static_cast<float>(i));
input_vals.push_back(T(i));
}
// holder for output_vals (expected)
std::vector<float> output_vals;
std::vector<T> 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<float>(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<T>({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<T>({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<T>({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<T>({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<T>({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<int32_t> X = {11, 21, 31,
12, 22, 32};
int32_t value = 0;
std::vector<int32_t> 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<int64_t> X = {11, 21, 31,
12, 22, 32};
int64_t value = 0;
std::vector<int64_t> 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<double> X = {11., 21., 31.,
12., 22., 32.};
double value = 0.;
std::vector<double> 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<T>({0}, // 1D
{},
{1, 1},
T(1),
{2},
{T(1), T(1)});
RunAllOpsetAllDomainPadTests({0}, // 1D empty pads
{},
{0, 0},
0.1f,
{0},
{});
RunAllOpsetAllDomainPadTests<T>({0}, // 1D empty pads
{},
{0, 0},
T(1),
{0},
{});
RunAllOpsetAllDomainPadTests({0}, // 1D offsetting pads
{},
{-1, 1},
0.1f,
{0},
{});
RunAllOpsetAllDomainPadTests<T>({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<T>({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<T>({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<T>({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<T>({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<T>({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<T>({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<T>({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<T>({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<T>({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