/* 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/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()); 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); 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); TensorFromVector(std::vector{factor}, ctx.device_context(), &factor_tensor); // 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); 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); auto runner_mul_1 = NpuOpRunner("Mul", {factor_bc_tensor, *x}, {x_power_mul_factor}, {}); runner_mul_1.Run(stream); // Step 4: Compute dx = dout * factor * x.pow(factor-1) dx->mutable_data(place); 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()); 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()); auto runner = NpuOpRunner("ReluGrad", {*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(); 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(); auto dx_runner = NpuOpRunner("SqrtGrad", {*out, *dout}, {*dx}, {}); dx_runner.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); auto one_runner = NpuOpRunner("OnesLike", {*x}, {one}, {}); one_runner.Run(stream); Tensor sub(x->type()); sub.mutable_data(x->dims(), place); auto sub_runner = NpuOpRunner("Sub", {*x, one}, {sub}, {}); sub_runner.Run(stream); auto out_runner = NpuOpRunner("Log1p", {sub}, {*out}, {}); out_runner.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(); 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(); 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(); auto dx_runner = NpuOpRunner("TanhGrad", {*out, *dout}, {*dx}, {}); dx_runner.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(); auto runner = NpuOpRunner("Square", {*x}, {*out}, {}); 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( 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);