Files
2026-07-13 13:33:03 +08:00

190 lines
7.3 KiB
C++

//
// OnnxPrelu.cpp
// MNNConverter
//
// Created by MNN on 2019/10/23.
// Copyright © 2018, Alibaba Group Holding Limited
//
#include "MNN_generated.h"
#include "OnnxExtraManager.hpp"
namespace MNN {
namespace Express {
class OnnxPreluTransform : public OnnxExtraManager::Transform {
public:
virtual EXPRP onExecute(EXPRP expr) const override {
auto inputs = expr->inputs();
MNN_THROW_CHECK(inputs.size() == 2, "Onnx Prelu Should have 2 inputs!");
auto slope = inputs[1];
auto slopeInfo = slope->getInfo();
auto slopeData = slope->readMap<float>();
if (slopeInfo == nullptr || slopeData == nullptr) {
auto k = _Select(_Less(inputs[0], _Scalar<float>(0)), slope, _Scalar<float>(1));
auto res = _Multiply(inputs[0], k);
res->setName(expr->outputName(0));
return res->expr().first;
}
auto config = Global<modelConfig>::Get();
auto dimSize = slopeInfo->dim.size();
const int slopeSize = (int)slopeInfo->size;
if (1 == slopeSize) {
auto res = _Relu(inputs[0], slopeData[0]);
res->setName(expr->outputName(0));
return res->expr().first;
}
bool needPermute = false;
std::vector<int> permuteDims;
int slopAxis = -1;
for (int i=0; i<dimSize; ++i) {
if (slopeInfo->dim[i] == slopeSize) {
slopAxis = i;
break;
}
}
auto input = inputs[0];
if (dimSize >= 2 && 1 != slopAxis) {
if (config->optimizeLevel < 2 || slopAxis == -1) {
auto k = _Select(_Less(inputs[0], _Scalar<float>(0)), slope, _Scalar<float>(1));
auto res = _Multiply(inputs[0], k);
res->setName(expr->outputName(0));
return res->expr().first;
}
needPermute = true;
permuteDims.resize(dimSize);
for (int i=0; i<dimSize; ++i) {
permuteDims[i] = i;
}
permuteDims[1] = slopAxis;
permuteDims[slopAxis] = 1;
input = _Transpose(input, permuteDims);
}
std::unique_ptr<PReluT> preluParam(new PReluT);
preluParam->slopeCount = slopeSize;
preluParam->slope.resize(slopeSize);
memcpy(preluParam->slope.data(), slopeData, slopeSize * sizeof(float));
// prelu(input, slope) => mergedPrelu(input)
std::unique_ptr<OpT> mergedOp(new OpT);
mergedOp->name = expr->name();
mergedOp->type = OpType_PReLU;
mergedOp->main.type = OpParameter_PRelu;
mergedOp->main.value = preluParam.release();
auto newExpr = Expr::create(mergedOp.get(), {input});
if (needPermute) {
auto output = _Transpose(Variable::create(newExpr), permuteDims);
newExpr = output->expr().first;
}
newExpr->setName(expr->name());
return newExpr;
}
};
class OnnxCeluTransform : public OnnxExtraManager::Transform {
public:
virtual EXPRP onExecute(EXPRP expr) const override {
float alpha = 1;
auto attrs = expr->get()->main_as_Extra()->attr();
if (attrs != nullptr) {
for (const auto& attr : *attrs) {
if (attr->key()->str() == "alpha") {
alpha = attr->f();
}
}
}
auto input = expr->inputs()[0];
auto alphaVar = _Const(alpha);
auto y = _Multiply(_Subtract(_Exp(_Divide(input, alphaVar)), _Const(1.0f)), alphaVar);
auto res = _Select(_Less(input, _Const(0.0f)), y, input);
auto newExpr = res->expr().first;
newExpr->setName(expr->name());
return newExpr;
}
};
class OnnxThresholdedReluTransform : public OnnxExtraManager::Transform {
public:
virtual EXPRP onExecute(EXPRP expr) const override {
float alpha = 1;
auto attrs = expr->get()->main_as_Extra()->attr();
if (attrs != nullptr) {
for (const auto& attr : *attrs) {
if (attr->key()->str() == "alpha") {
alpha = attr->f();
}
}
}
auto input = expr->inputs()[0];
auto res = _Select(_Greater(input, _Const(alpha)), input, _Const(0.0f));
auto newExpr = res->expr().first;
newExpr->setName(expr->name());
return newExpr;
}
};
class OnnxShrinkTransform : public OnnxExtraManager::Transform {
public:
virtual EXPRP onExecute(EXPRP expr) const override {
float bias = 0, lambd = 0.5;
auto attrs = expr->get()->main_as_Extra()->attr();
if (attrs != nullptr) {
for (const auto& attr : *attrs) {
if (attr->key()->str() == "bias") {
bias = attr->f();
} else if (attr->key()->str() == "lambd") {
lambd = attr->f();
}
}
}
auto input = expr->inputs()[0];
auto biasVar = _Const(bias);
auto res = _Select(_Greater(input, _Const(lambd)), _Subtract(input, biasVar), // x-bias for x > lambd
_Select(_Less(input, _Const(-lambd)), _Add(input, biasVar), // x+bias for x < -lambd
_Const(0.0))); // 0 for otherwise
auto newExpr = res->expr().first;
newExpr->setName(expr->name());
return newExpr;
}
};
class OnnxTriluTransform : public OnnxExtraManager::Transform {
public:
virtual EXPRP onExecute(EXPRP expr) const override {
auto inputs = expr->inputs();
auto shape = _Shape(inputs[0]), zero = _Scalar<int>(0), oneV = _Unsqueeze(_Scalar<int>(1), {0});
auto H = _Slice(shape, _Unsqueeze(_Scalar<int>(-2), {0}), oneV), W = _Slice(shape, _Unsqueeze(_Scalar<int>(-1), {0}), oneV);
auto rangeH = _Unsqueeze(_Range(zero, H, oneV), {1}), rangeW = _Unsqueeze(_Range(zero, W, oneV), {0});
bool upper = true;
auto attrs = expr->get()->main_as_Extra()->attr();
if (attrs != nullptr) {
for (const auto& attr : *attrs) {
if (attr->key()->str() == "upper") {
upper = attr->i();
}
}
}
auto k = (inputs.size() == 2 ? inputs[1] : _Scalar<int>(0));
auto mask = (upper ? _GreaterEqual(rangeW, rangeH + k) : _GreaterEqual(rangeH, rangeW - k));
mask = _Reshape(mask, _Concat({_Fill(_Unsqueeze(_Size(shape) - _Scalar<int>(2), {0}), oneV), _Shape(mask)}, 0));
auto res = _Select(mask, inputs[0], zero);
res->setName(expr->outputName(0));
return res->expr().first;
}
};
static auto gRegister = []() {
OnnxExtraManager::get()->insert("PRelu", std::shared_ptr<OnnxExtraManager::Transform>(new OnnxPreluTransform));
OnnxExtraManager::get()->insert("Celu", std::shared_ptr<OnnxExtraManager::Transform>(new OnnxCeluTransform));
OnnxExtraManager::get()->insert("ThresholdedRelu", std::shared_ptr<OnnxExtraManager::Transform>(new OnnxThresholdedReluTransform));
OnnxExtraManager::get()->insert("Shrink", std::shared_ptr<OnnxExtraManager::Transform>(new OnnxShrinkTransform));
OnnxExtraManager::get()->insert("Trilu", std::shared_ptr<OnnxExtraManager::Transform>(new OnnxTriluTransform));
return true;
}();
} // namespace Express
} // namespace MNN