// 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. #pragma once #include #include #include "paddle/phi/backends/xpu/enforce_xpu.h" #include "paddle/phi/backends/xpu/xpu_header.h" #include "paddle/phi/backends/xpu/xpu_info.h" #include "paddle/phi/kernels/funcs/blas/blas.h" #ifdef PADDLE_WITH_XPU_XRE5 #include "xblas/cublasLt.h" namespace xblas = baidu::xpu::xblas; #endif namespace phi { using XPUTypeFP16 = typename XPUTypeTrait::Type; using XPUTypeBF16 = typename XPUTypeTrait::Type; enum XPUFCCalcType { FC_INT16 = 0, FC_INT32, FC_FLOAT, FC_INT32_WITH_LL, FC_TF32, FC_FLOAT16, }; using XPUFCCalcTypeMap = std::vector>; inline XPUFCCalcType GetFCCalcTypeFromEnv(const XPUFCCalcTypeMap& env_map, XPUFCCalcType default_calc_type) { for (auto [env_name, calc_type] : env_map) { if (std::getenv(env_name) != nullptr) { return calc_type; } } return default_calc_type; } template inline XPUFCCalcType FCCalcType() { // FLOAT32 XPUFCCalcTypeMap calc_type_map = { {"XPU_PADDLE_FC_FLOAT", XPUFCCalcType::FC_FLOAT}, {"XPU_PADDLE_FC_LOCAL_INT16", XPUFCCalcType::FC_FLOAT}, {"XPU_PADDLE_FC_TF32", XPUFCCalcType::FC_TF32}, {"XPU_PADDLE_FC_INT16", XPUFCCalcType::FC_INT16}, {"XPU_PADDLE_FC_INT32", XPUFCCalcType::FC_INT32}, {"XPU_PADDLE_FC_INT32_WITH_LL", XPUFCCalcType::FC_INT32_WITH_LL}, }; #ifdef PADDLE_WITH_XPU_XRE5 // Use full float32 accumulation by default for better precision, matching // the GPU default (FLAGS_cublas_allow_tf32=false). Users who need TF32 // performance can set env var XPU_PADDLE_FC_TF32. auto default_calc_type = XPUFCCalcType::FC_FLOAT; #else auto default_calc_type = XPUFCCalcType::FC_INT16; #endif return GetFCCalcTypeFromEnv(calc_type_map, default_calc_type); } template <> inline XPUFCCalcType FCCalcType() { XPUFCCalcTypeMap calc_type_map = { {"XPU_PADDLE_FC_FLOAT16", XPUFCCalcType::FC_FLOAT16}, {"XPU_PADDLE_FC_INT16", XPUFCCalcType::FC_INT16}, {"XPU_PADDLE_FC_FLOAT", XPUFCCalcType::FC_FLOAT}, {"XPU_PADDLE_FC_LOCAL_INT16", XPUFCCalcType::FC_FLOAT}}; #ifdef PADDLE_WITH_XPU_XRE5 auto default_calc_type = XPUFCCalcType::FC_FLOAT16; #else auto default_calc_type = XPUFCCalcType::FC_INT16; #endif return GetFCCalcTypeFromEnv(calc_type_map, default_calc_type); } template <> inline XPUFCCalcType FCCalcType() { XPUFCCalcTypeMap calc_type_map = { // TF32 is the default, do not need to be listed here. {"XPU_PADDLE_FC_FLOAT", XPUFCCalcType::FC_FLOAT}, {"XPU_PADDLE_FC_LOCAL_INT16", XPUFCCalcType::FC_FLOAT}}; auto default_calc_type = XPUFCCalcType::FC_TF32; return GetFCCalcTypeFromEnv(calc_type_map, default_calc_type); } struct XpuFcInfo { int64_t bs; int64_t m; int64_t n; int64_t k; bool trans_x; bool trans_y; int64_t stride_x; int64_t stride_y; int64_t stride_out; float* max_x; float* max_y; float* max_out; const float* bias; bool is_x_need_broadcast; bool is_y_need_broadcast; const float* scale_x; const float* scale_y; int scale_x_mode; int scale_y_mode; XpuFcInfo() : bs(0), m(0), n(0), k(0), trans_x(false), trans_y(false), stride_x(0), stride_y(0), stride_out(0), max_x(nullptr), max_y(nullptr), max_out(nullptr), bias(nullptr), is_x_need_broadcast(false), is_y_need_broadcast(false), scale_x(nullptr), scale_y(nullptr), scale_x_mode(0), scale_y_mode(0) {} void InitFcInfo(int64_t bs, int64_t m, int64_t n, int64_t k, bool trans_x, bool trans_y, float* max_x, float* max_y, float* max_out) { this->bs = bs; this->m = m; this->n = n; this->k = k; this->trans_x = trans_x; this->trans_y = trans_y; this->max_x = max_x; this->max_y = max_y; this->max_out = max_out; if (this->bs <= 1) { this->stride_x = trans_x ? m : k; this->stride_y = trans_y ? k : n; this->stride_out = n; } else { this->stride_x = m * k; this->stride_y = k * n; this->stride_out = m * n; } } }; static std::ostream& operator<<(std::ostream& os, const XpuFcInfo& fc_inf) { os << "fc_inf[ bs, m, n, k, trans_x, trans_y, stride_x, stride_y, " "stride_out] = " << "[" << fc_inf.bs << ", " << fc_inf.m << ", " << fc_inf.n << ", " << fc_inf.k << ", " << fc_inf.trans_x << ", " << fc_inf.trans_y << ", " << fc_inf.stride_x << ", " << fc_inf.stride_y << ", " << fc_inf.stride_out; return os; } static void GetFCInfo(const DDim& x_dims, const DDim& y_dims, bool trans_x, bool trans_y, XpuFcInfo* info) { DDim new_x_dims = (x_dims.size() > 1) ? x_dims : make_ddim({1, x_dims[0]}); DDim new_y_dims = (y_dims.size() > 1) ? y_dims : make_ddim({y_dims[0], 1}); auto mat_dim_a = funcs::CreateMatrixDescriptor(new_x_dims, 0, trans_x); auto mat_dim_b = funcs::CreateMatrixDescriptor(new_y_dims, 0, trans_y); if (x_dims.size() >= 3 && y_dims.size() <= 2) { if (!trans_x || mat_dim_a.batch_size_ == 1) { mat_dim_a.height_ *= mat_dim_a.batch_size_; mat_dim_a.batch_size_ = 0; } else { info->is_y_need_broadcast = true; } } if (y_dims.size() >= 3 && x_dims.size() <= 2) { info->is_x_need_broadcast = (mat_dim_b.batch_size_ > 1); } PADDLE_ENFORCE_EQ(mat_dim_a.width_, mat_dim_b.height_, common::errors::InvalidArgument( "Shape mistake in matmul_op xdims = %s ydims = %s " "x_trans = %d y_trans = %d", x_dims.to_str(), y_dims.to_str(), mat_dim_a.trans_, mat_dim_b.trans_)); if (mat_dim_a.batch_size_ == 0 && mat_dim_b.batch_size_ == 1) { mat_dim_a.batch_size_ = mat_dim_b.batch_size_ = 0; } if (mat_dim_a.batch_size_ == 1 && mat_dim_b.batch_size_ == 0) { mat_dim_a.batch_size_ = mat_dim_b.batch_size_ = 0; } info->m = mat_dim_a.height_; info->n = mat_dim_b.width_; info->k = mat_dim_a.width_; info->bs = std::max(mat_dim_a.batch_size_, mat_dim_b.batch_size_); info->trans_x = trans_x; info->trans_y = trans_y; if (info->bs <= 1) { info->stride_x = trans_x ? info->m : info->k; info->stride_y = trans_y ? info->k : info->n; info->stride_out = info->n; } else { info->stride_x = info->m * info->k; info->stride_y = info->k * info->n; info->stride_out = info->m * info->n; } } template static void xblas_fc_wrapper(xpu::Context* xpu_ctx, const XPUType* x, const XPUType* w, XPUType* y, int64_t m, int64_t n, int64_t k, bool x_trans, bool w_trans, const float* x_maxptr, const float* w_maxptr, float* y_maxptr, int64_t ldx, int64_t ldw, int64_t ldy, float alpha, float beta, const float* bias, const xpu::Activation_t& act, const float* scale_x, const float* scale_w, int scale_x_mode, int scale_w_mode) { int r = 0; xpu::ctx_guard RAII_GUARD(xpu_ctx); if (x_trans && std::getenv("XPU_PADDLE_FC_TRANS_A") != nullptr && std::is_same::value) { XPUType* l3_addr = nullptr; l3_addr = RAII_GUARD.alloc_l3_or_gm(m * k); PADDLE_ENFORCE_XDNN_NOT_NULL(l3_addr); std::vector shape = {k, m}; std::vector axis = {1, 0}; r = xpu::transpose(xpu_ctx, x, l3_addr, shape, axis); PADDLE_ENFORCE_XDNN_SUCCESS(r, "transpose"); #ifdef PADDLE_WITH_XPU_XRE5 r = xblas::fc_fusion(xpu_ctx, l3_addr, w, y, m, n, k, false, w_trans, x_maxptr, w_maxptr, y_maxptr, k, ldw, ldy, alpha, beta, bias, act, scale_x, scale_w, scale_x_mode, scale_w_mode); PADDLE_ENFORCE_XBLAS_SUCCESS(r, "xblas_fc_fusion"); #else r = xpu::fc_fusion(xpu_ctx, l3_addr, w, y, m, n, k, false, w_trans, x_maxptr, w_maxptr, y_maxptr, k, ldw, ldy, alpha, beta, bias, act); PADDLE_ENFORCE_XDNN_SUCCESS(r, "xpu_fc_fusion"); #endif } else { #ifdef PADDLE_WITH_XPU_XRE5 if constexpr (std::is_same::value) { if (std::getenv("XPU_PADDLE_FC_BFLOAT16_XTE") != nullptr) { const int MAXPTR_N = xpu_ctx->max_ptr_size(); int64_t x_len = m * k; XPUTypeFP16* x_fp16 = nullptr; x_fp16 = RAII_GUARD.alloc_l3_or_gm(x_len); PADDLE_ENFORCE_XDNN_NOT_NULL(x_fp16); int64_t w_len = k * n; XPUTypeFP16* w_fp16 = nullptr; w_fp16 = RAII_GUARD.alloc_l3_or_gm(w_len); PADDLE_ENFORCE_XDNN_NOT_NULL(w_fp16); float* xte_scale_x = nullptr; float* xte_scale_w = nullptr; xte_scale_x = RAII_GUARD.alloc_l3_or_gm(1); PADDLE_ENFORCE_XDNN_NOT_NULL(xte_scale_x); xte_scale_w = RAII_GUARD.alloc_l3_or_gm(1); PADDLE_ENFORCE_XDNN_NOT_NULL(xte_scale_w); float* xte_x_maxptr = nullptr; float* xte_w_maxptr = nullptr; if (x_maxptr == nullptr) { xte_x_maxptr = RAII_GUARD.alloc_l3_or_gm(MAXPTR_N); PADDLE_ENFORCE_XDNN_NOT_NULL(xte_x_maxptr); int r = xpu::findmax(xpu_ctx, x, xte_x_maxptr, x_len); PADDLE_ENFORCE_XDNN_SUCCESS(r, "xpu_findmax"); r = xpu::cast_te( xpu_ctx, x, xte_x_maxptr, x_fp16, xte_scale_x, x_len); PADDLE_ENFORCE_XDNN_SUCCESS(r, "xpu_cast_te"); } else { r = xpu::cast_te(xpu_ctx, x, x_maxptr, x_fp16, xte_scale_x, x_len); PADDLE_ENFORCE_XDNN_SUCCESS(r, "xpu_cast_te"); } if (w_maxptr == nullptr) { xte_w_maxptr = RAII_GUARD.alloc_l3_or_gm(MAXPTR_N); PADDLE_ENFORCE_XDNN_NOT_NULL(xte_w_maxptr); r = xpu::findmax(xpu_ctx, w, xte_w_maxptr, w_len); PADDLE_ENFORCE_XDNN_SUCCESS(r, "xpu_findmax"); r = xpu::cast_te( xpu_ctx, w, xte_w_maxptr, w_fp16, xte_scale_w, w_len); PADDLE_ENFORCE_XDNN_SUCCESS(r, "xpu_cast_te"); } else { r = xpu::cast_te(xpu_ctx, w, w_maxptr, w_fp16, xte_scale_w, w_len); PADDLE_ENFORCE_XDNN_SUCCESS(r, "xpu_cast_te"); } r = xblas:: fc_fusion( xpu_ctx, x_fp16, w_fp16, y, m, n, k, x_trans, w_trans, x_maxptr ? x_maxptr : xte_x_maxptr, w_maxptr ? w_maxptr : xte_w_maxptr, y_maxptr, ldx, ldw, ldy, alpha, beta, bias, act, xte_scale_x, xte_scale_w, scale_x_mode, scale_w_mode); PADDLE_ENFORCE_XBLAS_SUCCESS(r, "xblas_fc_fusion"); return; } } r = xblas::fc_fusion(xpu_ctx, x, w, y, m, n, k, x_trans, w_trans, x_maxptr, w_maxptr, y_maxptr, ldx, ldw, ldy, alpha, beta, bias, act, scale_x, scale_w, scale_x_mode, scale_w_mode); PADDLE_ENFORCE_XBLAS_SUCCESS(r, "xblas_fc_fusion"); #else r = xpu::fc_fusion(xpu_ctx, x, w, y, m, n, k, x_trans, w_trans, x_maxptr, w_maxptr, y_maxptr, ldx, ldw, ldy, alpha, beta, bias, act); PADDLE_ENFORCE_XDNN_SUCCESS(r, "xpu_fc_fusion"); #endif } } #define DECLARE_UNSUPPORTED_XBLAS_FC_WRAPPER(XPUType, FCT) \ template <> \ void xblas_fc_wrapper(xpu::Context * xpu_ctx, \ const XPUType* x, \ const XPUType* w, \ XPUType* y, \ int64_t m, \ int64_t n, \ int64_t k, \ bool x_trans, \ bool w_trans, \ const float* x_maxptr, \ const float* w_maxptr, \ float* y_maxptr, \ int64_t ldx, \ int64_t ldw, \ int64_t ldy, \ float alpha, \ float beta, \ const float* bias, \ const xpu::Activation_t& act, \ const float* scale_x, \ const float* scale_w, \ int scale_x_mode, \ int scale_w_mode) { \ int r = xpu::Error_t::INVALID_PARAM; \ PADDLE_ENFORCE_XDNN_SUCCESS(r, "xblas_fc_wrapper"); \ } DECLARE_UNSUPPORTED_XBLAS_FC_WRAPPER(XPUTypeBF16, int_with_ll_t) DECLARE_UNSUPPORTED_XBLAS_FC_WRAPPER(XPUTypeBF16, int16_t) DECLARE_UNSUPPORTED_XBLAS_FC_WRAPPER(XPUTypeBF16, int32_t) DECLARE_UNSUPPORTED_XBLAS_FC_WRAPPER(XPUTypeBF16, XPUTypeFP16) DECLARE_UNSUPPORTED_XBLAS_FC_WRAPPER(XPUTypeFP16, int32_t) DECLARE_UNSUPPORTED_XBLAS_FC_WRAPPER(XPUTypeFP16, tfloat32) #ifndef PADDLE_WITH_XPU_XRE5 // disable in kl2 DECLARE_UNSUPPORTED_XBLAS_FC_WRAPPER(float, XPUTypeFP16) #endif template static void xblas_fc_batch_wrapper(xpu::Context* xpu_ctx, int64_t bs, bool trans_x, bool trans_w, int64_t m, int64_t n, int64_t k, float alpha, const XPUType* x, int64_t stride_x, const XPUType* w, int64_t stride_w, float beta, XPUType* y, int64_t stride_y, const float* x_maxptr, const float* w_maxptr) { #ifdef PADDLE_WITH_XPU_XRE5 int r = xblas::fc_batched( xpu_ctx, bs, trans_x, trans_w, m, n, k, alpha, reinterpret_cast(x), stride_x, reinterpret_cast(w), stride_w, beta, reinterpret_cast(y), stride_y, x_maxptr, w_maxptr); PADDLE_ENFORCE_XBLAS_SUCCESS(r, "xblas_fc_batched"); #else int r = xpu::fc_batched( xpu_ctx, bs, trans_x, trans_w, m, n, k, alpha, reinterpret_cast(x), stride_x, reinterpret_cast(w), stride_w, beta, reinterpret_cast(y), stride_y, x_maxptr, w_maxptr); PADDLE_ENFORCE_XDNN_SUCCESS(r, "xdnn_fc_batched"); #endif } #define DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(XPUType, FCT, TGEMM_OUT) \ template <> \ void xblas_fc_batch_wrapper( \ xpu::Context * xpu_ctx, \ int64_t bs, \ bool trans_x, \ bool trans_w, \ int64_t m, \ int64_t n, \ int64_t k, \ float alpha, \ const XPUType* x, \ int64_t stride_x, \ const XPUType* w, \ int64_t stride_w, \ float beta, \ XPUType* y, \ int64_t stride_y, \ const float* x_maxptr, \ const float* w_maxptr) { \ int r = xpu::Error_t::INVALID_PARAM; \ PADDLE_ENFORCE_XDNN_SUCCESS(r, "xblas_fc_batched"); \ } DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(XPUTypeBF16, int_with_ll_t, XPUTypeFP16) DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(XPUTypeFP16, tfloat32, XPUTypeFP16) DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(XPUTypeBF16, float, XPUTypeFP16) DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(XPUTypeBF16, XPUTypeFP16, XPUTypeFP16) DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(XPUTypeBF16, int32_t, XPUTypeFP16) DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(XPUTypeBF16, int16_t, XPUTypeFP16) DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(XPUTypeFP16, int32_t, XPUTypeFP16) DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(XPUTypeBF16, int_with_ll_t, float) DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(XPUTypeBF16, XPUTypeFP16, float) DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(XPUTypeFP16, tfloat32, float) DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(XPUTypeBF16, int32_t, float) DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(XPUTypeBF16, int16_t, float) DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(XPUTypeFP16, int32_t, float) #ifndef PADDLE_WITH_XPU_XRE5 // disable in kl2 DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(XPUTypeBF16, tfloat32, float) DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(XPUTypeBF16, float, float) DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(float, XPUTypeFP16, float) DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(float, XPUTypeFP16, XPUTypeFP16) DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(XPUTypeFP16, XPUTypeFP16, float) DECLARE_UNSUPPORTED_XBLAS_FC_BATCH_WRAPPER(XPUTypeFP16, XPUTypeFP16, XPUTypeFP16) #endif template static void MatMulXPUFunction( xpu::Context* xpu_ctx, const T* x, const T* y, T* out, const XpuFcInfo& fcinfo, float alpha, float beta = 0.f, bool is_grad = false, xpu::Activation_t act = xpu::Activation_t::LINEAR) { using XPUType = typename XPUTypeTrait::Type; int fc_calc_type = FCCalcType(); decltype(&xblas_fc_wrapper) xblas_fc_api_list[6] = { &xblas_fc_wrapper, &xblas_fc_wrapper, &xblas_fc_wrapper, &xblas_fc_wrapper, &xblas_fc_wrapper, &xblas_fc_wrapper, }; decltype(&xblas_fc_batch_wrapper) xblas_fc_batch_api_list[6] = { &xblas_fc_batch_wrapper, &xblas_fc_batch_wrapper, &xblas_fc_batch_wrapper, &xblas_fc_batch_wrapper, &xblas_fc_batch_wrapper, &xblas_fc_batch_wrapper, }; auto xblas_fc_api = xblas_fc_api_list[fc_calc_type]; if (std::getenv("XPU_PADDLE_FC_GRAD_LOCAL") != nullptr) { if (is_grad) { xblas_fc_api = xblas_fc_api_list[2]; } } auto xblas_fc_batch_api = xblas_fc_batch_api_list[fc_calc_type]; if (fc_calc_type == XPUFCCalcType::FC_FLOAT16 && std::getenv("XPU_PADDLE_FC_FLOAT16") != nullptr) { xblas_fc_batch_api = &xblas_fc_batch_wrapper; } int64_t m = fcinfo.m; int64_t n = fcinfo.n; int64_t k = fcinfo.k; int64_t batch_size = fcinfo.bs; int64_t ldx = fcinfo.stride_x; int64_t ldy = fcinfo.stride_y; int64_t ldout = fcinfo.stride_out; bool trans_x = fcinfo.trans_x; bool trans_y = fcinfo.trans_y; float* max_x = fcinfo.max_x; float* max_y = fcinfo.max_y; float* max_out = fcinfo.max_out; bool is_x_need_broadcast = fcinfo.is_x_need_broadcast; bool is_y_need_broadcast = fcinfo.is_y_need_broadcast; const float* bias = fcinfo.bias; const float* scale_x = fcinfo.scale_x; const float* scale_y = fcinfo.scale_y; int scale_x_mode = fcinfo.scale_x_mode; int scale_y_mode = fcinfo.scale_y_mode; xpu::ctx_guard RAII_GUARD(xpu_ctx); if (batch_size <= 1) { xblas_fc_api(xpu_ctx, reinterpret_cast(x), reinterpret_cast(y), reinterpret_cast(out), m, n, k, trans_x, trans_y, max_x, max_y, max_out, ldx, ldy, ldout, alpha, beta, bias, act, scale_x, scale_y, scale_x_mode, scale_y_mode); } else { const XPUType* x_data = reinterpret_cast(x); if (is_x_need_broadcast) { XPUType* x_broadcast_data = nullptr; x_broadcast_data = RAII_GUARD.alloc_l3_or_gm(batch_size * m * k); PADDLE_ENFORCE_XDNN_NOT_NULL(x_broadcast_data); std::vector x_shape = {1, m, k}; std::vector new_x_shape = {batch_size, m, k}; int r = xpu::broadcast( xpu_ctx, x_data, x_broadcast_data, x_shape, new_x_shape); PADDLE_ENFORCE_XDNN_SUCCESS(r, "broadcast"); x_data = x_broadcast_data; } const XPUType* y_data = reinterpret_cast(y); if (is_y_need_broadcast) { XPUType* y_broadcast_data = nullptr; y_broadcast_data = RAII_GUARD.alloc_l3_or_gm(batch_size * k * n); PADDLE_ENFORCE_XDNN_NOT_NULL(y_broadcast_data); std::vector y_shape = {1, k, n}; std::vector new_y_shape = {batch_size, k, n}; int r = xpu::broadcast( xpu_ctx, y_data, y_broadcast_data, y_shape, new_y_shape); PADDLE_ENFORCE_XDNN_SUCCESS(r, "broadcast"); y_data = y_broadcast_data; } // batch matmul xblas_fc_batch_api(xpu_ctx, // Context* xpu_ctx, batch_size, // int64_t batch_size, trans_x, // bool x_trans, trans_y, // bool w_trans, m, // int64_t m, n, // int64_t n, k, // int64_t k, alpha, // float alpha, x_data, // const TX* x, ldx, // int64_t stride_a, y_data, // const TW* w, ldy, // int64_t stride_b, beta, // float beta, reinterpret_cast(out), // TY* y, ldout, // int64_t stride_c, max_x, // const float* x_maxptr, max_y); // const float* w_maxptr } } template static std::tuple MatmulGradFcInfo(xpu::Context* xpu_ctx, xpu::ctx_guard* RAII_GUARD, const XpuFcInfo& dout_shape, bool trans_x, bool trans_y, const T* x, const T* y, const T* dout) { XpuFcInfo dx_shape, dy_shape; const T* dx_a = NULL; const T* dx_b = NULL; const T* dy_a = NULL; const T* dy_b = NULL; bool copy_to_l3 = false; float* max_dout = NULL; int maxptr_size = xpu_ctx->max_ptr_size(); uint64_t l3_size = uint64_t(xpu_ctx->_l3_mgr.get_size()); int64_t bs = (dout_shape.bs <= 1) ? (1) : (dout_shape.bs); int64_t dx_size = bs * dout_shape.m * dout_shape.k; int64_t dy_size = bs * dout_shape.k * dout_shape.n; int64_t dout_size = bs * dout_shape.m * dout_shape.n; if (trans_x && trans_y) { copy_to_l3 = l3_size >= (dout_size * 2 + dy_size) * sizeof(T); } else if (trans_x) { copy_to_l3 = l3_size >= dout_size * sizeof(T); } else if (trans_y) { copy_to_l3 = l3_size >= dout_size * 2 * sizeof(T); } else { copy_to_l3 = l3_size >= (dout_size + dx_size) * sizeof(T); } const T* dout_new = dout; int r = 0; if (copy_to_l3) { T* dout_l3 = RAII_GUARD->alloc_l3(dout_size); PADDLE_ENFORCE_XDNN_NOT_NULL(dout_l3); if ((dout_shape.bs > 1) || ((dout_shape.bs <= 1) && (FCCalcType() == XPUFCCalcType::FC_FLOAT))) { r = xpu::copy(xpu_ctx, dout, dout_l3, dout_size); PADDLE_ENFORCE_XDNN_SUCCESS(r, "copy"); dout_new = dout_l3; } else { max_dout = RAII_GUARD->alloc_l3_or_gm(maxptr_size); PADDLE_ENFORCE_XDNN_NOT_NULL(max_dout); r = xpu::findmax_copy_fusion(xpu_ctx, dout, max_dout, dout_l3, dout_size); PADDLE_ENFORCE_XDNN_SUCCESS(r, "findmax_copy_fusion"); dout_new = dout_l3; } } else if (((dout_shape.bs <= 1) && (FCCalcType() != XPUFCCalcType::FC_FLOAT))) { max_dout = RAII_GUARD->alloc_l3_or_gm(maxptr_size); PADDLE_ENFORCE_XDNN_NOT_NULL(max_dout); r = xpu::findmax_copy_fusion( xpu_ctx, dout, max_dout, reinterpret_cast(NULL), dout_size); PADDLE_ENFORCE_XDNN_SUCCESS(r, "findmax_copy_fusion"); } if (trans_x && trans_y) { // dx = T(y) * T(dout) dx_shape.InitFcInfo(dout_shape.bs, dout_shape.k, dout_shape.m, dout_shape.n, true, true, nullptr, max_dout, nullptr); dx_a = y, dx_b = dout_new; dx_shape.is_x_need_broadcast = dout_shape.is_y_need_broadcast; // dy = T(dout) * T(x) dy_shape.InitFcInfo(dout_shape.bs, dout_shape.n, dout_shape.k, dout_shape.m, true, true, max_dout, nullptr, nullptr); dy_a = dout_new, dy_b = x; dy_shape.is_y_need_broadcast = dout_shape.is_x_need_broadcast; } else if (trans_x) { // dx = y * T(dout) dx_shape.InitFcInfo(dout_shape.bs, dout_shape.k, dout_shape.m, dout_shape.n, false, true, nullptr, max_dout, nullptr); dx_a = y, dx_b = dout_new; dx_shape.is_x_need_broadcast = dout_shape.is_y_need_broadcast; // dy = x * dout dy_shape.InitFcInfo(dout_shape.bs, dout_shape.k, dout_shape.n, dout_shape.m, false, false, nullptr, max_dout, nullptr); dy_shape.is_x_need_broadcast = dout_shape.is_x_need_broadcast; dy_a = x, dy_b = dout_new; } else if (trans_y) { // dx = dout * y dx_shape.InitFcInfo(dout_shape.bs, dout_shape.m, dout_shape.k, dout_shape.n, false, false, max_dout, nullptr, nullptr); dx_a = dout_new, dx_b = y; dx_shape.is_y_need_broadcast = dout_shape.is_y_need_broadcast; // dy = T(dout) * x dy_shape.InitFcInfo(dout_shape.bs, dout_shape.n, dout_shape.k, dout_shape.m, true, false, max_dout, nullptr, nullptr); dy_a = dout_new, dy_b = x; dy_shape.is_y_need_broadcast = dout_shape.is_x_need_broadcast; } else { // dx = dout * T(y) dx_shape.InitFcInfo(dout_shape.bs, dout_shape.m, dout_shape.k, dout_shape.n, false, true, max_dout, nullptr, nullptr); dx_a = dout_new, dx_b = y; dx_shape.is_y_need_broadcast = dout_shape.is_y_need_broadcast; // dy = T(x) * dout dy_shape.InitFcInfo(dout_shape.bs, dout_shape.k, dout_shape.n, dout_shape.m, true, false, nullptr, max_dout, nullptr); dy_shape.is_x_need_broadcast = dout_shape.is_x_need_broadcast; dy_a = x, dy_b = dout_new; } std::tuple result = std::make_tuple(dx_shape, dy_shape, dx_a, dx_b, dy_a, dy_b); return result; } } // namespace phi