mindspore2022/mindspore/ccsrc/optimizer/ad/dfunctor.h

203 lines
7.7 KiB
C++

/**
* This is the C++ adaptation and derivative work of Myia (https://github.com/mila-iqia/myia/).
*
* Copyright 2020 Huawei Technologies Co., Ltd
*
* 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.
*/
#ifndef MINDSPORE_CCSRC_OPTIMIZER_AD_D_FUNCTOR_H_
#define MINDSPORE_CCSRC_OPTIMIZER_AD_D_FUNCTOR_H_
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include <iostream>
#include "ir/anf.h"
#include "ir/meta_func_graph.h"
#include "ir/func_graph_cloner.h"
#include "pipeline/resource.h"
#include "optimizer/ad/adjoint.h"
#include "operator/ops.h"
#include "debug/trace.h"
namespace mindspore {
namespace ad {
using Registry = std::unordered_map<PrimitivePtr, FuncGraphPtr>;
class KPrim;
extern KPrim g_k_prims;
class DFunctor;
using DFunctorPtr = std::shared_ptr<DFunctor>;
// D Functor's rules to map closure object and morphisms.
class DFunctor {
public:
DFunctor(const FuncGraphPtr &primal_graph, const pipeline::ResourceBasePtr &resources);
~DFunctor() = default;
// Map object in D category to K category.
void MapObject();
// Map morphism in D category to K category.
void MapMorphism();
FuncGraphPtr k_graph();
// Construct user defined k object.
FuncGraphPtr KUserDefined(const FuncGraphPtr &primal);
// Register functor objects to form a global view.
void Init(const DFunctorPtr &functor, bool is_top = false);
bool IsInScope(const AnfNodePtr &node);
// Clear resources.
static void Clear();
private:
// Map one morphism.
AdjointPtr MapMorphism(const AnfNodePtr &morph);
bool IsFreeMorphism(const AnfNodePtr &node);
// Map morphism that's not attached to output.
void MapFreeMorphism();
void BackPropagateFv(const AnfNodePtr &fv, const AnfNodePtr &din);
void BackPropagateSwitchLayer(const CNodePtr &cnode_morph, const CNodePtr &env);
void BackPropagate(const CNodePtr &cnode_morph, const CNodePtr &k_app, const AdjointPtr &node_adjoint);
AnfNodePtr AttachFvDoutToTape(const AnfNodePtr &grad_fv);
AnfNodePtr AttachIndirectFvDoutToTape(const AnfNodePtr &grad_fv);
// Map Anfnode object from D category to K category.
AnfNodePtr MapToK(const AnfNodePtr &primal);
// Map FuncGraph object from D category to K category.
AnfNodePtr MapToK(const FuncGraphPtr &primal);
// MapObject impls.
void MapFvObject();
void MapValueObject();
void MapParamObject();
// Find adjoint with its primary k.
AdjointPtr FindAdjoint(const AnfNodePtr &primal);
// Broadcast stop flags.
void BroadCastStopFlag();
bool AllReferencesStopped(const CNodePtr &node);
// Update k hole with adjoint_definition, only applied in recursive case.
void UpdateAdjoint(const AdjointPtr &adjoint_definition);
void CallDoutHoleOnTape();
std::unordered_map<AnfNodePtr, AdjointPtr> anfnode_to_adjoin_;
// Cache for indirect fv backpropagation, K o K can only do backprop layer by layer.
std::unordered_map<AnfNodePtr, AdjointPtr> anfnode_to_adjoin_indirect_fv_;
FuncGraphPtr primal_graph_;
// K object for primal_graph_;
FuncGraphPtr k_graph_;
// The Backprop part of k_graph_.
FuncGraphPtr tape_;
// Dout parameter for primal_graph_.
AnfNodePtr dout_;
pipeline::ResourceBasePtr resources_;
// Cut off stopped objects in category D.
bool need_cut_;
bool is_top_;
static std::unordered_map<FuncGraphPtr, std::shared_ptr<DFunctor>> func_graph_to_functor_;
static std::unordered_map<AnfNodePtr, AdjointPtr> anfnode_to_adjoin_definition_;
static FuncGraphSet scope_;
};
// D Functor's rules to map primitive object.
class KPrim {
public:
KPrim() = default;
~KPrim() = default;
FuncGraphPtr KPrimitive(const ValueNodePtr &value_node, const pipeline::ResourceBasePtr &resources);
MetaFuncGraphPtr KMetaFuncGraph(const PrimitivePtr &prim);
FuncGraphPtr KUserDefinedCellBprop(FuncGraphPtr bprop);
void clear() {
bprop_registry_meta_.clear();
bprop_registry_.clear();
}
private:
FuncGraphPtr GetBprop(const PrimitivePtr &prim);
FuncGraphPtr GetFprop(const PrimitivePtr &prim);
FuncGraphPtr FakeBprop(const ValueNodePtr &value_node, const pipeline::ResourceBasePtr &resources);
FuncGraphPtr BpropCut(const ValueNodePtr &value_node, const pipeline::ResourceBasePtr &resources);
// Given a bprop rule, do the K mapping.
template <typename T>
FuncGraphPtr BpropToK(const T &primal, const FuncGraphPtr &bprop_g);
AnfNodePtr BuildOutput(const FuncGraphPtr &bprop_fg);
void TransformArgs(const FuncGraphManagerPtr &mng, const FuncGraphPtr &bprop_fg, const FuncGraphPtr &outer,
std::vector<AnfNodePtr> *const transf_args);
void CheckBprop(const FuncGraphPtr &bprop_fg, const string &prim_to_check);
Registry bprop_registry_;
std::unordered_map<PrimitivePtr, MetaFuncGraphPtr> bprop_registry_meta_;
};
template <typename T>
FuncGraphPtr KPrim::BpropToK(const T &primal, const FuncGraphPtr &bprop_fg) {
MS_EXCEPTION_IF_NULL(primal);
MS_EXCEPTION_IF_NULL(bprop_fg);
CheckBprop(bprop_fg, primal->ToString());
auto debug_info = std::make_shared<GraphDebugInfo>();
debug_info->set_name(primal->ToString());
auto cloned_bprop_fg = BasicClone(bprop_fg);
MS_EXCEPTION_IF_NULL(cloned_bprop_fg);
cloned_bprop_fg->debug_info()->set_name("");
cloned_bprop_fg->debug_info()->set_trace_info(std::make_shared<TraceGradBprop>(debug_info));
AnfNodePtr bout = BuildOutput(cloned_bprop_fg);
cloned_bprop_fg->set_output(bout);
TraceManager::DebugTrace(std::make_shared<TraceGradFprop>(debug_info));
auto outer = std::make_shared<FuncGraph>();
(void)outer->transforms().emplace("primal", FuncGraphTransform(primal));
outer->set_output(NewValueNode(kNone));
TraceManager::EndTrace();
auto mng = Manage({cloned_bprop_fg, outer}, false);
// Make sure (out, dout) provided.
if (cloned_bprop_fg->parameters().size() < 2) {
MS_LOG(EXCEPTION) << "Primitive or Cell " << primal->ToString()
<< " bprop requires out and dout at least, but only got " << cloned_bprop_fg->parameters().size()
<< " params. NodeInfo: " << trace::GetDebugInfo(cloned_bprop_fg->debug_info());
}
// In a bprop definition, the last two param should be out and dout.
auto dout = cloned_bprop_fg->parameters()[cloned_bprop_fg->parameters().size() - 1];
auto out_param = cloned_bprop_fg->parameters()[cloned_bprop_fg->parameters().size() - 2];
std::vector<AnfNodePtr> transf_args;
TransformArgs(mng, cloned_bprop_fg, outer, &transf_args);
TraceManager::DebugTrace(std::make_shared<TraceEquiv>(dout->debug_info()));
(void)transf_args.insert(transf_args.begin(), NewValueNode(primal));
auto out_value = outer->NewCNode(transf_args);
TraceManager::EndTrace();
(void)mng->Replace(out_param, out_value);
TraceManager::DebugTrace(std::make_shared<TraceGradSens>(out_param->debug_info()));
auto new_dout = cloned_bprop_fg->add_parameter();
(void)mng->Replace(dout, new_dout);
// We remove all parameters except new_dout.
std::vector<AnfNodePtr> newBpropParams = {new_dout};
cloned_bprop_fg->set_parameters(newBpropParams);
TraceManager::EndTrace();
outer->set_output(outer->NewCNode({NewValueNode(prim::kPrimMakeTuple), out_value, NewValueNode(cloned_bprop_fg)}));
return BasicClone(outer);
}
} // namespace ad
} // namespace mindspore
#endif // MINDSPORE_CCSRC_OPTIMIZER_AD_D_FUNCTOR_H_