Files
paddlepaddle--paddle/paddle/phi/kernels/onednn/activation_kernel.cc
T
2026-07-13 12:40:42 +08:00

249 lines
8.8 KiB
C++

// Copyright (c) 2022 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 License.
#include "paddle/phi/kernels/activation_kernel.h"
#include "paddle/phi/kernels/gelu_grad_kernel.h"
#include "paddle/phi/backends/onednn/onednn_context.h"
#include "paddle/phi/backends/onednn/onednn_reuse.h"
#include "paddle/phi/common/place.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/kernels/funcs/activation_functor.h"
namespace phi {
#define DEFINE_ONEDNN_ACTIVATION_KERNEL(name, functor_class) \
template <typename T, typename Context> \
void name##Kernel( \
const Context& dev_ctx, const DenseTensor& x, DenseTensor* out) { \
functor_class<T> functor; \
functor(dev_ctx, x, 0, 0, out); \
}
#define DEFINE_ONEDNN_ACT_KERNEL_WITH_ONE_ATTRS(name, functor_class, attr) \
template <typename T, typename Context> \
void name##Kernel(const Context& dev_ctx, \
const DenseTensor& x, \
float attr, \
DenseTensor* out) { \
functor_class<T> functor; \
functor(dev_ctx, x, attr, 0, out); \
}
#define DEFINE_ONEDNN_ACT_KERNEL_WITH_ONE_DOUBLE_ATTRS( \
name, functor_class, attr) \
template <typename T, typename Context> \
void name##Kernel(const Context& dev_ctx, \
const DenseTensor& x, \
double attr, \
DenseTensor* out) { \
functor_class<T> functor; \
functor(dev_ctx, x, static_cast<float>(attr), 0, out); \
}
template <typename T>
void EltwiseForward(const OneDNNContext& dev_ctx,
const DenseTensor& x,
float alpha,
float beta,
DenseTensor* out,
dnnl::algorithm algorithm) {
bool is_inplaced = x.IsSharedBufferWith(*out);
funcs::ActivationOneDNNHandler<T> handler(
algorithm, alpha, beta, dev_ctx.GetEngine(), dev_ctx.GetPlace(), &x);
auto src_memory_p = handler.AcquireSrcMemory(&x);
std::shared_ptr<dnnl::memory> dst_memory_p = nullptr;
if (is_inplaced) {
dst_memory_p = src_memory_p;
dev_ctx.template Alloc<T>(out);
} else {
dst_memory_p = handler.AcquireDstMemory(out);
}
auto activation_p = handler.AcquireForwardPrimitive();
auto& astream = OneDNNContext::tls().get_stream();
activation_p->execute(
astream, {{DNNL_ARG_FROM, *src_memory_p}, {DNNL_ARG_TO, *dst_memory_p}});
astream.wait();
out->set_mem_desc(dst_memory_p->get_desc());
}
template <typename T, dnnl::algorithm algorithm>
struct OneDNNActivationFunc : public funcs::BaseActivationFunctor<T> {
void operator()(const OneDNNContext& dev_ctx,
const DenseTensor& x,
float alpha,
float beta,
DenseTensor* out) const {
if (out && out->numel() == 0) {
dev_ctx.template Alloc<T>(out);
return;
}
EltwiseForward<T>(dev_ctx, x, alpha, beta, out, algorithm);
}
};
template <typename T>
using AbsOneDNNFunctor = OneDNNActivationFunc<T, dnnl::algorithm::eltwise_abs>;
template <typename T>
using EluOneDNNFunctor = OneDNNActivationFunc<T, dnnl::algorithm::eltwise_elu>;
template <typename T>
using ExpOneDNNFunctor = OneDNNActivationFunc<T, dnnl::algorithm::eltwise_exp>;
template <typename T>
using GeluTanhOneDNNFunctor =
OneDNNActivationFunc<T, dnnl::algorithm::eltwise_gelu_tanh>;
template <typename T>
using GeluErfOneDNNFunctor =
OneDNNActivationFunc<T, dnnl::algorithm::eltwise_gelu_erf>;
template <typename T>
using HardSwishOneDNNFunctor =
OneDNNActivationFunc<T, dnnl::algorithm::eltwise_hardswish>;
template <typename T>
using MishOneDNNFunctor =
OneDNNActivationFunc<T, dnnl::algorithm::eltwise_mish>;
template <typename T>
using ReluOneDNNFunctor =
OneDNNActivationFunc<T, dnnl::algorithm::eltwise_relu>;
template <typename T>
using Relu6OneDNNFunctor =
OneDNNActivationFunc<T, dnnl::algorithm::eltwise_clip_v2>;
template <typename T>
using RoundOneDNNFunctor =
OneDNNActivationFunc<T, dnnl::algorithm::eltwise_round>;
template <typename T>
using SigmoidOneDNNFunctor =
OneDNNActivationFunc<T, dnnl::algorithm::eltwise_logistic>;
template <typename T>
using SqrtOneDNNFunctor =
OneDNNActivationFunc<T, dnnl::algorithm::eltwise_sqrt>;
template <typename T>
using SwishOneDNNFunctor =
OneDNNActivationFunc<T, dnnl::algorithm::eltwise_swish>;
template <typename T>
using TanhOneDNNFunctor =
OneDNNActivationFunc<T, dnnl::algorithm::eltwise_tanh>;
DEFINE_ONEDNN_ACTIVATION_KERNEL(Abs, AbsOneDNNFunctor)
DEFINE_ONEDNN_ACTIVATION_KERNEL(Exp, ExpOneDNNFunctor)
DEFINE_ONEDNN_ACTIVATION_KERNEL(Relu, ReluOneDNNFunctor)
DEFINE_ONEDNN_ACTIVATION_KERNEL(Sigmoid, SigmoidOneDNNFunctor)
DEFINE_ONEDNN_ACTIVATION_KERNEL(Sqrt, SqrtOneDNNFunctor)
DEFINE_ONEDNN_ACTIVATION_KERNEL(Tanh, TanhOneDNNFunctor)
// round eltwise primitive doesn't support BF16, nor does it support grad
template <typename T, typename Context>
void RoundKernel(const Context& dev_ctx,
const DenseTensor& x,
const int decimals,
DenseTensor* out) {
float ten_pow_decimals = std::pow(10, decimals);
DenseTensor out1;
DenseTensorMeta meta_out(x.dtype(), x.dims());
out1.set_meta(meta_out);
out1.set_lod(x.lod());
out1.set_mem_desc(x.mem_desc());
dev_ctx.template Alloc<T>(&out1);
for (int i = 0; i < x.numel(); i++) {
out1.data<T>()[i] = x.data<T>()[i] * ten_pow_decimals;
}
RoundOneDNNFunctor<T> functor;
functor(dev_ctx, out1, 0, 0, out);
for (int i = 0; i < x.numel(); i++) {
out->data<T>()[i] = out->data<T>()[i] * (1 / ten_pow_decimals);
}
}
DEFINE_ONEDNN_ACT_KERNEL_WITH_ONE_ATTRS(Elu, EluOneDNNFunctor, alpha)
DEFINE_ONEDNN_ACT_KERNEL_WITH_ONE_DOUBLE_ATTRS(LeakyRelu,
ReluOneDNNFunctor,
alpha)
DEFINE_ONEDNN_ACT_KERNEL_WITH_ONE_ATTRS(Mish, MishOneDNNFunctor, threshold)
template <typename T, typename Context>
void HardSwishKernel(const Context& dev_ctx,
const DenseTensor& x,
DenseTensor* out) {
HardSwishOneDNNFunctor<T> functor;
functor(dev_ctx, x, 1.0 / 6.0, 1.0 / 2.0, out);
}
template <typename T, typename Context>
void GeluKernel(const Context& dev_ctx,
const DenseTensor& x,
bool approximate,
DenseTensor* out) {
if (approximate) {
GeluTanhOneDNNFunctor<T> functor;
functor(dev_ctx, x, 0, 0, out);
} else {
GeluErfOneDNNFunctor<T> functor;
functor(dev_ctx, x, 0, 0, out);
}
}
template <typename T, typename Context>
void Relu6Kernel(const Context& dev_ctx,
const DenseTensor& x,
DenseTensor* out) {
Relu6OneDNNFunctor<T> functor;
functor(dev_ctx, x, 0, 6.0, out);
}
template <typename T, typename Context>
void SwishKernel(const Context& dev_ctx,
const DenseTensor& x,
DenseTensor* out) {
SwishOneDNNFunctor<T> functor;
functor(dev_ctx, x, 1.0, 0, out);
}
} // namespace phi
PD_REGISTER_KERNEL(round, OneDNN, ONEDNN, phi::RoundKernel, float) {}
#define PD_REGISTER_ACTIVATION_KERNEL(name, func) \
PD_REGISTER_KERNEL(name, OneDNN, ONEDNN, phi::func, float, phi::bfloat16) {}
PD_REGISTER_ACTIVATION_KERNEL(abs, AbsKernel)
PD_REGISTER_ACTIVATION_KERNEL(elu, EluKernel)
PD_REGISTER_ACTIVATION_KERNEL(exp, ExpKernel)
PD_REGISTER_ACTIVATION_KERNEL(gelu, GeluKernel)
PD_REGISTER_ACTIVATION_KERNEL(hardswish, HardSwishKernel)
PD_REGISTER_ACTIVATION_KERNEL(leaky_relu, LeakyReluKernel)
PD_REGISTER_ACTIVATION_KERNEL(mish, MishKernel)
PD_REGISTER_ACTIVATION_KERNEL(relu, ReluKernel)
PD_REGISTER_ACTIVATION_KERNEL(relu6, Relu6Kernel)
PD_REGISTER_ACTIVATION_KERNEL(sigmoid, SigmoidKernel)
PD_REGISTER_ACTIVATION_KERNEL(sqrt, SqrtKernel)
PD_REGISTER_ACTIVATION_KERNEL(swish, SwishKernel)
PD_REGISTER_ACTIVATION_KERNEL(tanh, TanhKernel)