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

326 lines
12 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/coalesce_tensor_kernel.h"
#include <sstream>
#include <vector>
#include "glog/logging.h"
#include "paddle/phi/backends/cpu/cpu_context.h"
#include "paddle/phi/backends/device_memory_alignment.h"
#include "paddle/phi/backends/gpu/gpu_context.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/kernels/funcs/math_function.h"
#ifdef PADDLE_WITH_XPU
#include "paddle/phi/backends/xpu/xpu_context.h"
#include "paddle/phi/kernels/funcs/math_function_impl.h"
#endif
namespace phi {
template <typename Context>
struct FillConstantVisitor {
FillConstantVisitor(const Context &dev_ctx,
DenseTensor *tensor,
const float value)
: dev_ctx_(dev_ctx), tensor_(tensor), value_(value) {}
template <typename T>
void apply(typename std::enable_if<std::is_same<T, int8_t>::value ||
std::is_same<T, int16_t>::value>::type * =
nullptr) const {
PADDLE_THROW(
errors::InvalidArgument("Not support data type for set_constant attr"));
}
template <typename T>
void apply(typename std::enable_if<!(std::is_same<T, int8_t>::value ||
std::is_same<T, int16_t>::value)>::type
* = nullptr) const {
phi::funcs::SetConstant<Context, T> set_constant;
set_constant(dev_ctx_, tensor_, static_cast<T>(value_));
}
const Context &dev_ctx_;
DenseTensor *tensor_;
float value_;
};
void GetMemSizeAndDtype(const std::vector<const DenseTensor *> &lod_tensors,
size_t *numel,
const size_t &size_of_dtype,
const phi::Place &place,
const bool use_align = true,
const int align_size = -1) {
*numel = 0;
std::stringstream ss;
ss << "alloc_space_for_vars: ";
for (size_t i = 0; i < lod_tensors.size(); ++i) {
auto size = lod_tensors[i]->numel();
PADDLE_ENFORCE_GT(size,
0,
errors::InvalidArgument(
"The number of `%d`-th tensor's elements is 0.", i));
auto len = use_align
? phi::Alignment(static_cast<size_t>(size) * size_of_dtype,
place,
align_size) /
size_of_dtype
: static_cast<size_t>(size);
const void *ptr =
lod_tensors[i]->initialized() ? lod_tensors[i]->data() : nullptr;
VLOG(4) << size << " " << len;
ss << "input(" << i << "-th tensor) dim:(" << lod_tensors[i]->dims() << ") "
<< " address:" << ptr << " len: " << len << ", ";
*numel += len;
}
VLOG(10) << ss.str();
}
template <typename T, typename Context>
void CoalesceTensorKernel(const Context &dev_ctx,
const std::vector<const DenseTensor *> &input,
DataType dtype,
bool copy_data,
bool set_constant,
bool persist_output,
float constant,
bool use_align,
int align_size,
int size_of_dtype,
const std::vector<int64_t> &concated_shapes,
const std::vector<int64_t> &concated_ranks,
std::vector<DenseTensor *> output,
DenseTensor *fused_output) {
PADDLE_ENFORCE_GT(
input.size(),
static_cast<size_t>(0),
errors::InvalidArgument("The CoalesceTensor operator has no input."));
PADDLE_ENFORCE_EQ(input.size(),
output.size(),
errors::InvalidArgument(
"The number of CoalesceTensor operator's input and "
"output is not match, "
"input number is %u, output number is %u.",
input.size(),
output.size()));
// Input & Output check: only support DenseTensor
bool has_not_init_in_vars = false;
for (size_t i = 0; i < input.size(); ++i) {
PADDLE_ENFORCE_NOT_NULL(
input[i],
errors::InvalidArgument("The %d-th input tensor cannot be nullptr.",
i));
PADDLE_ENFORCE_NOT_NULL(
output[i],
errors::InvalidArgument("The %d-th output tensor cannot be nullptr.",
i));
if (!input[i]->initialized()) {
has_not_init_in_vars = true;
}
}
if (has_not_init_in_vars) {
PADDLE_ENFORCE_EQ(
concated_ranks.size(),
output.size(),
errors::InvalidArgument("The attribute(concated_ranks) length must be "
"equal to the output tensor number."));
int64_t accumulated_ranks = 0;
for (size_t i = 0; i < input.size(); ++i) {
phi::DDim dims(concated_shapes.data() + accumulated_ranks,
static_cast<int>(concated_ranks[i]));
if (!input[i]->initialized()) {
PADDLE_ENFORCE_EQ(
input[i],
output[i],
errors::InvalidArgument(
"The %d-th output tensor and %d-th input tensor when the "
"%d-th input tensor is not initialized.",
i,
i,
i));
output[i]->Resize(dims);
} else {
PADDLE_ENFORCE_EQ(input[i]->dims(),
dims,
errors::InvalidArgument(
"The %d-th input tensor shape does not match the "
"attribute(concated_shapes) and "
"attribute(concated_ranks).",
i));
}
accumulated_ranks += concated_ranks[i];
PADDLE_ENFORCE_LE(
accumulated_ranks,
concated_shapes.size(),
errors::InvalidArgument("The attribute(concated_shapes) and "
"attribute(concated_ranks) do not match."));
}
PADDLE_ENFORCE_EQ(
accumulated_ranks,
concated_shapes.size(),
errors::InvalidArgument("The attribute(concated_shapes) and "
"attribute(concated_ranks) do not match."));
}
// Init the output as input
for (size_t i = 0; i < input.size(); ++i) {
output[i]->Resize(input[i]->dims());
}
// Get numel and dtype
size_t numel = 0;
if (size_of_dtype == -1) {
size_of_dtype = static_cast<int>(phi::SizeOf(dtype));
}
GetMemSizeAndDtype(
input, &numel, size_of_dtype, dev_ctx.GetPlace(), use_align, align_size);
// Alloc the continuous space
void *fused_tensor_ptr = dev_ctx.Alloc(
&fused_output->Resize({static_cast<int64_t>(numel)}), dtype);
VLOG(10) << "Fused tensor addr " << fused_tensor_ptr;
// Init the continuous space
size_t offset = 0;
if (copy_data) {
for (auto item : input) {
size_t len = static_cast<size_t>(item->numel());
auto sub_tensor = fused_output->Slice(
static_cast<int64_t>(offset),
static_cast<int64_t>(offset) + static_cast<int64_t>(len));
phi::Copy(dev_ctx, *item, dev_ctx.GetPlace(), false, &sub_tensor);
offset += use_align
? phi::Alignment(
len * size_of_dtype, dev_ctx.GetPlace(), align_size) /
size_of_dtype
: len;
}
} else if (set_constant) {
phi::VisitDataType(
dtype, FillConstantVisitor<Context>(dev_ctx, fused_output, constant));
} else if (persist_output) {
for (auto &item : output) {
size_t len = static_cast<size_t>(item->numel());
auto sub_tensor = fused_output->Slice(
static_cast<int64_t>(offset),
static_cast<int64_t>(offset) + static_cast<int64_t>(len));
// some var may not persistable, or persistable var may not init
if (item->initialized()) {
phi::Copy(dev_ctx, *item, dev_ctx.GetPlace(), false, &sub_tensor);
}
offset += use_align
? phi::Alignment(
len * size_of_dtype, dev_ctx.GetPlace(), align_size) /
size_of_dtype
: len;
}
}
// Make the outputs point to the continuous space.
offset = 0;
std::stringstream ss;
ss << "alloc_space_for_vars: ";
for (size_t i = 0; i < output.size(); ++i) {
size_t len = static_cast<size_t>(output[i]->numel());
auto dim = output[i]->dims();
VLOG(4) << len << " " << dim << " " << offset;
output[i]
->ShareDataWith(fused_output->Slice(
static_cast<int64_t>(offset),
static_cast<int64_t>(offset) + static_cast<int64_t>(len)))
.Resize(dim);
len = use_align ? phi::Alignment(
len * size_of_dtype, dev_ctx.GetPlace(), align_size) /
size_of_dtype
: len;
ss << "output(" << i << "-th tensor) dim:(" << dim << ")"
<< " address: " << output[i]->data() << " len: " << len << ", ";
offset += len;
}
PADDLE_ENFORCE_EQ((int64_t)offset,
fused_output->numel(),
errors::InvalidArgument(
"The alloc_space_for_vars's offset: %s is unequal with "
"fused_output's numel: %s.",
offset,
fused_output->numel()));
VLOG(10) << ss.str();
}
} // namespace phi
PD_REGISTER_KERNEL(coalesce_tensor,
CPU,
ALL_LAYOUT,
phi::CoalesceTensorKernel,
int,
float,
double) {
kernel->InputAt(0).SetBackend(phi::Backend::ALL_BACKEND);
kernel->OutputAt(1).SetDataType(phi::DataType::UNDEFINED);
}
#ifdef PADDLE_WITH_CUDA
PD_REGISTER_KERNEL(coalesce_tensor,
GPU,
ALL_LAYOUT,
phi::CoalesceTensorKernel,
phi::float16,
phi::bfloat16,
int,
float,
double) {
kernel->InputAt(0).SetBackend(phi::Backend::ALL_BACKEND);
kernel->OutputAt(1).SetDataType(phi::DataType::UNDEFINED);
}
#endif
#ifdef PADDLE_WITH_HIP
PD_REGISTER_KERNEL(coalesce_tensor,
GPU,
ALL_LAYOUT,
phi::CoalesceTensorKernel,
phi::float16,
phi::bfloat16,
int,
float,
double) {
kernel->InputAt(0).SetBackend(phi::Backend::ALL_BACKEND);
kernel->OutputAt(1).SetDataType(phi::DataType::UNDEFINED);
}
#endif
#ifdef PADDLE_WITH_XPU
PD_REGISTER_KERNEL(coalesce_tensor,
XPU,
ALL_LAYOUT,
phi::CoalesceTensorKernel,
phi::float16,
phi::bfloat16,
int,
float,
double) {
kernel->InputAt(0).SetBackend(phi::Backend::ALL_BACKEND);
kernel->OutputAt(1).SetDataType(phi::DataType::UNDEFINED);
}
#endif