diff --git a/paddle/fluid/framework/op_desc.cc b/paddle/fluid/framework/op_desc.cc index 7af5c54ceed74fc334dd10438cc5b0b62c06042d..519bf8c633a013fedab4f529dad014a71ad2d594 100644 --- a/paddle/fluid/framework/op_desc.cc +++ b/paddle/fluid/framework/op_desc.cc @@ -447,6 +447,11 @@ void OpDesc::SetOutput(const std::string ¶m_name, this->outputs_[param_name] = args; } +void OpDesc::RemoveOutput(const std::string &name) { + outputs_.erase(name); + need_update_ = true; +} + bool OpDesc::HasProtoAttr(const std::string &name) const { auto &op_info = OpInfoMap::Instance(); if (op_info.Has(desc_.type())) { diff --git a/paddle/fluid/framework/op_desc.h b/paddle/fluid/framework/op_desc.h index 95c33bca6c7f1df6ad71a3b4c2f82d726cafb5fc..1bc1a308e453bb816b00d6ca9a62358f8d33082a 100644 --- a/paddle/fluid/framework/op_desc.h +++ b/paddle/fluid/framework/op_desc.h @@ -65,6 +65,7 @@ class OpDesc { void SetOutput(const std::string ¶m_name, const std::vector &args); + void RemoveOutput(const std::string &name); bool HasAttr(const std::string &name) const { return attrs_.find(name) != attrs_.end(); diff --git a/paddle/fluid/pybind/protobuf.cc b/paddle/fluid/pybind/protobuf.cc index 06b3f10fefafa81ac1eca712952a18ee80d7e084..6fa49a85423c58061975007f9c2f4467c8d1ad09 100644 --- a/paddle/fluid/pybind/protobuf.cc +++ b/paddle/fluid/pybind/protobuf.cc @@ -235,6 +235,7 @@ void BindOpDesc(pybind11::module *m) { const std::vector &vec_var_name) { self.SetOutput(name, vec_var_name); }) + .def("remove_output", &pd::OpDesc::RemoveOutput) .def("input_arg_names", &pd::OpDesc::InputArgumentNames) .def("output_arg_names", &pd::OpDesc::OutputArgumentNames) .def("_rename_input", &pd::OpDesc::RenameInput) diff --git a/python/paddle/fluid/dygraph/io.py b/python/paddle/fluid/dygraph/io.py index af4ba16ee8f64cb6293dd11413492e013c32b99d..ce40fde1630ad04708d93c3d1ad74a7f22268838 100644 --- a/python/paddle/fluid/dygraph/io.py +++ b/python/paddle/fluid/dygraph/io.py @@ -413,6 +413,23 @@ class _ProgramHolder(object): # Therefore, in order to reuse the method of backward.py, build the program here. program = _build_program_by_desc(program_desc_copy) + # 3. Add the outputs which is only used for training and not saved in + # inference program. + for block_idx in six.moves.range(program.num_blocks): + block = program.block(block_idx) + for op in block.ops: + if op.type == "batch_norm": + if "ReserveSpace" not in op.output_names or len( + op.output("ReserveSpace")) == 0: + reserve_space = block.create_var( + name=unique_name.generate_with_ignorable_key( + ".".join(["reserve_space", 'tmp'])), + dtype=block.var(op.input("X")[0]).dtype, + type=core.VarDesc.VarType.LOD_TENSOR, + persistable=False, + stop_gradient=True) + op.desc.set_output("ReserveSpace", [reserve_space.name]) + targets = [] for out in self._output_descs: targets.append(program.global_block().var(out.name())) diff --git a/python/paddle/fluid/framework.py b/python/paddle/fluid/framework.py index ccfec944a794053ca9aa208d74a05b8988f71aad..59e22f24f33dde392333b7c87b94d3e3d1a1c322 100644 --- a/python/paddle/fluid/framework.py +++ b/python/paddle/fluid/framework.py @@ -5021,6 +5021,9 @@ class Program(object): op = block.op(j) if op.has_attr('is_test'): op._set_attr('is_test', True) + if op.type() == "batch_norm": + # Remove the output ReserveSpace of batch_norm if exists. + op.remove_output("ReserveSpace") res.blocks = [ Block(res, i) for i in six.moves.range(res.desc.num_blocks()) ]