diff --git a/docs/OperatorKernels.md b/docs/OperatorKernels.md
index 7f438b6d86..a2f2efc119 100644
--- a/docs/OperatorKernels.md
+++ b/docs/OperatorKernels.md
@@ -36,7 +36,8 @@ Do not modify directly.*
|Asinh|*in* input:**T**
*out* output:**T**|9+|**T** = tensor(float)|
|Atan|*in* input:**T**
*out* output:**T**|7+|**T** = tensor(float)|
|Atanh|*in* input:**T**
*out* output:**T**|9+|**T** = tensor(float)|
-|AveragePool|*in* X:**T**
*out* Y:**T**|11+|**T** = tensor(float)|
+|AveragePool|*in* X:**T**
*out* Y:**T**|19+|**T** = tensor(float)|
+|||[11, 18]|**T** = tensor(float)|
|||10|**T** = tensor(float)|
|||[7, 9]|**T** = tensor(float)|
|BatchNormalization|*in* X:**T**
*in* scale:**T**
*in* B:**T**
*in* input_mean:**U**
*in* input_var:**U**
*out* Y:**T**
*out* running_mean:**U**
*out* running_var:**U**
or
*in* X:**T**
*in* scale:**T**
*in* B:**T**
*in* mean:**T**
*in* var:**T**
*out* Y:**T**
*out* mean:**T**
*out* var:**T**
*out* saved_mean:**T**
*out* saved_var:**T**
or
*in* X:**T**
*in* scale:**T1**
*in* B:**T1**
*in* input_mean:**T2**
*in* input_var:**T2**
*out* Y:**T**
*out* running_mean:**T2**
*out* running_var:**T2**|15+|**T** = tensor(double), tensor(float)
**T1** = tensor(double), tensor(float)
**T2** = tensor(double), tensor(float)|
@@ -225,7 +226,8 @@ Do not modify directly.*
|PRelu|*in* X:**T**
*in* slope:**T**
*out* Y:**T**|16+|**T** = tensor(float)|
|||[9, 15]|**T** = tensor(float)|
|||[7, 8]|**T** = tensor(float)|
-|Pad|*in* data:**T**
*in* pads:**tensor(int64)**
*in* constant_value:**T**
*in* axes:**Tind**
*out* output:**T**
or
*in* data:**T**
*in* pads:**tensor(int64)**
*in* constant_value:**T**
*out* output:**T**
or
*in* data:**T**
*out* output:**T**|18+|**T** = tensor(bool), tensor(double), tensor(float), tensor(int32), tensor(int64), tensor(int8), tensor(uint32), tensor(uint64), tensor(uint8)|
+|Pad|*in* data:**T**
*in* pads:**tensor(int64)**
*in* constant_value:**T**
*in* axes:**Tind**
*out* output:**T**
or
*in* data:**T**
*in* pads:**tensor(int64)**
*in* constant_value:**T**
*out* output:**T**
or
*in* data:**T**
*out* output:**T**|19+|**T** = tensor(bool), tensor(double), tensor(float), tensor(int32), tensor(int64), tensor(int8), tensor(uint32), tensor(uint64), tensor(uint8)|
+|||18|**T** = tensor(bool), tensor(double), tensor(float), tensor(int32), tensor(int64), tensor(int8), tensor(uint32), tensor(uint64), tensor(uint8)|
|||[13, 17]|**T** = tensor(bool), tensor(double), tensor(float), tensor(int32), tensor(int64), tensor(int8), tensor(uint32), tensor(uint64), tensor(uint8)|
|||[11, 12]|**T** = tensor(double), tensor(float), tensor(int32), tensor(int64), tensor(int8), tensor(uint32), tensor(uint64), tensor(uint8)|
|||[2, 10]|**T** = tensor(double), tensor(float)|
diff --git a/onnxruntime/core/providers/cpu/cpu_execution_provider.cc b/onnxruntime/core/providers/cpu/cpu_execution_provider.cc
index 96f2590624..cb011622fe 100644
--- a/onnxruntime/core/providers/cpu/cpu_execution_provider.cc
+++ b/onnxruntime/core/providers/cpu/cpu_execution_provider.cc
@@ -460,13 +460,13 @@ class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDoma
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Det);
class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, ScatterElements);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, NonMaxSuppression);
-class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, AveragePool);
+class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 18, AveragePool);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, MaxUnpool);
class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 17, LpPool);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Conv);
#ifdef MLAS_F16VEC_INTRINSICS_SUPPORTED
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, MLFloat16, Conv);
-class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, MLFloat16, AveragePool);
+class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 18, MLFloat16, AveragePool);
#endif
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, ConvTranspose);
class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, If);
@@ -913,15 +913,22 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain,
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, uint16_t, BitwiseXor);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, uint32_t, BitwiseXor);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, uint64_t, BitwiseXor);
-class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, Pad);
+class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, 18, Pad);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, ScatterND);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, ScatterElements);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, Split);
#if !defined(DISABLE_OPTIONAL_TYPE)
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, OptionalHasElement);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, OptionalGetElement);
+
#endif
+// Opset 19
+class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, AveragePool);
+#ifdef MLAS_F16VEC_INTRINSICS_SUPPORTED
+class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, MLFloat16, AveragePool);
+#endif
+class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, Pad);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, float, Resize);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, int32_t, Resize);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, int8_t, Resize);
@@ -1534,7 +1541,7 @@ Status RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) {
BuildKernelCreateInfo,
BuildKernelCreateInfo,
- BuildKernelCreateInfo,
+ BuildKernelCreateInfo,
BuildKernelCreateInfo,
BuildKernelCreateInfo,
BuildKernelCreateInfo,
@@ -2292,7 +2299,7 @@ Status RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) {
BuildKernelCreateInfo,
BuildKernelCreateInfo,
BuildKernelCreateInfo,
- BuildKernelCreateInfo,
+ BuildKernelCreateInfo,
BuildKernelCreateInfo,
BuildKernelCreateInfo,
BuildKernelCreateInfo,
@@ -2300,6 +2307,10 @@ Status RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) {
BuildKernelCreateInfo,
BuildKernelCreateInfo,
#endif
+
+ // Opset 19
+ BuildKernelCreateInfo,
+ BuildKernelCreateInfo,
BuildKernelCreateInfo,
BuildKernelCreateInfo,
BuildKernelCreateInfo,
@@ -2321,7 +2332,8 @@ Status RegisterFp16Kernels(KernelRegistry& kernel_registry) {
static const BuildKernelCreateInfoFn function_table[] = {
BuildKernelCreateInfo,
BuildKernelCreateInfo,
- BuildKernelCreateInfo,
+ BuildKernelCreateInfo,
+ BuildKernelCreateInfo,
BuildKernelCreateInfo,
BuildKernelCreateInfo,
BuildKernelCreateInfo,
diff --git a/onnxruntime/core/providers/cpu/fp16/fp16_pool.cc b/onnxruntime/core/providers/cpu/fp16/fp16_pool.cc
index 9960ef3779..7c1e05f7ce 100644
--- a/onnxruntime/core/providers/cpu/fp16/fp16_pool.cc
+++ b/onnxruntime/core/providers/cpu/fp16/fp16_pool.cc
@@ -231,9 +231,15 @@ ONNX_CPU_OPERATOR_TYPED_KERNEL(
KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()),
PoolFp16);
+ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL(
+ AveragePool, 11, 18,
+ MLFloat16,
+ KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()),
+ PoolFp16);
+
ONNX_CPU_OPERATOR_TYPED_KERNEL(
AveragePool,
- 11,
+ 19,
MLFloat16,
KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()),
PoolFp16);
diff --git a/onnxruntime/core/providers/cpu/nn/pool.cc b/onnxruntime/core/providers/cpu/nn/pool.cc
index 084669c970..9230398680 100644
--- a/onnxruntime/core/providers/cpu/nn/pool.cc
+++ b/onnxruntime/core/providers/cpu/nn/pool.cc
@@ -249,6 +249,81 @@ Status MaxPoolV8::ComputeImpl(OpKernelContext* context) const {
return Status::OK();
}
+template
+Status AveragePoolV19::Compute(OpKernelContext* context) const {
+ concurrency::ThreadPool* tp = context->GetOperatorThreadPool();
+ bool need_dilation = false;
+ for (auto n : pool_attrs_.dilations) {
+ need_dilation |= n > 1;
+ }
+
+ const auto* X = context->Input(0);
+ const TensorShape& x_shape = X->Shape();
+
+ ORT_RETURN_IF_NOT(x_shape.NumDimensions() >= 3, "Input dimension cannot be less than 3.");
+
+ auto pads = pool_attrs_.pads;
+ auto kernel_shape = pool_attrs_.kernel_shape;
+
+ auto output_dims = pool_attrs_.SetOutputSize(x_shape, x_shape[1], &pads);
+ Tensor* Y = context->Output(0, output_dims);
+
+ const auto* X_data = X->Data();
+ auto* Y_data = Y->MutableData();
+
+ // The main loop
+ int64_t channels = x_shape[1];
+ int64_t height = x_shape[2];
+ int64_t width = kernel_shape.size() > 1 ? x_shape[3] : 1;
+ int64_t depth = kernel_shape.size() > 2 ? x_shape[4] : 1;
+ int64_t pooled_height = output_dims[2];
+ int64_t pooled_width = kernel_shape.size() > 1 ? output_dims[3] : 1;
+ int64_t pooled_depth = kernel_shape.size() > 2 ? output_dims[4] : 1;
+ const int64_t total_channels = x_shape[0] * channels;
+
+ switch (kernel_shape.size()) {
+ case 1: {
+ int64_t x_step = height;
+ int64_t y_step = pooled_height;
+ const int64_t dilation_h = pool_attrs_.dilations[0];
+
+ RunLoop>(tp, onnxruntime::narrow(total_channels),
+ {X_data, Y_data, x_step, y_step, dilation_h, pooled_height, stride_h(),
+ height, kernel_shape, pads, pool_attrs_.count_include_pad, p_});
+ break;
+ }
+
+ case 2: {
+ int64_t x_step = height * width;
+ int64_t y_step = pooled_height * pooled_width;
+ const int64_t dilation_h = pool_attrs_.dilations[0];
+ const int64_t dilation_w = pool_attrs_.dilations[1];
+ RunLoop>(
+ tp, onnxruntime::narrow(total_channels),
+ {X_data, Y_data, x_step, y_step, dilation_h, dilation_w, pooled_height, pooled_width, stride_h(),
+ stride_w(), height, width, kernel_shape, pads, pool_attrs_.count_include_pad, p_});
+ break;
+ }
+ case 3: {
+ int64_t x_step = height * width * depth;
+ int64_t y_step = pooled_height * pooled_width * pooled_depth;
+ const int64_t dilation_h = pool_attrs_.dilations[0];
+ const int64_t dilation_w = pool_attrs_.dilations[1];
+ const int64_t dilation_d = pool_attrs_.dilations[2];
+ RunLoop>(tp, onnxruntime::narrow(total_channels),
+ {X_data, Y_data, x_step, y_step,
+ dilation_h, dilation_w, dilation_d, pooled_height, pooled_width,
+ pooled_depth, stride_h(), stride_w(), stride_d(), height,
+ width, depth, kernel_shape, pads, pool_attrs_.count_include_pad, p_});
+ break;
+ }
+ default:
+ return Status(ONNXRUNTIME, INVALID_ARGUMENT, "Unsupported kernel dimension : " + std::to_string(kernel_shape.size()));
+ }
+
+ return Status::OK();
+}
+
template
Status LpPoolV18::Compute(OpKernelContext* context) const {
concurrency::ThreadPool* tp = context->GetOperatorThreadPool();
@@ -332,8 +407,16 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL(AveragePool, 10, 10,
KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()),
Pool);
-ONNX_CPU_OPERATOR_KERNEL(AveragePool, 11, KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()),
- Pool);
+ONNX_CPU_OPERATOR_VERSIONED_KERNEL(AveragePool, 11, 18,
+ KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()),
+ Pool);
+
+ONNX_CPU_OPERATOR_KERNEL(AveragePool, 19,
+ KernelDefBuilder()
+ .TypeConstraint(
+ "T",
+ DataTypeImpl::GetTensorType()),
+ AveragePoolV19);
ONNX_CPU_OPERATOR_VERSIONED_KERNEL(MaxPool, 1, 7,
KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()),
diff --git a/onnxruntime/core/providers/cpu/nn/pool.h b/onnxruntime/core/providers/cpu/nn/pool.h
index 98a9c8abb6..7796b28b83 100644
--- a/onnxruntime/core/providers/cpu/nn/pool.h
+++ b/onnxruntime/core/providers/cpu/nn/pool.h
@@ -25,6 +25,20 @@ class Pool : public OpKernel, public PoolBase {
PoolProcessContext pool_context_;
};
+// For averagepool v19 and beyond
+// version 19: Added dilations
+template
+class AveragePoolV19 : public OpKernel, public PoolBase {
+ public:
+ AveragePoolV19(const OpKernelInfo& info) : OpKernel(info), PoolBase(info) {
+ }
+
+ Status Compute(OpKernelContext* context) const override;
+
+ private:
+ int64_t p_;
+};
+
// For maxpool v8 and beyond
// version 8: Added storage_order And Indices
// version 10: Added ceil_mode
diff --git a/onnxruntime/core/providers/cpu/nn/pool_functors.h b/onnxruntime/core/providers/cpu/nn/pool_functors.h
index 1fbdadf05f..d3205278b7 100644
--- a/onnxruntime/core/providers/cpu/nn/pool_functors.h
+++ b/onnxruntime/core/providers/cpu/nn/pool_functors.h
@@ -376,6 +376,199 @@ struct MaxPool3DTask {
}
};
+template
+struct AveragePool1DTask final {
+ const T* X_data;
+ T* Y_data;
+ int64_t x_step;
+ int64_t y_step;
+ int64_t dilation_h;
+ int64_t pooled_height;
+ int64_t stride_h;
+ int64_t height;
+ gsl::span kernel_shape;
+ gsl::span pads;
+ bool count_include_pad;
+ int64_t p;
+ TensorOpCost Cost() {
+ double loop_count = static_cast(pooled_height * kernel_shape[0]);
+ return TensorOpCost{loop_count, loop_count, loop_count};
+ }
+
+ void operator()(std::ptrdiff_t begin, std::ptrdiff_t end) const {
+ for (std::ptrdiff_t c = begin; c < end; ++c) {
+ operator()(c);
+ }
+ }
+ void operator()(std::ptrdiff_t c) const {
+ const T* x_d = X_data + c * x_step;
+ T* y_d = Y_data + c * y_step;
+ for (int64_t ph = 0; ph < pooled_height; ++ph) {
+ int64_t hstart = ph * stride_h - pads[0];
+ int64_t hend = hstart + kernel_shape[0] * dilation_h;
+ y_d[ph] = 0;
+ int total_elements = 0;
+ for (int64_t h = hstart; h < hend; h += dilation_h) {
+ if (math::is_a_ge_zero_and_a_lt_b(h, height)) {
+ y_d[ph] += x_d[h];
+ total_elements++;
+ }
+ }
+ if (total_elements > 0) {
+ if (count_include_pad) {
+ y_d[ph] /= (1 + (hend - hstart - 1) / dilation_h);
+ } else {
+ y_d[ph] /= total_elements;
+ }
+ }
+ }
+ }
+};
+
+template
+struct AveragePool2DTask final {
+ const T* X_data;
+ T* Y_data;
+ int64_t x_step;
+ int64_t y_step;
+ int64_t dilation_h;
+ int64_t dilation_w;
+ int64_t pooled_height;
+ int64_t pooled_width;
+ int64_t stride_h;
+ int64_t stride_w;
+ int64_t height;
+ int64_t width;
+ gsl::span kernel_shape;
+ gsl::span pads;
+ bool count_include_pad;
+ int64_t p;
+
+ TensorOpCost Cost() {
+ double loop_count = static_cast(pooled_height * pooled_width * kernel_shape[0] * kernel_shape[1]);
+ return TensorOpCost{loop_count, loop_count, loop_count};
+ }
+
+ void operator()(std::ptrdiff_t begin, std::ptrdiff_t end) const {
+ for (std::ptrdiff_t c = begin; c < end; ++c) {
+ operator()(c);
+ }
+ }
+
+ void operator()(std::ptrdiff_t c) const {
+ const T* x_d = X_data + c * x_step;
+ T* y_d = Y_data + c * y_step;
+ for (int64_t ph = 0; ph < pooled_height; ++ph) {
+ int64_t hstart = ph * stride_h - pads[0];
+ int64_t hend = hstart + kernel_shape[0] * dilation_h;
+ for (int64_t pw = 0; pw < pooled_width; ++pw) {
+ int64_t wstart = pw * stride_w - pads[1];
+ int64_t wend = wstart + kernel_shape[1] * dilation_w;
+ const int64_t pool_index = ph * pooled_width + pw;
+ y_d[pool_index] = 0;
+ int total_elements = 0;
+ for (int64_t h = hstart; h < hend; h += dilation_h) {
+ if (math::is_a_ge_zero_and_a_lt_b(h, height)) {
+ for (int64_t w = wstart; w < wend; w += dilation_w) {
+ if (math::is_a_ge_zero_and_a_lt_b(w, width)) {
+ const int64_t input_index = h * width + w;
+ y_d[pool_index] += x_d[input_index];
+ total_elements++;
+ }
+ }
+ }
+ }
+ if (total_elements > 0) {
+ if (count_include_pad) {
+ y_d[pool_index] /= ((1 + (hend - hstart - 1) / dilation_h) * (1 + (wend - wstart - 1) / dilation_w));
+ } else {
+ y_d[pool_index] /= total_elements;
+ }
+ }
+ }
+ }
+ }
+};
+
+template
+struct AveragePool3DTask {
+ const T* X_data;
+ T* Y_data;
+ int64_t x_step;
+ int64_t y_step;
+ int64_t dilation_h;
+ int64_t dilation_w;
+ int64_t dilation_d;
+ int64_t pooled_height;
+ int64_t pooled_width;
+ int64_t pooled_depth;
+ int64_t stride_h;
+ int64_t stride_w;
+ int64_t stride_d;
+ int64_t height;
+ int64_t width;
+ int64_t depth;
+ gsl::span kernel_shape;
+ gsl::span pads;
+ bool count_include_pad;
+ int64_t p;
+
+ void operator()(std::ptrdiff_t begin, std::ptrdiff_t end) const {
+ for (std::ptrdiff_t c = begin; c < end; ++c) {
+ operator()(c);
+ }
+ }
+
+ TensorOpCost Cost() {
+ double loop_count = static_cast(pooled_height * pooled_width * pooled_depth * kernel_shape[0] *
+ kernel_shape[1] * kernel_shape[2]);
+ return TensorOpCost{loop_count, loop_count, loop_count};
+ }
+
+ void operator()(std::ptrdiff_t c) const {
+ const T* x_d = X_data + c * x_step;
+ T* y_d = Y_data + c * y_step;
+
+ for (int64_t ph = 0; ph < pooled_height; ++ph) {
+ int64_t hstart = ph * stride_h - pads[0];
+ int64_t hend = hstart + kernel_shape[0] * dilation_h;
+ for (int64_t pw = 0; pw < pooled_width; ++pw) {
+ int64_t wstart = pw * stride_w - pads[1];
+ int64_t wend = wstart + kernel_shape[1] * dilation_w;
+ for (int64_t pd = 0; pd < pooled_depth; ++pd) {
+ int64_t dstart = pd * stride_d - pads[2];
+ int64_t dend = dstart + kernel_shape[2] * dilation_d;
+ const int64_t pool_index = ph * pooled_width * pooled_depth + pw * pooled_depth + pd;
+ y_d[pool_index] = 0;
+ int total_elements = 0;
+ for (int64_t h = hstart; h < hend; h += dilation_h) {
+ if (math::is_a_ge_zero_and_a_lt_b(h, height)) {
+ for (int64_t w = wstart; w < wend; w += dilation_w) {
+ if (math::is_a_ge_zero_and_a_lt_b(w, width)) {
+ for (int64_t d = dstart; d < dend; d += dilation_d) {
+ if (math::is_a_ge_zero_and_a_lt_b(d, depth)) {
+ const int64_t input_index = h * width * depth + w * depth + d;
+ y_d[pool_index] += x_d[input_index];
+ total_elements++;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (total_elements > 0) {
+ if (count_include_pad) {
+ y_d[pool_index] /= ((1 + (hend - hstart - 1) / dilation_h) * (1 + (wend - wstart - 1) / dilation_w) * (1 + (dend - dstart - 1) / dilation_d));
+ } else {
+ y_d[pool_index] /= total_elements;
+ }
+ }
+ }
+ }
+ }
+ }
+};
+
template
struct LpPool1DTask final {
const T* X_data;
diff --git a/onnxruntime/core/providers/cpu/tensor/pad.cc b/onnxruntime/core/providers/cpu/tensor/pad.cc
index c46acfc928..fe5267f207 100644
--- a/onnxruntime/core/providers/cpu/tensor/pad.cc
+++ b/onnxruntime/core/providers/cpu/tensor/pad.cc
@@ -79,12 +79,26 @@ ORT_SPECIFY_OP_KERNEL_ARG_DEFAULT_TYPES(
uint8_t,
bool);
+ORT_SPECIFY_OP_KERNEL_ARG_DEFAULT_TYPES(
+ kCpuExecutionProvider, kOnnxDomain, Pad, 19, Input, 0,
+ float,
+ double,
+ int32_t,
+ int64_t,
+ uint32_t,
+ uint64_t,
+ int8_t,
+ uint8_t,
+ bool);
+
ORT_SPECIFY_OP_KERNEL_ARG_REQUIRED_TYPES(
kCpuExecutionProvider, kOnnxDomain, Pad, 11, Input, 0, int32_t, int64_t);
ORT_SPECIFY_OP_KERNEL_ARG_REQUIRED_TYPES(
kCpuExecutionProvider, kOnnxDomain, Pad, 13, Input, 0, int32_t, int64_t);
ORT_SPECIFY_OP_KERNEL_ARG_REQUIRED_TYPES(
kCpuExecutionProvider, kOnnxDomain, Pad, 18, Input, 0, int32_t, int64_t);
+ORT_SPECIFY_OP_KERNEL_ARG_REQUIRED_TYPES(
+ kCpuExecutionProvider, kOnnxDomain, Pad, 19, Input, 0, int32_t, int64_t);
} // namespace op_kernel_type_control
using EnabledPad2Types = ORT_OP_KERNEL_ARG_ENABLED_TYPE_LIST(
@@ -95,6 +109,8 @@ using EnabledPad13Types = ORT_OP_KERNEL_ARG_ENABLED_TYPE_LIST(
kCpuExecutionProvider, kOnnxDomain, Pad, 13, Input, 0);
using EnabledPad18Types = ORT_OP_KERNEL_ARG_ENABLED_TYPE_LIST(
kCpuExecutionProvider, kOnnxDomain, Pad, 18, Input, 0);
+using EnabledPad19Types = ORT_OP_KERNEL_ARG_ENABLED_TYPE_LIST(
+ kCpuExecutionProvider, kOnnxDomain, Pad, 19, Input, 0);
using AllEnabledPadTypes =
utils::TypeSetUnion<
@@ -131,15 +147,24 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL(
BuildKernelDefConstraintsFromTypeList()),
Pad);
-ONNX_CPU_OPERATOR_KERNEL(
+ONNX_CPU_OPERATOR_VERSIONED_KERNEL(
Pad,
- 18,
+ 18, 18,
KernelDefBuilder()
.TypeConstraint(
"T",
BuildKernelDefConstraintsFromTypeList()),
Pad);
+ONNX_CPU_OPERATOR_KERNEL(
+ Pad,
+ 19,
+ KernelDefBuilder()
+ .TypeConstraint(
+ "T",
+ BuildKernelDefConstraintsFromTypeList()),
+ Pad);
+
using PadsVector = PadBase::PadsVector;
// This is the general padding method to n-dimensionally do edge or reflection padding (based on the inputDelta values)
@@ -426,6 +451,7 @@ static Status PadImpl(OpKernelContext* ctx,
break;
case Mode::Reflect:
+ case Mode::Wrap:
// Loop over the output tensor, writing out padding between the blocks of copied data
// On loop entry, 'pad' is already set to the first continuous block of padding, and
// after every pass through the inner loop it gets set to the next continuous pad size.
@@ -438,12 +464,46 @@ static Status PadImpl(OpKernelContext* ctx,
int64_t prePad = reshaped_pad[inner_axis];
int64_t postPad = reshaped_pad[inner_axis + new_dims_count];
if (inner_no_pad_size == 1) {
- PadInnermostAxis(axisStart - prePad, axisStart + prePad, -1 /* inputDelta */, onnxruntime::narrow(prePad));
- PadInnermostAxis(output, output - 2, -1 /* inputDelta */, onnxruntime::narrow(postPad));
+ if (mode == Mode::Reflect) {
+ PadInnermostAxis(axisStart - prePad, axisStart + prePad, -1 /* inputDelta */, onnxruntime::narrow(prePad));
+ PadInnermostAxis(output, output - 2, -1 /* inputDelta */, onnxruntime::narrow(postPad));
+ } else {
+ PadInnermostAxis(axisStart - prePad, output - prePad, 1 /* inputDelta */, onnxruntime::narrow(prePad));
+ PadInnermostAxis(output, axisStart, 1 /* inputDelta */, onnxruntime::narrow(postPad));
+ }
} else {
// When inner_most axis(es) do not need pad, Above PadInnermostAxis() do not fit for Reflect mode.
- PadAxis(axisStart - prePad, axisStart + prePad, 1, -ptrdiff_t(inner_no_pad_size * 2), inner_no_pad_size, onnxruntime::narrow(pads[inner_axis]));
- PadAxis(output, output - 2 * inner_no_pad_size, 1, -ptrdiff_t(inner_no_pad_size * 2), inner_no_pad_size, onnxruntime::narrow(pads[inner_axis + data_rank]));
+ if (mode == Mode::Reflect) {
+ PadAxis(
+ axisStart - prePad,
+ axisStart + prePad,
+ 1,
+ -ptrdiff_t(inner_no_pad_size * 2),
+ inner_no_pad_size,
+ onnxruntime::narrow(pads[inner_axis]));
+ PadAxis(
+ output,
+ output - 2 * inner_no_pad_size,
+ 1,
+ -ptrdiff_t(inner_no_pad_size * 2),
+ inner_no_pad_size,
+ onnxruntime::narrow(pads[inner_axis + data_rank]));
+ } else {
+ PadAxis(
+ axisStart - prePad,
+ output - pads[inner_axis] * inner_no_pad_size,
+ 1,
+ 0,
+ inner_no_pad_size,
+ onnxruntime::narrow(pads[inner_axis]));
+ PadAxis(
+ output,
+ axisStart,
+ 1,
+ 0,
+ inner_no_pad_size,
+ onnxruntime::narrow(pads[inner_axis + data_rank]));
+ }
}
output += postPad;
alignSkip = onnxruntime::narrow(prePad);
@@ -454,9 +514,37 @@ static Status PadImpl(OpKernelContext* ctx,
T* axisStart = output - inner_pitch * input_extents[input_counters.Axis()];
int64_t prePad = reshaped_pad[input_counters.Axis()];
int64_t postPad = reshaped_pad[input_counters.Axis() + new_dims_count];
- PadAxis(axisStart - prePad * inner_pitch, axisStart + prePad * inner_pitch, 1, -inner_pitch * 2,
- inner_pitch, onnxruntime::narrow(prePad));
- PadAxis(output, output - 2 * inner_pitch, 1, -inner_pitch * 2, inner_pitch, onnxruntime::narrow(postPad));
+ if (mode == Mode::Reflect) {
+ PadAxis(
+ axisStart - prePad * inner_pitch,
+ axisStart + prePad * inner_pitch,
+ 1,
+ -inner_pitch * 2,
+ inner_pitch,
+ onnxruntime::narrow(prePad));
+ PadAxis(
+ output,
+ output - 2 * inner_pitch,
+ 1,
+ -inner_pitch * 2,
+ inner_pitch,
+ onnxruntime::narrow(postPad));
+ } else {
+ PadAxis(
+ axisStart - prePad * inner_pitch,
+ output - prePad * inner_pitch,
+ 1,
+ 0,
+ inner_pitch,
+ onnxruntime::narrow(prePad));
+ PadAxis(
+ output,
+ axisStart,
+ 1,
+ 0,
+ inner_pitch,
+ onnxruntime::narrow(postPad));
+ }
output += inner_pitch * postPad;
alignSkip += inner_pitch * SafeInt(prePad);
}
diff --git a/onnxruntime/core/providers/cpu/tensor/padbase.h b/onnxruntime/core/providers/cpu/tensor/padbase.h
index 5600b2bc1e..d869ed1a6d 100644
--- a/onnxruntime/core/providers/cpu/tensor/padbase.h
+++ b/onnxruntime/core/providers/cpu/tensor/padbase.h
@@ -10,7 +10,8 @@ namespace onnxruntime {
enum class Mode : int {
Constant = 0,
Reflect,
- Edge
+ Edge,
+ Wrap
};
class PadBase {
@@ -32,6 +33,8 @@ class PadBase {
mode_ = Mode::Reflect;
else if (mode == "edge")
mode_ = Mode::Edge;
+ else if (mode == "wrap")
+ mode_ = Mode::Wrap;
else
ORT_THROW("Invalid 'mode' attribute value");
}
diff --git a/onnxruntime/test/providers/cpu/nn/pool_op_test.cc b/onnxruntime/test/providers/cpu/nn/pool_op_test.cc
index 963187f990..10476ada2f 100644
--- a/onnxruntime/test/providers/cpu/nn/pool_op_test.cc
+++ b/onnxruntime/test/providers/cpu/nn/pool_op_test.cc
@@ -938,6 +938,35 @@ TEST(PoolTest, AveragePool_10_ceil1_2d) {
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kAclExecutionProvider});
}
+TEST(PoolTest, AveragePool_19_dilation_2d) {
+ // TODO: Unskip when fixed #41968513
+ if (DefaultDmlExecutionProvider().get() != nullptr) {
+ GTEST_SKIP() << "Skipping because of the following error: MLOperatorAuthorImpl.cpp(2100): The parameter is incorrect.";
+ }
+
+ OpTester test("AveragePool", 19);
+
+ test.AddAttribute("auto_pad", "");
+ test.AddAttribute("strides", std::vector{1, 1});
+ test.AddAttribute("dilations", std::vector{2, 2});
+ test.AddAttribute("pads", vector{0, 0, 0, 0});
+ test.AddAttribute("kernel_shape", vector{2, 2});
+ test.AddAttribute("ceil_mode", (int64_t)1);
+
+ std::vector x_vals = {
+ 1, 3, 2, 4,
+ 5, 7, 6, 8,
+ 9, 11, 10, 12,
+ 13, 15, 14, 16};
+ std::vector x_dims = {1, 1, 4, 4};
+ std::vector expected_dims = {1, 1, 2, 2};
+ std::vector expected_vals = {5.5f, 7.5f, 9.5f, 11.5f};
+
+ test.AddInput("X", x_dims, x_vals);
+ test.AddOutput("Y", expected_dims, expected_vals);
+ test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kAclExecutionProvider, kOpenVINOExecutionProvider});
+}
+
TEST(PoolTest, GlobalAveragePool) {
OpTester test("GlobalAveragePool");
diff --git a/onnxruntime/test/providers/cpu/tensor/pad_test.cc b/onnxruntime/test/providers/cpu/tensor/pad_test.cc
index cc067fcaad..9b6c3f1b36 100644
--- a/onnxruntime/test/providers/cpu/tensor/pad_test.cc
+++ b/onnxruntime/test/providers/cpu/tensor/pad_test.cc
@@ -173,6 +173,19 @@ TYPED_TEST(PadOpTest, Pad_Reflect_1D) {
"reflect");
}
+TYPED_TEST(PadOpTest, Pad_Wrap_1D) {
+ using T = TypeParam;
+ RunOnnxOpsetTypedTest({3, 2},
+ {T(1), T(2), T(3), T(4), T(5), T(6)},
+ {0, 1, 0, 1},
+ false,
+ T(0),
+ false,
+ {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)},
+ "wrap");
+}
+
TYPED_TEST(PadOpTest, Pad_Edge_1D) {
using T = TypeParam;
RunAllOpsetAllDomainPadTests({3, 2},
@@ -363,6 +376,27 @@ TYPED_TEST(PadOpTest, Pad_Reflect_2D) {
"reflect");
}
+TYPED_TEST(PadOpTest, Pad_Wrap_2D) {
+ using T = TypeParam;
+ RunOnnxOpsetTypedTest({3, 3},
+ {T(11), T(21), T(31),
+ T(12), T(22), T(32),
+ T(13), T(23), T(33)},
+ {2, 2, 2, 2},
+ false,
+ T(0),
+ false,
+ {7, 7},
+ {T(22), T(32), T(12), T(22), T(32), T(12), T(22),
+ T(23), T(33), T(13), T(23), T(33), T(13), T(23),
+ T(21), T(31), T(11), T(21), T(31), T(11), T(21),
+ T(22), T(32), T(12), T(22), T(32), T(12), T(22),
+ T(23), T(33), T(13), T(23), T(33), T(13), T(23),
+ T(21), T(31), T(11), T(21), T(31), T(11), T(21),
+ T(22), T(32), T(12), T(22), T(32), T(12), T(22)},
+ "wrap");
+}
+
TYPED_TEST(PadOpTest, Pad_Constant_3D_Inner_No_Padding) {
using T = TypeParam;
RunAllOpsetAllDomainPadTests({3, 2, 5},
@@ -540,6 +574,99 @@ TYPED_TEST(PadOpTest, Pad_Reflect_3D_Inner_No_Padding) {
"reflect");
}
+TYPED_TEST(PadOpTest, Pad_wrap_3D_Inner_No_Padding) {
+ using T = TypeParam;
+ RunOnnxOpsetTypedTest({3, 2, 5},
+ {T(1), T(2), T(3), T(4), T(5),
+ T(6), T(7), T(8), T(9), T(10),
+ T(11), T(12), T(13), T(14), T(15),
+ T(16), T(17), T(18), T(19), T(20),
+ T(21), T(22), T(23), T(24), T(25),
+ T(26), T(27), T(28), T(29), T(30)},
+ {1, 1, 0, 1, 1, 0},
+ false,
+ T(0),
+ false,
+ {5, 4, 5},
+ {T(26), T(27), T(28), T(29), T(30),
+ T(21), T(22), T(23), T(24), T(25),
+ T(26), T(27), T(28), T(29), T(30),
+ T(21), T(22), T(23), T(24), T(25),
+
+ T(6), T(7), T(8), T(9), T(10),
+ T(1), T(2), T(3), T(4), T(5),
+ T(6), T(7), T(8), T(9), T(10),
+ T(1), T(2), T(3), T(4), T(5),
+
+ T(16), T(17), T(18), T(19), T(20),
+ T(11), T(12), T(13), T(14), T(15),
+ T(16), T(17), T(18), T(19), T(20),
+ T(11), T(12), T(13), T(14), T(15),
+
+ T(26), T(27), T(28), T(29), T(30),
+ T(21), T(22), T(23), T(24), T(25),
+ T(26), T(27), T(28), T(29), T(30),
+ T(21), T(22), T(23), T(24), T(25),
+
+ T(6), T(7), T(8), T(9), T(10),
+ T(1), T(2), T(3), T(4), T(5),
+ T(6), T(7), T(8), T(9), T(10),
+ T(1), T(2), T(3), T(4), T(5)},
+ "wrap");
+}
+
+TYPED_TEST(PadOpTest, Pad_wrap_3D_Inner_No_Padding2) {
+ using T = TypeParam;
+
+ RunOnnxOpsetTypedTest({3, 2, 5},
+ {T(1), T(2), T(3), T(4), T(5),
+ T(6), T(7), T(8), T(9), T(10),
+ T(11), T(12), T(13), T(14), T(15),
+ T(16), T(17), T(18), T(19), T(20),
+ T(21), T(22), T(23), T(24), T(25),
+ T(26), T(27), T(28), T(29), T(30)},
+ {1, 2, 0, 1, 2, 0},
+ false,
+ T(0),
+ false,
+ {5, 6, 5},
+ {T(21), T(22), T(23), T(24), T(25),
+ T(26), T(27), T(28), T(29), T(30),
+ T(21), T(22), T(23), T(24), T(25),
+ T(26), T(27), T(28), T(29), T(30),
+ T(21), T(22), T(23), T(24), T(25),
+ T(26), T(27), T(28), T(29), T(30),
+
+ T(1), T(2), T(3), T(4), T(5),
+ T(6), T(7), T(8), T(9), T(10),
+ T(1), T(2), T(3), T(4), T(5),
+ T(6), T(7), T(8), T(9), T(10),
+ T(1), T(2), T(3), T(4), T(5),
+ T(6), T(7), T(8), T(9), T(10),
+
+ T(11), T(12), T(13), T(14), T(15),
+ T(16), T(17), T(18), T(19), T(20),
+ T(11), T(12), T(13), T(14), T(15),
+ T(16), T(17), T(18), T(19), T(20),
+ T(11), T(12), T(13), T(14), T(15),
+ T(16), T(17), T(18), T(19), T(20),
+
+ T(21), T(22), T(23), T(24), T(25),
+ T(26), T(27), T(28), T(29), T(30),
+ T(21), T(22), T(23), T(24), T(25),
+ T(26), T(27), T(28), T(29), T(30),
+ T(21), T(22), T(23), T(24), T(25),
+ T(26), T(27), T(28), T(29), T(30),
+
+ T(1), T(2), T(3), T(4), T(5),
+ T(6), T(7), T(8), T(9), T(10),
+ T(1), T(2), T(3), T(4), T(5),
+ T(6), T(7), T(8), T(9), T(10),
+ T(1), T(2), T(3), T(4), T(5),
+ T(6), T(7), T(8), T(9), T(10)},
+ "wrap");
+}
+
TYPED_TEST(PadOpTest, Pad_Reflect_3D_Last_Pad_Slice_Inner_No_Padding) {
using T = TypeParam;
RunAllOpsetAllDomainPadTests({2, 3, 5},