| @@ -793,6 +793,20 @@ AnfNodePtr PynativeExecutor::GetObjNode(const py::object &obj) { | |||||
| return node; | return node; | ||||
| } | } | ||||
| AnfNodePtr PynativeExecutor::GetParamNode(const py::object &obj) { | |||||
| auto id = GetId(obj); | |||||
| auto ¶m = graph_info_map_[curr_g_].param_map[id]; | |||||
| if (param.second.size() == 1 && param.second[0] == -1) { | |||||
| return param.first; | |||||
| } | |||||
| auto para_node = param.first; | |||||
| for (auto &idx : param.second) { | |||||
| std::vector<AnfNodePtr> tuple_get_item_inputs{NewValueNode(prim::kPrimTupleGetItem), para_node, NewValueNode(idx)}; | |||||
| para_node = curr_g_->NewCNode(tuple_get_item_inputs); | |||||
| } | |||||
| return para_node; | |||||
| } | |||||
| std::string PynativeExecutor::GetCellId(const py::object &cell, const py::args &args) { | std::string PynativeExecutor::GetCellId(const py::object &cell, const py::args &args) { | ||||
| auto cell_id = GetId(cell); | auto cell_id = GetId(cell); | ||||
| for (size_t i = 0; i < args.size(); i++) { | for (size_t i = 0; i < args.size(); i++) { | ||||
| @@ -995,9 +1009,18 @@ void PynativeExecutor::NewGraphInner(const py::object &cell, const py::args &arg | |||||
| graph_info_map_[g] = GraphInfo(); | graph_info_map_[g] = GraphInfo(); | ||||
| } | } | ||||
| for (size_t i = 0; i < args.size(); i++) { | for (size_t i = 0; i < args.size(); i++) { | ||||
| auto param = args[i]; | |||||
| auto new_param = g->add_parameter(); | auto new_param = g->add_parameter(); | ||||
| std::string param_obj = GetId(args[i]); | |||||
| graph_info_map_[g].param_map[param_obj] = new_param; | |||||
| std::string param_obj = GetId(param); | |||||
| if (py::isinstance<py::tuple>(param)) { | |||||
| auto tuple = param.cast<py::tuple>(); | |||||
| auto tuple_size = static_cast<int>(tuple.size()); | |||||
| for (int j = 0; j < tuple_size; j++) { | |||||
| set_param_map(curr_g_, GetId(tuple[j]), new_param, j); | |||||
| SetTupleParam(tuple[j], new_param, std::vector<int>{j}); | |||||
| } | |||||
| } | |||||
| set_param_map(curr_g_, param_obj, new_param); | |||||
| } | } | ||||
| } | } | ||||
| @@ -1028,16 +1051,16 @@ AnfNodePtr PynativeExecutor::GetInput(const py::object &obj, bool op_mask) { | |||||
| auto value = py::cast<tensor::TensorPtr>(obj); | auto value = py::cast<tensor::TensorPtr>(obj); | ||||
| free_param->set_default_param(value); | free_param->set_default_param(value); | ||||
| MS_LOG(DEBUG) << "Top graph set free parameter " << obj_id; | MS_LOG(DEBUG) << "Top graph set free parameter " << obj_id; | ||||
| graph_info_map_[df_builder_].param_map[obj_id] = free_param; | |||||
| set_param_map(df_builder_, obj_id, free_param); | |||||
| return free_param; | return free_param; | ||||
| } | } | ||||
| return graph_info_map_[df_builder_].param_map[obj_id]; | |||||
| return graph_info_map_[df_builder_].param_map[obj_id].first; | |||||
| } | } | ||||
| // if input is graph output | // if input is graph output | ||||
| if (graph_info_map_[curr_g_].param_map.count(obj_id) != 0) { | if (graph_info_map_[curr_g_].param_map.count(obj_id) != 0) { | ||||
| // op(x, y) | // op(x, y) | ||||
| node = graph_info_map_[curr_g_].param_map[obj_id]; | |||||
| node = GetParamNode(obj); | |||||
| } else if (graph_info_map_[curr_g_].obj_node_map.count(obj_id) != 0) { | } else if (graph_info_map_[curr_g_].obj_node_map.count(obj_id) != 0) { | ||||
| // out = op(op1(x, y)) | // out = op(op1(x, y)) | ||||
| // out = op(cell1(x, y)) | // out = op(cell1(x, y)) | ||||
| @@ -1085,6 +1108,19 @@ void PynativeExecutor::SetTupleOutput(const py::object &obj, const AnfNodePtr &c | |||||
| } | } | ||||
| } | } | ||||
| // for param ((a, (b, c)), d) need multi getitem | |||||
| void PynativeExecutor::SetTupleParam(const py::object &obj, const AnfNodePtr ¶_node, std::vector<int> idx) { | |||||
| if (py::isinstance<py::tuple>(obj)) { | |||||
| auto tuple = obj.cast<py::tuple>(); | |||||
| for (int i = 0; i < static_cast<int>(tuple.size()); i++) { | |||||
| std::vector<int> tmp = idx; | |||||
| tmp.push_back(i); | |||||
| set_param_map(curr_g_, GetId(tuple[i]), para_node, tmp); | |||||
| SetTupleParam(tuple[i], para_node, tmp); | |||||
| } | |||||
| } | |||||
| } | |||||
| void PynativeExecutor::Pushp() { graph_p_.push(curr_g_); } | void PynativeExecutor::Pushp() { graph_p_.push(curr_g_); } | ||||
| void PynativeExecutor::Popp() { | void PynativeExecutor::Popp() { | ||||
| @@ -1132,7 +1168,7 @@ void PynativeExecutor::EndGraphByOutId(const std::string &out_id, const py::obje | |||||
| const py::args &args) { | const py::args &args) { | ||||
| AnfNodePtr output_node; | AnfNodePtr output_node; | ||||
| if (graph_info_map_[curr_g_].param_map.count(out_id)) { | if (graph_info_map_[curr_g_].param_map.count(out_id)) { | ||||
| output_node = graph_info_map_[curr_g_].param_map[out_id]; | |||||
| output_node = GetParamNode(out); | |||||
| } else { | } else { | ||||
| output_node = GetObjNode(out); | output_node = GetObjNode(out); | ||||
| } | } | ||||
| @@ -1186,7 +1222,7 @@ std::vector<AnfNodePtr> PynativeExecutor::GetWeightsArgs(const py::object &weigh | |||||
| auto param_id = GetId(param); | auto param_id = GetId(param); | ||||
| AnfNodePtr para_node = nullptr; | AnfNodePtr para_node = nullptr; | ||||
| if (graph_info_map_[df_builder_].param_map.count(param_id)) { | if (graph_info_map_[df_builder_].param_map.count(param_id)) { | ||||
| para_node = graph_info_map_[df_builder_].param_map[param_id]; | |||||
| para_node = graph_info_map_[df_builder_].param_map[param_id].first; | |||||
| } else { | } else { | ||||
| auto name_attr = mindspore::parse::python_adapter::GetPyObjAttr(param, "name"); | auto name_attr = mindspore::parse::python_adapter::GetPyObjAttr(param, "name"); | ||||
| if (py::isinstance<py::none>(name_attr)) { | if (py::isinstance<py::none>(name_attr)) { | ||||
| @@ -59,7 +59,7 @@ void ConvertInputs(const PrimitivePyPtr &prim, const py::list &py_args, py::tupl | |||||
| void ClearPyNativeSession(); | void ClearPyNativeSession(); | ||||
| struct GraphInfo { | struct GraphInfo { | ||||
| std::unordered_map<std::string, AnfNodePtr> param_map; | |||||
| std::unordered_map<std::string, std::pair<AnfNodePtr, std::vector<int>>> param_map; | |||||
| std::unordered_map<std::string, std::pair<AnfNodePtr, std::vector<int>>> obj_node_map; | std::unordered_map<std::string, std::pair<AnfNodePtr, std::vector<int>>> obj_node_map; | ||||
| AnfNodePtr output; | AnfNodePtr output; | ||||
| std::vector<std::string> objects; | std::vector<std::string> objects; | ||||
| @@ -92,6 +92,7 @@ class PynativeExecutor : public std::enable_shared_from_this<PynativeExecutor> { | |||||
| void set_grad_flag(bool flag) { grad_flag_ = flag; } | void set_grad_flag(bool flag) { grad_flag_ = flag; } | ||||
| AnfNodePtr GetInput(const py::object &obj, bool op_mask); | AnfNodePtr GetInput(const py::object &obj, bool op_mask); | ||||
| AnfNodePtr GetObjNode(const py::object &obj); | AnfNodePtr GetObjNode(const py::object &obj); | ||||
| AnfNodePtr GetParamNode(const py::object &obj); | |||||
| std::string GetCellId(const py::object &obj, const py::args &args); | std::string GetCellId(const py::object &obj, const py::args &args); | ||||
| FuncGraphPtr curr_g() { return curr_g_; } | FuncGraphPtr curr_g() { return curr_g_; } | ||||
| void set_pyobj(FuncGraphPtr g, const std::string obj) { graph_info_map_[g].objects.push_back(obj); } | void set_pyobj(FuncGraphPtr g, const std::string obj) { graph_info_map_[g].objects.push_back(obj); } | ||||
| @@ -104,6 +105,17 @@ class PynativeExecutor : public std::enable_shared_from_this<PynativeExecutor> { | |||||
| void set_obj_node_map(FuncGraphPtr g, const std::string obj, AnfNodePtr node, std::vector<int> index) { | void set_obj_node_map(FuncGraphPtr g, const std::string obj, AnfNodePtr node, std::vector<int> index) { | ||||
| graph_info_map_[g].obj_node_map[obj] = std::make_pair(node, index); | graph_info_map_[g].obj_node_map[obj] = std::make_pair(node, index); | ||||
| } | } | ||||
| void set_param_map(FuncGraphPtr g, const std::string obj, AnfNodePtr node) { | |||||
| graph_info_map_[g].param_map[obj] = std::make_pair(node, std::vector<int>{-1}); | |||||
| } | |||||
| void set_param_map(FuncGraphPtr g, const std::string obj, AnfNodePtr node, int index) { | |||||
| graph_info_map_[g].param_map[obj] = std::make_pair(node, std::vector<int>{index}); | |||||
| } | |||||
| void set_param_map(FuncGraphPtr g, const std::string obj, AnfNodePtr node, std::vector<int> index) { | |||||
| graph_info_map_[g].param_map[obj] = std::make_pair(node, index); | |||||
| } | |||||
| AnfNodePtr MakeCNode(const OpExecInfoPtr &op_exec_info, std::vector<bool> *op_masks, | AnfNodePtr MakeCNode(const OpExecInfoPtr &op_exec_info, std::vector<bool> *op_masks, | ||||
| abstract::AbstractBasePtrList *args_spec_list); | abstract::AbstractBasePtrList *args_spec_list); | ||||
| void MakeCNode(const OpExecInfoPtr &op_exec_info, const py::object &out, const AnfNodePtr &cnode); | void MakeCNode(const OpExecInfoPtr &op_exec_info, const py::object &out, const AnfNodePtr &cnode); | ||||
| @@ -119,6 +131,7 @@ class PynativeExecutor : public std::enable_shared_from_this<PynativeExecutor> { | |||||
| FuncGraphPtr GradGraph(FuncGraphPtr g, const GradOperationPtr &grad_op, const std::vector<AnfNodePtr> &weights, | FuncGraphPtr GradGraph(FuncGraphPtr g, const GradOperationPtr &grad_op, const std::vector<AnfNodePtr> &weights, | ||||
| size_t arg_size); | size_t arg_size); | ||||
| void SetTupleOutput(const py::object &obj, const AnfNodePtr &cnode, std::vector<int> idx); | void SetTupleOutput(const py::object &obj, const AnfNodePtr &cnode, std::vector<int> idx); | ||||
| void SetTupleParam(const py::object &obj, const AnfNodePtr ¶_node, std::vector<int> idx); | |||||
| AnfNodePtr MakeValueNode(const py::object &obj, const std::string &obj_id); | AnfNodePtr MakeValueNode(const py::object &obj, const std::string &obj_id); | ||||
| py::tuple RunOpInner(const py::args &args); | py::tuple RunOpInner(const py::args &args); | ||||
| py::tuple RunOpInner(const OpExecInfoPtr &op_exec_info); | py::tuple RunOpInner(const OpExecInfoPtr &op_exec_info); | ||||
| @@ -0,0 +1,77 @@ | |||||
| import numpy as np | |||||
| import mindspore.nn as nn | |||||
| from mindspore import context, Tensor | |||||
| from mindspore.ops import operations as P | |||||
| from mindspore.ops import composite as C | |||||
| def setup_module(module): | |||||
| context.set_context(mode=context.PYNATIVE_MODE) | |||||
| class Block1(nn.Cell): | |||||
| """ Define Cell with tuple input as paramter.""" | |||||
| def __init__(self): | |||||
| super(Block1, self).__init__() | |||||
| self.mul = P.Mul() | |||||
| def construct(self, tuple_xy): | |||||
| x, y = tuple_xy | |||||
| z = self.mul(x, y) | |||||
| return z | |||||
| class Block2(nn.Cell): | |||||
| """ definition with tuple in tuple output in Cell.""" | |||||
| def __init__(self): | |||||
| super(Block2, self).__init__() | |||||
| self.mul = P.Mul() | |||||
| self.add = P.TensorAdd() | |||||
| def construct(self, x, y): | |||||
| z1 = self.mul(x, y) | |||||
| z2 = self.add(z1, x) | |||||
| z3 = self.add(z1, y) | |||||
| return (z1, (z2, z3)) | |||||
| class Net1(nn.Cell): | |||||
| def __init__(self): | |||||
| super(Net1, self).__init__() | |||||
| self.block = Block1() | |||||
| def construct(self, x, y): | |||||
| res = self.block((x, y)) | |||||
| return res | |||||
| class Net2(nn.Cell): | |||||
| def __init__(self): | |||||
| super(Net2, self).__init__() | |||||
| self.add = P.TensorAdd() | |||||
| self.block = Block2() | |||||
| def construct(self, x, y): | |||||
| z1, (z2, z3) = self.block(x, y) | |||||
| res = self.add(z1, z2) | |||||
| res = self.add(res, z3) | |||||
| return res | |||||
| def test_net(): | |||||
| context.set_context(save_graphs=True) | |||||
| x = Tensor(np.ones([1, 1, 3, 3]).astype(np.float32) * 2) | |||||
| y = Tensor(np.ones([1, 1, 3, 3]).astype(np.float32) * 3) | |||||
| net1 = Net1() | |||||
| grad_op = C.GradOperation(get_all=True) | |||||
| output = grad_op(net1)(x, y) | |||||
| assert np.all(output[0].asnumpy() == y.asnumpy()) | |||||
| assert np.all(output[1].asnumpy() == x.asnumpy()) | |||||
| net2 = Net2() | |||||
| output = grad_op(net2)(x, y) | |||||
| expect_x = np.ones([1, 1, 3, 3]).astype(np.float32) * 10 | |||||
| expect_y = np.ones([1, 1, 3, 3]).astype(np.float32) * 7 | |||||
| assert np.all(output[0].asnumpy() == expect_x) | |||||
| assert np.all(output[1].asnumpy() == expect_y) | |||||