mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-07-30 20:18:08 +00:00
extract pooling attributes into a separate class (#1906)
Refactor cpu provider's pool ops by extracting pooling attributes into a separate helper class PoolAttributes. With this change, other providers such as Nuphar can re-use the same routines for processing pooling attributes. This refactorying doesn't have any functional changes.
This commit is contained in:
parent
0317e825f1
commit
e769617f75
8 changed files with 253 additions and 226 deletions
|
|
@ -29,10 +29,10 @@ class MaxpoolWithMask : public OpKernel, public PoolBase {
|
|||
//TODO: fix this checker later
|
||||
//ONNXRUNTIME_RETURN_IF_NOT((x_shape[2] == m_shape[2]) && (x_shape[3] == m_shape[3]), " Input shape and mask shape mismatch: ", x_shape, " vs ", m_shape);
|
||||
|
||||
std::vector<int64_t> pads = pads_;
|
||||
std::vector<int64_t> kernel_shape = kernel_shape_;
|
||||
std::vector<int64_t> pads = pool_attrs_.pads;
|
||||
std::vector<int64_t> kernel_shape = pool_attrs_.kernel_shape;
|
||||
|
||||
std::vector<int64_t> output_dims = PoolBase::SetOutputSize(x_shape, x_shape[1], &pads, dilations_, ceil_mode_);
|
||||
std::vector<int64_t> output_dims = pool_attrs_.SetOutputSize(x_shape, x_shape[1], &pads);
|
||||
Tensor* Y = context->Output(0, TensorShape(output_dims));
|
||||
|
||||
const float* X_data = X->template Data<float>();
|
||||
|
|
|
|||
|
|
@ -171,17 +171,17 @@ Status NchwcPoolBase::NchwcPool(OpKernelContext* context, MLAS_POOLING_KIND kind
|
|||
ORT_ENFORCE((X_shape[1] % MlasNchwcGetBlockSize()) == 0);
|
||||
|
||||
|
||||
std::vector<int64_t> pads = pads_;
|
||||
std::vector<int64_t> output_dims = PoolBase::SetOutputSize(X_shape, X_shape[1], &pads, dilations_, ceil_mode_);
|
||||
std::vector<int64_t> pads = pool_attrs_.pads;
|
||||
std::vector<int64_t> output_dims = pool_attrs_.SetOutputSize(X_shape, X_shape[1], &pads);
|
||||
auto* Y = context->Output(0, output_dims);
|
||||
|
||||
MlasNchwcPool(kind,
|
||||
2,
|
||||
X_shape.GetDims().data(),
|
||||
global_pooling_ ? nullptr : kernel_shape_.data(),
|
||||
global_pooling_ ? nullptr : dilations_.data(),
|
||||
global_pooling_ ? nullptr : pads.data(),
|
||||
global_pooling_ ? nullptr : strides_.data(),
|
||||
pool_attrs_.global_pooling ? nullptr : pool_attrs_.kernel_shape.data(),
|
||||
pool_attrs_.global_pooling ? nullptr : pool_attrs_.dilations.data(),
|
||||
pool_attrs_.global_pooling ? nullptr : pads.data(),
|
||||
pool_attrs_.global_pooling ? nullptr : pool_attrs_.strides.data(),
|
||||
output_dims.data(),
|
||||
X->template Data<float>(),
|
||||
Y->template MutableData<float>(),
|
||||
|
|
@ -195,7 +195,8 @@ Status NchwcMaxPool::Compute(OpKernelContext* context) const {
|
|||
}
|
||||
|
||||
Status NchwcAveragePool::Compute(OpKernelContext* context) const {
|
||||
return NchwcPoolBase::NchwcPool(context, count_include_pad_ ? MlasAveragePoolingIncludePad : MlasAveragePoolingExcludePad);
|
||||
return NchwcPoolBase::NchwcPool(context, pool_attrs_.count_include_pad ? MlasAveragePoolingIncludePad :
|
||||
MlasAveragePoolingExcludePad);
|
||||
}
|
||||
|
||||
} // namespace contrib
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ class NchwcConv : public OpKernel, public ConvBase {
|
|||
class NchwcPoolBase : public PoolBase {
|
||||
public:
|
||||
NchwcPoolBase(const OpKernelInfo& info) : PoolBase(info) {
|
||||
if (!global_pooling_)
|
||||
ORT_ENFORCE(kernel_shape_.size() == 2, "kernel_shape num_dims is not compatible with X num_dims.");
|
||||
if (!pool_attrs_.global_pooling)
|
||||
ORT_ENFORCE(pool_attrs_.kernel_shape.size() == 2, "kernel_shape num_dims is not compatible with X num_dims.");
|
||||
}
|
||||
|
||||
Status NchwcPool(OpKernelContext* context, MLAS_POOLING_KIND kind) const;
|
||||
|
|
|
|||
|
|
@ -15,16 +15,16 @@ Status Pool<T, PoolType>::Compute(OpKernelContext* context) const {
|
|||
|
||||
ORT_RETURN_IF_NOT(x_shape.NumDimensions() >= 3, "Input dimension cannot be less than 3.");
|
||||
|
||||
std::vector<int64_t> pads = pads_;
|
||||
std::vector<int64_t> kernel_shape = kernel_shape_;
|
||||
std::vector<int64_t> pads = pool_attrs_.pads;
|
||||
std::vector<int64_t> kernel_shape = pool_attrs_.kernel_shape;
|
||||
|
||||
if (global_pooling_) {
|
||||
if (pool_attrs_.global_pooling) {
|
||||
const auto& input_dims = x_shape.GetDims();
|
||||
kernel_shape.assign(input_dims.begin() + 2, input_dims.end());
|
||||
pads.assign(kernel_shape.size(), 0);
|
||||
}
|
||||
|
||||
std::vector<int64_t> output_dims = PoolBase::SetOutputSize(x_shape, x_shape[1], &pads, dilations_, ceil_mode_);
|
||||
std::vector<int64_t> output_dims = pool_attrs_.SetOutputSize(x_shape, x_shape[1], &pads);
|
||||
Tensor* Y = context->Output(0, output_dims);
|
||||
|
||||
const auto* X_data = X->template Data<float>();
|
||||
|
|
@ -60,7 +60,7 @@ Status Pool<T, PoolType>::Compute(OpKernelContext* context) const {
|
|||
for (int64_t h = hstart; h < hend; ++h) {
|
||||
PoolType::Process(x_d[h], Yh, pool_context_);
|
||||
}
|
||||
if (count_include_pad_) {
|
||||
if (pool_attrs_.count_include_pad) {
|
||||
PoolType::Finalize(kernel_shape[0], Yh, pool_context_);
|
||||
} else {
|
||||
PoolType::Finalize(hend - hstart, Yh, pool_context_);
|
||||
|
|
@ -100,7 +100,7 @@ Status Pool<T, PoolType>::Compute(OpKernelContext* context) const {
|
|||
PoolType::Process(x_d[input_index], Yh, pool_context_);
|
||||
}
|
||||
}
|
||||
if (count_include_pad_) {
|
||||
if (pool_attrs_.count_include_pad) {
|
||||
PoolType::Finalize(kernel_shape[0] * kernel_shape[1], Yh, pool_context_);
|
||||
} else {
|
||||
PoolType::Finalize((hend - hstart) * (wend - wstart), Yh, pool_context_);
|
||||
|
|
@ -147,7 +147,7 @@ Status Pool<T, PoolType>::Compute(OpKernelContext* context) const {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (count_include_pad_) {
|
||||
if (pool_attrs_.count_include_pad) {
|
||||
PoolType::Finalize(kernel_shape[0] * kernel_shape[1] * kernel_shape[2], Yh, pool_context_);
|
||||
} else {
|
||||
PoolType::Finalize(
|
||||
|
|
@ -179,12 +179,13 @@ Status PoolBase::Compute(OpKernelContext* context, MLAS_POOLING_KIND kind) const
|
|||
if (pooling_dims > 3) {
|
||||
return Status(ONNXRUNTIME, INVALID_ARGUMENT, "Unsupported pooling size.");
|
||||
}
|
||||
if (!global_pooling_) {
|
||||
ORT_RETURN_IF_NOT(pooling_dims == kernel_shape_.size(), "kernel_shape num_dims is not compatible with X num_dims.");
|
||||
if (!pool_attrs_.global_pooling) {
|
||||
ORT_RETURN_IF_NOT(pooling_dims == pool_attrs_.kernel_shape.size(),
|
||||
"kernel_shape num_dims is not compatible with X num_dims.");
|
||||
}
|
||||
|
||||
std::vector<int64_t> pads = pads_;
|
||||
std::vector<int64_t> output_dims = PoolBase::SetOutputSize(x_shape, x_shape[1], &pads, dilations_, ceil_mode_);
|
||||
std::vector<int64_t> pads = pool_attrs_.pads;
|
||||
std::vector<int64_t> output_dims = pool_attrs_.SetOutputSize(x_shape, x_shape[1], &pads);
|
||||
Tensor* Y = context->Output(0, output_dims);
|
||||
|
||||
// Get access to the internal threadpool
|
||||
|
|
@ -195,9 +196,9 @@ Status PoolBase::Compute(OpKernelContext* context, MLAS_POOLING_KIND kind) const
|
|||
MlasPool(kind,
|
||||
pooling_dims,
|
||||
X->Shape().GetDims().data(),
|
||||
global_pooling_ ? nullptr : kernel_shape_.data(),
|
||||
global_pooling_ ? nullptr : pads.data(),
|
||||
global_pooling_ ? nullptr : strides_.data(),
|
||||
pool_attrs_.global_pooling ? nullptr : pool_attrs_.kernel_shape.data(),
|
||||
pool_attrs_.global_pooling ? nullptr : pads.data(),
|
||||
pool_attrs_.global_pooling ? nullptr : pool_attrs_.strides.data(),
|
||||
output_dims.data(),
|
||||
X->template Data<float>(),
|
||||
Y->template MutableData<float>(),
|
||||
|
|
@ -213,7 +214,8 @@ Status Pool<float, MaxPool<1 /*VERSION*/>>::Compute(OpKernelContext* context) co
|
|||
|
||||
template <>
|
||||
Status Pool<float, AveragePool>::Compute(OpKernelContext* context) const {
|
||||
return PoolBase::Compute(context, count_include_pad_ ? MlasAveragePoolingIncludePad : MlasAveragePoolingExcludePad);
|
||||
return PoolBase::Compute(context, pool_attrs_.count_include_pad ? MlasAveragePoolingIncludePad
|
||||
: MlasAveragePoolingExcludePad);
|
||||
}
|
||||
|
||||
template <>
|
||||
|
|
@ -222,7 +224,7 @@ Status Pool<float, MaxPool<8 /*VERSION*/>>::Compute(OpKernelContext* context) co
|
|||
// and also if dilation is not required
|
||||
|
||||
bool need_dilation = false;
|
||||
for (auto n : dilations_) {
|
||||
for (auto n : pool_attrs_.dilations) {
|
||||
need_dilation |= n > 1;
|
||||
}
|
||||
|
||||
|
|
@ -235,10 +237,10 @@ Status Pool<float, MaxPool<8 /*VERSION*/>>::Compute(OpKernelContext* context) co
|
|||
|
||||
ORT_RETURN_IF_NOT(x_shape.NumDimensions() >= 3, "Input dimension cannot be less than 3.");
|
||||
|
||||
std::vector<int64_t> pads = pads_;
|
||||
std::vector<int64_t> kernel_shape = kernel_shape_;
|
||||
std::vector<int64_t> pads = pool_attrs_.pads;
|
||||
std::vector<int64_t> kernel_shape = pool_attrs_.kernel_shape;
|
||||
|
||||
std::vector<int64_t> output_dims = PoolBase::SetOutputSize(x_shape, x_shape[1], &pads, dilations_, ceil_mode_);
|
||||
std::vector<int64_t> output_dims = pool_attrs_.SetOutputSize(x_shape, x_shape[1], &pads);
|
||||
Tensor* Y = context->Output(0, output_dims);
|
||||
Tensor* I = context->Output(1, output_dims);
|
||||
|
||||
|
|
@ -260,7 +262,7 @@ Status Pool<float, MaxPool<8 /*VERSION*/>>::Compute(OpKernelContext* context) co
|
|||
int64_t x_step = height;
|
||||
int64_t y_step = pooled_height;
|
||||
const int64_t total_channels = x_shape[0] * channels;
|
||||
const int64_t dilation_h = dilations_[0];
|
||||
const int64_t dilation_h = pool_attrs_.dilations[0];
|
||||
|
||||
#ifdef USE_OPENMP
|
||||
#pragma omp parallel for
|
||||
|
|
@ -294,8 +296,8 @@ Status Pool<float, MaxPool<8 /*VERSION*/>>::Compute(OpKernelContext* context) co
|
|||
int64_t x_step = height * width;
|
||||
int64_t y_step = pooled_height * pooled_width;
|
||||
const int64_t total_channels = x_shape[0] * channels;
|
||||
const int64_t dilation_h = dilations_[0];
|
||||
const int64_t dilation_w = dilations_[1];
|
||||
const int64_t dilation_h = pool_attrs_.dilations[0];
|
||||
const int64_t dilation_w = pool_attrs_.dilations[1];
|
||||
|
||||
#ifdef USE_OPENMP
|
||||
#pragma omp parallel for
|
||||
|
|
@ -331,8 +333,8 @@ Status Pool<float, MaxPool<8 /*VERSION*/>>::Compute(OpKernelContext* context) co
|
|||
}
|
||||
y_d[pool_index] = Yh;
|
||||
if (i_d != nullptr)
|
||||
i_d[pool_index] = storage_order_ == 0 ? c * x_step + h_index * width + w_index
|
||||
: c * x_step + h_index + w_index * height;
|
||||
i_d[pool_index] = pool_attrs_.storage_order == 0 ? c * x_step + h_index * width + w_index
|
||||
: c * x_step + h_index + w_index * height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -343,9 +345,9 @@ Status Pool<float, MaxPool<8 /*VERSION*/>>::Compute(OpKernelContext* context) co
|
|||
int64_t x_step = height * width * depth;
|
||||
int64_t y_step = pooled_height * pooled_width * pooled_depth;
|
||||
const int64_t total_channels = x_shape[0] * channels;
|
||||
const int64_t dilation_h = dilations_[0];
|
||||
const int64_t dilation_w = dilations_[1];
|
||||
const int64_t dilation_d = dilations_[2];
|
||||
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];
|
||||
|
||||
#ifdef USE_OPENMP
|
||||
#pragma omp parallel for
|
||||
|
|
@ -391,8 +393,8 @@ Status Pool<float, MaxPool<8 /*VERSION*/>>::Compute(OpKernelContext* context) co
|
|||
}
|
||||
y_d[pool_index] = Yh;
|
||||
if (i_d != nullptr)
|
||||
i_d[pool_index] = storage_order_ == 0 ? c * x_step + h_index * width * depth + w_index * depth + d_index
|
||||
: c * x_step + h_index + w_index * height + d_index * height * width;
|
||||
i_d[pool_index] = pool_attrs_.storage_order == 0 ? c * x_step + h_index * width * depth + w_index * depth + d_index
|
||||
: c * x_step + h_index + w_index * height + d_index * height * width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
176
onnxruntime/core/providers/cpu/nn/pool_attributes.h
Normal file
176
onnxruntime/core/providers/cpu/nn/pool_attributes.h
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/common/common.h"
|
||||
#include "core/framework/op_node_proto_helper.h"
|
||||
#include "core/framework/tensor_shape.h"
|
||||
#include "core/providers/cpu/nn/autopad_type.h"
|
||||
|
||||
namespace onnxruntime {
|
||||
|
||||
// A helper struct holding attributes for Pool-family ops
|
||||
struct PoolAttributes {
|
||||
static bool IsGlobalPooling(const std::string& op_name) {
|
||||
return op_name == "GlobalAveragePool" || op_name == "GlobalMaxPool" || op_name == "GlobalLpPool";
|
||||
}
|
||||
|
||||
PoolAttributes(const OpNodeProtoHelper<ProtoHelperNodeContext> &info,
|
||||
const std::string& op_name, int start_ver_p)
|
||||
: global_pooling(IsGlobalPooling(op_name)), start_version(start_ver_p) {
|
||||
if (global_pooling) {
|
||||
return;
|
||||
}
|
||||
|
||||
ORT_ENFORCE(info.GetAttrs<int64_t>("kernel_shape", kernel_shape).IsOK(),
|
||||
"No kernel shape is set.");
|
||||
|
||||
std::string auto_padding;
|
||||
ORT_ENFORCE(info.GetAttr<std::string>("auto_pad", &auto_padding).IsOK());
|
||||
auto_pad = StringToAutoPadType(auto_padding);
|
||||
|
||||
if (!info.GetAttrs<int64_t>("pads", pads).IsOK() || pads.empty()) {
|
||||
pads.resize(kernel_shape.size() * 2, 0);
|
||||
}
|
||||
|
||||
if (!info.GetAttrs<int64_t>("strides", strides).IsOK() || strides.empty()) {
|
||||
strides.resize(kernel_shape.size(), 1);
|
||||
}
|
||||
|
||||
if (!info.GetAttr<int64_t>("ceil_mode", &ceil_mode).IsOK()) {
|
||||
ceil_mode = 0;
|
||||
}
|
||||
|
||||
default_dilations = false;
|
||||
if (!info.GetAttrs<int64_t>("dilations", dilations).IsOK() || dilations.empty()) {
|
||||
dilations.resize(kernel_shape.size(), 1);
|
||||
default_dilations = true;
|
||||
} else {
|
||||
default_dilations = std::all_of(dilations.begin(), dilations.end(), [](int64_t i) { return i == 1; });
|
||||
}
|
||||
|
||||
if (op_name == "AveragePool") {
|
||||
int64_t temp;
|
||||
ORT_ENFORCE(info.GetAttr<int64_t>("count_include_pad", &temp).IsOK());
|
||||
count_include_pad = (temp != 0);
|
||||
}
|
||||
|
||||
if (op_name == "MaxPool") {
|
||||
if (start_version == 8) {
|
||||
storage_order = info.GetAttrOrDefault<int64_t>("storage_order", 0 /*default_value*/);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t dim = 0; dim < kernel_shape.size(); ++dim) {
|
||||
ORT_ENFORCE(kernel_shape[dim] > 0);
|
||||
ORT_ENFORCE(pads[dim] < kernel_shape[dim] && pads[dim + kernel_shape.size()] < kernel_shape[dim],
|
||||
"Pad should be smaller than kernel.");
|
||||
}
|
||||
|
||||
ORT_ENFORCE(strides.size() == kernel_shape.size());
|
||||
ORT_ENFORCE(dilations.size() == kernel_shape.size(),
|
||||
"Dilations dimensions should match kernel shape");
|
||||
}
|
||||
|
||||
const bool global_pooling;
|
||||
const int start_version;
|
||||
|
||||
bool count_include_pad{};
|
||||
int64_t storage_order{0}; // MaxPool_8 only. 0 is row major, and 1 is column major. Default is 0.
|
||||
int64_t ceil_mode{0}; // Introduced in MaxPool_10
|
||||
std::vector<int64_t> kernel_shape;
|
||||
std::vector<int64_t> pads;
|
||||
std::vector<int64_t> strides;
|
||||
std::vector<int64_t> dilations; // Introduced in MaxPool_10
|
||||
// default_dilations is true if dilations is not set or all dilations are 1
|
||||
bool default_dilations;
|
||||
AutoPadType auto_pad;
|
||||
|
||||
std::vector<int64_t> SetOutputSize(const TensorShape& input_shape,
|
||||
int64_t output_channel,
|
||||
std::vector<int64_t>* actual_pads) const {
|
||||
ORT_ENFORCE(input_shape.Size() > 0);
|
||||
std::vector<int64_t> output_dims;
|
||||
int64_t N = input_shape[0];
|
||||
InferOutputSize(input_shape.GetDims(), &output_dims, actual_pads);
|
||||
|
||||
output_dims.insert(output_dims.begin(), {N, output_channel});
|
||||
|
||||
return output_dims;
|
||||
}
|
||||
|
||||
void InferOutputSize(const std::vector<int64_t>& input_dims,
|
||||
std::vector<int64_t>* output_dims,
|
||||
std::vector<int64_t>* actual_pads) const {
|
||||
ORT_ENFORCE(input_dims.size() >= 2);
|
||||
if (global_pooling) {
|
||||
output_dims->assign(input_dims.size() - 2, 1);
|
||||
} else {
|
||||
for (size_t dim = 0; dim < input_dims.size() - 2; ++dim) {
|
||||
int64_t dim_size = 0;
|
||||
ComputeSizePadDilations(static_cast<int>(input_dims[dim + 2]),
|
||||
strides[dim],
|
||||
kernel_shape[dim],
|
||||
&actual_pads->at(dim),
|
||||
&actual_pads->at(input_dims.size() + dim - 2),
|
||||
dilations[dim],
|
||||
&dim_size);
|
||||
output_dims->push_back(dim_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ComputeSizePadDilations(const int64_t in_size,
|
||||
const int64_t stride,
|
||||
const int64_t kernel,
|
||||
int64_t* pad_head,
|
||||
int64_t* pad_tail,
|
||||
int64_t dilation,
|
||||
int64_t* out_size) const {
|
||||
if (auto_pad != AutoPadType::NOTSET) {
|
||||
switch (auto_pad) {
|
||||
case AutoPadType::VALID:
|
||||
*pad_head = 0;
|
||||
*pad_tail = 0;
|
||||
*out_size = ComputeOutputSize(in_size, stride, kernel, 0, dilation);
|
||||
break;
|
||||
case AutoPadType::SAME_LOWER: {
|
||||
int64_t legacy_target_size = (in_size + stride - 1) / stride;
|
||||
int64_t pad_needed = (legacy_target_size - 1) * stride + kernel - in_size;
|
||||
*pad_head = (pad_needed + 1) / 2;
|
||||
*pad_tail = pad_needed - *pad_head;
|
||||
*out_size = ComputeOutputSize(in_size, stride, kernel, pad_needed, dilation);
|
||||
break;
|
||||
}
|
||||
case AutoPadType::SAME_UPPER: {
|
||||
int64_t legacy_target_size = (in_size + stride - 1) / stride;
|
||||
int64_t pad_needed = (legacy_target_size - 1) * stride + kernel - in_size;
|
||||
*pad_head = pad_needed / 2;
|
||||
*pad_tail = pad_needed - *pad_head;
|
||||
*out_size = ComputeOutputSize(in_size, stride, kernel, pad_needed, dilation);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ORT_THROW("Unsupported AutoPad Type.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*out_size = ComputeOutputSize(in_size, stride, kernel, *pad_head + *pad_tail, dilation);
|
||||
}
|
||||
}
|
||||
|
||||
int64_t ComputeOutputSize(int64_t in_size,
|
||||
int64_t stride,
|
||||
int64_t kernel,
|
||||
int64_t pad_needed,
|
||||
int64_t dilation) const {
|
||||
if (ceil_mode == 0) {
|
||||
return static_cast<int64_t>(static_cast<float>(in_size + pad_needed - dilation * (kernel - 1) - 1) / stride + 1);
|
||||
}
|
||||
return static_cast<int64_t>(
|
||||
std::ceil(static_cast<float>(in_size + pad_needed - dilation * (kernel - 1) - 1) / stride + 1));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace onnxruntime
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
#include <cmath>
|
||||
#include "core/common/common.h"
|
||||
#include "core/framework/op_kernel.h"
|
||||
#include "core/providers/cpu/nn/autopad_type.h"
|
||||
#include "core/providers/cpu/nn/pool_attributes.h"
|
||||
#include "core/util/math.h"
|
||||
#include "core/mlas/inc/mlas.h"
|
||||
|
||||
|
|
@ -100,190 +100,37 @@ class LpPool {
|
|||
|
||||
class PoolBase {
|
||||
private:
|
||||
static bool IsGlobalPooling(const std::string& op_name) {
|
||||
return op_name == "GlobalAveragePool" || op_name == "GlobalMaxPool" || op_name == "GlobalLpPool";
|
||||
static int GetStartVersion(const OpKernelInfo& info) {
|
||||
int start, end;
|
||||
info.GetKernelDef().SinceVersion(&start, &end);
|
||||
return start;
|
||||
}
|
||||
|
||||
protected:
|
||||
PoolBase(const OpKernelInfo& info) : op_name_(info.GetKernelDef().OpName()), global_pooling_(IsGlobalPooling(op_name_)) {
|
||||
int end;
|
||||
info.GetKernelDef().SinceVersion(&start_version_, &end);
|
||||
|
||||
if (!global_pooling_) {
|
||||
ORT_ENFORCE(info.GetAttrs<int64_t>("kernel_shape", kernel_shape_).IsOK(),
|
||||
"No kernel shape is set.");
|
||||
|
||||
std::string auto_padding;
|
||||
ORT_ENFORCE(info.GetAttr<std::string>("auto_pad", &auto_padding).IsOK());
|
||||
auto_pad_ = StringToAutoPadType(auto_padding);
|
||||
|
||||
if (!info.GetAttrs<int64_t>("pads", pads_).IsOK() || pads_.empty()) {
|
||||
pads_.resize(kernel_shape_.size() * 2, 0);
|
||||
}
|
||||
|
||||
if (!info.GetAttrs<int64_t>("strides", strides_).IsOK() || strides_.empty()) {
|
||||
strides_.resize(kernel_shape_.size(), 1);
|
||||
}
|
||||
|
||||
if (!info.GetAttr<int64_t>("ceil_mode", &ceil_mode_).IsOK()) {
|
||||
ceil_mode_ = 0;
|
||||
}
|
||||
|
||||
default_dilations_ = false;
|
||||
if (!info.GetAttrs<int64_t>("dilations", dilations_).IsOK() || dilations_.empty()) {
|
||||
dilations_.resize(kernel_shape_.size(), 1);
|
||||
default_dilations_ = true;
|
||||
} else {
|
||||
default_dilations_ = std::all_of(dilations_.begin(), dilations_.end(), [](int64_t i) { return i == 1; });
|
||||
}
|
||||
|
||||
if (op_name_ == "AveragePool") {
|
||||
int64_t temp;
|
||||
ORT_ENFORCE(info.GetAttr<int64_t>("count_include_pad", &temp).IsOK());
|
||||
count_include_pad_ = (temp != 0);
|
||||
}
|
||||
|
||||
if (op_name_ == "MaxPool") {
|
||||
if (start_version_ == 8) {
|
||||
storage_order_ = info.GetAttrOrDefault<int64_t>("storage_order", 0 /*default_value*/);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t dim = 0; dim < kernel_shape_.size(); ++dim) {
|
||||
ORT_ENFORCE(kernel_shape_[dim] > 0);
|
||||
ORT_ENFORCE(pads_[dim] < kernel_shape_[dim] && pads_[dim + kernel_shape_.size()] < kernel_shape_[dim],
|
||||
"Pad should be smaller than kernel.");
|
||||
}
|
||||
|
||||
ORT_ENFORCE(strides_.size() == kernel_shape_.size());
|
||||
ORT_ENFORCE(dilations_.size() == kernel_shape_.size(),
|
||||
"Dilations dimensions should match kernel shape");
|
||||
}
|
||||
PoolBase(const OpKernelInfo& info)
|
||||
: op_name_(info.GetKernelDef().OpName()),
|
||||
pool_attrs_(info, op_name_, GetStartVersion(info)) {
|
||||
}
|
||||
|
||||
~PoolBase() = default;
|
||||
;
|
||||
|
||||
std::vector<int64_t> SetOutputSize(const TensorShape& input_shape,
|
||||
int64_t output_channel,
|
||||
std::vector<int64_t>* pads,
|
||||
const std::vector<int64_t>& dilations,
|
||||
int64_t ceil_mode) const {
|
||||
ORT_ENFORCE(input_shape.Size() > 0);
|
||||
std::vector<int64_t> output_dims;
|
||||
int64_t N = input_shape[0];
|
||||
InferOutputSize(input_shape.GetDims(), &output_dims, pads, dilations, ceil_mode);
|
||||
|
||||
output_dims.insert(output_dims.begin(), {N, output_channel});
|
||||
|
||||
return output_dims;
|
||||
}
|
||||
|
||||
inline void InferOutputSize(const std::vector<int64_t>& input_dims,
|
||||
std::vector<int64_t>* output_dims,
|
||||
std::vector<int64_t>* pads,
|
||||
const std::vector<int64_t>& dilations,
|
||||
int64_t ceil_mode) const {
|
||||
ORT_ENFORCE(input_dims.size() >= 2);
|
||||
if (global_pooling_) {
|
||||
output_dims->assign(input_dims.size() - 2, 1);
|
||||
} else {
|
||||
for (size_t dim = 0; dim < input_dims.size() - 2; ++dim) {
|
||||
int64_t dim_size = 0;
|
||||
ComputeSizePadDilations(static_cast<int>(input_dims[dim + 2]),
|
||||
strides_[dim],
|
||||
kernel_shape_[dim],
|
||||
&pads->at(dim),
|
||||
&pads->at(input_dims.size() + dim - 2),
|
||||
dilations[dim],
|
||||
ceil_mode,
|
||||
&dim_size);
|
||||
output_dims->push_back(dim_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void ComputeSizePadDilations(const int64_t in_size,
|
||||
const int64_t stride,
|
||||
const int64_t kernel,
|
||||
int64_t* pad_head,
|
||||
int64_t* pad_tail,
|
||||
int64_t dilation,
|
||||
int64_t ceil_mode,
|
||||
int64_t* out_size) const {
|
||||
if (auto_pad_ != AutoPadType::NOTSET) {
|
||||
switch (auto_pad_) {
|
||||
case AutoPadType::VALID:
|
||||
*pad_head = 0;
|
||||
*pad_tail = 0;
|
||||
*out_size = ComputeOutputSize(in_size, stride, kernel, 0, dilation, ceil_mode);
|
||||
break;
|
||||
case AutoPadType::SAME_LOWER: {
|
||||
int64_t legacy_target_size = (in_size + stride - 1) / stride;
|
||||
int64_t pad_needed = (legacy_target_size - 1) * stride + kernel - in_size;
|
||||
*pad_head = (pad_needed + 1) / 2;
|
||||
*pad_tail = pad_needed - *pad_head;
|
||||
*out_size = ComputeOutputSize(in_size, stride, kernel, pad_needed, dilation, ceil_mode);
|
||||
break;
|
||||
}
|
||||
case AutoPadType::SAME_UPPER: {
|
||||
int64_t legacy_target_size = (in_size + stride - 1) / stride;
|
||||
int64_t pad_needed = (legacy_target_size - 1) * stride + kernel - in_size;
|
||||
*pad_head = pad_needed / 2;
|
||||
*pad_tail = pad_needed - *pad_head;
|
||||
*out_size = ComputeOutputSize(in_size, stride, kernel, pad_needed, dilation, ceil_mode);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ORT_THROW("Unsupported AutoPad Type.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*out_size = ComputeOutputSize(in_size, stride, kernel, *pad_head + *pad_tail, dilation, ceil_mode);
|
||||
}
|
||||
}
|
||||
|
||||
inline int64_t ComputeOutputSize(int64_t in_size,
|
||||
int64_t stride,
|
||||
int64_t kernel,
|
||||
int64_t pad_needed,
|
||||
int64_t dilation,
|
||||
int64_t ceil_mode) const {
|
||||
if (ceil_mode == 0) {
|
||||
return static_cast<int64_t>(static_cast<float>(in_size + pad_needed - dilation * (kernel - 1) - 1) / stride + 1);
|
||||
}
|
||||
return static_cast<int64_t>(
|
||||
std::ceil(static_cast<float>(in_size + pad_needed - dilation * (kernel - 1) - 1) / stride + 1));
|
||||
}
|
||||
|
||||
Status Compute(OpKernelContext* context, MLAS_POOLING_KIND kind) const;
|
||||
|
||||
protected:
|
||||
const std::string op_name_;
|
||||
const bool global_pooling_;
|
||||
bool count_include_pad_{};
|
||||
int64_t storage_order_{0}; // MaxPool_8 only. 0 is row major, and 1 is column major. Default is 0.
|
||||
int64_t ceil_mode_{0}; // Introduced in MaxPool_10
|
||||
std::vector<int64_t> kernel_shape_;
|
||||
std::vector<int64_t> pads_;
|
||||
std::vector<int64_t> strides_;
|
||||
std::vector<int64_t> dilations_; // Introduced in MaxPool_10
|
||||
int start_version_;
|
||||
// default_dilations_ is true if dilations_ is not set or all dilations_ are 1
|
||||
bool default_dilations_;
|
||||
|
||||
AutoPadType auto_pad_;
|
||||
PoolAttributes pool_attrs_;
|
||||
|
||||
inline int64_t stride_h() const {
|
||||
return global_pooling_ ? 1 : strides_[0];
|
||||
return pool_attrs_.global_pooling ? 1 : pool_attrs_.strides[0];
|
||||
}
|
||||
|
||||
inline int64_t stride_w() const {
|
||||
return global_pooling_ ? 1 : strides_[1];
|
||||
return pool_attrs_.global_pooling ? 1 : pool_attrs_.strides[1];
|
||||
}
|
||||
|
||||
inline int64_t stride_d() const {
|
||||
return global_pooling_ ? 1 : strides_[2];
|
||||
return pool_attrs_.global_pooling ? 1 : pool_attrs_.strides[2];
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -113,17 +113,17 @@ Status Pool<T, PoolType>::ComputeInternal(OpKernelContext* context) const {
|
|||
return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Input dimension cannot be less than 3.");
|
||||
}
|
||||
|
||||
std::vector<int64_t> kernel_shape = kernel_shape_;
|
||||
std::vector<int64_t> pads = pads_;
|
||||
std::vector<int64_t> strides = strides_;
|
||||
std::vector<int64_t> kernel_shape = pool_attrs_.kernel_shape;
|
||||
std::vector<int64_t> pads = pool_attrs_.pads;
|
||||
std::vector<int64_t> strides = pool_attrs_.strides;
|
||||
|
||||
if (global_pooling_) {
|
||||
if (pool_attrs_.global_pooling) {
|
||||
kernel_shape.assign(x_dims.begin() + 2, x_dims.end());
|
||||
pads.assign(kernel_shape.size(), 0);
|
||||
strides.assign(kernel_shape.size(), 1);
|
||||
}
|
||||
|
||||
std::vector<int64_t> y_dims = PoolBase::SetOutputSize(x_shape, x_shape[1], &pads, dilations_, ceil_mode_);
|
||||
std::vector<int64_t> y_dims = pool_attrs_.SetOutputSize(x_shape, x_shape[1], &pads);
|
||||
Tensor* Y = context->Output(0, TensorShape(y_dims));
|
||||
|
||||
auto x_data = reinterpret_cast<const CudaT*>(X->template Data<T>());
|
||||
|
|
@ -150,7 +150,8 @@ Status Pool<T, PoolType>::ComputeInternal(OpKernelContext* context) const {
|
|||
|
||||
cudnnPoolingMode_t mode = CUDNN_POOLING_MAX;
|
||||
if (PoolType::type == onnxruntime::PoolType::kAveragePool) {
|
||||
mode = count_include_pad_ ? CUDNN_POOLING_AVERAGE_COUNT_INCLUDE_PADDING : CUDNN_POOLING_AVERAGE_COUNT_EXCLUDE_PADDING;
|
||||
mode = pool_attrs_.count_include_pad ? CUDNN_POOLING_AVERAGE_COUNT_INCLUDE_PADDING :
|
||||
CUDNN_POOLING_AVERAGE_COUNT_EXCLUDE_PADDING;
|
||||
}
|
||||
CudnnPoolingDescriptor pooling_desc;
|
||||
ORT_RETURN_IF_ERROR(pooling_desc.Set(mode, kernel_shape, pads, strides));
|
||||
|
|
@ -171,24 +172,24 @@ Status Pool<T, MaxPool<8>>::ComputeInternal(OpKernelContext* context) const {
|
|||
return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Input dimension cannot be less than 3.");
|
||||
}
|
||||
|
||||
std::vector<int64_t> kernel_shape = this->kernel_shape_;
|
||||
std::vector<int64_t> pads = this->pads_;
|
||||
std::vector<int64_t> strides = this->strides_;
|
||||
std::vector<int64_t> kernel_shape = this->pool_attrs_.kernel_shape;
|
||||
std::vector<int64_t> pads = this->pool_attrs_.pads;
|
||||
std::vector<int64_t> strides = this->pool_attrs_.strides;
|
||||
|
||||
if (this->global_pooling_) {
|
||||
if (this->pool_attrs_.global_pooling) {
|
||||
kernel_shape.assign(x_dims.begin() + 2, x_dims.end());
|
||||
pads.assign(kernel_shape.size(), 0);
|
||||
strides.assign(kernel_shape.size(), 1);
|
||||
}
|
||||
|
||||
std::vector<int64_t> y_dims = PoolBase::SetOutputSize(x_shape, x_shape[1], &pads, this->dilations_, this->ceil_mode_);
|
||||
std::vector<int64_t> y_dims = this->pool_attrs_.SetOutputSize(x_shape, x_shape[1], &pads);
|
||||
Tensor* Y = context->Output(0, TensorShape(y_dims));
|
||||
|
||||
auto x_data = reinterpret_cast<const CudaT*>(X->template Data<T>());
|
||||
auto y_data = reinterpret_cast<CudaT*>(Y->template MutableData<T>());
|
||||
|
||||
Tensor* I = context->Output(1, TensorShape(y_dims));
|
||||
if (nullptr != I || !this->default_dilations_) {
|
||||
if (nullptr != I || !this->pool_attrs_.default_dilations) {
|
||||
auto i_data = nullptr == I ? nullptr : I->template MutableData<int64_t>();
|
||||
MaxPoolWithIndex<CudaT>(
|
||||
x_shape,
|
||||
|
|
@ -196,8 +197,8 @@ Status Pool<T, MaxPool<8>>::ComputeInternal(OpKernelContext* context) const {
|
|||
kernel_shape,
|
||||
strides,
|
||||
pads,
|
||||
this->dilations_,
|
||||
this->storage_order_,
|
||||
this->pool_attrs_.dilations,
|
||||
this->pool_attrs_.storage_order,
|
||||
x_data,
|
||||
y_data,
|
||||
i_data);
|
||||
|
|
|
|||
|
|
@ -244,17 +244,17 @@ Status Pool<T, PoolType>::Compute(OpKernelContext* context) const {
|
|||
return onnxruntime::Pool<T, PoolType>::Compute(context);
|
||||
}
|
||||
|
||||
std::vector<int64_t> kernel_shape = this->kernel_shape_;
|
||||
std::vector<int64_t> pads = this->pads_;
|
||||
std::vector<int64_t> strides = this->strides_;
|
||||
std::vector<int64_t> kernel_shape = this->pool_attrs_.kernel_shape;
|
||||
std::vector<int64_t> pads = this->pool_attrs_.pads;
|
||||
std::vector<int64_t> strides = this->pool_attrs_.strides;
|
||||
|
||||
if (this->global_pooling_) {
|
||||
if (this->pool_attrs_.global_pooling) {
|
||||
kernel_shape.assign(x_dims.begin() + 2, x_dims.end());
|
||||
pads.assign(kernel_shape.size() * 2, 0);
|
||||
strides.assign(kernel_shape.size(), 1);
|
||||
}
|
||||
|
||||
std::vector<int64_t> y_dims = PoolBase::SetOutputSize(x_shape, x_shape[1], &pads, this->dilations_, this->ceil_mode_);
|
||||
std::vector<int64_t> y_dims = this->pool_attrs_.SetOutputSize(x_shape, x_shape[1], &pads);
|
||||
Tensor* Y = context->Output(0, TensorShape(y_dims));
|
||||
|
||||
size_t num_outputs = OpKernel::Node().OutputDefs().size();
|
||||
|
|
@ -285,7 +285,7 @@ Status Pool<T, PoolType>::Compute(OpKernelContext* context) const {
|
|||
src_dims_mkl, dst_dims_mkl,
|
||||
kernel_mkl, strides_mkl,
|
||||
padding_left_mkl, padding_right_mkl,
|
||||
this->count_include_pad_);
|
||||
this->pool_attrs_.count_include_pad);
|
||||
PoolPrimitive<T, PoolType>* pool_primitive = PoolPrimitivePool<T, PoolType>::Get(pool_params);
|
||||
auto fwd_primitive_desc = pool_primitive->GetPrimitiveDesc();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue