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

662 lines
26 KiB
C++

// Copyright (c) 2019 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/imperative/tracer.h"
#include <map>
#include <set>
#include <unordered_set>
#include <utility>
#include "paddle/common/flags.h"
#include "paddle/fluid/eager/api/utils/global_utils.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/imperative/amp_auto_cast.h"
#include "paddle/fluid/imperative/execution_context.h"
#include "paddle/fluid/imperative/layout_autotune.h"
#include "paddle/fluid/imperative/op_base.h"
#include "paddle/fluid/operators/ops_extra_info.h"
#include "paddle/phi/api/lib/api_gen_utils.h"
#include "paddle/phi/common/place.h"
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/phi/core/platform/denormal.h"
#include "paddle/phi/core/platform/device/device_wrapper.h"
#include "paddle/phi/core/platform/profiler.h"
#include "paddle/phi/core/platform/profiler/event_tracing.h"
#include "paddle/utils/string/string_helper.h"
COMMON_DECLARE_bool(use_mkldnn);
COMMON_DECLARE_bool(use_onednn);
COMMON_DECLARE_string(tracer_onednn_ops_on);
COMMON_DECLARE_string(tracer_onednn_ops_off);
COMMON_DECLARE_bool(use_stride_kernel);
namespace paddle::imperative {
thread_local std::string Tracer::python_stack_ = "";
thread_local bool Tracer::use_layout_autotune_ = false;
static thread_local std::shared_ptr<Tracer> g_current_tracer(nullptr);
static thread_local std::shared_ptr<AmpAttrs> g_current_amp_attrs =
std::make_shared<AmpAttrs>();
static thread_local bool g_has_grad = true;
TEST_API void Tracer::DisableLayoutAutoTune() { use_layout_autotune_ = false; }
TEST_API void Tracer::EnableLayoutAutoTune() {
use_layout_autotune_ = true;
if (FLAGS_use_stride_kernel) {
LOG(WARNING) << "When the layout_autotune policy is on, Paddle will turn "
"off the Stride policy. This will cause the input and "
"output of the Strided API no longer share memory, which "
"may cause problems with model accuracy.";
FLAGS_use_stride_kernel = false;
}
}
bool Tracer::UseLayoutAutoTune() {
#if defined(PADDLE_WITH_CUDA)
if (phi::backends::gpu::TensorCoreAvailable()) {
return use_layout_autotune_;
}
#endif
use_layout_autotune_ = false;
return false;
}
TEST_API void Tracer::SetPythonStack(std::string stack_str) {
python_stack_ = stack_str;
}
TEST_API std::string Tracer::GetPythonStack() { return python_stack_; }
const std::shared_ptr<Tracer>& GetCurrentTracer() { return g_current_tracer; }
TEST_API void SetCurrentTracer(const std::shared_ptr<Tracer>& tracer) {
g_current_tracer = tracer;
VLOG(6) << "Set current tracer: " << g_current_tracer;
}
const std::shared_ptr<AmpAttrs>& GetCurrentAmpAttrs() {
return g_current_amp_attrs;
}
void PassStopGradient(const NameVarBaseMap& outs, bool generate_grad) {
for (const auto& pair : outs) {
for (const auto& var : pair.second) {
// NOTE(zhiqiu): this happens when None output are passed from python
// side. For example, fake_quantize_dequantize_moving_average_abs_max may
// pass None OutAccum in eval mode.
// It can be refined by generate several different pybind interface for
// one operator with different function signature.
if (var == nullptr) {
VLOG(4) << pair.first << " is NULL";
continue;
}
VLOG(6) << "Set output: " << var->Name()
<< "'s OverriddenStopGradient as " << generate_grad;
var->InnerSetOverriddenStopGradient(generate_grad);
}
}
}
void IncreaseVarbaseReferenceCountUntilCopyComplete(
const std::shared_ptr<imperative::VarBase>& var, const phi::Place& place) {
// Note(zhiqiu): Follow the logic of TensorCopy to determine the place that we
// need to add callback, see tensor_utils.cc:245
auto place_ = phi::is_gpu_place(place) ? place : var->Place();
auto tracer = imperative::GetCurrentTracer();
auto gc = tracer->MutableGarbageCollectorIfNotExists(place_);
// Note(zhiqiu): This is an empty callback, the only way is to "reference"
// var, so it will not be destructed until the kernels launched at current
// stream of given place is finished.
auto callback = [var, place_]() {
VLOG(4) << "Run callback of var:" << var->Name() << " at place " << place_;
};
gc->DirectClearCallback(callback);
}
paddle::framework::GarbageCollector* Tracer::MutableGarbageCollectorIfNotExists(
const phi::Place& place) {
// if not exists, create a new GarbageCollector at given place
if (gcs_.count(place) == 0) {
std::unique_ptr<framework::GarbageCollector> gc;
if (phi::is_gpu_place(place)) {
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
gc = std::make_unique<framework::DefaultStreamGarbageCollector>(place, 0);
VLOG(10) << "Created GarbageCollector at " << place;
#else
PADDLE_THROW(common::errors::PermissionDenied(
"Paddle can't use CUDA device since it's not compiled with CUDA,"
"Please recompile or reinstall Paddle with GPU support."));
#endif
} else if (phi::is_cuda_pinned_place(place)) {
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
gc = std::make_unique<framework::CUDAPinnedGarbageCollector>(place, 0);
VLOG(10) << "Created GarbageCollector at " << place;
#else
PADDLE_THROW(common::errors::PermissionDenied(
"Paddle can't use CUDAPinned device since it's not compiled with "
"CUDA,"
"Please recompile or reinstall Paddle with GPU support."));
#endif
} else if (phi::is_xpu_place(place)) {
#if defined(PADDLE_WITH_XPU)
gc = std::make_unique<framework::XPUGarbageCollector>(place, 0);
VLOG(10) << "Created GarbageCollector at " << place;
#else
PADDLE_THROW(common::errors::PermissionDenied(
"Paddle can't use XPU device since it's not compiled with XPU,"
"Please recompile or reinstall Paddle with XPU support."));
#endif
} else if (phi::is_xpu_pinned_place(place)) {
#if defined(PADDLE_WITH_XPU)
gc = std::make_unique<framework::XPUPinnedGarbageCollector>(place, 0);
VLOG(10) << "Created GarbageCollector at " << place;
#else
PADDLE_THROW(common::errors::PermissionDenied(
"Paddle can't use XPUPinned device since it's not compiled with XPU,"
"Please recompile or reinstall Paddle with XPU support."));
#endif
} else if (phi::is_cpu_place(place)) {
gc = std::make_unique<framework::CPUGarbageCollector>(place, 0);
VLOG(10) << "Created GarbageCollector at " << place;
} else if (phi::is_ipu_place(place)) {
#if defined(PADDLE_WITH_IPU)
gc = std::make_unique<framework::IPUGarbageCollector>(place, 0);
VLOG(10) << "Created GarbageCollector at " << place;
#else
PADDLE_THROW(common::errors::PermissionDenied(
"Paddle can't use IPU device since it's not compiled with IPU,"
"Please recompile or reinstall Paddle with IPU support."));
#endif
} else if (phi::is_custom_place(place)) {
#if defined(PADDLE_WITH_CUSTOM_DEVICE)
if (framework::IsFastEagerDeletionModeEnabled()) {
gc =
std::make_unique<framework::CustomDeviceUnsafeFastGarbageCollector>(
place, 0);
VLOG(10) << "Created UnsafeFastGarbageCollector at " << place;
} else {
gc = std::make_unique<framework::CustomDefaultStreamGarbageCollector>(
place, 0);
VLOG(10) << "Created GarbageCollector at " << place;
}
#else
PADDLE_THROW(common::errors::PermissionDenied(
"Paddle can't use CustomDevice since it's not compiled with "
"CustomDevice,"
"Please recompile or reinstall Paddle with CustomDevice "
"support."));
#endif
} else {
PADDLE_THROW(common::errors::PreconditionNotMet(
"Unsupported place for garbage collection"));
}
gcs_.emplace(place, std::move(gc));
}
return gcs_.at(place).get();
}
template <typename VarType>
void Tracer::TraceOp(const std::string& type,
const NameVarMap<VarType>& ins,
const NameVarMap<VarType>& outs,
framework::AttributeMap attrs,
const phi::Place& place,
bool trace_backward,
const std::map<std::string, std::string>& inplace_map,
paddle::framework::AttributeMap* passed_default_attrs_,
bool use_default_attr_map) {
TraceOpImpl<VarType>(type,
ins,
outs,
attrs,
place,
trace_backward,
inplace_map,
passed_default_attrs_,
use_default_attr_map);
}
template <typename VarType>
void Tracer::TraceOpImpl(const std::string& type,
const NameVarMap<VarType>& ins,
const NameVarMap<VarType>& outs,
framework::AttributeMap& attrs,
const phi::Place& place,
bool trace_backward,
const std::map<std::string, std::string>& inplace_map,
paddle::framework::AttributeMap* passed_default_attrs_,
bool use_default_attr_map) {
phi::RecordEvent op_type_record_event(
type, phi::TracerEventType::Operator, 1);
platform::ScopedFlushDenormal flush;
VLOG(4) << "Trace Op: " << type;
if (FLAGS_use_mkldnn || FLAGS_use_onednn) {
// if both lists are empty all ops are enabled (default for
// FLAGS_use_onednn=1)
// if ops_on list is not empty only ops from that list are enabled
if (!FLAGS_tracer_onednn_ops_on.empty()) {
auto is_on = FLAGS_tracer_onednn_ops_on.find(type) != std::string::npos;
attrs["use_mkldnn"] = is_on;
attrs["use_onednn"] = is_on;
} else {
// if ops_on list is empty all ops are enabled except types from off_list
auto is_off = FLAGS_tracer_onednn_ops_off.find(type) != std::string::npos;
attrs["use_mkldnn"] = !is_off;
attrs["use_onednn"] = !is_off;
}
}
auto op = framework::OpRegistry::CreateOp(type, {}, {}, {}, false);
const auto& op_info = op->Info();
auto* attr_checker = op_info.Checker();
if (attr_checker) {
attr_checker->Check(&attrs, true, /*only_check_exist_value=*/true);
}
const auto& extra_attr_checkers =
operators::ExtraInfoUtils::Instance().GetExtraAttrsChecker(type);
for (const auto& checker : extra_attr_checkers) {
checker(&attrs, true);
}
static paddle::framework::AttributeMap empty_attrs_map = {};
const paddle::framework::AttributeMap& default_attrs =
attr_checker == nullptr ? empty_attrs_map
: attr_checker->GetDefaultAttrMap();
std::unique_ptr<NameVarMap<VarType>> ins_amp = nullptr;
if (GetCurrentAmpAttrs()->GetAmpLevel() == AmpLevel::O1) {
if (GetCurrentAmpAttrs()->GetAmpPhiDtype() == DataType::FLOAT16) {
VLOG(5) << "Float16 Auto Mixed Precision O1 run operator: " << type;
ins_amp = std::make_unique<NameVarMap<VarType>>(
AutoCastInputs<VarType>(type, ins));
} else if (GetCurrentAmpAttrs()->GetAmpPhiDtype() == DataType::BFLOAT16) {
VLOG(5) << "BFloat16 Auto Mixed Precision O1 run operator: " << type;
ins_amp = std::make_unique<NameVarMap<VarType>>(
AutoCastBF16Inputs<VarType>(type, ins));
}
} else if (GetCurrentAmpAttrs()->GetAmpLevel() == AmpLevel::O2) {
if (GetCurrentAmpAttrs()->GetAmpPhiDtype() == DataType::FLOAT16) {
VLOG(5) << "Float16 Auto Mixed Precision O2 run operator: " << type;
ins_amp = std::make_unique<NameVarMap<VarType>>(
CastPureFp16Inputs<VarType>(type, ins));
} else if (GetCurrentAmpAttrs()->GetAmpPhiDtype() == DataType::BFLOAT16) {
VLOG(5) << "BFloat16 Auto Mixed Precision O2 run operator: " << type;
ins_amp = std::make_unique<NameVarMap<VarType>>(
CastPureBf16Inputs<VarType>(type, ins));
}
}
if (phi::is_gpu_place(place)) {
const auto& new_tmp = ins_amp == nullptr ? ins : *ins_amp;
const auto& tracer = imperative::GetCurrentTracer();
ins_amp = std::make_unique<NameVarMap<VarType>>(
imperative::AutoTuneLayout<VarType>(
type, new_tmp, outs, &attrs, tracer));
}
const auto& new_ins = ins_amp == nullptr ? ins : *ins_amp;
try {
if (phi::is_gpu_place(place)) {
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
platform::SetDeviceId(place.device);
#else
PADDLE_THROW(common::errors::PreconditionNotMet(
"PaddlePaddle should compile with GPU if use CUDAPlace."));
#endif
} else if (phi::is_xpu_place(place)) {
#ifdef PADDLE_WITH_XPU
platform::SetXPUDeviceId(place.device);
#else
PADDLE_THROW(common::errors::PreconditionNotMet(
"PaddlePaddle should compile with XPU if use XPUPlace."));
#endif
} else if (phi::is_custom_place(place)) {
#ifdef PADDLE_WITH_CUSTOM_DEVICE
phi::DeviceManager::SetDevice(place);
#else
PADDLE_THROW(common::errors::PreconditionNotMet(
"PaddlePaddle should compile with CustomDevice if use "
"CustomPlace."));
#endif
}
if (!use_default_attr_map) {
PADDLE_ENFORCE_NOT_NULL(passed_default_attrs_,
common::errors::PermissionDenied(
"Detected default_attrs = nullptr."));
VLOG(6) << "Use passed in default attrs";
OpBase::Run(*op, new_ins, outs, attrs, (*passed_default_attrs_), place);
} else {
VLOG(6) << "Use Checker's default attrs";
if (passed_default_attrs_) {
// TODO(jiabin): Update this without copy
*passed_default_attrs_ = default_attrs;
}
OpBase::Run(*op, new_ins, outs, attrs, default_attrs, place);
}
} catch (platform::EnforceNotMet& exception) {
framework::AppendErrorOpHint(type, &exception);
throw exception;
} catch (std::exception& ex) {
PADDLE_THROW(
common::errors::Fatal("Operator %s raises an %s exception.\n"
"The exception content is\n:%s.",
type,
common::demangle(typeid(ex).name()),
ex.what()));
} catch (...) {
// NOTE: this branch represents a very serious bug with
// low probability of occurrence, and we can't get its
// exception content here.
PADDLE_THROW(common::errors::Fatal(
"Operator %s raises an unknown exception.", type));
}
{
phi::RecordEvent node_creation_record_event(
"grad_node_creation", phi::TracerEventType::OperatorInner, 1);
if (ComputeRequiredGrad(new_ins, outs, trace_backward)) {
PADDLE_ENFORCE_EQ(
passed_default_attrs_,
nullptr,
common::errors::PermissionDenied(
"We expect passed_default_attrs_ is nullptr while "
"use_default_attr_map is true, however we got not null "
"passed_default_attrs_. Please check your usage of trace_op. "));
CreateGradOpNode(
*op, new_ins, outs, attrs, default_attrs, place, inplace_map);
} else {
VLOG(3) << "No Grad to track for Op: " << type;
}
VLOG(6) << "Finish Trace Op: " << type;
}
}
template TEST_API void Tracer::TraceOp<VarBase>(
const std::string& type,
const NameVarMap<VarBase>& ins,
const NameVarMap<VarBase>& outs,
framework::AttributeMap attrs,
const phi::Place& place,
bool trace_backward,
const std::map<std::string, std::string>& inplace_map,
paddle::framework::AttributeMap* default_attrs,
bool use_default_attr_map);
template PADDLE_API void Tracer::TraceOp<egr::EagerVariable>(
const std::string& type,
const NameVarMap<egr::EagerVariable>& ins,
const NameVarMap<egr::EagerVariable>& outs,
framework::AttributeMap attrs,
const phi::Place& place,
bool trace_backward,
const std::map<std::string, std::string>& inplace_map_,
paddle::framework::AttributeMap* default_attrs,
bool use_default_attr_map);
void Tracer::TraceOp(const std::string& type,
const NameVarBaseMap& ins,
const NameVarBaseMap& outs,
framework::AttributeMap attrs,
const std::map<std::string, std::string>& inplace_map) {
TraceOp<VarBase>(type,
ins,
outs,
std::move(attrs),
expected_place_,
g_has_grad,
inplace_map);
}
void Tracer::TraceOp(const std::string& type,
const NameTensorMap& ins,
const NameTensorMap& outs,
paddle::framework::AttributeMap& attrs,
const phi::Place& place,
paddle::framework::AttributeMap* default_attrs,
bool use_default_attr_map,
const std::map<std::string, std::string>& inplace_map) {
VLOG(6) << "Running On Eager TraceOp with use_default_attr_map: "
<< use_default_attr_map;
std::map<DenseTensor*, DenseTensor*> need_backup_inputs2outputs;
std::map<DenseTensor*, std::shared_ptr<phi::Allocation>>
need_backup_inputs2holder;
std::map<DenseTensor*, phi::DDim> need_backup_inputs2strides;
std::map<DenseTensor*, size_t> need_backup_inputs2offset;
if (FLAGS_use_stride_kernel) {
for (auto& iter : inplace_map) {
auto inputs_iter = ins.find(iter.first);
for (size_t i = 0; i < inputs_iter->second.size(); i++) {
auto var = inputs_iter->second[i]->MutableVar();
if (var->IsType<DenseTensor>()) {
auto dense_tensor = var->GetMutable<DenseTensor>();
if (!dense_tensor->meta().is_contiguous()) {
NameTensorMap* tmp_out = const_cast<NameTensorMap*>(&outs);
auto outputs_iter = tmp_out->find(iter.second);
outputs_iter->second[i] = std::make_shared<egr::EagerVariable>(
egr::Controller::Instance().GenerateUniqueName());
need_backup_inputs2outputs[dense_tensor] =
outputs_iter->second[i]
->MutableVar()
->GetMutable<DenseTensor>();
need_backup_inputs2holder[dense_tensor] = dense_tensor->Holder();
need_backup_inputs2strides[dense_tensor] = dense_tensor->strides();
need_backup_inputs2offset[dense_tensor] = dense_tensor->offset();
}
}
}
}
TraceOpImpl<egr::EagerVariable>(type,
ins,
outs,
attrs,
place,
false,
{},
default_attrs,
use_default_attr_map);
auto dev_ctx = phi::DeviceContextPool::Instance().Get(place);
for (auto& iter : need_backup_inputs2outputs) {
iter.first->ResetHolder(need_backup_inputs2holder[iter.first]);
iter.first->set_strides(need_backup_inputs2strides[iter.first]);
iter.first->set_offset(need_backup_inputs2offset[iter.first]);
paddle::experimental::TransStrideLegacy(dev_ctx, iter.second, iter.first);
iter.second->ResetHolder(need_backup_inputs2holder[iter.first]);
iter.second->set_strides(need_backup_inputs2strides[iter.first]);
iter.second->set_offset(need_backup_inputs2offset[iter.first]);
}
} else {
TraceOpImpl<egr::EagerVariable>(type,
ins,
outs,
attrs,
place,
false,
inplace_map,
default_attrs,
use_default_attr_map);
}
}
void Tracer::TraceOp(const std::string& type,
const NameTensorMap& ins,
const NameTensorMap& outs,
paddle::framework::AttributeMap attrs) {
VLOG(6) << "Running On Eager TraceOp(4 args): ";
TraceOpImpl<egr::EagerVariable>(
type, ins, outs, attrs, expected_place_, false, {}, nullptr, true);
}
void Tracer::TraceOp(const std::string& type,
const NameTensorMap& ins,
const NameTensorMap& outs,
paddle::framework::AttributeMap& attrs,
const std::map<std::string, std::string>& inplace_map) {
VLOG(6) << "Running On Eager TraceOp(less): ";
std::map<DenseTensor*, DenseTensor*> need_backup_inputs2outputs;
if (FLAGS_use_stride_kernel) {
for (auto& iter : inplace_map) {
auto inputs_iter = ins.find(iter.first);
for (size_t i = 0; i < inputs_iter->second.size(); i++) {
auto var = inputs_iter->second[i]->MutableVar();
if (var->IsType<DenseTensor>()) {
auto dense_tensor = var->GetMutable<DenseTensor>();
if (!dense_tensor->meta().is_contiguous()) {
NameTensorMap* tmp_out = const_cast<NameTensorMap*>(&outs);
auto outputs_iter = tmp_out->find(iter.second);
outputs_iter->second[i] = std::make_shared<egr::EagerVariable>(
egr::Controller::Instance().GenerateUniqueName());
need_backup_inputs2outputs[dense_tensor] =
outputs_iter->second[i]
->MutableVar()
->GetMutable<DenseTensor>();
}
}
}
}
} else {
TraceOpImpl<egr::EagerVariable>(type,
ins,
outs,
attrs,
expected_place_,
false,
inplace_map,
nullptr,
true);
}
}
TEST_API void Tracer::SetExpectedPlace(phi::Place place) {
expected_place_ = place;
}
TEST_API bool Tracer::HasGrad() const { return g_has_grad; }
TEST_API void Tracer::SetHasGrad(bool has_grad) { g_has_grad = has_grad; }
TEST_API void Tracer::SetUsePromote(bool use_promote) {
VLOG(4) << "set use_promote to " << use_promote;
g_current_amp_attrs->SetUsePromote(use_promote);
}
TEST_API bool Tracer::GetUsePromote() const {
return g_current_amp_attrs->GetUsePromote();
}
TEST_API void Tracer::SetAmpLevel(AmpLevel level) {
VLOG(4) << "set amp_level to " << static_cast<unsigned int>(level);
g_current_amp_attrs->SetAmpLevel(level);
}
TEST_API AmpLevel Tracer::GetAmpLevel() const {
return g_current_amp_attrs->GetAmpLevel();
}
bool Tracer::ComputeRequiredGrad(const NameVarBaseMap& ins,
const NameVarBaseMap& outs,
bool trace_backward) {
if (!trace_backward) return false;
for (const auto& name_pair : ins) {
for (const auto& var_base : name_pair.second) {
if (!var_base->OverriddenStopGradient()) {
VLOG(6) << "Find out input: " << var_base->Name()
<< "'s GeneratedGrad is True";
PassStopGradient(outs, var_base->OverriddenStopGradient());
return true;
}
}
}
return false;
}
void Tracer::SetAmpDtype(std::string amp_dtype) {
VLOG(4) << "set amp_dtype to " << amp_dtype;
g_current_amp_attrs->SetAmpDtype(amp_dtype);
}
std::string Tracer::GetAmpDtype() const {
return g_current_amp_attrs->GetAmpDtype();
}
DataType Tracer::GetAmpPhiDtype() const {
return g_current_amp_attrs->GetAmpPhiDtype();
}
bool Tracer::ComputeRequiredGrad(const NameTensorMap& ins,
const NameTensorMap& outs,
bool trace_backward) {
return false;
}
phi::KernelSignature Tracer::GetExpectedKernelSignature(
const std::string& type,
const NameTensorMap& ins,
const NameTensorMap& outs,
framework::AttributeMap attrs) const {
auto op = framework::OpRegistry::CreateOp(type, {}, {}, {}, false);
framework::RuntimeContext ctx({}, {});
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* dev_ctx = pool.Get(CPUPlace());
const auto& op_info = op->Info();
auto* attr_checker = op_info.Checker();
if (attr_checker) {
attr_checker->Check(&attrs, true, /*only_check_exist_value=*/true);
}
static paddle::framework::AttributeMap empty_attrs_map = {};
const paddle::framework::AttributeMap& default_attrs =
attr_checker == nullptr ? empty_attrs_map
: attr_checker->GetDefaultAttrMap();
auto dygraph_exe_ctx =
imperative::DygraphExecutionContext<egr::EagerVariable>(
*op,
framework::Scope(),
*dev_ctx,
ctx,
ins,
outs,
attrs,
default_attrs);
auto* opbase_with_kernel =
dynamic_cast<framework::OperatorWithKernel*>(op.get());
PADDLE_ENFORCE_NE(opbase_with_kernel,
nullptr,
common::errors::InvalidArgument(
"This op type:`%s` is not a OperatorWithKernel, only "
"OperatorWithKernel can get KernelSignature",
type));
if (phi::KernelFactory::Instance().HasStructuredKernel(type)) {
return phi::KernelSignature(op->Type().c_str());
} else {
return phi::KernelSignature(
opbase_with_kernel->GetExpectedPhiKernelArgs(dygraph_exe_ctx));
}
}
} // namespace paddle::imperative