Files
paddlepaddle--paddle/paddle/fluid/eager/utils.cc
T
2026-07-13 12:40:42 +08:00

1863 lines
68 KiB
C++

// Copyright (c) 2021 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/fluid/eager/utils.h"
#include <chrono>
#include <ctime>
#include <iomanip>
#include <ostream>
#ifdef _WIN32
#include <Windows.h>
#else
#include <unistd.h>
#endif
#include "paddle/fluid/eager/accumulation/accumulation_node.h"
#include "paddle/fluid/eager/api/utils/global_utils.h"
#include "paddle/fluid/eager/api/utils/hook_utils.h"
#include "paddle/fluid/eager/grad_node_info.h"
#include "paddle/fluid/eager/tensor_wrapper.h"
#include "paddle/common/layout.h"
#include "paddle/fluid/framework/data_layout.h"
#include "paddle/fluid/framework/op_call_stack.h"
#include "paddle/fluid/framework/phi_utils.h"
#include "paddle/fluid/framework/variable.h"
#include "paddle/phi/api/all.h"
#include "paddle/phi/api/lib/data_transform.h"
#include "paddle/phi/common/logging_utils.h"
#include "paddle/phi/core/compat/convert_utils.h"
#include "paddle/phi/core/tensor_meta.h"
#include "paddle/phi/kernels/funcs/tensor_formatter.h"
#include "paddle/utils/md5.h"
COMMON_DECLARE_bool(enable_unique_name);
COMMON_DECLARE_int32(tensor_md5_checksum_precision);
COMMON_DECLARE_bool(tensor_md5_checksum_use_binary_format);
#ifdef _WIN32
#define getprocessid GetCurrentProcessId
typedef int pid_t;
#else
#define getprocessid getpid
#endif
namespace egr {
using paddle::inference::analysis::Dot;
void SetGradOutputDistAttrIter::visit_element(paddle::Tensor* element,
const GradSlotMeta& meta) {
if (element == nullptr) {
VLOG(4) << "The input element is nullptr when calling "
"SetGradOutputDistAttrIter.";
return;
}
if (meta.IsDistMeta()) {
// Here the element is empty or defined DistTensor
VLOG(4) << "The input element is set DistTensor impl when calling "
"SetGradOutputDistAttrIter.";
element->set_impl(std::make_shared<phi::distributed::DistTensor>(
phi::DDim(), meta.DistAttr()));
} else {
// Here the element is empty or defined DenseTensor
VLOG(4) << "The input element is set DistTensor impl using dense meta "
"when calling SetGradOutputDistAttrIter.";
phi::distributed::Placements placements;
for (int64_t i = 0; i < mesh_.ndim(); ++i) {
placements.emplace_back(std::make_shared<phi::distributed::Replicate>());
}
auto dist_attr = phi::distributed::ToTensorDistAttr(
mesh_, placements, meta.GetTensorMeta().dims);
element->set_impl(
std::make_shared<phi::distributed::DistTensor>(phi::DDim(), dist_attr));
}
}
void SetGradOutputDistAttrIter::visit(paddle::Tensor* element) {
if (!out_meta_[out_indexes_[cur_pos_]].empty()) {
visit_element(element, out_meta_[out_indexes_[cur_pos_]][0]);
}
cur_pos_++;
}
void SetGradOutputDistAttrIter::visit(
const std::vector<paddle::Tensor*>& elements) {
if (!out_meta_[out_indexes_[cur_pos_]].empty()) {
for (size_t i = 0; i < elements.size(); ++i) {
visit_element(elements.at(i), out_meta_[out_indexes_[cur_pos_]][i]);
}
}
cur_pos_++;
}
/**
* Implementation of Eager Utils.
**/
AutogradMeta* EagerUtils::autograd_meta(paddle::Tensor* target) {
auto* p_autograd_meta = target->get_autograd_meta();
if (!p_autograd_meta) {
auto p_autograd_meta_ptr = std::make_shared<AutogradMeta>();
p_autograd_meta = p_autograd_meta_ptr.get();
target->set_autograd_meta(p_autograd_meta_ptr);
}
return static_cast<AutogradMeta*>(p_autograd_meta);
}
AutogradMeta* EagerUtils::unsafe_autograd_meta(const paddle::Tensor& target) {
auto* p_autograd_meta = target.get_autograd_meta();
PADDLE_ENFORCE(p_autograd_meta,
common::errors::Fatal(
"Null autograd_meta gotten from unsafe_autograd_meta()"));
return static_cast<AutogradMeta*>(p_autograd_meta);
}
std::vector<AutogradMeta*> EagerUtils::unsafe_autograd_meta(
const std::vector<paddle::Tensor>& targets) {
std::vector<AutogradMeta*> metas;
metas.reserve(targets.size());
for (const paddle::Tensor& t : targets) {
metas.emplace_back(unsafe_autograd_meta(t));
}
return metas;
}
AutogradMeta* EagerUtils::nullable_autograd_meta(const paddle::Tensor& target) {
auto* p_autograd_meta = target.get_autograd_meta();
if (!p_autograd_meta) return nullptr;
return static_cast<AutogradMeta*>(p_autograd_meta);
}
AutogradMeta* EagerUtils::nullable_autograd_meta(
const paddle::optional<paddle::Tensor>& target) {
if (target.get_ptr() != nullptr) {
return EagerUtils::nullable_autograd_meta(*(target.get_ptr()));
}
return nullptr;
}
std::vector<AutogradMeta*> EagerUtils::nullable_autograd_meta(
const std::vector<paddle::Tensor>& targets) {
std::vector<AutogradMeta*> metas;
metas.reserve(targets.size());
for (const paddle::Tensor& t : targets) {
metas.emplace_back(nullable_autograd_meta(t));
}
return metas;
}
std::vector<AutogradMeta*> EagerUtils::nullable_autograd_meta(
const paddle::optional<std::vector<paddle::Tensor>>& targets) {
std::vector<AutogradMeta*> metas;
if (targets.get_ptr() != nullptr) {
metas.reserve(targets.get_ptr()->size());
for (const paddle::Tensor& t : (*(targets.get_ptr()))) {
metas.emplace_back(nullable_autograd_meta(t));
}
}
return metas;
}
std::vector<AutogradMeta*> EagerUtils::nullable_autograd_meta(
const std::vector<paddle::Tensor*>& targets) {
std::vector<AutogradMeta*> metas;
metas.reserve(targets.size());
for (const paddle::Tensor* t : targets) {
metas.emplace_back(nullable_autograd_meta(*t));
}
return metas;
}
std::vector<AutogradMeta*> EagerUtils::autograd_meta(
std::vector<paddle::Tensor>* targets) {
std::vector<AutogradMeta*> ret;
ret.reserve(targets->size());
// for autograd_meta we can tolerate it has nullptr.
for (auto& target : *targets) {
auto* p_autograd_meta = autograd_meta(&target);
ret.emplace_back(p_autograd_meta);
}
return ret;
}
std::vector<AutogradMeta*> EagerUtils::autograd_meta(
std::vector<paddle::Tensor*>* targets) {
std::vector<AutogradMeta*> ret;
ret.reserve(targets->size());
// for autograd_meta we can tolerate it has nullptr.
for (auto& target : *targets) {
auto* p_autograd_meta = autograd_meta(target);
ret.emplace_back(p_autograd_meta);
}
return ret;
}
std::pair<size_t, size_t> EagerUtils::OutRankInfo(
const paddle::Tensor& target) {
return unsafe_autograd_meta(target)->OutRankInfo();
}
std::shared_ptr<GradNodeBase> EagerUtils::grad_node(
const paddle::Tensor& target) {
auto* meta = nullable_autograd_meta(target);
if (meta) {
return meta->GetMutableGradNode();
} else {
return nullptr;
}
}
paddle::Tensor* EagerUtils::mutable_grad(const paddle::Tensor& target) {
auto* meta = nullable_autograd_meta(target);
if (meta) {
return meta->MutableGrad();
} else {
return nullptr;
}
}
void EagerUtils::SetHistory(std::vector<AutogradMeta*>* autograd_metas,
const std::shared_ptr<GradNodeBase>& grad_node) {
for (const auto& autograd_meta : *autograd_metas) {
if (autograd_meta->GradNode()) {
VLOG(7) << "Should not set grad node twice, original node is:"
<< autograd_meta->GradNode()->name()
<< " current is: " << grad_node->name();
}
autograd_meta->SetGradNode(grad_node);
}
}
void EagerUtils::SetHistory(AutogradMeta* autograd_meta,
const std::shared_ptr<GradNodeBase>& grad_node) {
if (autograd_meta->GradNode()) {
VLOG(7) << "Should not set grad node twice, original node is:"
<< autograd_meta->GradNode()->name()
<< "current is: " << grad_node->name();
}
autograd_meta->SetGradNode(grad_node);
}
void EagerUtils::SetOutRankWithSlot(std::vector<AutogradMeta*>* targets,
size_t slot_id) {
// Set OutRankInfo from 0 to size of targets
for (size_t i = 0; i < targets->size(); i++) {
(*targets)[i]->SetSingleOutRankWithSlot(slot_id, i);
}
}
void EagerUtils::SetOutRankWithSlot(AutogradMeta* target, size_t slot_id) {
target->SetSingleOutRankWithSlot(slot_id, 0);
}
bool EagerUtils::IsLeafTensor(const paddle::Tensor& target) {
std::shared_ptr<GradNodeBase> grad_node_ptr = grad_node(target);
if (!grad_node_ptr ||
std::dynamic_pointer_cast<GradNodeAccumulation>(grad_node_ptr)) {
return true;
}
return false;
}
void EagerUtils::CheckInplace(const paddle::Tensor& target,
const AutogradMeta* autograd_meta,
bool require_any_grad) {
if (require_any_grad && autograd_meta) {
PADDLE_ENFORCE_EQ(!autograd_meta->StopGradient() && IsLeafTensor(target),
false,
common::errors::InvalidArgument(
"Leaf Var (%s) that doesn't stop gradient "
"can't use inplace strategy.",
target.name()));
}
}
std::shared_ptr<egr::EagerVariable> EagerUtils::TrySyncToVar(
const paddle::Tensor& tensor) {
return std::make_shared<egr::EagerVariable>(tensor);
}
std::vector<std::shared_ptr<egr::EagerVariable>> EagerUtils::TrySyncToVars(
const paddle::Tensor& tensor) {
return {TrySyncToVar(tensor)};
}
std::vector<std::shared_ptr<egr::EagerVariable>> EagerUtils::TrySyncToVars(
paddle::Tensor* tensor) {
PADDLE_ENFORCE_NOT_NULL(
tensor,
common::errors::Fatal(
"Should Not Pass Empty tensor pointer in, since only output can "
"reach this, please check output value and make sure it's not null"));
return {TrySyncToVar(*tensor)};
}
std::vector<std::shared_ptr<egr::EagerVariable>> EagerUtils::TrySyncToVars(
const std::vector<paddle::Tensor*>& tensors) {
std::vector<std::shared_ptr<EagerVariable>> res;
size_t num = tensors.size();
res.reserve(num);
for (size_t i = 0; i < num; i++) {
auto* tensor = tensors[i];
PADDLE_ENFORCE_NOT_NULL(
tensor,
common::errors::Fatal(
"Tensor is null and cannot be copied. "
"We are trying to TrySyncToVars tensor from its "
"shared_ptr, this error may indicate some outputs "
"are nullptr"));
res.emplace_back(TrySyncToVar(*tensor));
}
return res;
}
std::vector<std::shared_ptr<egr::EagerVariable>> EagerUtils::TrySyncToVars(
const std::vector<paddle::Tensor>& tensors) {
std::vector<std::shared_ptr<EagerVariable>> res;
size_t num = tensors.size();
res.reserve(num);
for (size_t i = 0; i < num; i++) {
res.emplace_back(TrySyncToVar(tensors[i]));
}
return res;
}
std::vector<std::shared_ptr<EagerVariable>> EagerUtils::CreateVars(
const size_t num) {
std::vector<std::shared_ptr<EagerVariable>> res;
res.reserve(num);
for (size_t i = 0; i < num; i++) {
res.emplace_back(
new EagerVariable(egr::Controller::Instance().GenerateUniqueName()));
}
return res;
}
void EagerUtils::HandleViewBetweenInputAndOutput(
const std::shared_ptr<EagerVariable>& input_var,
const std::shared_ptr<EagerVariable>& view_output_var) {
PADDLE_ENFORCE_EQ(
input_var->Var().IsInitialized(),
true,
common::errors::InvalidArgument("Tensor %s has not been initialized!",
input_var->name()));
if (phi::DenseTensor::classof(input_var->GetTensorBase().get())) {
auto input_dense_tensor =
std::dynamic_pointer_cast<phi::DenseTensor>(input_var->GetTensorBase());
PADDLE_ENFORCE_EQ(
input_dense_tensor->IsInitialized(),
true,
common::errors::InvalidArgument(
"DenseTensor %s has not been initialized!", input_var->name()));
auto* view_output_tensor =
view_output_var->MutableVar()->GetMutable<phi::DenseTensor>();
view_output_tensor->ShareBufferWith(*input_dense_tensor);
view_output_tensor->ShareInplaceVersionCounterWith(*input_dense_tensor);
VLOG(3) << "Perform View between Output Var(" << view_output_var->name()
<< ") and Input Var(" << input_var->name()
<< "), share allocation and inplace version.";
}
}
void EagerUtils::HandleViewBetweenInputAndOutput(
const paddle::Tensor& input_tensor, paddle::Tensor* view_output_tensor) {
PADDLE_ENFORCE_EQ(
input_tensor.has_allocation(),
true,
common::errors::InvalidArgument("Tensor %s has not been initialized!",
input_tensor.name()));
if (input_tensor.is_dense_tensor()) {
auto input_dense_tensor =
std::dynamic_pointer_cast<phi::DenseTensor>(input_tensor.impl());
if (view_output_tensor->impl() == nullptr) {
view_output_tensor->set_impl(std::make_shared<phi::DenseTensor>());
} else {
PADDLE_ENFORCE(view_output_tensor->is_dense_tensor(),
common::errors::Unavailable(
"DenseTensor can not be inplaced with other Tensor."));
}
auto view_output_dense_tensor =
std::dynamic_pointer_cast<phi::DenseTensor>(view_output_tensor->impl());
view_output_dense_tensor->ShareBufferWith(*input_dense_tensor);
view_output_dense_tensor->ShareInplaceVersionCounterWith(
*input_dense_tensor);
VLOG(4) << "Perform View between Output Tensor("
<< view_output_tensor->name() << ") and Input Tensor("
<< input_tensor.name()
<< "), share allocation and inplace version.";
} else if (input_tensor.is_dist_tensor()) {
auto input_dense_tensor =
std::dynamic_pointer_cast<phi::distributed::DistTensor>(
input_tensor.impl())
->unsafe_mutable_value();
if (view_output_tensor->impl() == nullptr) {
view_output_tensor->set_impl(
std::make_shared<phi::distributed::DistTensor>(
input_tensor.dims(),
std::dynamic_pointer_cast<phi::distributed::DistTensor>(
input_tensor.impl())
->dist_attr()));
} else {
PADDLE_ENFORCE(view_output_tensor->is_dist_tensor(),
common::errors::Unavailable(
"DistTensor can not be inplaced with other Tensor."));
}
auto view_output_dense_tensor =
std::dynamic_pointer_cast<phi::distributed::DistTensor>(
view_output_tensor->impl())
->unsafe_mutable_value();
view_output_dense_tensor->ShareBufferWith(*input_dense_tensor);
view_output_dense_tensor->ShareInplaceVersionCounterWith(
*input_dense_tensor);
VLOG(4) << "Perform View between Output Tensor("
<< view_output_tensor->name() << ") and Input Tensor("
<< input_tensor.name()
<< "), share allocation and inplace version.";
}
}
std::vector<paddle::Tensor> EagerUtils::GetOutputs(
const std::vector<std::shared_ptr<EagerVariable>>& outs) {
std::vector<paddle::Tensor> res;
res.reserve(outs.size());
for (const auto& out : outs) {
PADDLE_ENFORCE_NOT_NULL(
out.get(),
common::errors::Fatal(
"Eager Tensor %s is null and cannot be copied. "
"We are trying to Get Output tensor from its "
"shared_ptr, this error may indicate some outputs "
"are nullptr",
out->name()));
res.emplace_back(out->GetTensorBase(), out->name());
}
return res;
}
paddle::Tensor EagerUtils::GetOutput(
const std::shared_ptr<EagerVariable>& out) {
PADDLE_ENFORCE_NOT_NULL(
out.get(),
common::errors::Fatal(
"Eager Tensor %s is null and cannot be copied. We "
"are trying to Get Output tensor from its shared_ptr, "
"this error may indicate output is nullptr",
out->name()));
return paddle::Tensor(out->GetTensorBase(), out->name());
}
void EagerUtils::GetOutput(const std::shared_ptr<EagerVariable>& out,
paddle::Tensor* out_var) {
PADDLE_ENFORCE_NOT_NULL(
out_var,
common::errors::Fatal("Tensor is null and cannot be copied. "
"We are trying to OverwriteOutput from its "
"shared_ptr, this error may indicate some outputs "
"are nullptr"));
out_var->set_impl(out->GetTensorBase());
out_var->set_name(out->name());
}
void EagerUtils::GetOutputs(
const std::vector<std::shared_ptr<EagerVariable>>& outs,
std::vector<paddle::Tensor>* result) {
for (const auto& out : outs) {
result->emplace_back(out->GetTensorBase());
}
}
void EagerUtils::GetOutputs(
const std::vector<std::shared_ptr<EagerVariable>>& outs,
const std::vector<paddle::Tensor*>& out_var) {
for (size_t i = 0; i < outs.size(); i++) {
PADDLE_ENFORCE_NOT_NULL(
out_var[i],
common::errors::Fatal(
"Tensor is null and cannot be copied. "
"We are trying to OverwriteOutput from its "
"shared_ptr, this error may indicate some outputs "
"are nullptr"));
out_var[i]->set_impl(outs[i]->GetTensorBase());
}
}
void EagerUtils::GetOutputs(const std::shared_ptr<EagerVariable>& out,
std::vector<paddle::Tensor>* result) {
result->emplace_back(out->GetTensorBase());
}
void EagerUtils::GetOutputs(const std::shared_ptr<EagerVariable>& out,
const std::vector<paddle::Tensor*>& out_var) {
PADDLE_ENFORCE_NOT_NULL(
out_var[0],
common::errors::Fatal("Tensor is null and cannot be copied. "
"We are trying to OverwriteOutput from its "
"shared_ptr, this error may indicate some outputs "
"are nullptr"));
out_var[0]->set_impl(out->GetTensorBase());
}
void EagerUtils::Output2Result(const std::vector<paddle::Tensor*>& out_var,
std::vector<paddle::Tensor>* result) {
result->reserve(out_var.size());
for (auto* item : out_var) {
result->emplace_back(*item);
}
}
paddle::Tensor EagerUtils::RecoverTensorWrapper(TensorWrapper* tw) {
return tw->recover();
}
std::vector<paddle::Tensor> EagerUtils::RecoverTensorWrapper(
std::vector<TensorWrapper>* tw) {
std::vector<paddle::Tensor> ret;
for (auto& t : *tw) {
ret.emplace_back(t.recover());
}
return ret;
}
std::shared_ptr<egr::GradNodeBase> EagerUtils::GetGradAccumulationNode(
const paddle::Tensor& tensor) {
auto* autograd_ptr = nullable_autograd_meta(tensor);
if (!autograd_ptr) {
return nullptr;
}
auto node_ptr = autograd_ptr->GetMutableGradNode();
if (node_ptr && node_ptr.get()) {
if (!autograd_ptr->StopGradient()) {
auto accumulation_ptr =
std::dynamic_pointer_cast<GradNodeAccumulation>(node_ptr);
if (accumulation_ptr) {
return accumulation_ptr;
} else {
// Current GradNode is not a egr::GradNodeAccumulation
PADDLE_THROW(common::errors::Fatal(
"GetGradAccumulationNode should only be called on leaf tensor, but "
"target tensor: %s has GradNode which is not a "
"GradNodeAccumulation, and this should not happened unless target "
"tensor is modified by some ops and calling set history for it.",
tensor.name()));
}
} else {
// Current Tensor does not have grad since it's stop_gradient is true;
return nullptr;
}
} else {
if (!autograd_ptr->StopGradient()) {
VLOG(6) << "Add GradNodeAccumulation for tensor: " << tensor.name();
autograd_ptr->SetGradNode(
std::make_shared<egr::GradNodeAccumulation>(tensor));
return autograd_ptr->GetMutableGradNode();
} else {
return nullptr;
}
}
}
void EagerUtils::FillZeroForEmptyOptionalGradInput(
std::vector<paddle::Tensor>* in_grads,
const std::vector<GradSlotMeta>& grad_in_metas) {
for (size_t i = 0; i < in_grads->size(); i++) {
paddle::Tensor& grad = (*in_grads)[i];
if (!grad.initialized() && grad_in_metas[i].HasTensorMeta()) {
if (grad_in_metas[i].IsDistMeta()) {
grad.set_impl(std::make_shared<phi::distributed::DistTensor>(
grad_in_metas[i].DistTensorGlobalDims(),
grad_in_metas[i].DistAttr()));
if (grad_in_metas[i].GetTensorMeta().dims.size() != -1) {
auto tensor_with_zero = paddle::experimental::full(
common::vectorize(grad_in_metas[i].GetTensorMeta().dims),
0.0,
grad_in_metas[i].GetTensorMeta().dtype,
grad_in_metas[i].GetPlace());
*(static_cast<phi::distributed::DistTensor*>(grad.impl().get())
->unsafe_mutable_value()) =
*(static_cast<phi::DenseTensor*>(tensor_with_zero.impl().get()));
}
} else {
auto tensor_with_zero = paddle::experimental::full(
common::vectorize(grad_in_metas[i].GetTensorMeta().dims),
0.0,
grad_in_metas[i].GetTensorMeta().dtype,
grad_in_metas[i].GetPlace());
grad.set_impl(tensor_with_zero.impl());
}
}
}
}
void EagerUtils::FillZeroForEmptyOptionalGradOutput(
std::vector<paddle::Tensor>* output_grads,
const std::vector<GradSlotMeta>& grad_output_metas) {
for (size_t i = 0; i < output_grads->size(); i++) {
if (grad_output_metas[i].IsStopGradient()) {
continue;
}
paddle::Tensor& grad = (*output_grads)[i];
if (!grad.initialized() && grad_output_metas[i].HasTensorMeta()) {
if (grad.defined() && grad.is_selected_rows()) {
continue;
}
if (grad_output_metas[i].IsDistMeta()) {
grad.set_impl(std::make_shared<phi::distributed::DistTensor>(
grad_output_metas[i].DistTensorGlobalDims(),
grad_output_metas[i].DistAttr()));
if (grad_output_metas[i].GetTensorMeta().dims.size() != -1) {
auto tensor_with_zero = paddle::experimental::full(
common::vectorize(grad_output_metas[i].GetTensorMeta().dims),
0.0,
grad_output_metas[i].GetTensorMeta().dtype,
grad_output_metas[i].GetPlace());
*(static_cast<phi::distributed::DistTensor*>(grad.impl().get())
->unsafe_mutable_value()) =
*(static_cast<phi::DenseTensor*>(tensor_with_zero.impl().get()));
}
} else {
auto tensor_with_zero =
paddle::experimental::full( // only create dense tensor.
common::vectorize(grad_output_metas[i].GetTensorMeta().dims),
0.0,
grad_output_metas[i].GetTensorMeta().dtype,
grad_output_metas[i].GetPlace());
grad.set_impl(tensor_with_zero.impl());
}
}
}
}
void EagerUtils::FillZeroForEmptyGradInput(paddle::Tensor* in_grad,
const GradSlotMeta& grad_in_meta) {
if (!in_grad->initialized()) {
PADDLE_ENFORCE(
grad_in_meta.HasTensorMeta(),
common::errors::Fatal(
"Unable to fill empty grad inputs due to empty GradSlotMeta"));
const auto& tensor_meta = grad_in_meta.GetTensorMeta();
if (grad_in_meta.IsDistMeta()) {
in_grad->set_impl(std::make_shared<phi::distributed::DistTensor>(
grad_in_meta.DistTensorGlobalDims(), grad_in_meta.DistAttr()));
if (tensor_meta.dims.size() != -1) {
auto tensor_with_zero =
paddle::experimental::full(common::vectorize(tensor_meta.dims),
0.0,
tensor_meta.dtype,
grad_in_meta.GetPlace());
*(static_cast<phi::distributed::DistTensor*>(in_grad->impl().get())
->unsafe_mutable_value()) =
*(static_cast<phi::DenseTensor*>(tensor_with_zero.impl().get()));
} else {
*(static_cast<phi::distributed::DistTensor*>(in_grad->impl().get())
->unsafe_mutable_value()) =
phi::DenseTensor(
std::make_shared<phi::Allocation>(
nullptr, 0, phi::distributed::GetDefaultPlace()),
phi::DenseTensorMeta());
}
} else {
auto tensor_with_zero =
paddle::experimental::full(common::vectorize(tensor_meta.dims),
0.0,
tensor_meta.dtype,
grad_in_meta.GetPlace());
in_grad->set_impl(tensor_with_zero.impl());
}
}
}
void EagerUtils::FillZeroForEmptyOptionalGradInput(
paddle::Tensor* in_grad, const GradSlotMeta& grad_in_meta) {
if (!in_grad->initialized() && grad_in_meta.HasTensorMeta()) {
const auto& tensor_meta = grad_in_meta.GetTensorMeta();
if (grad_in_meta.IsDistMeta()) {
in_grad->set_impl(std::make_shared<phi::distributed::DistTensor>(
grad_in_meta.DistTensorGlobalDims(), grad_in_meta.DistAttr()));
if (tensor_meta.dims.size() != -1) {
auto tensor_with_zero =
paddle::experimental::full(common::vectorize(tensor_meta.dims),
0.0,
tensor_meta.dtype,
grad_in_meta.GetPlace());
*(static_cast<phi::distributed::DistTensor*>(in_grad->impl().get())
->unsafe_mutable_value()) =
*(static_cast<phi::DenseTensor*>(tensor_with_zero.impl().get()));
}
} else {
auto tensor_with_zero =
paddle::experimental::full(common::vectorize(tensor_meta.dims),
0.0,
tensor_meta.dtype,
grad_in_meta.GetPlace());
in_grad->set_impl(tensor_with_zero.impl());
}
}
}
void EagerUtils::FillZeroForEmptyGradInput(
std::vector<paddle::Tensor>* in_grads,
const std::vector<GradSlotMeta>& grad_in_metas) {
for (size_t i = 0; i < in_grads->size(); i++) {
FillZeroForEmptyGradInput(&in_grads->at(i), grad_in_metas[i]);
}
}
static std::string indent_after_newlines(const std::string& input,
const std::string& indent = "\t",
int count = 1) {
std::string result;
std::string indentation;
for (int i = 0; i < count; i++) {
indentation += indent;
}
bool need_indent = false;
for (char c : input) {
if (need_indent && c != '\n' && c != '\r') {
result += indentation;
need_indent = false;
}
result += c;
if (c == '\n') {
need_indent = true;
}
}
if (need_indent) {
result += indentation;
}
return result;
}
std::string EagerUtils::GradNodeStr(const egr::GradNodeBase& node) {
if (VLOG_IS_ON(6)) {
const char* GRAD_NODE_TEMPLATE =
"\nBackwardOutMeta: %s ,\nBackwardInMeta: %s \n";
const char* GRAD_SLOT_META_TEMPLATE = " {\nSlotSize: [%d]: %s\n} ";
const char* SLOT_INFO_TEMPLATE =
"\nSlotID: %s,\nStopGradients: %s,\nEdges[ %s ]\n";
auto out_metas = node.OutputMeta();
auto in_metas = node.InputMeta();
std::string out_slot_str = "";
std::string in_slot_str = "";
const char* EDGE_INFO_TEMPLATE = " { [%d, %d]: [%s, %s] }, ";
std::string slot_str = "";
for (size_t i = 0; i < out_metas.size(); i++) {
std::string edges_str = "";
std::string sg_str = "";
for (const GradSlotMeta& meta : out_metas[i]) {
const egr::Edge& edge = meta.GetEdge();
if (edge.IsInitialized()) {
edges_str += paddle::string::Sprintf(EDGE_INFO_TEMPLATE,
edge.GetEdgeRankInfo().first,
edge.GetEdgeRankInfo().second,
edge.GetGradNode(),
edge.GetGradNode()->name());
} else {
edges_str += paddle::string::Sprintf("{ NULL Edge }");
}
sg_str += meta.IsStopGradient() ? "1, " : "0, ";
}
out_slot_str +=
paddle::string::Sprintf(SLOT_INFO_TEMPLATE, i, sg_str, edges_str);
}
std::string out_meta_str = paddle::string::Sprintf(
GRAD_SLOT_META_TEMPLATE, out_metas.size(), out_slot_str);
for (size_t i = 0; i < in_metas.size(); i++) {
std::string edges_str = "";
std::string sg_str = "";
for (const GradSlotMeta& meta : in_metas[i]) {
edges_str += paddle::string::Sprintf("{ NULL Edge }");
sg_str += meta.IsStopGradient() ? "1, " : "0, ";
}
in_slot_str +=
paddle::string::Sprintf(SLOT_INFO_TEMPLATE, i, sg_str, edges_str);
}
std::string in_meta_str = paddle::string::Sprintf(
GRAD_SLOT_META_TEMPLATE, in_metas.size(), in_slot_str);
return paddle::string::Sprintf(GRAD_NODE_TEMPLATE,
indent_after_newlines(out_meta_str),
indent_after_newlines(in_meta_str));
} else if (VLOG_IS_ON(5)) {
const char* GRAD_NODE_TEMPLATE =
"\nBackwardOutMeta: %s ,\nBackwardInMeta: %s \n";
const char* GRAD_SLOT_META_TEMPLATE = "\nSlotSize: %d";
std::string out_meta_str = paddle::string::Sprintf(
GRAD_SLOT_META_TEMPLATE, node.OutputMeta().size());
std::string in_meta_str = paddle::string::Sprintf(GRAD_SLOT_META_TEMPLATE,
node.InputMeta().size());
return paddle::string::Sprintf(GRAD_NODE_TEMPLATE,
indent_after_newlines(out_meta_str),
indent_after_newlines(in_meta_str));
} else {
return "[ Not specified grad node log level. ] ";
}
}
std::string EagerUtils::GradNodeStr(const paddle::Tensor& t) {
auto* ad_meta = nullable_autograd_meta(t);
if (ad_meta && (ad_meta->GetMutableGradNode().get())) {
return GradNodeStr((*ad_meta->GetMutableGradNode().get()));
} else {
return "None";
}
}
template <typename T>
std::string FormatData(const phi::DenseTensor& print_tensor,
int precision,
bool use_binary = false) {
int64_t print_size = print_tensor.numel();
std::stringstream data_stream;
const T* data = nullptr;
phi::DenseTensor cpu_tensor;
if (print_tensor.place().GetType() == phi::AllocationType::CPU) {
data = print_tensor.data<T>();
} else {
phi::CPUPlace cpu_place;
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto dev_ctx = pool.Get(print_tensor.place());
phi::Copy(*dev_ctx, print_tensor, cpu_place, true, &cpu_tensor);
data = cpu_tensor.data<T>();
}
if (print_size > 0) {
auto print_element =
[&data_stream, &precision, &use_binary](const auto& elem) {
auto to_binary = [](const auto& elem) {
const unsigned char* bytes =
reinterpret_cast<const unsigned char*>(&elem);
std::ostringstream oss;
for (size_t i = 0; i < sizeof(elem); ++i) {
oss << bytes[i];
}
return oss.str();
};
if constexpr (std::is_same_v<T, phi::complex64> ||
std::is_same_v<T, phi::complex128>) {
if (use_binary) {
data_stream << to_binary(elem.real) << to_binary(elem.imag);
} else {
data_stream << std::fixed << std::setprecision(precision)
<< static_cast<double>(elem.real) << "+" << std::fixed
<< std::setprecision(precision)
<< static_cast<double>(elem.imag) << "j";
}
} else {
if (use_binary) {
data_stream << to_binary(elem);
} else {
data_stream << std::fixed << std::setprecision(precision)
<< static_cast<double>(elem);
}
}
};
print_element(data[0]);
for (int64_t i = 1; i < print_size; ++i) {
print_element(data[i]);
}
}
return data_stream.str();
}
std::string GetTensorMD5Checksum(const paddle::Tensor& t) {
if (!t.defined() || !t.has_allocation()) {
return "None";
}
// only data
phi::funcs::TensorFormatter formatter;
std::stringstream data_stream;
phi::DenseTensor* dense_tensor_ptr = nullptr;
if (t.is_dist_tensor()) {
auto dist_t =
std::static_pointer_cast<phi::distributed::DistTensor>(t.impl());
dense_tensor_ptr = dist_t->unsafe_mutable_value();
} else {
dense_tensor_ptr = dynamic_cast<phi::DenseTensor*>(t.impl().get());
}
auto& dense_tensor = *(dense_tensor_ptr);
auto dtype = dense_tensor.dtype();
int precision = FLAGS_tensor_md5_checksum_precision;
bool use_binary = FLAGS_tensor_md5_checksum_use_binary_format;
std::string data_str = "";
if (dtype == phi::DataType::FLOAT32) {
data_str = FormatData<float>(dense_tensor, precision, use_binary);
} else if (dtype == phi::DataType::FLOAT64) {
data_str = FormatData<double>(dense_tensor, precision, use_binary);
} else if (dtype == phi::DataType::INT32) {
data_str = FormatData<int>(dense_tensor, precision, use_binary);
} else if (dtype == phi::DataType::INT64) {
data_str = FormatData<int64_t>(dense_tensor, precision, use_binary);
} else if (dtype == phi::DataType::BOOL) {
data_str = FormatData<bool>(dense_tensor, precision, use_binary);
} else if (dtype == phi::DataType::FLOAT16) {
data_str = FormatData<phi::float16>(dense_tensor, precision, use_binary);
} else if (dtype == phi::DataType::BFLOAT16) {
data_str = FormatData<phi::bfloat16>(dense_tensor, precision, use_binary);
} else if (dtype == phi::DataType::FLOAT8_E4M3FN) {
data_str =
FormatData<phi::float8_e4m3fn>(dense_tensor, precision, use_binary);
} else if (dtype == phi::DataType::FLOAT8_E5M2) {
data_str =
FormatData<phi::float8_e5m2>(dense_tensor, precision, use_binary);
} else if (dtype == phi::DataType::COMPLEX64) {
data_str = FormatData<phi::complex64>(dense_tensor, precision, use_binary);
} else if (dtype == phi::DataType::COMPLEX128) {
data_str = FormatData<phi::complex128>(dense_tensor, precision, use_binary);
}
return paddle::md5(data_str);
}
/**
* Print Input Output (level 0 means least info, level 2 means most info)
* **/
std::string EagerUtils::TensorStr(const paddle::Tensor& t) {
std::string tensor_name_str = "";
if (t.name() == "") {
tensor_name_str = "None";
} else {
tensor_name_str = t.name();
}
const char* TENSOR_INFO_TEMPLATE =
"\n\tType: %s,\n\tDtype: %s,\n\tPlace: %s,\n\tShape: %s,\n\tDistAttr: "
"%s\n";
std::string tensor_info_str = "";
if (t.defined()) {
if (t.is_dist_tensor()) {
const char* DIST_TENSOR_INFO_TEMPLATE =
"\n\tType: %s,\n\tDtype: %s,\n\t Place: %s,\n\tIs_defined: "
"%s,\n\tIs_initialized: %s,\n "
"Shape: %s,\n DistAttr: %s";
auto dist_t =
std::static_pointer_cast<phi::distributed::DistTensor>(t.impl());
if (t.initialized()) {
tensor_info_str += paddle::string::Sprintf(
DIST_TENSOR_INFO_TEMPLATE,
t.impl()->type_info().name(),
t.dtype(),
t.place().DebugString(),
dist_t->defined(),
dist_t->initialized(),
paddle::string::Sprintf(
"%s, Local Shape: %s", t.dims(), dist_t->local_dims()),
dist_t->dist_attr());
} else {
// NOTE: If the tensor is a dist-tensor, it's place may be `unknown` in
// the no-calculation rank.
tensor_info_str += paddle::string::Sprintf(DIST_TENSOR_INFO_TEMPLATE,
t.impl()->type_info().name(),
t.dtype(),
"Unknown",
dist_t->defined(),
dist_t->initialized(),
t.dims(),
dist_t->dist_attr());
}
} else {
if (t.has_allocation()) {
tensor_info_str += paddle::string::Sprintf(TENSOR_INFO_TEMPLATE,
t.impl()->type_info().name(),
t.dtype(),
t.place().DebugString(),
t.dims(),
"Unknown");
} else {
tensor_info_str += paddle::string::Sprintf(TENSOR_INFO_TEMPLATE,
t.impl()->type_info().name(),
"Unknown",
"Unknown",
"Unknown",
"Unknown");
}
}
} else {
tensor_info_str += "Unknown";
}
if (VLOG_IS_ON(11)) {
const char* TENSOR_PRINT_TEMPLATE =
"{\n\tName: %s,\n\tInitialized: "
"%d,\n\tTensor_Ptr:%d,\n\tTensor_Impl_Ptr: %d,\n\t "
"\n\tTensorInfo:{ %s },\n\tValue:{ %s },\n\tADInfo:[ %s ]}";
auto* ad_meta = nullable_autograd_meta(t);
if (ad_meta && (ad_meta->WeakGrad().lock().get())) {
std::string ad_info_str = "";
const char* AD_INFO_TEMPLATE =
"\n\tGrad: %s ,\n\tGradNode: %s ,\n\tStopGradient: [ %d ]";
ad_info_str += paddle::string::Sprintf(
AD_INFO_TEMPLATE,
indent_after_newlines(TensorStr(ad_meta->Grad())),
indent_after_newlines(GradNodeStr(t)),
ad_meta->StopGradient());
auto* data_ptr = dynamic_cast<phi::DenseTensor*>(t.impl().get());
if (t.has_allocation() && data_ptr) {
return paddle::string::Sprintf(TENSOR_PRINT_TEMPLATE,
tensor_name_str,
t.has_allocation(),
&t,
t.impl(),
indent_after_newlines(tensor_info_str),
*data_ptr,
indent_after_newlines(ad_info_str));
} else {
return paddle::string::Sprintf(TENSOR_PRINT_TEMPLATE,
tensor_name_str,
t.has_allocation(),
&t,
t.impl(),
indent_after_newlines(tensor_info_str),
"None",
indent_after_newlines(ad_info_str));
}
} else {
auto* data_ptr = dynamic_cast<phi::DenseTensor*>(t.impl().get());
if (t.has_allocation() && data_ptr) {
return paddle::string::Sprintf(TENSOR_PRINT_TEMPLATE,
tensor_name_str,
t.has_allocation(),
&t,
t.impl(),
indent_after_newlines(tensor_info_str),
*data_ptr,
"None");
} else {
return paddle::string::Sprintf(TENSOR_PRINT_TEMPLATE,
tensor_name_str,
t.has_allocation(),
&t,
t.impl(),
indent_after_newlines(tensor_info_str),
"None",
"None");
}
}
} else if (VLOG_IS_ON(6)) {
const char* TENSOR_PRINT_TEMPLATE =
"{\n\tName: %s,\n\tInitialized: "
"%d,\n\tTensor_Ptr:%d,\n\tTensor_Impl_Ptr: %d,"
"\n\tTensorInfo: { %s \n\t},\n\tADInfo:{ %s \n\t}\n}";
auto* ad_meta = nullable_autograd_meta(t);
if (ad_meta && (ad_meta->WeakGrad().lock().get())) {
std::string ad_info_str = "";
const char* AD_INFO_TEMPLATE =
"\n\tGrad: %s ,\n\tGradNode: %s ,\n\tStopGradient: [ %d ]";
ad_info_str += paddle::string::Sprintf(
AD_INFO_TEMPLATE,
indent_after_newlines(TensorStr(ad_meta->Grad())),
indent_after_newlines(GradNodeStr(t), "\t", 2),
ad_meta->StopGradient());
return paddle::string::Sprintf(TENSOR_PRINT_TEMPLATE,
tensor_name_str,
t.has_allocation(),
&t,
t.impl(),
indent_after_newlines(tensor_info_str),
indent_after_newlines(ad_info_str));
} else {
return paddle::string::Sprintf(TENSOR_PRINT_TEMPLATE,
tensor_name_str,
t.has_allocation(),
&t,
t.impl(),
indent_after_newlines(tensor_info_str),
"None");
}
} else if (VLOG_IS_ON(5)) {
const char* TENSOR_PRINT_TEMPLATE =
"{\n\tName: %s,\n\tInitialized: "
"%d,\n\tTensor_Ptr:%d,\n\tTensor_Impl_Ptr: %d, "
"\n\tTensorInfo: [ %s ]}";
return paddle::string::Sprintf(TENSOR_PRINT_TEMPLATE,
tensor_name_str,
t.has_allocation(),
&t,
t.impl(),
indent_after_newlines(tensor_info_str));
} else if (VLOG_IS_ON(4)) {
const char* TENSOR_PRINT_TEMPLATE =
"{\n\tName: %s,\n\tInitialized: "
"%d,\n\tTensor_Ptr:%d,\n\tTensor_Impl_Ptr: %d }";
return paddle::string::Sprintf(TENSOR_PRINT_TEMPLATE,
tensor_name_str,
t.has_allocation(),
&t,
t.impl());
} else if (VLOG_IS_ON(3)) {
const char* TENSOR_PRINT_TEMPLATE = "{\n\tName: %s, %s}";
return paddle::string::Sprintf(
TENSOR_PRINT_TEMPLATE, tensor_name_str, tensor_info_str);
}
{ return "[ Not specified tensor log level ]"; }
}
std::string EagerUtils::TensorStr(const std::vector<paddle::Tensor>& tensors) {
std::string tensors_str = "";
for (const auto& tensor : tensors) {
tensors_str += TensorStr(tensor) + ", ";
}
return "[ " + tensors_str + " ]";
}
std::string EagerUtils::TensorStr(const std::vector<paddle::Tensor*>& tensors) {
std::string tensors_str = "";
for (const auto& tensor : tensors) {
tensors_str += TensorStr(*tensor) + ", ";
}
return "[ " + tensors_str + " ]";
}
std::string EagerUtils::TensorStr(const paddle::optional<paddle::Tensor>& t) {
if (!t.is_initialized()) {
return "{ UnDefinedTensor }";
} else {
return TensorStr((*t.get_ptr()));
}
}
std::string EagerUtils::TensorStr(
const paddle::optional<std::vector<paddle::Tensor>>& tensors) {
std::string tensors_str = "";
if (!tensors.is_initialized()) {
return "[ UnDefinedTensor List ]";
} else {
for (const auto& tensor : (*tensors.get_ptr())) {
tensors_str += TensorStr(tensor) + ", ";
}
return "[ " + tensors_str + " ]";
}
}
void DistTensorTypeParser::operator()(const paddle::Tensor& x) {
if (x.defined() && x.is_dist_tensor()) {
*mesh = &(std::dynamic_pointer_cast<phi::distributed::DistTensor>(x.impl())
->process_mesh());
result = true;
}
}
void DistTensorTypeParser::operator()(
const paddle::optional<paddle::Tensor>& x) {
if (x) {
if (x.get_ptr()->defined() && x.get_ptr()->is_dist_tensor()) {
*mesh = &(std::dynamic_pointer_cast<phi::distributed::DistTensor>(
x.get_ptr()->impl())
->process_mesh());
result = true;
}
}
}
void DistTensorTypeParser::operator()(const std::vector<paddle::Tensor>& x) {
if (!x.empty()) {
for (auto& t : x) {
if (t.defined() && t.is_dist_tensor()) {
*mesh =
&(std::dynamic_pointer_cast<phi::distributed::DistTensor>(t.impl())
->process_mesh());
result = true;
break;
}
}
}
}
void DistTensorTypeParser::operator()(
const paddle::optional<std::vector<paddle::Tensor>>& x) {
if (x) {
if (!(x.get_ptr()->empty())) {
for (auto& t : *(x.get_ptr())) {
if (t.defined() && t.is_dist_tensor()) {
*mesh = &(
std::dynamic_pointer_cast<phi::distributed::DistTensor>(t.impl())
->process_mesh());
result = true;
break;
}
}
}
}
}
void CheckInputsNeedConvertDistTensor::operator()(const paddle::Tensor& x) {
if (x.defined()) {
if (x.is_dist_tensor()) {
*mesh =
&(std::dynamic_pointer_cast<phi::distributed::DistTensor>(x.impl())
->process_mesh());
have_dist = true;
} else if (x.is_dense_tensor()) {
have_dense = true;
}
}
}
void CheckInputsNeedConvertDistTensor::operator()(
const paddle::optional<paddle::Tensor>& x) {
if (x) {
if (x.get_ptr()->defined()) {
if (x.get_ptr()->is_dist_tensor()) {
*mesh = &(std::dynamic_pointer_cast<phi::distributed::DistTensor>(
x.get_ptr()->impl())
->process_mesh());
have_dist = true;
} else if (x.get_ptr()->is_dense_tensor()) {
have_dense = true;
}
}
}
}
void CheckInputsNeedConvertDistTensor::operator()(
const std::vector<paddle::Tensor>& x) {
if (!x.empty()) {
for (auto& t : x) {
if (t.defined()) {
if (t.is_dist_tensor()) {
*mesh = &(
std::dynamic_pointer_cast<phi::distributed::DistTensor>(t.impl())
->process_mesh());
have_dist = true;
} else if (t.is_dense_tensor()) {
have_dense = true;
}
}
}
}
}
void CheckInputsNeedConvertDistTensor::operator()(
const paddle::optional<std::vector<paddle::Tensor>>& x) {
if (x) {
if (x.get_ptr()->empty()) return;
for (auto& t : *(x.get_ptr())) {
if (!t.defined()) continue;
if (t.is_dist_tensor()) {
*mesh =
&(std::dynamic_pointer_cast<phi::distributed::DistTensor>(t.impl())
->process_mesh());
have_dist = true;
} else if (t.is_dense_tensor()) {
have_dense = true;
}
}
}
}
void DistTensorConverter::convert(paddle::Tensor* x) {
ConvertToDistTensor(x, mesh);
}
void DistTensorConverter::operator()(paddle::Tensor* x) {
DistTensorConverter::convert(x);
}
void DistTensorConverter::operator()(paddle::optional<paddle::Tensor>* x) {
if (*x) {
DistTensorConverter::convert(x->get_ptr());
}
}
void DistTensorConverter::operator()(std::vector<paddle::Tensor>* x) {
if (!x->empty()) {
for (auto& t : *x) {
DistTensorConverter::convert(&t);
}
}
}
void DistTensorConverter::operator()(
paddle::optional<std::vector<paddle::Tensor>>* x) {
if (*x) {
if (!(x->get_ptr()->empty())) {
for (auto& t : *(x->get_ptr())) {
if (!t.is_dist_tensor()) {
DistTensorConverter::convert(&t);
}
}
}
}
}
void ConvertToDistTensor(paddle::Tensor* x,
const phi::distributed::ProcessMesh* mesh) {
if (!x->defined()) {
return;
}
if (x->is_dist_tensor()) {
auto dist_ptr =
std::dynamic_pointer_cast<phi::distributed::DistTensor>(x->impl());
if (!dist_ptr->skip_check_mesh() && x->dims().size() > 0) {
// NOTE(pkuzyc): In MoE expert parallelism, the mesh of the
// inputs and outputs of different experts are different, so
// skip checking mesh in the following two cases:
// 1. The ``skip_check_mesh_`` flag is true. The MoE-related apis
// sets this flag to indicate that the difference between tensor's
// mesh is allowed.
// 2. The tensor is a 0-D tensor. Specifically, in MoE expert
// parallelism, the learning rate's mesh is global, but expert
// weights' mesh is the subset of the global mesh, this is also
// allowed so skip checking the mesh of 0-D tensor.
PADDLE_ENFORCE_EQ(
std::dynamic_pointer_cast<phi::distributed::DistTensor>(x->impl())
->process_mesh(),
*mesh,
common::errors::InvalidArgument(
"Input %s has different mesh. However all inputs should "
"have the same mesh.",
x->name()));
}
return;
} else {
PADDLE_ENFORCE_EQ(
phi::DenseTensor::classof(x->impl().get()),
true,
common::errors::InvalidArgument(
"Failed to convert input %s impl to phi::distributed::DistTensor "
"as it's not phi::DenseTensor.",
x->name()));
phi::distributed::Placements placements;
for (int64_t i = 0; i < mesh->ndim(); ++i) {
placements.emplace_back(std::make_shared<phi::distributed::Replicate>());
}
auto dense_t = std::static_pointer_cast<phi::DenseTensor>(x->impl());
// auto parallel in dygraph doesn't support strided kernel.
if (!dense_t->meta().is_contiguous()) {
*dense_t = paddle::experimental::Trans2Contiguous(*dense_t);
}
x->set_impl(std::make_shared<phi::distributed::DistTensor>(
dense_t, *mesh, placements));
}
}
std::shared_ptr<paddle::Tensor> DistTensorPtrConverter::builder(
const paddle::Tensor& x) {
PADDLE_ENFORCE_EQ(
x.defined(),
true,
common::errors::InvalidArgument(
"Input tensor for DistTensor conversion is not defined. "
"All inputs must be valid tensors."));
if (x.is_dist_tensor()) {
auto dist_impl =
std::dynamic_pointer_cast<phi::distributed::DistTensor>(x.impl());
PADDLE_ENFORCE_NE(
dist_impl,
nullptr,
common::errors::InvalidArgument("Input tensor claims to be DistTensor "
"but has invalid implementation."));
PADDLE_ENFORCE_EQ(
dist_impl->process_mesh(),
*mesh,
common::errors::InvalidArgument(
"Input DistTensor's mesh does not match builder's mesh. "
"Expected mesh: %s, Got mesh: %s",
mesh->to_string(),
dist_impl->process_mesh().to_string()));
return std::make_shared<paddle::Tensor>(x);
}
auto dense_impl = std::dynamic_pointer_cast<phi::DenseTensor>(x.impl());
PADDLE_ENFORCE_NE(dense_impl,
nullptr,
common::errors::InvalidArgument(
"Failed to convert input tensor '%s' to DistTensor: "
"Tensor implementation is not DenseTensor.",
x.name()));
std::shared_ptr<phi::DenseTensor> dense_tensor =
std::make_shared<phi::DenseTensor>(*dense_impl);
phi::distributed::Placements placements;
placements.reserve(mesh->ndim());
for (int64_t i = 0; i < mesh->ndim(); ++i) {
placements.emplace_back(std::make_shared<phi::distributed::Replicate>());
}
auto dist_tensor_impl = std::make_shared<phi::distributed::DistTensor>(
dense_tensor, *mesh, placements);
return std::make_shared<paddle::Tensor>(dist_tensor_impl);
}
std::shared_ptr<paddle::Tensor> DistTensorPtrConverter::operator()(
const paddle::Tensor& x) {
return builder(x);
}
std::string CreateNodeLabelInDot(GradNodeBase* node) {
std::ostringstream oss;
oss << node->name() << "\\nPtr: " << std::hex << node;
return oss.str();
}
std::string CreateForwardNodeLabelInDot(GradNodeBase* node) {
std::ostringstream oss;
std::string name = node->name();
if (name == "GradNodeAccumulation") {
name = "Node";
} else {
// erase "GradNode"
const std::string suffix = "GradNode";
size_t pos = name.find(suffix);
if (pos != std::string::npos) {
name.erase(pos, suffix.length());
}
}
oss << name << "\\nGradNode: " << std::hex << node;
return oss.str();
}
std::string CreateEdgeLabelInDot(const paddle::Tensor& tensor) {
std::ostringstream oss;
if (VLOG_IS_ON(6) || FLAGS_enable_unique_name) {
oss << tensor.name() << "\\n"
<< tensor.place() << "\\n"
<< tensor.dtype() << "[" << tensor.dims() << "]";
} else {
oss << tensor.place() << "\\n"
<< tensor.dtype() << "[" << tensor.dims() << "]";
}
return oss.str();
}
std::string CreateEdgeLabelInDot(const phi::DenseTensorMeta& tensor) {
std::ostringstream oss;
oss << tensor.dtype << " [" << tensor.dims << "]";
return oss.str();
}
void SaveStringToFile(const std::string& file_path,
const std::string& str,
const std::string& mode) {
std::ios_base::openmode open_mode = std::ios::out;
if (mode == "append") {
open_mode |= std::ios::app;
} else if (mode == "trunc") {
open_mode |= std::ios::trunc;
}
std::ofstream outFile(file_path, open_mode);
if (!outFile) {
PADDLE_THROW(
common::errors::Fatal("Cannot open file %s for writing.", file_path));
return;
}
outFile << str;
outFile.close();
return;
}
TEST_API void SaveTensorMD5CheckSumToFile(const std::string& file_path,
const paddle::Tensor& t) {
const std::string& md5_checksum = GetTensorMD5Checksum(t);
SaveStringToFile(file_path, t.name() + ":" + md5_checksum + "\n", "append");
}
TEST_API void SaveTensorMD5CheckSumToFile(
const std::string& file_path, const paddle::optional<paddle::Tensor>& t) {
if (t.get_ptr()) {
SaveTensorMD5CheckSumToFile(file_path, *t.get_ptr());
}
}
TEST_API void SaveTensorMD5CheckSumToFile(
const std::string& file_path, const std::vector<paddle::Tensor>& tensors) {
for (auto& t : tensors) {
SaveTensorMD5CheckSumToFile(file_path, t);
}
}
TEST_API void SaveTensorMD5CheckSumToFile(
const std::string& file_path,
const paddle::optional<std::vector<paddle::Tensor>>& tensors) {
if (tensors.get_ptr()) {
SaveTensorMD5CheckSumToFile(file_path, *(tensors.get_ptr()));
}
}
void SaveDebugInfo(std::string dir_path,
const std::string& serialized_forward_graph,
const std::string& call_stack,
const std::string& serialized_backward_graph,
const std::string& debug_grad_tensors) {
// Use timestamps to distinguish multiple logs
auto now = std::chrono::system_clock::now();
auto now_time_t = std::chrono::system_clock::to_time_t(now);
auto now_tm = *std::localtime(&now_time_t);
auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(
now.time_since_epoch())
.count() %
1000000;
std::ostringstream oss;
oss << std::put_time(&now_tm, "%Y-%m-%d_%H:%M:%S");
oss << "." << std::setfill('0') << std::setw(6) << microseconds;
std::string timestamp = oss.str();
#ifdef _WIN32
auto sep = '\\';
std::for_each(dir_path.begin(), dir_path.end(), [](char& ch) {
if (ch == '/') {
ch = '\\';
}
});
#else
auto sep = '/';
#endif // _WIN32
std::string file_path_prefix =
(dir_path.back() == sep ? dir_path : dir_path + sep) + timestamp;
if (serialized_forward_graph.empty() == false) {
std::string forward_graph_file_path =
file_path_prefix + "_ref_forward_graph" + ".dot";
VLOG(4) << "Save forward graph to file : " << forward_graph_file_path;
SaveStringToFile(forward_graph_file_path, serialized_forward_graph);
}
if (call_stack.empty() == false) {
std::string call_stack_file = file_path_prefix + "_call_stack" + ".log";
VLOG(4) << "Save call stack to file : " << call_stack_file;
SaveStringToFile(call_stack_file, call_stack);
}
if (serialized_backward_graph.empty() == false) {
std::string backward_graph_file_path =
file_path_prefix + "_backward_graph" + ".dot";
VLOG(4) << "Save backward graph to file : " << backward_graph_file_path;
SaveStringToFile(backward_graph_file_path, serialized_backward_graph);
}
if (debug_grad_tensors.empty() == false) {
std::string grad_tensors_file_path =
file_path_prefix + "_grad_tensors" + ".log";
VLOG(4) << "Save grad tensors for debug to file : "
<< grad_tensors_file_path;
SaveStringToFile(grad_tensors_file_path, debug_grad_tensors);
}
}
const std::string GenerateUniqueTensorName(const std::string& unique_api_name,
const std::string& var_name,
const paddle::Tensor* tensor) {
// example: {unique_api_name}_{var_name}_fp16_1024x1024
std::ostringstream oss;
oss << unique_api_name << "_" << var_name << "_" << tensor->dtype() << "_";
for (int i = 0; i < tensor->dims().size(); ++i) {
if (i != 0) {
oss << "x";
}
oss << tensor->dims()[i];
}
return oss.str();
}
TEST_API void SetTensorName(const std::string& unique_api_name,
const std::string& var_name,
paddle::Tensor* tensor) {
if (!tensor->defined() || !tensor->has_allocation()) return;
const std::string& unique_name =
egr::GenerateUniqueTensorName(unique_api_name, var_name, tensor);
tensor->set_name(unique_name);
}
TEST_API void SetTensorName(const std::string& unique_api_name,
const std::string& var_name,
paddle::optional<paddle::Tensor>* tensor) {
if (tensor->get_ptr() != nullptr) {
paddle::Tensor* t = tensor->get_ptr();
if (!t->defined() || !t->has_allocation()) return;
t->set_name(egr::GenerateUniqueTensorName(unique_api_name, var_name, t));
}
}
TEST_API void SetTensorName(const std::string& unique_api_name,
const std::string& var_name,
std::vector<paddle::Tensor>* tensors) {
for (size_t i = 0; i < tensors->size(); i++) {
auto& t = (*tensors)[i];
if (t.defined() && t.has_allocation()) {
t.set_name(egr::GenerateUniqueTensorName(
unique_api_name, var_name + "_" + std::to_string(i), &t));
}
}
}
TEST_API void SetTensorName(const std::string& unique_api_name,
const std::string& var_name,
std::vector<paddle::Tensor*>* tensors) {
for (size_t i = 0; i < tensors->size(); i++) {
auto& t = (*tensors)[i];
if (t->defined() && t->has_allocation()) {
t->set_name(egr::GenerateUniqueTensorName(
unique_api_name, var_name + "_" + std::to_string(i), t));
}
}
}
TEST_API void SetTensorName(
const std::string& unique_api_name,
const std::string& var_name,
paddle::optional<std::vector<paddle::Tensor>>* tensors) {
if (tensors->get_ptr() != nullptr) {
SetTensorName(unique_api_name, var_name, tensors->get_ptr());
}
}
static std::string GenerateGradTensorName(const GradSlotMeta& meta) {
const std::string& forward_name = meta.GetForwardTensorName();
std::string grad_name = forward_name + "@Grad";
return grad_name;
}
TEST_API void SetGradTensorName(
paddle::Tensor* tensor,
const int slot,
const paddle::small_vector<std::vector<GradSlotMeta>, kSlotSmallVectorSize>&
bwd_out_meta) {
const auto& metas = bwd_out_meta[slot];
if (metas.size() == 0) return;
std::string name = GenerateGradTensorName(metas[0]);
if (tensor != nullptr && tensor->defined() && tensor->has_allocation()) {
tensor->set_name(name);
}
}
TEST_API void SetGradTensorName(
std::vector<paddle::Tensor>* tensors,
const int slot,
const paddle::small_vector<std::vector<GradSlotMeta>, kSlotSmallVectorSize>
bwd_out_meta) {
const auto& metas = bwd_out_meta[slot];
for (size_t i = 0; i < tensors->size() && i < metas.size(); i++) {
auto& t = (*tensors)[i];
if (t.defined() && t.has_allocation()) {
std::string name = GenerateGradTensorName(metas[i]);
t.set_name(name);
}
}
}
std::string AddNodeToDebugBackwardGraph(Dot* dot,
GradNodeBase* node,
bool need_dump_backward_subgraph) {
std::string dot_node_label = "";
// If need_dump_backward_subgraph is true,it means that we should capture
// gradnode in subgraph which to be stored in
// EagerBackwardSubGraphNodeRecorder. If we need capture subgraph, the
// gradnode not related subgraph will not be captured
if (need_dump_backward_subgraph &&
!egr::EagerBackwardSubGraphNodeRecorder::Instance().IsGradNodeInVizGuard(
node)) {
// no need to add node to dot graph
} else {
dot_node_label = CreateNodeLabelInDot(node);
if (!dot->ContainsNode(dot_node_label)) {
dot->AddNode(dot_node_label,
paddle::inference::analysis::grey_box_attrs,
dot_node_label,
false);
}
}
return dot_node_label;
}
void AddEdgeToDebugBackwardGraph(Dot* dot,
GradNodeBase* node,
GradNodeBase* next_node,
const paddle::Tensor& t,
const std::string& node_label,
bool need_dump_backward_subgraph) {
std::string dot_node_label = node_label;
if (need_dump_backward_subgraph &&
!egr::EagerBackwardSubGraphNodeRecorder::Instance().IsGradNodeInVizGuard(
node) &&
!egr::EagerBackwardSubGraphNodeRecorder::Instance().IsGradNodeInVizGuard(
next_node)) {
// if we need capture subgraph, the gradnode not related subgraph
// will not be captured
} else {
std::string dot_next_node_label = CreateNodeLabelInDot(next_node);
if (!dot->ContainsNode(dot_next_node_label)) {
if (next_node->name() == "GradNodeAccumulation") {
dot->AddNode(dot_next_node_label,
paddle::inference::analysis::teal_box_attrs,
dot_next_node_label,
false);
} else {
if (need_dump_backward_subgraph == false ||
egr::EagerBackwardSubGraphNodeRecorder::Instance()
.IsGradNodeInVizGuard(next_node)) {
dot->AddNode(dot_next_node_label,
paddle::inference::analysis::grey_box_attrs,
dot_next_node_label,
false);
} else {
// The next node is not in subgraph but the node is in subgraph,
// we use orange_box to mark it
dot->AddNode(dot_next_node_label,
paddle::inference::analysis::orange_box_attrs,
dot_next_node_label,
false);
}
}
}
// if need_dump_backward_subgraph but next_node is in subgraph and node is
// not in subgraph we will add node in subgraph and add edge
if (need_dump_backward_subgraph &&
egr::EagerBackwardSubGraphNodeRecorder::Instance().IsGradNodeInVizGuard(
next_node) &&
!egr::EagerBackwardSubGraphNodeRecorder::Instance()
.IsGradNodeInVizGuard(node)) {
dot_node_label = CreateNodeLabelInDot(node);
// The node is not in subgraph but the node_next node is in subgraph
// we use orange_box to mark it too
if (!dot->ContainsNode(dot_node_label)) {
dot->AddNode(dot_node_label,
paddle::inference::analysis::orange_box_attrs,
dot_node_label,
false);
}
}
std::string tensor_label = CreateEdgeLabelInDot(t);
dot->AddEdge(dot_node_label, dot_next_node_label, {}, tensor_label);
}
}
const std::string FormatTensor(const paddle::Tensor& t) {
if (!t.defined() || !t.has_allocation()) {
return "None";
}
// only data
phi::funcs::TensorFormatter formatter;
phi::DenseTensor* dense_tensor_ptr = nullptr;
if (t.is_dist_tensor()) {
auto dist_t =
std::static_pointer_cast<phi::distributed::DistTensor>(t.impl());
dense_tensor_ptr = dist_t->unsafe_mutable_value();
} else {
dense_tensor_ptr = dynamic_cast<phi::DenseTensor*>(t.impl().get());
}
auto& dense_tensor = *(dense_tensor_ptr);
return formatter.Format(dense_tensor, t.name());
}
void SaveStringToFileWithPID(const std::string& filename,
const std::string& content,
const std::string& mode) {
pid_t pid = getprocessid();
// Create the new filename with PID suffix
std::string newFilename = filename + "." + std::to_string(pid);
SaveStringToFile(newFilename, content, mode);
}
void SavePythonCallStackToFile(const std::string& file_name,
const std::string& api_name) {
SaveStringToFileWithPID(
file_name,
api_name + " : \n" + egr::Controller::Instance().GetPythonStack(),
"append");
}
#define SEPARATOR "============================"
std::string FormatPyLayerBackwardErrorMsg(GradNodeBase* node,
std::string error_mesg) {
std::ostringstream oss;
oss << SEPARATOR << " Error message in backward of " << node->name() << "("
<< node << ")" << SEPARATOR << std::endl;
oss << error_mesg << std::endl;
oss << SEPARATOR << SEPARATOR << SEPARATOR << SEPARATOR << std::endl;
return "\n{\n" + paddle::framework::InsertIndentationIntoEachLine(oss.str()) +
"\n}\n";
}
void CheckGradNodeAccumulation(const paddle::Tensor& tensor) {
auto* autograd_meta = egr::EagerUtils::nullable_autograd_meta(tensor);
if (!autograd_meta) return;
auto grad_node = autograd_meta->GetMutableGradNode();
if (!grad_node || !grad_node.get()) return;
auto accumulation_node =
std::dynamic_pointer_cast<egr::GradNodeAccumulation>(grad_node);
if (!accumulation_node) return;
phi::DataType tensor_dtype = tensor.dtype();
const auto& input_metas = accumulation_node->InputMeta();
if (input_metas.empty() || input_metas[0].empty()) return;
const auto& slot_meta = input_metas[0][0];
if (slot_meta.HasTensorMeta()) {
const auto& tensor_meta = slot_meta.GetTensorMeta();
phi::DataType meta_dtype = tensor_meta.dtype;
if (tensor_dtype != meta_dtype) {
VLOG(7) << "Updating GradNodeAccumulation(" << accumulation_node.get()
<< ") meta dtype from " << phi::DataTypeToString(meta_dtype)
<< " to " << phi::DataTypeToString(tensor_dtype);
accumulation_node->SetGradInMeta(tensor, 0);
}
}
}
void CheckGradNodeAccumulation(const paddle::optional<paddle::Tensor>& tensor) {
if (!tensor) return;
CheckGradNodeAccumulation(*tensor);
}
void CheckGradNodeAccumulation(
const paddle::optional<std::vector<paddle::Tensor>>& tensors) {
if (!tensors) return;
for (const auto& tensor : *tensors) {
CheckGradNodeAccumulation(tensor);
}
}
void CheckGradNodeAccumulation(const std::vector<paddle::Tensor>& tensors) {
for (const auto& tensor : tensors) {
CheckGradNodeAccumulation(tensor);
}
}
void CheckGradNodeAccumulation(
const std::vector<std::vector<paddle::Tensor*>>& tensors) {
for (const auto& sub_tensors : tensors) {
for (const auto& tensor : sub_tensors) {
CheckGradNodeAccumulation(*tensor);
}
}
}
void CheckGradNodeAccumulation(
const paddle::small_vector<std::vector<paddle::Tensor*>>& tensors) {
for (const auto& sub_tensors : tensors) {
for (const auto& tensor : sub_tensors) {
CheckGradNodeAccumulation(*tensor);
}
}
}
LogLevelGuardBackward::LogLevelGuardBackward(bool need_backward_vlog_guard,
GradNodeBase* node) {
//
if (need_backward_vlog_guard &&
egr::EagerBackwardSubGraphNodeRecorder::Instance().IsGradNodeInVlogGuard(
node)) {
saved_level_ = FLAGS_v;
SetVLOGLevel(egr::EagerBackwardSubGraphNodeRecorder::Instance()
.GetSubGraphBwdVlogLevel(node));
initialized_ = true;
}
}
void LogLevelGuardBackward::SetVLOGLevel(int level) {
FLAGS_v = level;
phi::set_phi_vlog_level(level);
}
LogLevelGuardBackward::~LogLevelGuardBackward() {
if (PD_UNLIKELY(initialized_)) {
// We should restore the log level
SetVLOGLevel(saved_level_);
}
}
} // namespace egr