/* Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the Licnse. */ #include #include #include "paddle/fluid/framework/ddim.h" #include "paddle/fluid/framework/framework.pb.h" #include "paddle/fluid/framework/tensor_util.h" #include "paddle/fluid/operators/activation_op.h" #include "paddle/fluid/operators/npu_op_runner.h" namespace paddle { namespace operators { using Tensor = framework::Tensor; template class PowNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* x = ctx.Input("X"); auto* out = ctx.Output("Out"); auto factor = ctx.Attr("factor"); out->mutable_data(ctx.GetPlace()); const auto& runner = NpuOpRunner("Power", {*x}, {*out}, {{"power", factor}, {"scale", static_cast(1.0)}, {"shift", static_cast(0.0)}}); auto stream = ctx.template device_context() .stream(); runner.Run(stream); } }; template class PowGradNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* x = ctx.Input("X"); auto* dout = ctx.Input(framework::GradVarName("Out")); auto* dx = ctx.Output(framework::GradVarName("X")); auto factor = ctx.Attr("factor"); auto x_dims = x->dims(); auto place = ctx.GetPlace(); auto stream = ctx.template device_context() .stream(); // NOTE(liym27): dx = dout * factor * x.pow(factor-1) // Step1: Compute x_pow = x.pow(factor-1) Tensor x_pow(x->type()); x_pow.mutable_data(x->dims(), place); const auto& runner_pow = NpuOpRunner( "Power", {*x}, {x_pow}, {{"power", factor - static_cast(1)}}); runner_pow.Run(stream); // Step 2: Construct a broadcast factor, which has the same shape with x. // 2.1 Get a factor tensor with shape [1]. Tensor factor_tensor(framework::proto::VarType::FP32); factor_tensor.mutable_data({1}, place); FillNpuTensorWithConstant(&factor_tensor, factor); // 2.2 Get the factor which has the shape with x and the same value with // factor. Tensor factor_bc_tensor(framework::proto::VarType::FP32); factor_bc_tensor.mutable_data(x_dims, place); const auto& runner_bc = NpuOpRunner("FillD", {factor_tensor}, {factor_bc_tensor}, {{"dims", framework::vectorize(x_dims)}}); runner_bc.Run(stream); // Step 3: Compute x_power_mul_factor = factor * x.pow(factor-1) Tensor x_power_mul_factor(x->type()); x_power_mul_factor.mutable_data(x->dims(), place); const auto& runner_mul_1 = NpuOpRunner("Mul", {factor_bc_tensor, x_pow}, {x_power_mul_factor}, {}); runner_mul_1.Run(stream); // Step 4: Compute dx = dout * factor * x.pow(factor-1) dx->mutable_data(place); const auto& runner_mul_2 = NpuOpRunner("Mul", {*dout, x_power_mul_factor}, {*dx}, {}); runner_mul_2.Run(stream); } }; template class ReluNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* x = ctx.Input("X"); auto* out = ctx.Output("Out"); out->mutable_data(ctx.GetPlace()); const auto& runner = NpuOpRunner("Relu", { *x, }, {*out}, {}); auto stream = ctx.template device_context() .stream(); runner.Run(stream); } }; template class ReluGradNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* out = ctx.Input("Out"); auto* dout = ctx.Input(framework::GradVarName("Out")); auto* dx = ctx.Output(framework::GradVarName("X")); auto stream = ctx.template device_context() .stream(); dx->mutable_data(ctx.GetPlace()); const auto& runner = NpuOpRunner("ReluGrad", {*dout, *out}, {*dx}, {}); runner.Run(stream); } }; template class Relu6NPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* x = ctx.Input("X"); auto* out = ctx.Output("Out"); out->mutable_data(ctx.GetPlace()); const auto& runner = NpuOpRunner("Relu6", { *x, }, {*out}, {}); auto stream = ctx.template device_context() .stream(); runner.Run(stream); } }; template class Relu6GradNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* out = ctx.Input("Out"); auto* dout = ctx.Input(framework::GradVarName("Out")); auto* dx = ctx.Output(framework::GradVarName("X")); auto stream = ctx.template device_context() .stream(); dx->mutable_data(ctx.GetPlace()); const auto& runner = NpuOpRunner("Relu6Grad", {*dout, *out}, {*dx}, {}); runner.Run(stream); } }; template class SqrtNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* x = ctx.Input("X"); auto* out = ctx.Output("Out"); auto place = ctx.GetPlace(); out->mutable_data(place); auto stream = ctx.template device_context() .stream(); const auto& runner = NpuOpRunner("Sqrt", {*x}, {*out}, {}); runner.Run(stream); } }; template class SqrtGradNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* out = ctx.Input("Out"); auto* dout = ctx.Input(framework::GradVarName("Out")); auto* dx = ctx.Output(framework::GradVarName("X")); auto place = ctx.GetPlace(); dx->mutable_data(place); auto stream = ctx.template device_context() .stream(); const auto& runner_dx = NpuOpRunner("SqrtGrad", {*out, *dout}, {*dx}, {}); runner_dx.Run(stream); } }; template class LogNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* x = ctx.Input("X"); auto* out = ctx.Output("Out"); auto place = ctx.GetPlace(); out->mutable_data(place); auto stream = ctx.template device_context() .stream(); Tensor one(x->type()); one.mutable_data(x->dims(), place); const auto& runner_one = NpuOpRunner("OnesLike", {*x}, {one}, {}); runner_one.Run(stream); Tensor sub(x->type()); sub.mutable_data(x->dims(), place); const auto& runner_sub = NpuOpRunner("Sub", {*x, one}, {sub}, {}); runner_sub.Run(stream); const auto& runner_out = NpuOpRunner("Log1p", {sub}, {*out}, {}); runner_out.Run(stream); } }; template class LogGradNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* dout = ctx.Input(framework::GradVarName("Out")); auto* x = ctx.Input("X"); auto* dx = ctx.Output(framework::GradVarName("X")); auto place = ctx.GetPlace(); dx->mutable_data(place); auto stream = ctx.template device_context() .stream(); const auto& runner = NpuOpRunner("DivNoNan", {*dout, *x}, {*dx}, {}); runner.Run(stream); } }; template class TanhNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* x = ctx.Input("X"); auto* out = ctx.Output("Out"); auto place = ctx.GetPlace(); out->mutable_data(place); auto stream = ctx.template device_context() .stream(); const auto& runner = NpuOpRunner("Tanh", {*x}, {*out}, {}); runner.Run(stream); } }; template class TanhGradNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* dout = ctx.Input(framework::GradVarName("Out")); auto* out = ctx.Input("Out"); auto* dx = ctx.Output(framework::GradVarName("X")); auto place = ctx.GetPlace(); dx->mutable_data(place); auto stream = ctx.template device_context() .stream(); const auto& runner_dx = NpuOpRunner("TanhGrad", {*out, *dout}, {*dx}, {}); runner_dx.Run(stream); } }; template class SquareNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* x = ctx.Input("X"); auto* out = ctx.Output("Out"); auto place = ctx.GetPlace(); out->mutable_data(place); auto stream = ctx.template device_context() .stream(); const auto& runner = NpuOpRunner("Square", {*x}, {*out}, {}); runner.Run(stream); } }; template class SigmoidNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* x = ctx.Input("X"); auto* out = ctx.Output("Out"); auto place = ctx.GetPlace(); out->mutable_data(place); auto stream = ctx.template device_context() .stream(); const auto& runner = NpuOpRunner("Sigmoid", {*x}, {*out}, {}); runner.Run(stream); } }; template class SigmoidGradNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* dout = ctx.Input(framework::GradVarName("Out")); auto* out = ctx.Input("Out"); auto* dx = ctx.Output(framework::GradVarName("X")); auto place = ctx.GetPlace(); dx->mutable_data(place); auto stream = ctx.template device_context() .stream(); const auto& runner_dx = NpuOpRunner("SigmoidGrad", {*out, *dout}, {*dx}, {}); runner_dx.Run(stream); } }; // HardSwish = min(max(0, x+offset), threshold) * x / scale template class HardSwishNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* x = ctx.Input("X"); auto* out = ctx.Output("Out"); float threshold = ctx.Attr("threshold"); float scale = ctx.Attr("scale"); float offset = ctx.Attr("offset"); auto place = ctx.GetPlace(); out->mutable_data(place); auto stream = ctx.template device_context() .stream(); Tensor tensor_offset(x->type()); tensor_offset.mutable_data({1}, place); FillNpuTensorWithConstant(&tensor_offset, static_cast(offset)); Tensor add_offset_val(x->type()); add_offset_val.mutable_data(x->dims(), place); const auto& runner_add = NpuOpRunner("AddV2", {*x, tensor_offset}, {add_offset_val}); runner_add.Run(stream); Tensor tensor_threshold(x->type()); tensor_threshold.mutable_data({1}, place); FillNpuTensorWithConstant(&tensor_threshold, static_cast(threshold)); Tensor tensor_zero(x->type()); tensor_zero.mutable_data({1}, place); FillNpuTensorWithConstant(&tensor_zero, static_cast(0.0)); Tensor clip_val(x->type()); clip_val.mutable_data(x->dims(), place); const auto& runner_clip = NpuOpRunner( "ClipByValue", {add_offset_val, tensor_zero, tensor_threshold}, {clip_val}); runner_clip.Run(stream); Tensor tensor_scale_tmp(x->type()); tensor_scale_tmp.mutable_data({1}, place); FillNpuTensorWithConstant(&tensor_scale_tmp, static_cast(scale)); Tensor tensor_scale(x->type()); tensor_scale.mutable_data(x->dims(), place); const auto& runner_fill = NpuOpRunner("FillD", {tensor_scale_tmp}, {tensor_scale}, {{"dims", framework::vectorize(x->dims())}}); runner_fill.Run(stream); Tensor div_val(x->type()); div_val.mutable_data(x->dims(), place); const auto& runner_div = NpuOpRunner("Div", {clip_val, tensor_scale}, {div_val}); runner_div.Run(stream); const auto& runner_mul = NpuOpRunner("Mul", {*x, div_val}, {*out}); runner_mul.Run(stream); } }; template class HardSwishGradNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* x = ctx.Input("X"); auto* dout = ctx.Input(framework::GradVarName("Out")); auto* dx = ctx.Output(framework::GradVarName("X")); float threshold = ctx.Attr("threshold"); float scale = ctx.Attr("scale"); float offset = ctx.Attr("offset"); auto place = ctx.GetPlace(); dx->mutable_data(place); auto stream = ctx.template device_context() .stream(); Tensor tensor_offset(x->type()); tensor_offset.mutable_data({1}, place); FillNpuTensorWithConstant(&tensor_offset, static_cast(offset)); Tensor add_offset_val(x->type()); add_offset_val.mutable_data(x->dims(), place); const auto& runner_add = NpuOpRunner("AddV2", {*x, tensor_offset}, {add_offset_val}); runner_add.Run(stream); Tensor tmp1(x->type()); tmp1.mutable_data(x->dims(), place); const auto& runner_pow1 = NpuOpRunner("Power", {*x}, {tmp1}, {{"scale", 2.0f}, {"shift", offset}}); runner_pow1.Run(stream); Tensor tmp2(x->type()); tmp2.mutable_data(x->dims(), place); const auto& runner_ht_grad = NpuOpRunner("HardtanhGrad", {add_offset_val, tmp1}, {tmp2}, {{"min_val", 0.0f}, {"max_val", threshold}}); runner_ht_grad.Run(stream); Tensor tmp3(x->type()); tmp3.mutable_data(x->dims(), place); const auto& runner_pow2 = NpuOpRunner( "Power", {tmp2}, {tmp3}, {{"scale", 1.0f / scale}, {"shift", 1.0f}}); runner_pow2.Run(stream); Tensor tensor_threshold_tmp(x->type()); tensor_threshold_tmp.mutable_data({1}, place); FillNpuTensorWithConstant(&tensor_threshold_tmp, static_cast(threshold)); Tensor tensor_threshold(x->type()); tensor_threshold.mutable_data(x->dims(), place); const auto& runner_fill = NpuOpRunner("FillD", {tensor_threshold_tmp}, {tensor_threshold}, {{"dims", framework::vectorize(x->dims())}}); runner_fill.Run(stream); Tensor tmp_bool(framework::proto::VarType::BOOL); tmp_bool.mutable_data(x->dims(), place); const auto& runner_less = NpuOpRunner("Less", {add_offset_val, tensor_threshold}, {tmp_bool}); runner_less.Run(stream); Tensor tmp4(x->type()); tmp4.mutable_data(x->dims(), place); auto dst_dtype = ConvertToNpuDtype(x->type()); const auto& runner_cast = NpuOpRunner("Cast", {tmp_bool}, {tmp4}, {{"dst_type", static_cast(dst_dtype)}}); runner_cast.Run(stream); Tensor tmp5(x->type()); tmp5.mutable_data(x->dims(), place); const auto& runner_sub = NpuOpRunner("Sub", {tmp3, tmp4}, {tmp5}); runner_sub.Run(stream); const auto& runner_final = NpuOpRunner("Mul", {tmp5, *dout}, {*dx}); runner_final.Run(stream); } }; template class HardSigmoidNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* x = ctx.Input("X"); auto* out = ctx.Output("Out"); float slope = ctx.Attr("slope"); float offset = ctx.Attr("offset"); out->mutable_data(ctx.GetPlace()); framework::NPUAttributeMap attr_input = {{"alpha", slope}, {"beta", offset}}; auto stream = ctx.template device_context() .stream(); const auto& runner = NpuOpRunner("HardSigmoid", {*x}, {*out}, attr_input); runner.Run(stream); } }; template class HardSigmoidGradNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* dout = ctx.Input(framework::GradVarName("Out")); auto* out = ctx.Input("Out"); auto* dx = ctx.Output(framework::GradVarName("X")); float slope = ctx.Attr("slope"); float offset = ctx.Attr("offset"); dx->mutable_data(ctx.GetPlace()); framework::NPUAttributeMap attr_input = {{"alpha", slope}, {"beta", offset}}; auto stream = ctx.template device_context() .stream(); const auto& runner_dx = NpuOpRunner("HardSigmoidGrad", {*dout, *out}, {*dx}, attr_input); runner_dx.Run(stream); } }; template class ReciprocalNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* x = ctx.Input("X"); auto* out = ctx.Output("Out"); auto place = ctx.GetPlace(); out->mutable_data(place); auto stream = ctx.template device_context() .stream(); const auto& runner = NpuOpRunner("Reciprocal", {*x}, {*out}, {}); runner.Run(stream); } }; template class ReciprocalGradNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* out = ctx.Input("Out"); auto* dout = ctx.Input(framework::GradVarName("Out")); auto* dx = ctx.Output(framework::GradVarName("X")); auto place = ctx.GetPlace(); dx->mutable_data(place); auto stream = ctx.template device_context() .stream(); const auto& runner_dx = NpuOpRunner("ReciprocalGrad", {*out, *dout}, {*dx}, {}); runner_dx.Run(stream); } }; template class CosNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* x = ctx.Input("X"); auto* out = ctx.Output("Out"); auto place = ctx.GetPlace(); out->mutable_data(place); auto stream = ctx.template device_context() .stream(); const auto& runner = NpuOpRunner("Cos", {*x}, {*out}, {}); runner.Run(stream); } }; template class CosGradNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* dout = ctx.Input(framework::GradVarName("Out")); auto* x = ctx.Input("X"); auto* dx = ctx.Output(framework::GradVarName("X")); auto place = ctx.GetPlace(); dx->mutable_data(place); Tensor sin_out(x->type()); // Temporary Tensor sin_out.Resize(x->dims()); sin_out.mutable_data(place); auto stream = ctx.template device_context() .stream(); const auto& runner = NpuOpRunner("Sin", {*x}, {sin_out}, {}); runner.Run(stream); const auto& runner_dx = NpuOpRunner("Mul", {*dout, sin_out}, {*dx}, {}); runner_dx.Run(stream); Tensor tmp(x->type()); // Temporary Tensor tmp.Resize(framework::make_ddim({1, 1})); tmp.mutable_data(place); float factor = -1.; FillNpuTensorWithConstant(&tmp, static_cast(factor)); const auto& runner_dx_ = NpuOpRunner("Xdivy", {*dx, tmp}, {*dx}, {}); runner_dx_.Run(stream); // dx = -dout * Sine(x); } }; template class AtanNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* x = ctx.Input("X"); auto* out = ctx.Output("Out"); auto place = ctx.GetPlace(); out->mutable_data(place); const auto& runner = NpuOpRunner("Atan", {*x}, {*out}, {}); auto stream = ctx.template device_context() .stream(); runner.Run(stream); } }; template class AtanGradNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* dout = ctx.Input(framework::GradVarName("Out")); auto* x = ctx.Input("X"); auto* dx = ctx.Output(framework::GradVarName("X")); auto place = ctx.GetPlace(); dx->mutable_data(place); auto stream = ctx.template device_context() .stream(); const auto& runner_dx = NpuOpRunner("AtanGrad", {*x, *dout}, {*dx}, {}); runner_dx.Run(stream); } }; template class ExpNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* x = ctx.Input("X"); auto* out = ctx.Output("Out"); out->mutable_data(ctx.GetPlace()); const auto& runner = NpuOpRunner("Exp", {*x}, {*out}, {}); auto stream = ctx.template device_context() .stream(); runner.Run(stream); } }; template class ExpGradNPUKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { auto* out = ctx.Input("Out"); auto* dout = ctx.Input(framework::GradVarName("Out")); auto* dx = ctx.Output(framework::GradVarName("X")); dx->mutable_data(ctx.GetPlace()); auto stream = ctx.template device_context() .stream(); const auto& runner = NpuOpRunner("Mul", {*dout, *out}, {*dx}, {}); runner.Run(stream); } }; } // namespace operators } // namespace paddle namespace ops = paddle::operators; REGISTER_OP_NPU_KERNEL( pow, ops::PowNPUKernel, ops::PowNPUKernel); REGISTER_OP_NPU_KERNEL( pow_grad, ops::PowGradNPUKernel, ops::PowGradNPUKernel); REGISTER_OP_NPU_KERNEL( relu, ops::ReluNPUKernel, ops::ReluNPUKernel); REGISTER_OP_NPU_KERNEL( relu_grad, ops::ReluGradNPUKernel, ops::ReluGradNPUKernel); REGISTER_OP_NPU_KERNEL( relu6, ops::Relu6NPUKernel, ops::Relu6NPUKernel); REGISTER_OP_NPU_KERNEL( relu6_grad, ops::Relu6GradNPUKernel, ops::Relu6GradNPUKernel); REGISTER_OP_NPU_KERNEL( sqrt, ops::SqrtNPUKernel, ops::SqrtNPUKernel); REGISTER_OP_NPU_KERNEL( sqrt_grad, ops::SqrtGradNPUKernel, ops::SqrtGradNPUKernel); REGISTER_OP_NPU_KERNEL( log, ops::LogNPUKernel, ops::LogNPUKernel); REGISTER_OP_NPU_KERNEL( log_grad, ops::LogGradNPUKernel, ops::LogGradNPUKernel); REGISTER_OP_NPU_KERNEL( tanh, ops::TanhNPUKernel, ops::TanhNPUKernel); REGISTER_OP_NPU_KERNEL( tanh_grad, ops::TanhGradNPUKernel, ops::TanhGradNPUKernel); REGISTER_OP_NPU_KERNEL( square, ops::SquareNPUKernel, ops::SquareNPUKernel, ops::SquareNPUKernel); REGISTER_OP_NPU_KERNEL( sigmoid, ops::SigmoidNPUKernel, ops::SigmoidNPUKernel); REGISTER_OP_NPU_KERNEL( sigmoid_grad, ops::SigmoidGradNPUKernel, ops::SigmoidGradNPUKernel); REGISTER_OP_NPU_KERNEL(hard_swish, ops::HardSwishNPUKernel, ops::HardSwishNPUKernel); REGISTER_OP_NPU_KERNEL(hard_swish_grad, ops::HardSwishGradNPUKernel, ops::HardSwishGradNPUKernel); REGISTER_OP_NPU_KERNEL( hard_sigmoid, ops::HardSigmoidNPUKernel, ops::HardSigmoidNPUKernel); REGISTER_OP_NPU_KERNEL( hard_sigmoid_grad, ops::HardSigmoidGradNPUKernel, ops::HardSigmoidGradNPUKernel); REGISTER_OP_NPU_KERNEL( reciprocal, ops::ReciprocalNPUKernel, ops::ReciprocalNPUKernel, ops::ReciprocalNPUKernel); REGISTER_OP_NPU_KERNEL( reciprocal_grad, ops::ReciprocalGradNPUKernel, ops::ReciprocalGradNPUKernel, ops::ReciprocalGradNPUKernel); REGISTER_OP_NPU_KERNEL( cos, ops::CosNPUKernel, ops::CosNPUKernel); REGISTER_OP_NPU_KERNEL( cos_grad, ops::CosGradNPUKernel, ops::CosGradNPUKernel); REGISTER_OP_NPU_KERNEL( atan, ops::AtanNPUKernel, ops::AtanNPUKernel); REGISTER_OP_NPU_KERNEL( atan_grad, ops::AtanGradNPUKernel, ops::AtanGradNPUKernel); REGISTER_OP_NPU_KERNEL( exp, ops::ExpNPUKernel, ops::ExpNPUKernel); REGISTER_OP_NPU_KERNEL( exp_grad, ops::ExpGradNPUKernel, ops::ExpGradNPUKernel);