505 lines
22 KiB
C++
505 lines
22 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 "glog/logging.h"
|
|
#include "paddle/phi/backends/xpu/enforce_xpu.h"
|
|
#include "paddle/phi/core/kernel_registry.h"
|
|
|
|
#ifdef PADDLE_WITH_XPU_XRE5
|
|
#include "xblas/cublasLt.h"
|
|
namespace xblas = baidu::xpu::xblas;
|
|
#endif
|
|
|
|
namespace phi {
|
|
namespace fusion {
|
|
|
|
using XPUTypeFP16 = typename XPUTypeTrait<phi::float16>::Type;
|
|
using XPUTypeBF16 = typename XPUTypeTrait<phi::bfloat16>::Type;
|
|
|
|
template <typename T_X,
|
|
typename T_W,
|
|
typename T_OUT,
|
|
typename T_GEMM,
|
|
typename Context>
|
|
void FcXPUKernelImpl(const Context& dev_ctx,
|
|
const DenseTensor& x,
|
|
const optional<DenseTensor>& x_max,
|
|
const DenseTensor& w,
|
|
const optional<DenseTensor>& w_max,
|
|
const optional<DenseTensor>& bias,
|
|
const optional<DenseTensor>& scale_max,
|
|
const optional<DenseTensor>& out_max_in,
|
|
int in_num_col_dims,
|
|
bool transpose_x,
|
|
float alpha,
|
|
float beta,
|
|
int act_type,
|
|
float act_alpha,
|
|
DenseTensor* out,
|
|
DenseTensor* out_max) {
|
|
using XPUTypeX = typename XPUTypeTrait<T_X>::Type;
|
|
using XPUTypeW = typename XPUTypeTrait<T_W>::Type;
|
|
using XPUTypeOut = typename XPUTypeTrait<T_OUT>::Type;
|
|
auto in_mat_dims = flatten_to_2d(x.dims(), in_num_col_dims);
|
|
int m = in_mat_dims[0];
|
|
int k = in_mat_dims[1];
|
|
int64_t n = w.dims()[0];
|
|
|
|
// NOTE(large-tensor): XPU fc_fusion API not support int64
|
|
PADDLE_ENFORCE_LE_INT_MAX(n, "n");
|
|
|
|
auto* x_data = reinterpret_cast<const XPUTypeX*>(x.data<T_X>());
|
|
const float* x_max_data =
|
|
x_max.get_ptr() == nullptr ? nullptr : x_max.get_ptr()->data<float>();
|
|
auto* w_data = reinterpret_cast<const XPUTypeW*>(w.data<T_W>());
|
|
const float* w_max_data =
|
|
w_max.get_ptr() == nullptr ? nullptr : w_max.get_ptr()->data<float>();
|
|
const float* bias_data =
|
|
bias.get_ptr() == nullptr ? nullptr : bias.get_ptr()->data<float>();
|
|
auto* out_data =
|
|
reinterpret_cast<XPUTypeOut*>(dev_ctx.template Alloc<T_OUT>(out));
|
|
auto* scale_max_data = scale_max.get_ptr() == nullptr
|
|
? nullptr
|
|
: scale_max.get_ptr()->data<float>();
|
|
float* out_max_data = nullptr;
|
|
// when T_OUT is float and TGEMM is int8_t, out_max_data should better set to
|
|
// nullptr for better performance
|
|
if (!(std::is_same<T_OUT, float>::value &&
|
|
std::is_same<T_GEMM, int8_t>::value)) {
|
|
out_max_data = dev_ctx.template Alloc<float>(out_max);
|
|
out_max_data = out_max_in.get_ptr() != nullptr
|
|
? const_cast<float*>(out_max_in.get_ptr()->data<float>())
|
|
: out_max_data;
|
|
}
|
|
|
|
xpu::Activation_t act(static_cast<xpu::Activation_t::act_enum>(act_type));
|
|
if (act_type == xpu::Activation_t::LEAKY_RELU) {
|
|
act.leaky_alpha = act_alpha;
|
|
} else if (act_type == xpu::Activation_t::HARD_SIGMOID) {
|
|
act.hard_sigmoid_slope = act_alpha;
|
|
}
|
|
// only for xpu3
|
|
#ifdef PADDLE_WITH_XPU_XRE5
|
|
if constexpr (std::is_same<T_X, bfloat16>::value &&
|
|
std::is_same<T_W, bfloat16>::value &&
|
|
std::is_same<T_OUT, bfloat16>::value) {
|
|
// use xte to speedup bfloat16 calc
|
|
// whether to enable this feature requires a trade-off between performance
|
|
// precision
|
|
if (std::getenv("XPU_PADDLE_FC_BFLOAT16_XTE") != nullptr) {
|
|
xpu::ctx_guard RAII_GUARD(dev_ctx.x_context());
|
|
const int MAXPTR_N = dev_ctx.x_context()->max_ptr_size();
|
|
int x_len = m * k;
|
|
XPUTypeFP16* x_data_fp16 = nullptr;
|
|
x_data_fp16 = RAII_GUARD.alloc_l3_or_gm<XPUTypeFP16>(x_len);
|
|
PADDLE_ENFORCE_XDNN_NOT_NULL(x_data_fp16);
|
|
int w_len = k * n;
|
|
XPUTypeFP16* w_data_fp16 = nullptr;
|
|
w_data_fp16 = RAII_GUARD.alloc_l3_or_gm<XPUTypeFP16>(w_len);
|
|
PADDLE_ENFORCE_XDNN_NOT_NULL(w_data_fp16);
|
|
|
|
float* xte_scale_x = nullptr;
|
|
float* xte_scale_w = nullptr;
|
|
xte_scale_x = RAII_GUARD.alloc_l3_or_gm<float>(1);
|
|
PADDLE_ENFORCE_XDNN_NOT_NULL(xte_scale_x);
|
|
xte_scale_w = RAII_GUARD.alloc_l3_or_gm<float>(1);
|
|
PADDLE_ENFORCE_XDNN_NOT_NULL(xte_scale_w);
|
|
|
|
float* xte_x_maxptr = nullptr;
|
|
float* xte_w_maxptr = nullptr;
|
|
if (x_max_data == nullptr) {
|
|
xte_x_maxptr = RAII_GUARD.alloc_l3_or_gm<float>(MAXPTR_N);
|
|
PADDLE_ENFORCE_XDNN_NOT_NULL(xte_x_maxptr);
|
|
int r = xpu::findmax(dev_ctx.x_context(), x_data, xte_x_maxptr, x_len);
|
|
PADDLE_ENFORCE_XDNN_SUCCESS(r, "xpu_findmax");
|
|
r = xpu::cast_te(dev_ctx.x_context(),
|
|
x_data,
|
|
xte_x_maxptr,
|
|
x_data_fp16,
|
|
xte_scale_x,
|
|
x_len);
|
|
PADDLE_ENFORCE_XDNN_SUCCESS(r, "xpu_cast_te");
|
|
} else {
|
|
int r = xpu::cast_te(dev_ctx.x_context(),
|
|
x_data,
|
|
x_max_data,
|
|
x_data_fp16,
|
|
xte_scale_x,
|
|
x_len);
|
|
PADDLE_ENFORCE_XDNN_SUCCESS(r, "xpu_cast_te");
|
|
}
|
|
if (w_max_data == nullptr) {
|
|
xte_w_maxptr = RAII_GUARD.alloc_l3_or_gm<float>(MAXPTR_N);
|
|
PADDLE_ENFORCE_XDNN_NOT_NULL(xte_w_maxptr);
|
|
int r = xpu::findmax(dev_ctx.x_context(), w_data, xte_w_maxptr, w_len);
|
|
PADDLE_ENFORCE_XDNN_SUCCESS(r, "xpu_findmax");
|
|
r = xpu::cast_te(dev_ctx.x_context(),
|
|
w_data,
|
|
xte_w_maxptr,
|
|
w_data_fp16,
|
|
xte_scale_w,
|
|
w_len);
|
|
PADDLE_ENFORCE_XDNN_SUCCESS(r, "xpu_cast_te");
|
|
} else {
|
|
int r = xpu::cast_te(dev_ctx.x_context(),
|
|
w_data,
|
|
w_max_data,
|
|
w_data_fp16,
|
|
xte_scale_w,
|
|
w_len);
|
|
PADDLE_ENFORCE_XDNN_SUCCESS(r, "xpu_cast_te");
|
|
}
|
|
baidu::xpu::xblas::FcFusionTensor<const XPUTypeFP16> tensor_a1{
|
|
x_data_fp16,
|
|
x_max_data ? x_max_data : xte_x_maxptr,
|
|
transpose_x ? k : m,
|
|
transpose_x ? m : k,
|
|
transpose_x ? m : k,
|
|
transpose_x};
|
|
baidu::xpu::xblas::FcFusionTensor<const XPUTypeFP16> tensor_b1{
|
|
w_data_fp16, w_max_data ? w_max_data : xte_w_maxptr, n, k, k, true};
|
|
baidu::xpu::xblas::FcFusionTensor<const XPUTypeBF16> tensor_c1{
|
|
out_data, nullptr, m, n, n, false};
|
|
baidu::xpu::xblas::FcFusionTensor<XPUTypeBF16> tensor_d1{
|
|
out_data, nullptr, m, n, n, false};
|
|
baidu::xpu::xblas::FcFusionDesc<XPUTypeFP16, float, float> desc{alpha,
|
|
beta};
|
|
|
|
baidu::xpu::xblas::FcFusionEpilogue<float, float> epilogue1{
|
|
act, bias_data, xte_scale_x, xte_scale_w, 0, 0, out_max_data};
|
|
|
|
if (act_type == xpu::Activation_t::SWISH_GLU) {
|
|
tensor_d1 = baidu::xpu::xblas::FcFusionTensor<XPUTypeBF16>{
|
|
out_data, nullptr, m, n / 2, n / 2, false};
|
|
} else {
|
|
tensor_d1 = baidu::xpu::xblas::FcFusionTensor<XPUTypeBF16>{
|
|
out_data, nullptr, m, n, n, false};
|
|
}
|
|
|
|
int r = baidu::xpu::xblas::fc_fusion<XPUTypeFP16,
|
|
XPUTypeFP16,
|
|
XPUTypeBF16,
|
|
XPUTypeBF16,
|
|
XPUTypeFP16,
|
|
float,
|
|
float,
|
|
float,
|
|
float>(dev_ctx.x_context(),
|
|
tensor_a1,
|
|
tensor_b1,
|
|
tensor_c1,
|
|
tensor_d1,
|
|
desc,
|
|
epilogue1);
|
|
|
|
PADDLE_ENFORCE_XBLAS_SUCCESS(r, "xblas_fc_fusion");
|
|
}
|
|
}
|
|
if (std::getenv("XPU_PADDLE_FC_BFLOAT16_XTE") == nullptr) {
|
|
if constexpr (((std::is_same<T_X, float16>::value &&
|
|
std::is_same<T_W, int16_t>::value &&
|
|
std::is_same<T_GEMM, int16_t>::value &&
|
|
std::is_same<T_OUT, float>::value) ||
|
|
(std::is_same<T_X, float>::value &&
|
|
std::is_same<T_W, int16_t>::value &&
|
|
std::is_same<T_GEMM, int16_t>::value &&
|
|
std::is_same<T_OUT, float16>::value) ||
|
|
(std::is_same<T_X, float>::value &&
|
|
std::is_same<T_W, signed char>::value &&
|
|
std::is_same<T_GEMM, signed char>::value &&
|
|
std::is_same<T_OUT, signed char>::value))) {
|
|
int r = xpu::
|
|
fc_fusion<XPUTypeX, XPUTypeW, XPUTypeOut, T_GEMM>( // TX/TW/TY/TGEMM
|
|
dev_ctx.x_context(), // ctx
|
|
x_data, // x
|
|
w_data, // w
|
|
out_data, // y
|
|
m, // m
|
|
n, // n
|
|
k, // k
|
|
transpose_x, // x_trans
|
|
true, // w_trans
|
|
x_max_data, // x_maxptr
|
|
w_max_data, // w_maxptr
|
|
out_max_data, // y_maxptr
|
|
transpose_x ? m : k, // ldx
|
|
k, // ldw
|
|
n, // ldy
|
|
alpha, // alpha
|
|
beta, // beta
|
|
bias_data, // bias
|
|
act, // act
|
|
scale_max_data); // scale
|
|
PADDLE_ENFORCE_XDNN_SUCCESS(r, "fc_xpu");
|
|
} else {
|
|
baidu::xpu::xblas::FcFusionTensor<const XPUTypeX> tensor_a1{
|
|
x_data,
|
|
x_max_data,
|
|
transpose_x ? k : m,
|
|
transpose_x ? m : k,
|
|
transpose_x ? m : k,
|
|
transpose_x};
|
|
baidu::xpu::xblas::FcFusionTensor<const XPUTypeW> tensor_b1{
|
|
w_data, w_max_data, n, k, k, true};
|
|
baidu::xpu::xblas::FcFusionTensor<const XPUTypeOut> tensor_c1{
|
|
out_data, nullptr, m, n, n, false};
|
|
baidu::xpu::xblas::FcFusionTensor<XPUTypeOut> tensor_d1{
|
|
out_data, nullptr, m, n, n, false};
|
|
baidu::xpu::xblas::FcFusionDesc<T_GEMM, float, XPUTypeOut> desc{alpha,
|
|
beta};
|
|
|
|
baidu::xpu::xblas::FcFusionEpilogue<float, float> epilogue1{
|
|
act, bias_data, scale_max_data, nullptr, 0, 0, out_max_data};
|
|
|
|
if (act_type == xpu::Activation_t::SWISH_GLU) {
|
|
tensor_d1 = baidu::xpu::xblas::FcFusionTensor<XPUTypeOut>{
|
|
out_data, nullptr, m, n / 2, n / 2, false};
|
|
} else {
|
|
tensor_d1 = baidu::xpu::xblas::FcFusionTensor<XPUTypeOut>{
|
|
out_data, nullptr, m, n, n, false};
|
|
}
|
|
int r = baidu::xpu::xblas::fc_fusion<XPUTypeX,
|
|
XPUTypeW,
|
|
XPUTypeOut,
|
|
XPUTypeOut,
|
|
T_GEMM,
|
|
float,
|
|
XPUTypeOut,
|
|
float,
|
|
float>(dev_ctx.x_context(),
|
|
tensor_a1,
|
|
tensor_b1,
|
|
tensor_c1,
|
|
tensor_d1,
|
|
desc,
|
|
epilogue1);
|
|
PADDLE_ENFORCE_XBLAS_SUCCESS(r, "xblas_fc_fusion");
|
|
}
|
|
}
|
|
#else
|
|
int r =
|
|
xpu::fc_fusion<XPUTypeX, XPUTypeW, XPUTypeOut, T_GEMM>( // TX/TW/TY/TGEMM
|
|
dev_ctx.x_context(), // ctx
|
|
x_data, // x
|
|
w_data, // w
|
|
out_data, // y
|
|
m, // m
|
|
n, // n
|
|
k, // k
|
|
transpose_x, // x_trans
|
|
true, // w_trans
|
|
x_max_data, // x_maxptr
|
|
w_max_data, // w_maxptr
|
|
out_max_data, // y_maxptr
|
|
transpose_x ? m : k, // ldx
|
|
k, // ldw
|
|
n, // ldy
|
|
alpha, // alpha
|
|
beta, // beta
|
|
bias_data, // bias
|
|
act, // act
|
|
scale_max_data); // scale
|
|
|
|
PADDLE_ENFORCE_XDNN_SUCCESS(r, "fc_xpu");
|
|
#endif
|
|
}
|
|
|
|
#define FC_XPU_KERNEL_IMPL(x_dtype_, w_dtype_, out_dtype_, gemm_dtype_) \
|
|
FcXPUKernelImpl<x_dtype_, w_dtype_, out_dtype_, gemm_dtype_>( \
|
|
dev_ctx, \
|
|
x, \
|
|
x_max, \
|
|
w, \
|
|
w_max, \
|
|
bias, \
|
|
scale_max, \
|
|
out_max_in, \
|
|
in_num_col_dims, \
|
|
transpose_x, \
|
|
alpha, \
|
|
beta, \
|
|
act_type, \
|
|
act_alpha, \
|
|
out, \
|
|
out_max);
|
|
|
|
template <typename T, typename Context>
|
|
void FcXPUKernel(const Context& dev_ctx,
|
|
const DenseTensor& x,
|
|
const optional<DenseTensor>& x_max,
|
|
const DenseTensor& w,
|
|
const optional<DenseTensor>& w_max,
|
|
const optional<DenseTensor>& bias,
|
|
const optional<DenseTensor>& scale_max,
|
|
const optional<DenseTensor>& out_max_in,
|
|
int in_num_col_dims,
|
|
bool transpose_x,
|
|
float alpha,
|
|
float beta,
|
|
int act_type,
|
|
float act_alpha,
|
|
DataType out_dtype,
|
|
DenseTensor* out,
|
|
DenseTensor* out_max) {
|
|
// Dont use template T param
|
|
VLOG(4) << "Fc kernel type: " << x.dtype() << " ," << w.dtype() << " ,"
|
|
<< out_dtype;
|
|
if (x.dtype() == DataType::FLOAT32) {
|
|
// float32/float16 kernel
|
|
if (w.dtype() == DataType::INT16) {
|
|
if (out_dtype == DataType::FLOAT32) {
|
|
FC_XPU_KERNEL_IMPL(float, int16_t, float, int16_t);
|
|
} else if (out_dtype == DataType::FLOAT16) {
|
|
FC_XPU_KERNEL_IMPL(float, int16_t, dtype::float16, int16_t);
|
|
} else {
|
|
PADDLE_THROW(common::errors::Unimplemented(
|
|
"Not support x_dtype is %s, w_dtype is %s and out_dtype is "
|
|
"%s.",
|
|
DataTypeToString(x.dtype()),
|
|
DataTypeToString(w.dtype()),
|
|
DataTypeToString(out_dtype)));
|
|
}
|
|
} else if (w.dtype() == DataType::INT8) {
|
|
if (out_dtype == DataType::FLOAT32) {
|
|
FC_XPU_KERNEL_IMPL(float, int8_t, float, int8_t);
|
|
} else if (out_dtype == DataType::INT8) {
|
|
FC_XPU_KERNEL_IMPL(float, int8_t, int8_t, int8_t);
|
|
} else if (out_dtype == DataType::FLOAT16) {
|
|
FC_XPU_KERNEL_IMPL(float, int8_t, dtype::float16, int8_t);
|
|
} else {
|
|
PADDLE_THROW(common::errors::Unimplemented(
|
|
"Not support x_dtype is %s, w_dtype is %s and out_dtype is "
|
|
"%s.",
|
|
DataTypeToString(x.dtype()),
|
|
DataTypeToString(w.dtype()),
|
|
DataTypeToString(out_dtype)));
|
|
}
|
|
} else if (w.dtype() == DataType::FLOAT32) {
|
|
FC_XPU_KERNEL_IMPL(float, float, float, int32_t);
|
|
} else {
|
|
PADDLE_THROW(common::errors::Unimplemented(
|
|
"Not support x_dtype is %s, w_dtype is %s and out_dtype is %s.",
|
|
DataTypeToString(x.dtype()),
|
|
DataTypeToString(w.dtype()),
|
|
DataTypeToString(out_dtype)));
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (x.dtype() == DataType::FLOAT16) {
|
|
// float16 kernel
|
|
if (w.dtype() == DataType::INT16) {
|
|
if (out_dtype == DataType::FLOAT32) {
|
|
FC_XPU_KERNEL_IMPL(phi::float16, int16_t, float, int16_t);
|
|
} else if (out_dtype == DataType::FLOAT16) {
|
|
FC_XPU_KERNEL_IMPL(phi::float16, int16_t, dtype::float16, int16_t);
|
|
} else {
|
|
PADDLE_THROW(common::errors::Unimplemented(
|
|
"Not support x_dtype is %s, w_dtype is %s and out_dtype is "
|
|
"%s.",
|
|
DataTypeToString(x.dtype()),
|
|
DataTypeToString(w.dtype()),
|
|
DataTypeToString(out_dtype)));
|
|
}
|
|
} else if (w.dtype() == DataType::INT8) {
|
|
if (out_dtype == DataType::FLOAT16) {
|
|
FC_XPU_KERNEL_IMPL(phi::float16, int8_t, dtype::float16, int8_t);
|
|
} else if (out_dtype == DataType::INT8) {
|
|
FC_XPU_KERNEL_IMPL(phi::float16, int8_t, int8_t, int8_t);
|
|
} else {
|
|
PADDLE_THROW(common::errors::Unimplemented(
|
|
"Not support x_dtype is %s, w_dtype is %s and out_dtype is "
|
|
"%s.",
|
|
DataTypeToString(x.dtype()),
|
|
DataTypeToString(w.dtype()),
|
|
DataTypeToString(out_dtype)));
|
|
}
|
|
} else {
|
|
PADDLE_THROW(common::errors::Unimplemented(
|
|
"Not support x_dtype is %s, w_dtype is %s and out_dtype is %s.",
|
|
DataTypeToString(x.dtype()),
|
|
DataTypeToString(w.dtype()),
|
|
DataTypeToString(out_dtype)));
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (x.dtype() == DataType::INT8) {
|
|
if (w.dtype() == DataType::INT8) {
|
|
if (out_dtype == DataType::FLOAT32) {
|
|
FC_XPU_KERNEL_IMPL(int8_t, int8_t, float, int8_t);
|
|
} else if (out_dtype == DataType::FLOAT16) {
|
|
FC_XPU_KERNEL_IMPL(int8_t, int8_t, dtype::float16, int8_t);
|
|
} else if (out_dtype == DataType::INT8) {
|
|
FC_XPU_KERNEL_IMPL(int8_t, int8_t, int8_t, int8_t);
|
|
} else {
|
|
PADDLE_THROW(common::errors::Unimplemented(
|
|
"Not support x_dtype is %s, w_dtype is %s and out_dtype is "
|
|
"%s.",
|
|
DataTypeToString(x.dtype()),
|
|
DataTypeToString(w.dtype()),
|
|
DataTypeToString(out_dtype)));
|
|
}
|
|
} else {
|
|
PADDLE_THROW(common::errors::Unimplemented(
|
|
"Not support x_dtype is %s, w_dtype is %s and out_dtype is %s.",
|
|
DataTypeToString(x.dtype()),
|
|
DataTypeToString(w.dtype()),
|
|
DataTypeToString(out_dtype)));
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (x.dtype() == DataType::BFLOAT16) {
|
|
// bfloat16 kernel
|
|
if (w.dtype() == DataType::BFLOAT16) {
|
|
if (out_dtype == DataType::BFLOAT16) {
|
|
FC_XPU_KERNEL_IMPL(phi::bfloat16, phi::bfloat16, phi::bfloat16, float);
|
|
} else {
|
|
PADDLE_THROW(common::errors::Unimplemented(
|
|
"Not support x_dtype is %s, w_dtype is %s and out_dtype is "
|
|
"%s.",
|
|
DataTypeToString(x.dtype()),
|
|
DataTypeToString(w.dtype()),
|
|
DataTypeToString(out_dtype)));
|
|
}
|
|
} else {
|
|
PADDLE_THROW(common::errors::Unimplemented(
|
|
"Not support x_dtype is %s, w_dtype is %s and out_dtype is %s.",
|
|
DataTypeToString(x.dtype()),
|
|
DataTypeToString(w.dtype()),
|
|
DataTypeToString(out_dtype)));
|
|
}
|
|
return;
|
|
}
|
|
|
|
PADDLE_THROW(common::errors::Unimplemented(
|
|
"Not support x_dtype is %s, w_dtype is %s and out_dtype is %s.",
|
|
DataTypeToString(x.dtype()),
|
|
DataTypeToString(w.dtype()),
|
|
DataTypeToString(out_dtype)));
|
|
}
|
|
|
|
} // namespace fusion
|
|
} // namespace phi
|
|
|
|
PD_REGISTER_KERNEL(fc_xpu,
|
|
XPU,
|
|
ALL_LAYOUT,
|
|
phi::fusion::FcXPUKernel,
|
|
float,
|
|
phi::float16,
|
|
int8_t,
|
|
phi::bfloat16) {}
|