未验证 提交 ab46b14c 编写于 作者: Q qiuwenbo 提交者: GitHub

赛题七-开发grad_fn、next_functions两个API 并暴露到python端-v1 (#54838)

* [尝试] 给tensor增加一个属性, 这个属性是一个定值 1

* 暴露gradnode 并构建gradnode新的方法(用来测试)进行暴露给python python端可以访问

* 开发grad_fn、next_functions两个API 并暴露到python端- 做一些规范化处理

* 增加一个单元测试

* 优化 code-style
上级 22c49634
...@@ -559,4 +559,20 @@ void GradNodeBase::HandleComplexGradToRealGrad( ...@@ -559,4 +559,20 @@ void GradNodeBase::HandleComplexGradToRealGrad(
} }
} }
std::vector<std::shared_ptr<GradNodeBase>> GradNodeBase::NextFunctions() {
std::vector<std::shared_ptr<GradNodeBase>> next_nodes;
const paddle::small_vector<std::vector<GradSlotMeta>, kSlotSmallVectorSize>&
metas = OutputMeta();
for (const auto& meta_list : metas) {
for (const GradSlotMeta& meta : meta_list) {
const auto& edge = meta.GetEdge();
std::shared_ptr<GradNodeBase> next_node = edge.GetMutableGradNode();
next_nodes.push_back(next_node);
}
}
return next_nodes;
}
} // namespace egr } // namespace egr
...@@ -251,6 +251,8 @@ class GradNodeBase { ...@@ -251,6 +251,8 @@ class GradNodeBase {
return true; return true;
} }
std::vector<std::shared_ptr<egr::GradNodeBase>> NextFunctions();
/** /**
* Apply GradientHook * Apply GradientHook
* **/ * **/
......
...@@ -22,6 +22,7 @@ limitations under the License. */ ...@@ -22,6 +22,7 @@ limitations under the License. */
#include "paddle/fluid/eager/api/all.h" #include "paddle/fluid/eager/api/all.h"
#include "paddle/fluid/eager/autograd_meta.h" #include "paddle/fluid/eager/autograd_meta.h"
#include "paddle/fluid/eager/utils.h" #include "paddle/fluid/eager/utils.h"
#include "paddle/fluid/imperative/op_base.h"
#include "paddle/fluid/memory/allocation/allocator.h" #include "paddle/fluid/memory/allocation/allocator.h"
#include "paddle/fluid/memory/memcpy.h" #include "paddle/fluid/memory/memcpy.h"
#include "paddle/fluid/platform/enforce.h" #include "paddle/fluid/platform/enforce.h"
...@@ -31,6 +32,7 @@ limitations under the License. */ ...@@ -31,6 +32,7 @@ limitations under the License. */
#include "paddle/phi/common/data_type.h" #include "paddle/phi/common/data_type.h"
#include "paddle/phi/core/compat/convert_utils.h" #include "paddle/phi/core/compat/convert_utils.h"
#include "paddle/phi/core/dense_tensor.h" #include "paddle/phi/core/dense_tensor.h"
#pragma GCC diagnostic ignored "-Wwrite-strings" #pragma GCC diagnostic ignored "-Wwrite-strings"
namespace paddle { namespace paddle {
...@@ -301,6 +303,41 @@ PyObject* tensor_properties_get_dtype(TensorObject* self, void* closure) { ...@@ -301,6 +303,41 @@ PyObject* tensor_properties_get_dtype(TensorObject* self, void* closure) {
EAGER_CATCH_AND_THROW_RETURN_NULL EAGER_CATCH_AND_THROW_RETURN_NULL
} }
PyObject* tensor_properties_get_grad_fn(TensorObject* self, void* closure) {
EAGER_TRY
if (!self->tensor.defined()) {
// Handle undefined tensors if necessary; otherwise, return nullptr or an
// appropriate PyObject. In this case, I will return Py_None.
Py_INCREF(Py_None);
return Py_None;
}
// Get GradNode from the tensor
auto meta = egr::EagerUtils::nullable_autograd_meta(
self->tensor); // If meta exists, get the GradNode
if (meta) {
// Get the GradNode from meta
auto grad_node = meta->GradNode(); // Convert GradNode to a Python object
// The conversion will depend on the structure of GradNode.
if (!grad_node) {
Py_INCREF(Py_None);
return Py_None;
}
PyObject* py_grad_node = ToPyObject(grad_node);
return py_grad_node;
} else {
// If meta does not exist, return an appropriate Python object (e.g., None
// or a special value).
Py_INCREF(Py_None);
return Py_None;
}
EAGER_CATCH_AND_THROW_RETURN_NULL
}
struct PyGetSetDef variable_properties[] = { struct PyGetSetDef variable_properties[] = {
{"grad", {"grad",
(getter)tensor_properties_get_grad, (getter)tensor_properties_get_grad,
...@@ -341,6 +378,11 @@ struct PyGetSetDef variable_properties[] = { ...@@ -341,6 +378,11 @@ struct PyGetSetDef variable_properties[] = {
{"dtype", (getter)tensor_properties_get_dtype, nullptr, nullptr, nullptr}, {"dtype", (getter)tensor_properties_get_dtype, nullptr, nullptr, nullptr},
{"type", (getter)tensor_properties_get_type, nullptr, nullptr, nullptr}, {"type", (getter)tensor_properties_get_type, nullptr, nullptr, nullptr},
{"is_leaf", (getter)tensor_properties_is_leaf, nullptr, nullptr, nullptr}, {"is_leaf", (getter)tensor_properties_is_leaf, nullptr, nullptr, nullptr},
{"grad_fn",
(getter)tensor_properties_get_grad_fn,
nullptr,
nullptr,
nullptr},
{nullptr, nullptr, nullptr, nullptr, nullptr}}; {nullptr, nullptr, nullptr, nullptr, nullptr}};
// variable_properties for core.eager.StringTensor // variable_properties for core.eager.StringTensor
......
...@@ -1006,6 +1006,14 @@ paddle::optional<paddle::Tensor> GetOptionalTensorFromArgs( ...@@ -1006,6 +1006,14 @@ paddle::optional<paddle::Tensor> GetOptionalTensorFromArgs(
} }
} }
PyObject* ToPyObject(egr::GradNodeBase* grad_node) {
py::object py_obj = py::cast(grad_node, py::return_value_policy::reference);
py::handle py_handle = py::handle(py_obj);
PyObject* py_grad_node = py_handle.ptr();
Py_INCREF(py_grad_node);
return py_grad_node;
}
static paddle::Tensor& GetTensorFromPyObject(const std::string& op_type, static paddle::Tensor& GetTensorFromPyObject(const std::string& op_type,
const std::string& arg_name, const std::string& arg_name,
PyObject* obj, PyObject* obj,
......
...@@ -21,6 +21,7 @@ typedef SSIZE_T ssize_t; ...@@ -21,6 +21,7 @@ typedef SSIZE_T ssize_t;
#undef copysign #undef copysign
#endif #endif
#include "paddle/fluid/eager/grad_node_info.h"
#include "paddle/fluid/eager/hooks.h" #include "paddle/fluid/eager/hooks.h"
#include "paddle/fluid/framework/lod_tensor.h" #include "paddle/fluid/framework/lod_tensor.h"
#include "paddle/fluid/framework/lod_tensor_array.h" #include "paddle/fluid/framework/lod_tensor_array.h"
...@@ -125,6 +126,8 @@ PyObject* ToPyObject( ...@@ -125,6 +126,8 @@ PyObject* ToPyObject(
const std::unordered_map<std::string, std::vector<std::string>>& value); const std::unordered_map<std::string, std::vector<std::string>>& value);
PyObject* ToPyObject(const paddle::framework::Vocab& value); PyObject* ToPyObject(const paddle::framework::Vocab& value);
PyObject* ToPyObject(egr::GradNodeBase* grad_node);
class PyTensorHook : public egr::TensorHook { class PyTensorHook : public egr::TensorHook {
public: public:
explicit PyTensorHook(PyObject* func) : py_func_(func) { explicit PyTensorHook(PyObject* func) : py_func_(func) {
......
...@@ -13,6 +13,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ...@@ -13,6 +13,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. */ limitations under the License. */
#include <Python.h> #include <Python.h>
#include "paddle/fluid/eager/grad_node_info.h"
// Avoid a problem with copysign defined in pyconfig.h on Windows. // Avoid a problem with copysign defined in pyconfig.h on Windows.
#ifdef copysign #ifdef copysign
#undef copysign #undef copysign
...@@ -776,6 +778,13 @@ PYBIND11_MODULE(libpaddle, m) { ...@@ -776,6 +778,13 @@ PYBIND11_MODULE(libpaddle, m) {
} }
}); });
py::class_<egr::GradNodeBase>(m, "GradNodeBase")
.def("name", &egr::GradNodeBase::name)
.def_property_readonly("next_functions",
&egr::GradNodeBase::NextFunctions)
.def("input_meta", &egr::GradNodeBase::InputMeta)
.def("output_meta", &egr::GradNodeBase::OutputMeta);
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
m.def("cudnn_version", &platform::DnnVersion); m.def("cudnn_version", &platform::DnnVersion);
m.def("gpu_memory_available", []() { m.def("gpu_memory_available", []() {
......
# 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.
"""
Test the tensor attribute grad_fn and the properties of the reverse node grad_node, such as next_function
"""
import unittest
import paddle
import paddle.nn as nn
class Testmodel(nn.Layer):
def __init__(self):
super(Testmodel, self).__init__()
def forward(self, x):
y = x**2
y = x + y
return y
class TestAnonmousSurvey(unittest.TestCase):
"""
Test the tensor attribute grad_fn and the properties of the reverse node grad_node, such as next_function
"""
def init_graph(self):
"""define reversed graph
func_name [str]: represents the name of the operator node
next_funcs [dict]: represents the operator node
"""
self.grad_fn_1 = {"func_name": "GradNodeAccumulation", "next_funcs": {}}
self.grad_fn_2 = {
"func_name": "PowGradNode",
"next_funcs": {"GradNodeAccumulation": self.grad_fn_1},
}
self.grad_fn_3 = {
"func_name": "AddGradNode",
"next_funcs": {
"GradNodeAccumulation": self.grad_fn_1,
"PowGradNode": self.grad_fn_2,
},
}
self.output_grad_fn = {"grad_fn": self.grad_fn_3}
def init_data(self):
"""define output of model
the final output will be saved self.output
"""
model = Testmodel()
x = paddle.randn([1, 3, 24, 24])
x.stop_gradient = False
self.output = model(x)
def setUp(self):
self.init_graph()
self.init_data()
def test_grad_fn_and_next_funs(self):
self.check_func(self.output.grad_fn, self.output_grad_fn["grad_fn"])
def check_func(self, grad_fn: grad_fn, grad_fn_json: dict) -> None:
"""
Check each node, grad_fn is tensor attribute. grad_fn_json is structure of next_node.
Args:
grad_fn (grad_fn): grad_fn of node
grad_fn_json (dict): grad_node_json of node
"""
# print(grad_fn.name())
# assert func name
self.assertEqual(grad_fn.name(), grad_fn_json["func_name"])
# Recursively test other nodes
if hasattr(grad_fn, 'next_functions') and grad_fn.next_functions[0]:
next_funcs_json = grad_fn_json["next_funcs"]
for u in grad_fn.next_functions:
self.check_func(u, next_funcs_json[u.name()])
unittest.main()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册