* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#include "pooling/common/op_api/pooling.h"
#include "aclnn_kernels/common/op_error_check.h"
#include "opdev/make_op_executor.h"
#include "opdev/op_def.h"
#include "opdev/op_dfx.h"
#include "opdev/op_executor.h"
#include "opdev/op_log.h"
#include "opdev/shape_utils.h"
using namespace op;
namespace l0op {
static const std::initializer_list<op::DataType> AICORE_DTYPE_SUPPORT_LIST = { op::DataType::DT_FLOAT,
op::DataType::DT_FLOAT16 };
const uint64_t NCHW_N_IDX = 0;
const uint64_t NCHW_C_IDX = 1;
const uint64_t NCHW_H_IDX = 2;
const uint64_t NCHW_W_IDX = 3;
const uint64_t C0_FP32 = 8;
const uint64_t C0_FP16 = 16;
inline static int64_t CeilDiv(int64_t value, int64_t factor)
{
int64_t valueNum = 0;
if (factor == 0) {
return valueNum;
}
if (value % factor == 0) {
valueNum = value / factor;
} else {
valueNum = value / factor + 1;
}
return valueNum;
}
static bool IsAiCoreSupport(const aclTensor *self)
{
return CheckType(self->GetDataType(), AICORE_DTYPE_SUPPORT_LIST);
}
OP_TYPE_REGISTER(Pooling);
const aclTensor *Pooling5Hd(const aclTensor *x, const aclTensor *weight, int64_t mode, bool globalPooling,
const aclIntArray *window, const aclIntArray *stride, const aclIntArray *pad,
const int64_t ceilMode, const char *dataFormat, aclOpExecutor *executor)
{
L0_DFX(Pooling5Hd, x, weight, mode, globalPooling, window, stride, pad, ceilMode, dataFormat);
if (!IsAiCoreSupport(x)) {
OP_LOGE(ACLNN_ERR_PARAM_INVALID, "data type not supports.");
return nullptr;
}
FVector<int64_t> newDilation { 1, 1, 1, 1 };
auto dilation4 = executor->AllocIntArray(newDilation.data(), 4);
FVector<int64_t> newWindow { (*window)[0], (*window)[1], (*window)[2], (*window)[3] };
auto window4 = executor->AllocIntArray(newWindow.data(), 4);
FVector<int64_t> newStride { (*stride)[0], (*stride)[1], (*stride)[2], (*stride)[3] };
auto stride4 = executor->AllocIntArray(newStride.data(), 4);
int64_t outH = 0;
int64_t outW = 0;
if (ceilMode == 0) {
outH = CeilDiv(x->GetViewShape().GetDim(2) + 2 * (*pad)[0] - (*window)[2], (*stride)[2]) + 1;
outW = CeilDiv(x->GetViewShape().GetDim(3) + 2 * (*pad)[2] - (*window)[3], (*stride)[3]) + 1;
} else {
outH = (x->GetViewShape().GetDim(2) + 2 * (*pad)[0] - (*window)[2]) / (*stride)[2] + 1;
outW = (x->GetViewShape().GetDim(3) + 2 * (*pad)[2] - (*window)[3]) / (*stride)[3] + 1;
}
int64_t padT = (*pad)[0];
int64_t padD = (*pad)[1];
int64_t padL = (*pad)[2];
int64_t padR = (*pad)[3];
if (ceilMode == 0) {
if ((outH - 1) * (*stride)[2] >= x->GetViewShape().GetDim(2) + (*pad)[0]) {
int64_t needPad = (outH - 2) * (*stride)[2] + (*window)[2] - x->GetViewShape().GetDim(2);
padD = needPad - padT;
}
if ((outW - 1) * (*stride)[3] >= x->GetViewShape().GetDim(3) + (*pad)[2]) {
int64_t needPad = (outW - 2) * (*stride)[3] + (*window)[3] - x->GetViewShape().GetDim(3);
padR = needPad - padL;
}
}
FVector<int64_t> newPad { padT, padD, padL, padR };
auto pad4 = executor->AllocIntArray(newPad.data(), 4);
auto poolingOut = executor->AllocTensor(x->GetDataType(), op::Format::FORMAT_NC1HWC0, op::Format::FORMAT_NCHW);
const char *priAttr1 = "";
const char *priAttr2 = "NOTSET";
auto ret = INFER_SHAPE(Pooling, OP_INPUT(x, weight), OP_OUTPUT(poolingOut),
OP_ATTR(mode, globalPooling, window4, stride4, pad4, dilation4, ceilMode, dataFormat, priAttr1, priAttr2));
int64_t c = poolingOut->GetViewShape().GetDim(NCHW_C_IDX);
int64_t c0 = 0;
int64_t c1 = 0;
if (x->GetDataType() == DataType::DT_FLOAT) {
c0 = C0_FP32;
c1 = CeilDiv(c, c0);
} else {
c0 = C0_FP16;
c1 = CeilDiv(c, c0);
}
const op::Shape shape = {poolingOut->GetViewShape().GetDim(NCHW_N_IDX), c1,
poolingOut->GetViewShape().GetDim(NCHW_H_IDX),
poolingOut->GetViewShape().GetDim(NCHW_W_IDX), c0};
poolingOut->SetStorageShape(shape);
if (ret != ACLNN_SUCCESS) {
OP_LOGE(ACLNN_ERR_PARAM_INVALID, "InferShape failed.");
return nullptr;
}
ret = ADD_TO_LAUNCHER_LIST_AICORE(Pooling, op::AI_CORE, OP_INPUT(x, weight), OP_OUTPUT(poolingOut),
OP_ATTR(mode, globalPooling, window4, stride4, pad4, dilation4, ceilMode, dataFormat, priAttr1, priAttr2));
OP_CHECK_ADD_TO_LAUNCHER_LIST_AICORE(ret != ACLNN_SUCCESS, return nullptr,
"Pooling ADD_TO_LAUNCHER_LIST_AICORE failed.");
return poolingOut;
}
}