Files
paddlepaddle--paddle/paddle/phi/infermeta/spmd_rules/replicated.cc
T
2026-07-13 12:40:42 +08:00

190 lines
7.4 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 "paddle/phi/infermeta/spmd_rules/replicated.h"
#include "glog/logging.h"
#include "paddle/phi/core/distributed/auto_parallel/dist_attr.h"
#include "paddle/phi/core/distributed/auto_parallel/inferspmd_utils.h"
#include "paddle/phi/core/distributed/auto_parallel/utils.h"
namespace phi {
namespace distributed {
////////////////// Utils Functions //////////////////
std::vector<int64_t> GetReplicatedDimsMapping(const int ndim) {
std::vector<int64_t> dims_mapping(ndim, -1);
return dims_mapping;
}
////////////////// InferMeta(Contains SPMD) Functions //////////////////
SpmdInfo ReplicatedInferSpmd(const std::vector<const DistMetaTensor*>& ins,
const std::vector<const DistMetaTensor*>& outs) {
// step1: Build Einsum Notation for input tensor's batch axis
int64_t ninputs = static_cast<int64_t>(ins.size());
int64_t noutputs = static_cast<int64_t>(outs.size());
// Step2: Unshard Output's Dims Mapping.
std::vector<TensorDistAttr> output_dist_attrs;
for (int64_t i = 0; i < noutputs; i++) {
VLOG(4) << outs[i]->dist_attr().to_string();
VLOG(4) << outs[i]->dims().to_str();
int ndim = outs[i]->dims().size();
TensorDistAttr dist_attr_dst =
CopyTensorDistAttrForOutput(ins[0]->dist_attr());
std::vector<int64_t> dst_dims_mapping = GetReplicatedDimsMapping(ndim);
dist_attr_dst.set_dims_mapping(dst_dims_mapping);
output_dist_attrs.emplace_back(dist_attr_dst);
}
// Step3: Merge and get Inputs' Batch Axis New Dims Mapping.
std::vector<TensorDistAttr> dst_input_dist_attrs;
for (int64_t i = 0; i < ninputs; i++) {
// `ndim == -1` means input is nullptr
int ndim = ins[i]->dims().size();
if (ndim == -1) {
continue;
}
TensorDistAttr dist_attr_dst =
CopyTensorDistAttrForOutput(ins[i]->dist_attr());
std::vector<int64_t> dst_dims_mapping = GetReplicatedDimsMapping(ndim);
dist_attr_dst.set_dims_mapping(dst_dims_mapping);
dst_input_dist_attrs.emplace_back(dist_attr_dst);
}
VLOG(4) << "ReplicatedSpmd InferForward:";
for (int64_t i = 0; i < ninputs; i++) {
if (ins[i]->dims().size() == -1) {
continue;
}
VLOG(4) << "Input" << std::to_string(i) << " shape: ["
<< str_join(vectorize(ins[i]->dims())) << "] "
<< "src_dims_mapping: ["
<< str_join(ins[i]->dist_attr().dims_mapping()) << "] "
<< "dst_dims_mapping: ["
<< str_join(dst_input_dist_attrs[i].dims_mapping()) << "]";
}
for (int64_t i = 0; i < noutputs; i++) {
VLOG(4) << "Output" << std::to_string(i) << " shape: ["
<< str_join(vectorize(outs[i]->dims())) << "] "
<< "dst_dims_mapping: ["
<< str_join(output_dist_attrs[i].dims_mapping()) << "]";
}
return {ToArgDistAttr(dst_input_dist_attrs),
ToArgDistAttr(output_dist_attrs)};
}
SpmdInfo ReplicatedInferSpmdReverse(
const std::vector<const DistMetaTensor*>& ins,
const std::vector<const DistMetaTensor*>& outs) {
// step1: Build Einsum Notation for input tensor's batch axis
int64_t ninputs = static_cast<int64_t>(ins.size());
int64_t noutputs = static_cast<int64_t>(outs.size());
// Step2: Unshard Output's Dims Mapping.
std::vector<TensorDistAttr> output_dist_attrs;
for (int64_t i = 0; i < noutputs; i++) {
int ndim = outs[i]->dims().size();
TensorDistAttr dist_attr_dst =
CopyTensorDistAttrForOutput(outs[i]->dist_attr());
std::vector<int64_t> dst_dims_mapping = GetReplicatedDimsMapping(ndim);
dist_attr_dst.set_dims_mapping(dst_dims_mapping);
output_dist_attrs.emplace_back(dist_attr_dst);
}
// Step3: Merge and get Inputs' Batch Axis New Dims Mapping.
std::vector<TensorDistAttr> dst_input_dist_attrs;
for (int64_t i = 0; i < ninputs; i++) {
int ndim = ins[i]->dims().size();
TensorDistAttr dist_attr_dst =
CopyTensorDistAttrForOutput(ins[i]->dist_attr());
std::vector<int64_t> dst_dims_mapping = GetReplicatedDimsMapping(ndim);
dist_attr_dst.set_dims_mapping(dst_dims_mapping);
dst_input_dist_attrs.emplace_back(dist_attr_dst);
}
VLOG(4) << "ReplicatedSpmd InferBackward:";
for (int64_t i = 0; i < noutputs; i++) {
VLOG(4) << "Output" << std::to_string(i) << " shape: ["
<< str_join(vectorize(outs[i]->dims())) << "] "
<< "src_dims_mapping: ["
<< str_join(outs[i]->dist_attr().dims_mapping()) << "] "
<< "dst_dims_mapping: ["
<< str_join(output_dist_attrs[i].dims_mapping()) << "]";
}
for (int64_t i = 0; i < ninputs; i++) {
VLOG(4) << "Input" << std::to_string(i) << " shape: ["
<< str_join(vectorize(ins[i]->dims())) << "] "
<< "dst_dims_mapping: ["
<< str_join(dst_input_dist_attrs[i].dims_mapping()) << "]";
}
return {ToArgDistAttr(dst_input_dist_attrs),
ToArgDistAttr(output_dist_attrs)};
}
SpmdInfo ReplicatedInferDynamic(
const std::vector<paddle::variant<const DistMetaTensor*,
const std::vector<DistMetaTensor>*>>&
inputs) {
std::vector<const DistMetaTensor*> nonnull_inputs;
int64_t ninputs = static_cast<int64_t>(inputs.size());
SpmdInfo spmd_info;
auto build_tensor_dist_attr = [&nonnull_inputs](
const DistMetaTensor& dist_meta_tensor) {
int ndim = dist_meta_tensor.dims().size();
TensorDistAttr dist_attr_dst =
CopyTensorDistAttrForOutput(dist_meta_tensor.dist_attr());
// `ndim == -1` means input is nullptr
if (ndim >= 0) {
std::vector<int64_t> dst_dims_mapping = GetReplicatedDimsMapping(ndim);
dist_attr_dst.set_dims_mapping(dst_dims_mapping);
nonnull_inputs.push_back(&dist_meta_tensor);
}
return dist_attr_dst;
};
for (int64_t i = 0; i < ninputs; i++) {
if (paddle::holds_alternative<const DistMetaTensor*>(inputs[i])) {
const auto* dist_meta_tensor_ptr =
PADDLE_GET_CONST(const DistMetaTensor*, inputs[i]);
const auto& dist_meta_tensor = *dist_meta_tensor_ptr;
auto dist_attr_dst = build_tensor_dist_attr(dist_meta_tensor);
VLOG(4) << "input " << i << ": dist attr: " << dist_attr_dst.to_string();
spmd_info.first.emplace_back(dist_attr_dst);
} else {
std::vector<phi::distributed::TensorDistAttr> list_dist_attr;
const auto* dist_meta_tensors_ptr =
PADDLE_GET_CONST(const std::vector<DistMetaTensor>*, inputs[i]);
const auto& dist_meta_tensors = *dist_meta_tensors_ptr;
for (const auto& dist_meta_tensor : dist_meta_tensors) {
auto dist_attr_dst = build_tensor_dist_attr(dist_meta_tensor);
VLOG(4) << "input " << i
<< ": dist attr: " << dist_attr_dst.to_string();
list_dist_attr.emplace_back(std::move(dist_attr_dst));
}
spmd_info.first.emplace_back(std::move(list_dist_attr));
}
}
return spmd_info;
}
} // namespace distributed
} // namespace phi