Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/OperatorKernels.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ The **OpSet Version** column uses the following notation:
|||[17, 19]|**T1** = tensor(double), tensor(float)<br/> **T2** = tensor(int32), tensor(int64)|
|DeformConv|*in* X:**T**<br> *in* W:**T**<br> *in* offset:**T**<br> *in* B:**T**<br> *in* mask:**T**<br> *out* Y:**T**|22+|**T** = tensor(double), tensor(float)|
|||[19, 21]|**T** = tensor(double), tensor(float)|
|DepthToSpace|*in* input:**T**<br> *out* output:**T**|13+|**T** = tensor(double), tensor(float), tensor(uint8)|
|||[11, 12]|**T** = tensor(double), tensor(float), tensor(uint8)|
|DepthToSpace|*in* input:**T**<br> *out* output:**T**|13+|**T** = tensor(double), tensor(float), tensor(int8), tensor(uint8)|
|||[11, 12]|**T** = tensor(double), tensor(float), tensor(int8), tensor(uint8)|
|||[1, 10]|**T** = tensor(double), tensor(float)|
|DequantizeLinear|*in* x:**T**<br> *in* x_scale:**tensor(float)**<br> *in* x_zero_point:**T**<br> *out* y:**tensor(float)**<br><br>or<br><br>*in* x:**T1**<br> *in* x_scale:**T2**<br> *in* x_zero_point:**T1**<br> *out* y:**T2**<br><br>or<br><br>*in* x:**T1**<br> *in* x_scale:**T2**<br> *in* x_zero_point:**T1**<br> *out* y:**T3**|25+|**T1** = tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int2), tensor(int32), tensor(int4), tensor(int8), tensor(uint16), tensor(uint2), tensor(uint4), tensor(uint8)<br/> **T2** = tensor(float), tensor(float16)|
|||24|**T1** = tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int4), tensor(int8), tensor(uint16), tensor(uint4), tensor(uint8)<br/> **T2** = tensor(float), tensor(float16)|
Expand Down Expand Up @@ -477,8 +477,8 @@ The **OpSet Version** column uses the following notation:
|||[1, 21]|**T** = tensor(float)|
|Softsign|*in* input:**T**<br> *out* output:**T**|22+|**T** = tensor(float)|
|||[1, 21]|**T** = tensor(float)|
|SpaceToDepth|*in* input:**T**<br> *out* output:**T**|13+|**T** = tensor(double), tensor(float)|
|||[1, 12]|**T** = tensor(double), tensor(float)|
|SpaceToDepth|*in* input:**T**<br> *out* output:**T**|13+|**T** = tensor(double), tensor(float), tensor(int8), tensor(uint8)|
|||[1, 12]|**T** = tensor(double), tensor(float), tensor(int8), tensor(uint8)|
|Split|*in* input:**T**<br> *in* split:**T**<br> *out* outputs...:**T**<br><br>or<br><br>*in* input:**T**<br> *in* split:**tensor(int64)**<br> *out* outputs:**T**<br><br>or<br><br>*in* input:**T**<br> *out* outputs:**T**|18+|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)|
|||[13, 17]|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)|
|||[11, 12]|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)|
Expand Down
55 changes: 40 additions & 15 deletions onnxruntime/core/providers/cpu/tensor/space_depth_ops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,19 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL(
12,
KernelDefBuilder()
.TypeConstraint("T", {DataTypeImpl::GetTensorType<float>(),
DataTypeImpl::GetTensorType<double>()}),
DataTypeImpl::GetTensorType<double>(),
DataTypeImpl::GetTensorType<uint8_t>(),
DataTypeImpl::GetTensorType<int8_t>()}),
SpaceToDepth);

ONNX_CPU_OPERATOR_KERNEL(
SpaceToDepth,
13,
KernelDefBuilder()
.TypeConstraint("T", {DataTypeImpl::GetTensorType<float>(),
DataTypeImpl::GetTensorType<double>()}),
DataTypeImpl::GetTensorType<double>(),
DataTypeImpl::GetTensorType<uint8_t>(),
DataTypeImpl::GetTensorType<int8_t>()}),
SpaceToDepth);

ONNX_CPU_OPERATOR_VERSIONED_KERNEL(
Expand All @@ -44,7 +48,8 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL(
KernelDefBuilder()
.TypeConstraint("T", {DataTypeImpl::GetTensorType<float>(),
DataTypeImpl::GetTensorType<double>(),
DataTypeImpl::GetTensorType<uint8_t>()}),
DataTypeImpl::GetTensorType<uint8_t>(),
DataTypeImpl::GetTensorType<int8_t>()}),
DepthToSpace);

