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

714 lines
28 KiB
C++

// Copyright (c) 2023 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 <memory>
#include "paddle/common/errors.h"
#include "paddle/phi/backends/onednn/onednn_reuse.h"
#include "paddle/phi/core/compat/convert_utils.h"
#include "paddle/phi/core/enforce.h"
#include "paddle/phi/core/expect.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/core/utils/data_type.h"
#include "paddle/phi/kernels/funcs/common_shape.h"
namespace phi::fusion {
using funcs::OneDNNGetDataType;
using funcs::to_void_cast;
using phi::OneDNNContext;
struct InnerProductCache {
dnnl::inner_product_forward inner_product_p;
dnnl::memory src_mem;
dnnl::memory weights_mem;
dnnl::memory bias_mem;
dnnl::memory dst_mem;
dnnl::memory src_scales_mem;
dnnl::memory wei_scales_mem;
dnnl::memory dst_scales_mem;
};
std::tuple<std::vector<float>,
std::vector<float>,
std::vector<float>,
std::vector<float>>
GetDNNLScales(const float scale_in,
const float scale_out,
const std::vector<float>& scale_weights) {
std::vector<float> dnnl_src_scales = {1.f / scale_in};
size_t count = scale_weights.size();
std::vector<float> dnnl_wei_scales(count);
#pragma omp parallel for if (count > 50)
for (size_t i = 0; i < count; i++) {
dnnl_wei_scales[i] = 1.f / scale_weights[i];
}
std::vector<float> dnnl_psum_scales = {1.f};
std::vector<float> dnnl_dst_scales = {1.f / scale_out};
return std::make_tuple(
dnnl_src_scales, dnnl_wei_scales, dnnl_psum_scales, dnnl_dst_scales);
}
template <typename T_in, typename T_w, typename T_out>
class FCOneDNNHandler
: public funcs::OneDNNHandlerNoCachingT<T_in, dnnl::inner_product_forward> {
public:
FCOneDNNHandler(const OneDNNContext& dev_ctx,
const DenseTensor* x,
const DenseTensor* weights,
const DenseTensor* bias,
DenseTensor* out UNUSED,
const float scale_in,
const float scale_out,
const std::vector<float>& scale_weights,
const bool force_fp32_output,
const int in_num_col_dims,
const std::string& activation_type,
dnnl::engine onednn_engine,
phi::Place cpu_place)
: funcs::OneDNNHandlerNoCachingT<T_in, dnnl::inner_product_forward>(
onednn_engine, cpu_place),
dev_ctx_(dev_ctx) {
this->memory_key_ = dev_ctx.GetInputsName("W")[0];
auto x_vec_dims = vectorize(x->dims());
auto weights_vec_dims = vectorize(weights->dims());
int MB = 1;
for (int i = 0; i < in_num_col_dims; ++i) {
MB *= x_vec_dims[i];
}
int IC = 1;
for (size_t i = in_num_col_dims; i < x_vec_dims.size(); ++i) {
IC *= x_vec_dims[i];
}
int OC = weights_vec_dims[1];
dnnl::memory::desc bias_md;
auto src_md = dnnl::memory::desc(
{MB, IC}, OneDNNGetDataType<T_in>(), dnnl::memory::format_tag::any);
auto weights_md = dnnl::memory::desc(
{OC, IC}, OneDNNGetDataType<T_w>(), dnnl::memory::format_tag::any);
auto dst_md = dnnl::memory::desc(
{MB, OC}, OneDNNGetDataType<T_out>(), dnnl::memory::format_tag::any);
if (bias) {
bias_md = dnnl::memory::desc({bias->numel()},
OneDNNGetDataType<float>(),
dnnl::memory::format_tag::a);
}
const auto attrs = CreateFCAttrs(dev_ctx,
scale_in,
scale_out,
scale_weights,
force_fp32_output,
activation_type);
this->AcquireForwardPrimitiveDescriptor(attrs,
dnnl::prop_kind::forward_inference,
src_md,
weights_md,
bias_md,
dst_md);
}
private:
dnnl::primitive_attr CreateFCAttrs(const OneDNNContext& dev_ctx,
const float scale_in,
const float scale_out,
const std::vector<float>& scale_weights,
const bool force_fp32_output,
const std::string& activation_type) {
dnnl::primitive_attr attributes;
dnnl::post_ops post_operations;
float activation_scale = 1.0f;
if (funcs::is_int8<T_w>()) {
std::vector<float> src_scales, wei_scales, psum_scales, dst_scales;
std::tie(src_scales, wei_scales, psum_scales, dst_scales) =
GetDNNLScales(scale_in, scale_out, scale_weights);
attributes.set_scales_mask(DNNL_ARG_SRC, 0);
dnnl::memory::desc src_scales_md(
{1}, dnnl::memory::data_type::f32, dnnl::memory::format_tag::x);
src_scales_mem_ = dnnl::memory(src_scales_md, this->engine_);
memcpy(src_scales_mem_.get_data_handle(),
src_scales.data(),
src_scales.size() * sizeof(float));
int mask = wei_scales.size() > 1 ? 1 : 0;
attributes.set_scales_mask(DNNL_ARG_WEIGHTS, mask);
dnnl::memory::desc wei_scales_md(
{static_cast<int64_t>(wei_scales.size())},
dnnl::memory::data_type::f32,
dnnl::memory::format_tag::x);
wei_scales_mem_ = dnnl::memory(wei_scales_md, this->engine_);
memcpy(wei_scales_mem_.get_data_handle(),
wei_scales.data(),
wei_scales.size() * sizeof(float));
if (!force_fp32_output) {
attributes.set_scales_mask(DNNL_ARG_DST, 0);
dnnl::memory::desc dst_scales_md(
{1}, dnnl::memory::data_type::f32, dnnl::memory::format_tag::x);
dst_scales_mem_ = dnnl::memory(dst_scales_md, this->engine_);
memcpy(dst_scales_mem_.get_data_handle(),
dst_scales.data(),
dst_scales.size() * sizeof(float));
}
}
// ReLU from "fc_fuse_pass"
if (activation_type == "relu") {
post_operations.append_eltwise(dnnl::algorithm::eltwise_relu, 0.0f, 0.0f);
}
AppendActivation(dev_ctx, post_operations, activation_scale);
if (dev_ctx.HasDnnAttr("fused_output_scale")) {
float scale_alpha =
PADDLE_GET_CONST(float, dev_ctx.GetDnnAttr("fused_output_scale"));
post_operations.append_eltwise(
dnnl::algorithm::eltwise_linear, scale_alpha, 0.0f);
}
attributes.set_post_ops(post_operations);
return attributes;
}
void AppendActivation(const OneDNNContext& dev_ctx,
dnnl::post_ops& post_ops, // NOLINT
float activation_scale = 1.0f) {
const auto invalid_attribute =
dev_ctx.HasDnnAttr("fuse_activation")
? PADDLE_GET_CONST(std::string,
dev_ctx.GetDnnAttr("fuse_activation"))
.empty()
: true;
if (invalid_attribute) return;
const auto fuse_activation =
PADDLE_GET_CONST(std::string, dev_ctx.GetDnnAttr("fuse_activation"));
const auto fuse_alpha =
dev_ctx.HasDnnAttr("fuse_alpha")
? PADDLE_GET_CONST(float, dev_ctx.GetDnnAttr("fuse_alpha"))
: 0.0f;
const auto fuse_beta =
dev_ctx.HasDnnAttr("fuse_beta")
? PADDLE_GET_CONST(float, dev_ctx.GetDnnAttr("fuse_beta"))
: 0.0f;
const auto activation_map = funcs::OneDNNActivationMap();
const auto& activation_type = activation_map.find(fuse_activation);
PADDLE_ENFORCE_NE(
activation_type,
activation_map.end(),
common::errors::InvalidArgument(
"Activation '%s' not found in oneDNN algorithms mapper",
fuse_activation));
post_ops.append_eltwise(activation_type->second, fuse_alpha, fuse_beta);
post_ops.append_eltwise(
dnnl::algorithm::eltwise_linear, activation_scale, 0.0f);
}
// Computing oneDNN's scaling mask which determines along which dimension
// slice should the scaling be applied.
int CreateMask(int slice_dimension, bool is_multi_channel_quantizied) {
return is_multi_channel_quantizied ? 1 << slice_dimension : 0;
}
std::shared_ptr<dnnl::memory> AcquireMemoryWithReorderAndAttrs(
const dnnl::memory::desc& user_md,
const dnnl::memory::desc& target_md,
void* ptr,
const dnnl::primitive_attr& attrs,
const std::vector<float>& scale_data) {
std::shared_ptr<dnnl::memory> target_memory_p;
auto user_memory_p =
std::make_shared<dnnl::memory>(user_md, this->engine_, ptr);
target_memory_p = std::make_shared<dnnl::memory>(target_md, this->engine_);
auto reorder_p = std::make_shared<dnnl::reorder>(
*user_memory_p, *target_memory_p, attrs);
auto scales_md =
dnnl::memory::desc({static_cast<int64_t>(scale_data.size())},
dnnl::memory::data_type::f32,
dnnl::memory::format_tag::x);
auto scale_mem =
dnnl::memory(scales_md,
this->engine_,
funcs::to_void_cast<float>(scale_data.data()));
auto& astream = OneDNNContext::tls().get_stream();
{
reorder_p->execute(astream,
{{DNNL_ARG_FROM, *user_memory_p},
{DNNL_ARG_TO, *target_memory_p},
{DNNL_ARG_ATTR_SCALES | DNNL_ARG_SRC, scale_mem}});
astream.wait();
}
return target_memory_p;
}
std::string memory_key_;
const OneDNNContext& dev_ctx_;
dnnl::memory src_scales_mem_;
dnnl::memory wei_scales_mem_;
dnnl::memory dst_scales_mem_;
public:
std::shared_ptr<dnnl::memory> AcquireSrcMemoryWithReorder(
const DenseTensor* x) {
const T_in* x_data = x->data<T_in>();
auto user_md = x->mem_desc();
if (x->dims().size() != 2) {
// reshape restrictions are always satisfied because in case of 3 or 4 dim
// input, plain layout is enforced
user_md = user_md.reshape(this->fwd_pd_->src_desc().get_dims());
}
return this->AcquireMemoryWithReorder(
user_md, this->fwd_pd_->src_desc(), to_void_cast<T_in>(x_data));
}
std::shared_ptr<dnnl::memory> AcquireBiasMemoryWithReorder(
const DenseTensor* bias) {
const float* bias_data = bias->data<float>();
return this->AcquireMemoryFromPrimitive(this->fwd_pd_->bias_desc(),
to_void_cast<float>(bias_data));
}
std::shared_ptr<dnnl::memory> AcquireWeightsMemoryWithReorder(
const DenseTensor* weights, const std::vector<float>& scale_data) {
const std::string weights_base_key = this->memory_key_ + "@weights";
std::string weights_key;
weights_key.reserve(128);
weights_key = funcs::ExtendKeyWithThreadInfoIfNeeded(
dev_ctx_,
funcs::CreateKey(
dev_ctx_, weights_base_key, this->fwd_pd_->weights_desc()));
auto memory_p = std::static_pointer_cast<dnnl::memory>(
this->dev_ctx_.GetBlob(weights_key));
if (!memory_p) {
const float* weights_data = weights->data<float>();
auto weights_dims = this->fwd_pd_->weights_desc().get_dims();
auto user_md = dnnl::memory::desc(weights_dims,
OneDNNGetDataType<float>(),
dnnl::memory::format_tag::io);
if (funcs::is_int8<T_w>()) {
dnnl::primitive_attr attrs;
int mask = CreateMask(0, scale_data.size() > 1);
attrs.set_scales_mask(DNNL_ARG_SRC, mask);
memory_p = this->AcquireMemoryWithReorderAndAttrs(
user_md,
this->fwd_pd_->weights_desc(),
to_void_cast<float>(weights_data),
attrs,
scale_data);
} else {
memory_p =
this->AcquireMemoryWithReorder(user_md,
this->fwd_pd_->weights_desc(),
to_void_cast<float>(weights_data));
}
this->dev_ctx_.SetBlob(weights_key, memory_p);
}
return memory_p;
}
std::shared_ptr<dnnl::memory> AcquireCustomDstMemory(DenseTensor* out) {
return this->template AcquireDstMemory<T_out>(out);
} // namespace operators
void SetScalesIfNeeded(std::unordered_map<int, dnnl::memory>* args) {
if (src_scales_mem_.get_desc().is_zero() != true) {
args->insert({DNNL_ARG_ATTR_SCALES | DNNL_ARG_SRC, src_scales_mem_});
args->insert({DNNL_ARG_ATTR_SCALES | DNNL_ARG_WEIGHTS, wei_scales_mem_});
}
// dst scales may be empty when force fp32 output
if (dst_scales_mem_.get(true)) {
args->insert({DNNL_ARG_ATTR_SCALES | DNNL_ARG_DST, dst_scales_mem_});
}
}
};
#define IF_CHANGE_FC_TW_TYPENAME(condition, ...) \
if (condition) { \
using T_w = int8_t; \
__VA_ARGS__(); \
} else { \
using T_w = T; \
__VA_ARGS__(); \
}
void RecomputeOutputDims(const int in_num_col_dims,
const bool padding_weights,
const DenseTensor* x,
const DenseTensor* weights,
DenseTensor* out) {
PADDLE_ENFORCE_EQ(padding_weights,
false,
common::errors::PermissionDenied(
"Weight padding in fc can not be used in oneDNN."));
std::vector<int64_t> output_dims;
funcs::FCOutputSize(x->dims(),
weights->dims(),
output_dims,
in_num_col_dims,
padding_weights);
out->Resize(output_dims);
out->set_lod(x->lod());
}
template <typename T>
void PrepareSrcMem(const std::shared_ptr<dnnl::inner_product_forward>& fc_p
UNUSED,
const std::shared_ptr<dnnl::memory>& src_mem,
const DenseTensor* x,
const dnnl::engine& engine) {
auto x_md = x->mem_desc().reshape(src_mem->get_desc().get_dims());
if (x_md != src_mem->get_desc()) {
dnnl::memory x_mem(x_md, engine, to_void_cast<T>(x->data<T>()));
auto reorder_p = dnnl::reorder(x_mem, *src_mem);
auto& astream = OneDNNContext::tls().get_stream();
reorder_p.execute(astream, x_mem, *src_mem);
astream.wait();
} else {
src_mem->set_data_handle(to_void_cast<T>(x->data<T>()));
}
}
template <typename T, typename T_out, typename T_w>
void RunKernel(const phi::OneDNNContext& dev_ctx,
const DenseTensor& input,
const DenseTensor& w,
const optional<DenseTensor>& bias,
const int in_num_col_dims,
const std::string& activation_type,
const bool use_onednn,
const bool padding_weights,
const bool use_quantizer,
const std::string& mkldnn_data_type,
const float scale_in,
const std::vector<float>& scale_weights,
const float scale_out,
const bool force_fp32_output,
DenseTensor* out) {
const auto& onednn_engine = dev_ctx.GetEngine();
std::shared_ptr<dnnl::inner_product_forward> fc_p;
std::shared_ptr<dnnl::memory> src_memory_p;
std::shared_ptr<dnnl::memory> weights_memory_p;
std::shared_ptr<dnnl::memory> bias_memory_p;
std::shared_ptr<dnnl::memory> dst_memory_p;
std::string cache_key;
cache_key.reserve(64);
cache_key = funcs::ExtendKeyWithThreadInfoIfNeeded(
dev_ctx,
funcs::CreateKey(dev_ctx,
dev_ctx.GetInputsName("Input")[0],
dev_ctx.GetInputsName("W")[0],
vectorize(input.dims()),
vectorize(w.dims())));
auto inner_product_cache =
std::static_pointer_cast<InnerProductCache>(dev_ctx.GetBlob(cache_key));
RecomputeOutputDims(in_num_col_dims, padding_weights, &input, &w, out);
std::unordered_map<int, dnnl::memory> fc_args;
if (inner_product_cache) {
fc_p = std::make_shared<dnnl::inner_product_forward>(
inner_product_cache->inner_product_p);
src_memory_p = std::make_shared<dnnl::memory>(inner_product_cache->src_mem);
PrepareSrcMem<T>(fc_p, src_memory_p, &input, onednn_engine);
weights_memory_p =
std::make_shared<dnnl::memory>(inner_product_cache->weights_mem);
dst_memory_p = std::make_shared<dnnl::memory>(inner_product_cache->dst_mem);
auto out_ptr =
dev_ctx.template Alloc<T_out>(out, dst_memory_p->get_desc().get_size());
dst_memory_p->set_data_handle(out_ptr);
fc_args.insert({DNNL_ARG_SRC, *src_memory_p});
fc_args.insert({DNNL_ARG_WEIGHTS, *weights_memory_p});
fc_args.insert({DNNL_ARG_DST, *dst_memory_p});
if (bias) {
bias_memory_p =
std::make_shared<dnnl::memory>(inner_product_cache->bias_mem);
fc_args.insert({DNNL_ARG_BIAS, *bias_memory_p});
}
if (inner_product_cache->src_scales_mem.get(true)) {
fc_args.insert({DNNL_ARG_ATTR_SCALES | DNNL_ARG_SRC,
inner_product_cache->src_scales_mem});
fc_args.insert({DNNL_ARG_ATTR_SCALES | DNNL_ARG_WEIGHTS,
inner_product_cache->wei_scales_mem});
}
if (inner_product_cache->dst_scales_mem.get(true)) {
fc_args.insert({DNNL_ARG_ATTR_SCALES | DNNL_ARG_DST,
inner_product_cache->dst_scales_mem});
}
} else {
// here
FCOneDNNHandler<T, T_w, T_out> handler(dev_ctx,
&input,
&w,
bias.get_ptr(),
out,
scale_in,
scale_out,
scale_weights,
force_fp32_output,
in_num_col_dims,
activation_type,
onednn_engine,
dev_ctx.GetPlace());
src_memory_p = handler.AcquireSrcMemoryWithReorder(&input);
weights_memory_p =
handler.AcquireWeightsMemoryWithReorder(&w, scale_weights);
dst_memory_p = handler.AcquireCustomDstMemory(out);
fc_args.insert({DNNL_ARG_SRC, *src_memory_p});
fc_args.insert({DNNL_ARG_WEIGHTS, *weights_memory_p});
fc_args.insert({DNNL_ARG_DST, *dst_memory_p});
if (bias) {
bias_memory_p = handler.AcquireBiasMemoryWithReorder(bias.get_ptr());
fc_args.insert({DNNL_ARG_BIAS, *bias_memory_p});
}
if (funcs::is_int8<T>()) {
handler.SetScalesIfNeeded(&fc_args);
}
fc_p = handler.AcquireForwardPrimitive();
}
auto& astream = OneDNNContext::tls().get_stream();
fc_p->execute(astream, fc_args);
astream.wait();
if (!inner_product_cache) {
auto ip_cache = std::make_shared<InnerProductCache>();
ip_cache->inner_product_p = *fc_p;
ip_cache->src_mem = *src_memory_p;
ip_cache->weights_mem = *weights_memory_p;
ip_cache->dst_mem = *dst_memory_p;
if (bias) {
ip_cache->bias_mem = *bias_memory_p;
}
if (fc_args.count(DNNL_ARG_ATTR_SCALES | DNNL_ARG_SRC)) {
ip_cache->src_scales_mem =
fc_args.at(DNNL_ARG_ATTR_SCALES | DNNL_ARG_SRC);
ip_cache->wei_scales_mem =
fc_args.at(DNNL_ARG_ATTR_SCALES | DNNL_ARG_WEIGHTS);
}
if (fc_args.count(DNNL_ARG_ATTR_SCALES | DNNL_ARG_DST)) {
ip_cache->dst_scales_mem =
fc_args.at(DNNL_ARG_ATTR_SCALES | DNNL_ARG_DST);
}
dev_ctx.SetBlob(cache_key, ip_cache);
}
const auto out_md = dst_memory_p->get_desc().reshape(vectorize(out->dims()));
std::vector<int> reshape2_shape = {};
if (dev_ctx.HasDnnAttr("fused_reshape2_shape")) {
reshape2_shape = PADDLE_GET_CONST(
std::vector<int>, dev_ctx.GetDnnAttr("fused_reshape2_shape"));
}
if (!reshape2_shape.empty()) {
funcs::SetOutMemDescWithReshape2FuseSupport(reshape2_shape, out, out_md);
} else {
out->set_mem_desc(out_md);
}
}
template <typename T, typename Context>
void FCKernel(const Context& dev_ctx,
const DenseTensor& input,
const DenseTensor& w,
const optional<DenseTensor>& bias,
const int in_num_col_dims,
const std::string& activation_type,
const bool padding_weights,
DenseTensor* out) {
const bool use_mkldnn =
dev_ctx.HasDnnAttr("use_mkldnn")
? PADDLE_GET_CONST(bool, dev_ctx.GetDnnAttr("use_mkldnn"))
: false;
const bool use_onednn =
(!use_mkldnn && dev_ctx.HasDnnAttr("use_onednn"))
? PADDLE_GET_CONST(bool, dev_ctx.GetDnnAttr("use_onednn"))
: use_mkldnn;
const bool use_quantizer =
dev_ctx.HasDnnAttr("use_quantizer")
? PADDLE_GET_CONST(bool, dev_ctx.GetDnnAttr("use_quantizer"))
: false;
const std::string mkldnn_data_type =
dev_ctx.HasDnnAttr("mkldnn_data_type")
? PADDLE_GET_CONST(std::string,
dev_ctx.GetDnnAttr("mkldnn_data_type"))
: "float32";
const std::string onednn_data_type =
(use_onednn && dev_ctx.HasDnnAttr("onednn_data_type"))
? PADDLE_GET_CONST(std::string,
dev_ctx.GetDnnAttr("onednn_data_type"))
: mkldnn_data_type;
const float scale_in =
dev_ctx.HasDnnAttr("Scale_in")
? PADDLE_GET_CONST(float, dev_ctx.GetDnnAttr("Scale_in"))
: 1.0f;
std::vector<float> tmp_scale_weights = {1.0f};
const std::vector<float> scale_weights =
dev_ctx.HasDnnAttr("Scale_weights")
? PADDLE_GET_CONST(std::vector<float>,
dev_ctx.GetDnnAttr("Scale_weights"))
: tmp_scale_weights;
const float scale_out =
dev_ctx.HasDnnAttr("Scale_out")
? PADDLE_GET_CONST(float, dev_ctx.GetDnnAttr("Scale_out"))
: 1.0f;
const bool force_fp32_output =
dev_ctx.HasDnnAttr("force_fp32_output")
? PADDLE_GET_CONST(bool, dev_ctx.GetDnnAttr("force_fp32_output"))
: false;
std::vector<std::string> onednn_data_type_list = {
"float32", "int8", "bfloat16"};
PADDLE_ENFORCE_EQ(std::find(onednn_data_type_list.begin(),
onednn_data_type_list.end(),
onednn_data_type) != onednn_data_type_list.end(),
true,
common::errors::InvalidArgument(
"The onednn_data_type should be [float32, "
"int8, bfloat16], but found %s.",
onednn_data_type.c_str()));
auto in_dims = input.dims();
if (use_onednn) {
PADDLE_ENFORCE_EQ(
in_dims.size() >= 2 && in_dims.size() <= 4,
true,
common::errors::Unimplemented(
"The Input of fc is expected to be a 2-D, 3-D or 4-D tensor when "
"use_onednn is set. But received the number of Input's "
"dimensions is %d, Input's shape is %s.",
in_dims.size(),
in_dims));
}
bool fuse_relu = activation_type == "relu";
IF_CHANGE_FC_TW_TYPENAME((std::is_same<T, uint8_t>::value), ([&] {
if (force_fp32_output) { // NOLINT
RunKernel<T, float, T_w>(dev_ctx,
input,
w,
bias,
in_num_col_dims,
activation_type,
use_onednn,
padding_weights,
use_quantizer,
onednn_data_type,
scale_in,
scale_weights,
scale_out,
force_fp32_output,
out);
} else if (funcs::is_int8<T>()) {
if (fuse_relu) {
RunKernel<T, uint8_t, T_w>(dev_ctx,
input,
w,
bias,
in_num_col_dims,
activation_type,
use_onednn,
padding_weights,
use_quantizer,
onednn_data_type,
scale_in,
scale_weights,
scale_out,
force_fp32_output,
out);
} else {
RunKernel<T, int8_t, T_w>(dev_ctx,
input,
w,
bias,
in_num_col_dims,
activation_type,
use_onednn,
padding_weights,
use_quantizer,
onednn_data_type,
scale_in,
scale_weights,
scale_out,
force_fp32_output,
out);
}
} else {
RunKernel<T, T, T_w>(dev_ctx,
input,
w,
bias,
in_num_col_dims,
activation_type,
use_onednn,
padding_weights,
use_quantizer,
onednn_data_type,
scale_in,
scale_weights,
scale_out,
force_fp32_output,
out);
}
}));
}
} // namespace phi::fusion
PD_REGISTER_KERNEL(fc,
OneDNN,
ONEDNN,
phi::fusion::FCKernel,
float,
phi::bfloat16,
uint8_t,
int8_t) {}