// // GeometryELU.cpp // MNN // // Created by MNN on 2020/07/23. // Copyright © 2018, Alibaba Group Holding Limited // #include "geometry/GeometryComputer.hpp" #include "core/OpCommonUtils.hpp" #include "geometry/GeometryComputerUtils.hpp" namespace MNN { static void initTensor(std::shared_ptr tensor, Tensor* input) { TensorUtils::copyShape(input, tensor.get(), true, true); } class GeometryELU : public GeometryComputer { public: virtual bool onCompute(const Op* op, const std::vector& inputs, const std::vector& outputs, Context& context, CommandBuffer& res) const override { MNN_ASSERT(1 == inputs.size()); MNN_ASSERT(1 == outputs.size()); auto input = inputs[0]; auto output = outputs[0]; // ELU : y = x > 0 ? x : alpha * (exp(x) - 1) // exp + sub + mul : y1 = alhpa * (exp(x) - 1) // exp std::shared_ptr expValue(new Tensor); { initTensor(expValue, input); auto cmd = GeometryComputerUtils::makeUnary(UnaryOpOperation_EXPM1, input, expValue.get()); res.extras.emplace_back(expValue); res.command.emplace_back(std::move(cmd)); } // mul std::shared_ptr mulValue(new Tensor); { auto alphaConst = context.allocConst(op, {}, halide_type_of()); float alpha = 0.0; if (op->type() == OpType_ELU) { alpha = op->main_as_ELU()->alpha(); } else if (op->type() == OpType_Selu){ alpha = op->main_as_Selu()->scale() * op->main_as_Selu()->alpha(); } alphaConst->host()[0] = alpha; initTensor(mulValue, input); auto cmd = GeometryComputerUtils::makeBinary(BinaryOpOperation_MUL, expValue.get(), alphaConst.get(), mulValue.get()); res.extras.emplace_back(mulValue); res.command.emplace_back(std::move(cmd)); } // compare + select : y = x > 0 ? x : y1 // compare std::shared_ptr compValue(new Tensor); { auto zeroConst = context.allocConst(op, {}, halide_type_of()); zeroConst->host()[0] = 0; TensorUtils::copyShape(input, compValue.get(), true, true); compValue->buffer().type = halide_type_of(); auto cmd = GeometryComputerUtils::makeBinary(BinaryOpOperation_GREATER, input, zeroConst.get(), compValue.get()); res.extras.emplace_back(compValue); res.command.emplace_back(std::move(cmd)); } std::shared_ptr scaleValue; if (op->type() == OpType_Selu) { scaleValue.reset(new Tensor); auto scaleConst = context.allocConst(op, {}, halide_type_of()); float scale = op->main_as_Selu()->scale(); scaleConst->host()[0] = scale; initTensor(scaleValue, input); auto cmd = GeometryComputerUtils::makeBinary(BinaryOpOperation_MUL, input, scaleConst.get(), scaleValue.get()); res.extras.emplace_back(scaleValue); res.command.emplace_back(std::move(cmd)); } // select { flatbuffers::FlatBufferBuilder builder; OpBuilder opBuilder(builder); opBuilder.add_type(OpType_Select); builder.Finish(opBuilder.Finish()); auto y0 = op->type() == OpType_ELU ? input : scaleValue.get(); auto cmd = GeometryComputerUtils::makeCommand(builder, {compValue.get(), y0, mulValue.get()}, {output}); res.command.emplace_back(std::move(cmd)); } return true; } }; static void _create() { std::shared_ptr comp(new GeometryELU); GeometryComputer::registerGeometryComputer(comp, {OpType_ELU, OpType_Selu}); } REGISTER_GEOMETRY(GeometryELU, _create); } // namespace MNN