ONNX_CPU_OPERATOR_KERNEL(
Expand All @@ -53,7 +58,8 @@ ONNX_CPU_OPERATOR_KERNEL(
KernelDefBuilder()
.TypeConstraint("T", {DataTypeImpl::GetTensorType<float>(),
DataTypeImpl::GetTensorType<double>(),
DataTypeImpl::GetTensorType<uint8_t>()}),
DataTypeImpl::GetTensorType<uint8_t>(),
DataTypeImpl::GetTensorType<int8_t>()}),
DepthToSpace);

// intermediate tensor shapes are:
Expand All @@ -70,15 +76,15 @@ using ConstEigenTensorMap = Eigen::TensorMap<Eigen::Tensor<const T, Intermediate
// helper method to fill in output buffer
// only this portion is templated to minimize binary size
template <typename T>
static void SpaceDepthOpCpuImpl(const Tensor& input, Tensor& output,
static void SpaceDepthOpCpuImpl(const T* input_data, T* output_data,
const std::array<Eigen::DenseIndex, IntermediateTensorRank>& permutation,
const Eigen::DenseIndex batch_size, // dim0 in both input and output
const Eigen::DenseIndex in_dim1, const Eigen::DenseIndex in_dim2, const Eigen::DenseIndex in_dim3,
const Eigen::DenseIndex in_dim4, const Eigen::DenseIndex in_dim5,
const Eigen::DenseIndex out_dim1, const Eigen::DenseIndex out_dim2, const Eigen::DenseIndex out_dim3,
const Eigen::DenseIndex out_dim4, const Eigen::DenseIndex out_dim5) {
EigenTensorMap<T>(output.MutableData<T>(), batch_size, out_dim1, out_dim2, out_dim3, out_dim4, out_dim5) =
ConstEigenTensorMap<T>(input.Data<T>(), batch_size,
EigenTensorMap<T>(output_data, batch_size, out_dim1, out_dim2, out_dim3, out_dim4, out_dim5) =
ConstEigenTensorMap<T>(input_data, batch_size,
in_dim1, in_dim2, in_dim3, in_dim4, in_dim5)
.shuffle(permutation);
}
Expand Down Expand Up @@ -109,7 +115,7 @@ Status SpaceToDepth::Compute(OpKernelContext* context) const {
std::array<Eigen::DenseIndex, IntermediateTensorRank> permutation{{0, 3, 5, 1, 2, 4}};

if (input.IsDataType<float>()) {
SpaceDepthOpCpuImpl<float>(input, output, permutation,
SpaceDepthOpCpuImpl<float>(input.Data<float>(), output.MutableData<float>(), permutation,
onnxruntime::narrow<ptrdiff_t>(batch),
onnxruntime::narrow<std::ptrdiff_t>(input_depth),
onnxruntime::narrow<std::ptrdiff_t>(input_height / blocksize_),
Expand All @@ -122,7 +128,7 @@ Status SpaceToDepth::Compute(OpKernelContext* context) const {
onnxruntime::narrow<std::ptrdiff_t>(input_height / blocksize_),
onnxruntime::narrow<std::ptrdiff_t>(input_width / blocksize_));
} else if (input.IsDataType<double>()) {
SpaceDepthOpCpuImpl<double>(input, output, permutation,
SpaceDepthOpCpuImpl<double>(input.Data<double>(), output.MutableData<double>(), permutation,
onnxruntime::narrow<ptrdiff_t>(batch),
onnxruntime::narrow<std::ptrdiff_t>(input_depth),
onnxruntime::narrow<std::ptrdiff_t>(input_height / blocksize_),
Expand All @@ -134,8 +140,24 @@ Status SpaceToDepth::Compute(OpKernelContext* context) const {
onnxruntime::narrow<std::ptrdiff_t>(input_depth),
onnxruntime::narrow<std::ptrdiff_t>(input_height / blocksize_),
onnxruntime::narrow<std::ptrdiff_t>(input_width / blocksize_));
} else if (input.IsDataType<uint8_t>() || input.IsDataType<int8_t>()) {
// uint8_t and int8_t share a single implementation: the op only moves 8-bit
// elements around, so the signedness of the data does not matter.
SpaceDepthOpCpuImpl<uint8_t>(static_cast<const uint8_t*>(input.DataRaw()),
static_cast<uint8_t*>(output.MutableDataRaw()), permutation,
onnxruntime::narrow<ptrdiff_t>(batch),
onnxruntime::narrow<std::ptrdiff_t>(input_depth),
onnxruntime::narrow<std::ptrdiff_t>(input_height / blocksize_),
onnxruntime::narrow<std::ptrdiff_t>(blocksize_),
onnxruntime::narrow<std::ptrdiff_t>(input_width / blocksize_),
onnxruntime::narrow<std::ptrdiff_t>(blocksize_),
onnxruntime::narrow<ptrdiff_t>(blocksize_),
onnxruntime::narrow<ptrdiff_t>(blocksize_),
onnxruntime::narrow<std::ptrdiff_t>(input_depth),
onnxruntime::narrow<std::ptrdiff_t>(input_height / blocksize_),
onnxruntime::narrow<std::ptrdiff_t>(input_width / blocksize_));
} else {
// user will not see this as the kernel doesn't claim support for types other than float and double
// user will not see this as the kernel doesn't claim support for types other than float, double, uint8_t and int8_t
return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Unsupported input type in SpaceToDepth op: ", input.DataType());
}

Expand Down Expand Up @@ -173,7 +195,7 @@ Status DepthToSpace::Compute(OpKernelContext* context) const {
: std::array<Eigen::DenseIndex, IntermediateTensorRank>{{0, 1, 4, 2, 5, 3}};

if (input.IsDataType<float>()) {
SpaceDepthOpCpuImpl<float>(input, output, permutation,
SpaceDepthOpCpuImpl<float>(input.Data<float>(), output.MutableData<float>(), permutation,
onnxruntime::narrow<std::ptrdiff_t>(batch),
onnxruntime::narrow<std::ptrdiff_t>(dim1),
onnxruntime::narrow<std::ptrdiff_t>(blocksize_),
Expand All @@ -186,7 +208,7 @@ Status DepthToSpace::Compute(OpKernelContext* context) const {
onnxruntime::narrow<std::ptrdiff_t>(input_width),
onnxruntime::narrow<std::ptrdiff_t>(blocksize_));
} else if (input.IsDataType<double>()) {
SpaceDepthOpCpuImpl<double>(input, output, permutation,
SpaceDepthOpCpuImpl<double>(input.Data<double>(), output.MutableData<double>(), permutation,
onnxruntime::narrow<std::ptrdiff_t>(batch),
onnxruntime::narrow<std::ptrdiff_t>(dim1),
onnxruntime::narrow<std::ptrdiff_t>(blocksize_),
Expand All @@ -198,8 +220,11 @@ Status DepthToSpace::Compute(OpKernelContext* context) const {
onnxruntime::narrow<std::ptrdiff_t>(blocksize_),
onnxruntime::narrow<std::ptrdiff_t>(input_width),
onnxruntime::narrow<std::ptrdiff_t>(blocksize_));
} else if (input.IsDataType<uint8_t>()) {
SpaceDepthOpCpuImpl<uint8_t>(input, output, permutation,
} else if (input.IsDataType<uint8_t>() || input.IsDataType<int8_t>()) {
// uint8_t and int8_t share a single implementation: the op only moves 8-bit
// elements around, so the signedness of the data does not matter.
SpaceDepthOpCpuImpl<uint8_t>(static_cast<const uint8_t*>(input.DataRaw()),
static_cast<uint8_t*>(output.MutableDataRaw()), permutation,
onnxruntime::narrow<std::ptrdiff_t>(batch),
onnxruntime::narrow<std::ptrdiff_t>(dim1),
onnxruntime::narrow<std::ptrdiff_t>(blocksize_),
Expand All @@ -212,7 +237,7 @@ Status DepthToSpace::Compute(OpKernelContext* context) const {
onnxruntime::narrow<std::ptrdiff_t>(input_width),
onnxruntime::narrow<std::ptrdiff_t>(blocksize_));
} else {
// user will not see this as the kernel doesn't claim support for types other than float and double
// user will not see this as the kernel doesn't claim support for types other than float, double, uint8_t and int8_t
return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Unsupported input type in DepthToSpace op: ", input.DataType());
}

Expand Down
88 changes: 87 additions & 1 deletion onnxruntime/test/providers/cpu/tensor/space_depth_ops_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ template <typename T>
class TensorOpTest : public ::testing::Test {
};

using TensorOpTestTypes = ::testing::Types<float, MLFloat16, uint8_t>;
using TensorOpTestTypes = ::testing::Types<float, MLFloat16, uint8_t, int8_t>;
TYPED_TEST_SUITE(TensorOpTest, TensorOpTestTypes);

TEST(TensorOpTest, SpaceToDepthTest_1) {
Expand Down Expand Up @@ -159,6 +159,71 @@ TEST(TensorOpTest, SpaceToDepthTest_3) {
test.Run();
}

TYPED_TEST(TensorOpTest, SpaceToDepthTest_int) {
// Same data as SpaceToDepthTest_2 (values 0..107 fit in both int8_t and uint8_t),
// exercised across the supported element types.
OpTester test("SpaceToDepth");
Comment thread
ArsalanShakil marked this conversation as resolved.
Outdated
constexpr int64_t blocksize = 3;
test.AddAttribute("blocksize", blocksize);
constexpr int64_t N = 2, C = 3, H = 3, W = 6;
Comment thread
ArsalanShakil marked this conversation as resolved.
const std::vector<float> X = {
0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.,
11., 12., 13., 14., 15., 16., 17., 18., 19., 20., 21.,
22., 23., 24., 25., 26., 27., 28., 29., 30., 31., 32.,
33., 34., 35., 36., 37., 38., 39., 40., 41., 42., 43.,
44., 45., 46., 47., 48., 49., 50., 51., 52., 53., 54.,
55., 56., 57., 58., 59., 60., 61., 62., 63., 64., 65.,
66., 67., 68., 69., 70., 71., 72., 73., 74., 75., 76.,
77., 78., 79., 80., 81., 82., 83., 84., 85., 86., 87.,
88., 89., 90., 91., 92., 93., 94., 95., 96., 97., 98.,
99., 100., 101., 102., 103., 104., 105., 106., 107.};

const std::vector<float> result = {
0., 3., 18., 21., 36., 39., 1., 4., 19., 22., 37.,
40., 2., 5., 20., 23., 38., 41., 6., 9., 24., 27.,
42., 45., 7., 10., 25., 28., 43., 46., 8., 11., 26.,
29., 44., 47., 12., 15., 30., 33., 48., 51., 13., 16.,
31., 34., 49., 52., 14., 17., 32., 35., 50., 53., 54.,
57., 72., 75., 90., 93., 55., 58., 73., 76., 91., 94.,
56., 59., 74., 77., 92., 95., 60., 63., 78., 81., 96.,
99., 61., 64., 79., 82., 97., 100., 62., 65., 80., 83.,
98., 101., 66., 69., 84., 87., 102., 105., 67., 70., 85.,
88., 103., 106., 68., 71., 86., 89., 104., 107.};

const std::vector<int64_t> output_shape = {2, 27, 1, 2};

if constexpr (std::is_same<TypeParam, float>::value) {
test.AddInput<float>("input", {N, C, H, W}, X);
test.AddOutput<float>("output", output_shape, result);
} else if constexpr (std::is_same<TypeParam, MLFloat16>::value) {
std::vector<TypeParam> X_fp16(X.size());
std::vector<TypeParam> result_fp16(result.size());
ConvertFloatToMLFloat16(X.data(), X_fp16.data(), X.size());
ConvertFloatToMLFloat16(result.data(), result_fp16.data(), result.size());
test.AddInput<TypeParam>("input", {N, C, H, W}, X_fp16);
test.AddOutput<TypeParam>("output", output_shape, result_fp16);
} else if constexpr (std::is_same<TypeParam, uint8_t>::value) {
std::vector<uint8_t> X_u8(X.size());
std::vector<uint8_t> result_u8(result.size());
ConvertFloatToUint8_t(X.data(), X_u8.data(), X.size());
ConvertFloatToUint8_t(result.data(), result_u8.data(), result.size());
test.AddInput<uint8_t>("input", {N, C, H, W}, X_u8);
test.AddOutput<uint8_t>("output", output_shape, result_u8);
} else if constexpr (std::is_same<TypeParam, int8_t>::value) {
std::vector<int8_t> X_i8(X.size());
std::vector<int8_t> result_i8(result.size());
ConvertFloatToInt8_t(X.data(), X_i8.data(), X.size());
ConvertFloatToInt8_t(result.data(), result_i8.data(), result.size());
test.AddInput<int8_t>("input", {N, C, H, W}, X_i8);
test.AddOutput<int8_t>("output", output_shape, result_i8);
} else {
ORT_THROW("Type not supported");
}

// type not supported by QNN EP: MLFloat16 and unsigned char
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kQnnExecutionProvider});
Comment thread
ArsalanShakil marked this conversation as resolved.
Outdated
}

TEST(TensorOpTest, DepthToSpaceTest_1) {
OpTester test("DepthToSpace", 7); // create an opset 7 model
constexpr int64_t blocksize = 2;
Expand Down Expand Up @@ -319,6 +384,13 @@ TYPED_TEST(TensorOpTest, DepthToSpaceTest_3) {
ConvertFloatToUint8_t(result.data(), result_u8.data(), result.size());
test.AddInput<uint8_t>("input", {N, C, H, W}, X_u8);
test.AddOutput<uint8_t>("output", {2, 3, 6, 4}, result_u8);
} else if constexpr (std::is_same<TypeParam, int8_t>::value) {
std::vector<int8_t> X_i8(X.size());
std::vector<int8_t> result_i8(result.size());
ConvertFloatToInt8_t(X.data(), X_i8.data(), X.size());
Comment thread
tianleiwu marked this conversation as resolved.
ConvertFloatToInt8_t(result.data(), result_i8.data(), result.size());
test.AddInput<int8_t>("input", {N, C, H, W}, X_i8);
test.AddOutput<int8_t>("output", {2, 3, 6, 4}, result_i8);
Comment thread
ArsalanShakil marked this conversation as resolved.
} else {
ORT_THROW("Type not supported");
}
Expand Down Expand Up @@ -383,6 +455,13 @@ TYPED_TEST(TensorOpTest, DepthToSpaceTest_4) {
ConvertFloatToUint8_t(result.data(), result_u8.data(), result.size());
test.AddInput<uint8_t>("input", {N, C, H, W}, X_u8);
test.AddOutput<uint8_t>("output", {2, 3, 6, 4}, result_u8);
} else if constexpr (std::is_same<TypeParam, int8_t>::value) {
std::vector<int8_t> X_i8(X.size());
std::vector<int8_t> result_i8(result.size());
ConvertFloatToInt8_t(X.data(), X_i8.data(), X.size());
ConvertFloatToInt8_t(result.data(), result_i8.data(), result.size());
test.AddInput<int8_t>("input", {N, C, H, W}, X_i8);
test.AddOutput<int8_t>("output", {2, 3, 6, 4}, result_i8);
Comment thread
ArsalanShakil marked this conversation as resolved.
} else {
ORT_THROW("Type not supported");
}
Expand Down Expand Up @@ -429,6 +508,13 @@ TYPED_TEST(TensorOpTest, DepthToSpaceTest_5) {
ConvertFloatToUint8_t(result.data(), result_u8.data(), result.size());
test.AddInput<uint8_t>("input", {N, C, H, W}, X_u8);
test.AddOutput<uint8_t>("output", {1, 1, 4, 6}, result_u8);
} else if constexpr (std::is_same<TypeParam, int8_t>::value) {
std::vector<int8_t> X_i8(X.size());
std::vector<int8_t> result_i8(result.size());
ConvertFloatToInt8_t(X.data(), X_i8.data(), X.size());
ConvertFloatToInt8_t(result.data(), result_i8.data(), result.size());
test.AddInput<int8_t>("input", {N, C, H, W}, X_i8);
test.AddOutput<int8_t>("output", {1, 1, 4, 6}, result_i8);
} else {
ORT_THROW("Type not supported");
}
Expand Down
6 changes: 6 additions & 0 deletions onnxruntime/test/unittest_util/conversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ inline void ConvertFloatToUint8_t(const float* f_datat, uint8_t* u8_data, size_t
output_vector = in_vector.template cast<uint8_t>();
}

inline void ConvertFloatToInt8_t(const float* f_datat, int8_t* i8_data, size_t input_size) {
auto in_vector = ConstEigenVectorMap<float>(f_datat, input_size);
auto output_vector = EigenVectorMap<int8_t>(static_cast<int8_t*>(static_cast<void*>(i8_data)), input_size);
output_vector = in_vector.template cast<int8_t>();
}

inline void ConvertMLFloat16ToFloat(const MLFloat16* h_data, float* f_data, size_t input_size) {
auto in_vector =
ConstEigenVectorMap<Eigen::half>(static_cast<const Eigen::half*>(static_cast<const void*>(h_data)), input_size);
Expand Down
Loading