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

205 lines
6.9 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/onednn/onednn_reuse.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/kernels/transpose_kernel.h"
namespace phi::fusion {
void SetInMemDescWithSqueeze2FuseSupport(
const std::vector<int> fused_squeeze2_axes,
DenseTensor* in,
const dnnl::memory::desc& in_md) {
const std::set<int64_t> squeeze2_axes_set(fused_squeeze2_axes.begin(),
fused_squeeze2_axes.end());
const std::vector<int64_t>& x_vec_dims = in_md.get_dims();
std::vector<int64_t> squeezed_op_tz(
x_vec_dims.size() - fused_squeeze2_axes.size(), 0);
int j = 0;
for (size_t i = 0; i < x_vec_dims.size(); ++i) {
if (squeeze2_axes_set.count(i) ||
squeeze2_axes_set.count(i - x_vec_dims.size())) { // NOLINT
PADDLE_ENFORCE_EQ(
x_vec_dims[i],
1,
errors::InvalidArgument(
"Squeeze2 input dim %d should be equal to one, but get %d.",
i,
x_vec_dims[i]));
continue;
}
squeezed_op_tz[j++] = x_vec_dims[i];
}
in->set_mem_desc(in_md.reshape(squeezed_op_tz));
in->Resize(squeezed_op_tz);
}
template <typename T, typename Context>
void FusedTransposeKernel(const Context& dev_ctx,
const DenseTensor& x,
const std::vector<int>& axis,
const std::vector<int>& fused_squeeze2_axes,
const std::vector<int>& fused_unsqueeze2_axes,
const std::vector<int>& fused_reshape2_shape,
const float scale,
const float shift,
const std::string& output_data_type,
DenseTensor* out) {
// Here we need to match dims to paddle layout
// as we are producing non-oneDNN result
auto x_dims = x.dims();
if ((x_dims.size() >= 3) &&
(phi::OneDNNContext::tls().get_cur_paddle_data_layout() ==
DataLayout::NHWC)) {
int axis_size = static_cast<int>(axis.size());
std::vector<int> formatted_axis = axis;
std::vector<int> count(axis_size, 0);
for (int i = 0; i < axis_size; i++) {
if (axis[i] < 0) {
formatted_axis[i] = axis[i] + axis_size;
}
}
auto dims = vectorize<int>(x_dims);
std::rotate(dims.begin() + 1, dims.begin() + 2, dims.end());
x_dims = x_dims.reshape(dims);
VLOG(3) << "Rotating Shape in Transpose from: ONEDNN to: NHWC output_shape";
DDim out_dims(x_dims);
for (size_t i = 0; i < axis.size(); i++) {
out_dims[i] = x_dims[formatted_axis[i]]; // NOLINT
}
out->Resize(out_dims);
}
PADDLE_ENFORCE_EQ(
dev_ctx.GetPlace().GetType(),
AllocationType::CPU,
errors::PreconditionNotMet("oneDNN Transpose kernel must use CPUPlace"));
if (!(fused_squeeze2_axes.empty())) {
SetInMemDescWithSqueeze2FuseSupport(fused_squeeze2_axes,
const_cast<DenseTensor*>(&x),
x.mem_desc()); // NOLINT
}
if (axis.size() == 1) {
Copy<Context>(dev_ctx, x, x.place(), false, out);
out->set_mem_desc(x.mem_desc());
return;
}
auto x_vec_dims = vectorize(x.dims());
auto x_type = funcs::ToOneDNNDataType(x.dtype());
dnnl::primitive_attr attrs;
const int32_t mask = 0;
if (scale != 1.0f) {
attrs.set_scales_mask(DNNL_ARG_SRC, mask);
}
if (shift != 0.0f) {
auto arg = output_data_type == "fp32" ? DNNL_ARG_SRC : DNNL_ARG_DST;
attrs.set_zero_points_mask(arg, mask);
}
DataType out_dtype;
if (output_data_type == "bf16") {
out_dtype = DataType::BFLOAT16;
} else if (output_data_type == "int8") {
out_dtype = DataType::INT8;
} else if (output_data_type == "uint8") {
out_dtype = DataType::UINT8;
} else if (output_data_type == "fp32") {
out_dtype = DataType::FLOAT32;
} else {
out_dtype = x.dtype();
}
auto out_type = funcs::ToOneDNNDataType(out_dtype);
funcs::ReorderOneDNNHandler reorder_handler(
x_vec_dims, x.dtype(), x_type, out_dtype, out_type, dev_ctx.GetEngine());
auto reorder_src_memory_p = reorder_handler.AcquireSrcMemory(
x.mem_desc(), funcs::to_void_cast(x.data<T>()));
auto fake_strides = funcs::FakeTransposeStrides(x_vec_dims, axis);
auto dst_md = dnnl::memory::desc(x_vec_dims, out_type, fake_strides);
auto reorder_dst_memory_p =
reorder_handler.AcquireDstMemory(out, dst_md, dev_ctx.GetPlace());
auto reorder_p = reorder_handler.AcquireReorder(
reorder_dst_memory_p, reorder_src_memory_p, attrs);
std::unordered_map<int, dnnl::memory> args = {
{DNNL_ARG_SRC, *reorder_src_memory_p},
{DNNL_ARG_DST, *reorder_dst_memory_p},
};
if (scale != 1.0f) {
auto scales_md = dnnl::memory::desc(
{1}, dnnl::memory::data_type::f32, dnnl::memory::format_tag::x);
auto scales = dnnl::memory(
scales_md, dev_ctx.GetEngine(), const_cast<float*>(&scale)); // NOLINT
args.insert({DNNL_ARG_ATTR_SCALES | DNNL_ARG_SRC, scales});
}
if (shift != 0.0f) {
auto zps_md = dnnl::memory::desc(
{1}, dnnl::memory::data_type::s32, dnnl::memory::format_tag::x);
auto zps = dnnl::memory(zps_md, dev_ctx.GetEngine());
*reinterpret_cast<int32_t*>(zps.get_data_handle()) =
static_cast<int32_t>(shift);
auto arg = output_data_type == "fp32" ? DNNL_ARG_SRC : DNNL_ARG_DST;
args.insert({DNNL_ARG_ATTR_ZERO_POINTS | arg, zps});
}
auto& astream = OneDNNContext::tls().get_stream();
reorder_p->execute(astream, args);
astream.wait();
auto out_md = reorder_dst_memory_p->get_desc().permute_axes(
funcs::TransposeToPermuteAxes(axis));
if (!fused_unsqueeze2_axes.empty()) {
funcs::SetOutMemDescWithUnsqueeze2FuseSupport(
fused_unsqueeze2_axes, out, out_md);
} else if (!fused_reshape2_shape.empty()) {
funcs::SetOutMemDescWithReshape2FuseSupport(
fused_reshape2_shape, out, out_md);
} else if (!fused_squeeze2_axes.empty()) {
out->set_mem_desc(out_md);
out->Resize(out_md.get_dims());
} else {
out->set_mem_desc(out_md);
}
}
} // namespace phi::fusion
PD_REGISTER_KERNEL(fused_transpose,
OneDNN,
ONEDNN,
phi::fusion::FusedTransposeKernel,
float,
uint8_t,
int8_t,
phi::bfloat16) {}