• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2019 Huawei Technologies Co., Ltd
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef MINDSPORE_CCSRC_FRONTEND_PARALLEL_AUTO_PARALLEL_COSTMODEL_H_
18 #define MINDSPORE_CCSRC_FRONTEND_PARALLEL_AUTO_PARALLEL_COSTMODEL_H_
19 
20 #include <algorithm>
21 #include <memory>
22 #include <string>
23 #include <utility>
24 #include <vector>
25 #include "frontend/parallel/strategy.h"
26 #include "frontend/parallel/tensor_layout/tensor_info.h"
27 #include "frontend/parallel/costmodel_context.h"
28 
29 namespace mindspore {
30 namespace parallel {
31 struct Decision;
32 using OperatorName = std::string;
33 using Attr = std::pair<std::string, ValuePtr>;
34 using Param = std::pair<std::pair<std::string, ValuePtr>, int64_t>;
35 using OperatorParams = std::vector<Param>;
36 using OperatorAttrs = std::vector<Attr>;
37 // OutPutInfo.fist: true if the operator's output is a tuple
38 // OutPutInfo.second: elements number of the tuple output. Only meaningful if OutPutInfo.fist is true.
39 using OutPutInfo = std::pair<bool, uint64_t>;
40 using OutPutInfoVector = std::vector<OutPutInfo>;
41 using OperatorArgs = std::pair<OperatorAttrs, OperatorParams>;
42 using Operator = std::pair<OperatorName, OperatorArgs>;
43 using OperatorVector = std::vector<Operator>;
44 using RedistributionOpListPtr = std::shared_ptr<std::pair<OperatorVector, OutPutInfoVector>>;
45 
46 struct Cost {
47   Cost();
48   Cost(double computation, double communication, const std::shared_ptr<Decision> &decision_ = nullptr)
computation_cost_Cost49       : computation_cost_(computation), communication_cost_(communication), decision_ptr_(std::move(decision_)) {
50     memory_with_reuse_ = 0.0;
51     communication_without_parameter_ = 0.0;
52     communication_with_partial_para_ = 0.0;
53     communication_redis_forward_ = 0.0;
54     communication_redis_backward_ = 0.0;
55     communication_forward_ = 0.0;
56   }
57   // 'memory_with_reuse_' calculates the peak memory usage in a training (or inference) phase
58   double memory_with_reuse_;
59   // 'computation_cost_'  models the training time of an iteration in a training phase. Currently, this is calculated
60   // by ONLY forward phase
61   double computation_cost_;
62   // 'communication_cost_' includes communications from operators (forward and backward) and edges (redistribution)
63   double communication_cost_;
64   // communication_without_parameter_ = communication_cost_ - (backward communication from operators)
65   double communication_without_parameter_;
66   // communication_with_partial_para_ =
67   // communication_without_parameter_ + COST_MODEL_GAMMA * (communication_cost_ - communication_without_parameter_ )
68   double communication_with_partial_para_;
69   // communication_forward_ = communication cost from operators (only forward phase) and forward redistribution.
70   double communication_forward_;
71   double communication_redis_forward_;
72   double communication_redis_backward_;
73   std::shared_ptr<Decision> decision_ptr_;
74 };
75 
76 using CostPtr = std::shared_ptr<Cost>;
77 using CostPtrList = std::vector<std::shared_ptr<Cost>>;
78 
79 class StrategyWithCost {
80  public:
StrategyWithCost(StrategyPtr strategy,std::vector<TensorInfo> inputs_,std::vector<TensorInfo> outputs_)81   StrategyWithCost(StrategyPtr strategy, std::vector<TensorInfo> inputs_, std::vector<TensorInfo> outputs_)
82       : strategy_ptr(std::move(strategy)), inputs_ptr(std::move(inputs_)), outputs_ptr(std::move(outputs_)) {}
StrategyWithCost(StrategyPtr strategy,CostPtrList c_list)83   StrategyWithCost(StrategyPtr strategy, CostPtrList c_list)
84       : strategy_ptr(std::move(strategy)), cost_list(std::move(c_list)) {}
85 
86   StrategyWithCost(const StrategyWithCost &swc) = delete;
StrategyWithCost(StrategyWithCost && swc)87   StrategyWithCost(StrategyWithCost &&swc)
88       : strategy_ptr(swc.strategy_ptr),
89         inputs_ptr(swc.inputs_ptr),
90         outputs_ptr(swc.outputs_ptr),
91         cost_list(swc.cost_list) {}
92   ~StrategyWithCost() = default;
93 
94   StrategyPtr strategy_ptr;
95   std::vector<TensorInfo> inputs_ptr;
96   std::vector<TensorInfo> outputs_ptr;
97   CostPtrList cost_list;
98 };
99 
100 enum DecisionType {
101   OP_ELIMINATION,
102   EDGE_ELIMINATION,
103   MERGE_ELIMINATION,
104   CONTRACT_ELIMINATION,
105   SOURCE_ELIMINATION,
106   TRIANGLE_ELIMINATION,
107   STAR_ELIMINATION,
108   FINAL_TYPE,
109   FINAL_SINGLE
110 };
111 
112 struct Decision : public Base {
113   ~Decision() override = default;
114   DecisionType type_;
115 };
116 
117 // 'OpEliminationDecision' is for the Operator Elimination in DP algorithm: u --> v --> w ==> u --> w.
118 // This data structure records the strategy 'op_strategy_' for v, the edge cost 'left_cost_' for 'u --> v', the
119 // operator cost 'middle_cost_' for v, and the edge cost 'right_cost_' for 'v --> w'
120 struct OpEliminationDecision : public Decision {
OpEliminationDecisionOpEliminationDecision121   OpEliminationDecision(StrategyPtr op_stra, CostPtr l_cost, CostPtr m_cost, CostPtr r_cost)
122       : op_strategy_(std::move(op_stra)),
123         left_cost_(std::move(l_cost)),
124         middle_cost_(std::move(m_cost)),
125         right_cost_(std::move(r_cost)) {
126     type_ = DecisionType::OP_ELIMINATION;
127   }
128 
129   StrategyPtr op_strategy_;
130   CostPtr left_cost_;
131   CostPtr middle_cost_;
132   CostPtr right_cost_;
133   MS_DECLARE_PARENT(OpEliminationDecision, Decision);
134 };
135 
136 /* 'EdgeEliminationDecision' is for the Edge Elimination in DP algorithm:
137    ____
138   /    \
139  u      v   ==>  u --> v, which replace the multi-edges by a single edge.
140   \____/
141  This data structure records the cost list for all edges 'edges_cost_list_'
142  */
143 struct EdgeEliminationDecision : public Decision {
EdgeEliminationDecisionEdgeEliminationDecision144   explicit EdgeEliminationDecision(CostPtrList cost_list) : edges_cost_list_(std::move(cost_list)) {
145     type_ = DecisionType::EDGE_ELIMINATION;
146   }
147 
148   CostPtrList edges_cost_list_;
149   MS_DECLARE_PARENT(EdgeEliminationDecision, Decision);
150 };
151 
152 // 'MergeEliminationDecision' is for the Merge Elimination in DP algorithm:
153 //       w
154 //       |
155 //       |   ==>  u --> v
156 // u --> v                    In the original graph, v has two alive incoming edges, w has one alive outgoing edge,
157 // and w has zero alive incoming edges. After the Merge Elimination, the result graph contains only 'u -- >v'.
158 // This data structure records the strategy 'merged_op_strategy_' for operator 'w',
159 // the cost 'merged_op_cost_' for operator 'w', and the edge cost 'edge_cost_' for 'w --> v'.
160 struct MergeEliminationDecision : public Decision {
MergeEliminationDecisionMergeEliminationDecision161   MergeEliminationDecision(StrategyPtr op_stra, CostPtr op_cost, CostPtr edge_c, StrategyPtr tar_op_stra,
162                            CostPtr target_op_c)
163       : merged_op_strategy_(std::move(op_stra)),
164         merged_op_cost_(std::move(op_cost)),
165         edge_cost_(std::move(edge_c)),
166         target_op_strategy_(std::move(tar_op_stra)),
167         target_op_cost_(std::move(target_op_c)) {
168     type_ = DecisionType::MERGE_ELIMINATION;
169   }
170 
171   StrategyPtr merged_op_strategy_;
172   CostPtr merged_op_cost_;
173   CostPtr edge_cost_;
174   StrategyPtr target_op_strategy_;
175   CostPtr target_op_cost_;
176   MS_DECLARE_PARENT(MergeEliminationDecision, Decision);
177 };
178 
179 // 'ContractEliminationDecision' is for the Contract Elimination in DP algorithm:
180 //  u --> v
181 //  |
182 //  |      ==>   u --> w
183 //  w                         In the original graph, u has two alive outgoing edges, v has one alive incoming edge,
184 // and v has zero outgoing edge. After the Contract Elimination, the result graph contains only 'u --> w'.
185 // This data structure records the strategy 'contracted_op_strategy_' for operator 'v', the cost for
186 // operator 'contracted_op_cost_', and the edge cost for 'edge_cost_'.
187 struct ContractEliminationDecision : public Decision {
ContractEliminationDecisionContractEliminationDecision188   ContractEliminationDecision(StrategyPtr contra_stra, CostPtr contra_op_cost, CostPtr edge_cost,
189                               StrategyPtr target_stra, CostPtr tar_cost)
190       : contracted_op_strategy_(std::move(contra_stra)),
191         contracted_op_cost_(std::move(contra_op_cost)),
192         edge_cost_(std::move(edge_cost)),
193         target_op_strategy_(std::move(target_stra)),
194         target_cost_(std::move(tar_cost)) {
195     type_ = DecisionType::CONTRACT_ELIMINATION;
196   }
197 
198   StrategyPtr contracted_op_strategy_;
199   CostPtr contracted_op_cost_;
200   CostPtr edge_cost_;
201   StrategyPtr target_op_strategy_;
202   CostPtr target_cost_;
203   MS_DECLARE_PARENT(ContractEliminationDecision, Decision);
204 };
205 
206 /* 'SourceEliminationDecision' is for the source Elimination in DP algorithm:
207  *                    1                             1,5
208  *                   /  \                          // \\
209  *                  /    \                        //   \\
210  *                 /      \                      //     \\
211  *                /        \                    //       \\
212  *               2 <-  5 -> 3    ==>           2          3
213  *                \        /                    \        /
214  *                  \    /                        \    /
215  *                    \ /                           \ /
216  *                     4                             4
217  *
218  *  In the original graph, '1' has two alive outgoing edges and no incoming edges. '5' has two alive outgoing edges and
219  *  no incoming edges. '4' has two alive incoming edges and no outgoing edges. Source Elimination will merge '5' into
220  * '1' new edges are generated to replace the old ones incident to '1' and '5'.
221  *
222  */
223 struct SourceEliminationDecision : public Decision {
SourceEliminationDecisionSourceEliminationDecision224   SourceEliminationDecision(StrategyPtr op1_stra, CostPtr op1_c, StrategyPtr op2_stra, CostPtr op2_c)
225       : op1_strategy_(std::move(op1_stra)),
226         op1_cost_(std::move(op1_c)),
227         op2_strategy_(std::move(op2_stra)),
228         op2_cost_(std::move(op2_c)) {
229     type_ = DecisionType::SOURCE_ELIMINATION;
230   }
231   StrategyPtr op1_strategy_;
232   CostPtr op1_cost_;
233   StrategyPtr op2_strategy_;
234   CostPtr op2_cost_;
235   MS_DECLARE_PARENT(SourceEliminationDecision, Decision);
236 };
237 
238 /* 'TriangleEliminationDecision' is for the Triangle Elimination in DP algorithm:
239  *
240  *       u
241  *      / \
242  *     /   \
243  *    v --- w   ==> v --- w  In the original graph, u has 2 outgoing edges, v has 1 outgoing edge,
244  * and w has 2 incoming edges, u can be eliminated into v.
245  * 'eliminated_op_strategy_' is for u, 'eliminated_op_cost_' is for u, 'eliminated_left_edge_' is for edge u --> v,
246  * 'eliminated_right_edge_' is for edge u --> w.
247  */
248 struct TriangleEliminationDecision : public Decision {
TriangleEliminationDecisionTriangleEliminationDecision249   TriangleEliminationDecision(StrategyPtr elimi_stra, CostPtr elimi_op_cost, CostPtr l_edge_cost, CostPtr r_edge_cost,
250                               StrategyPtr left_stra, CostPtr l_node_cost, StrategyPtr right_stra, CostPtr r_node_cost)
251       : eliminated_op_strategy_(std::move(elimi_stra)),
252         eliminated_op_cost_(std::move(elimi_op_cost)),
253         left_edge_cost_(std::move(l_edge_cost)),
254         right_edge_cost_(std::move(r_edge_cost)),
255         left_node_strategy_(std::move(left_stra)),
256         left_node_cost_(std::move(l_node_cost)),
257         right_node_strategy_(std::move(right_stra)),
258         right_node_cost_(std::move(r_node_cost)) {
259     type_ = DecisionType::TRIANGLE_ELIMINATION;
260   }
261 
262   StrategyPtr eliminated_op_strategy_;
263   CostPtr eliminated_op_cost_;
264   CostPtr left_edge_cost_;
265   CostPtr right_edge_cost_;
266   StrategyPtr left_node_strategy_;
267   CostPtr left_node_cost_;
268   StrategyPtr right_node_strategy_;
269   CostPtr right_node_cost_;
270   MS_DECLARE_PARENT(TriangleEliminationDecision, Decision);
271 };
272 
273 /* 'StarEliminationDecision' is for the Star Elimination in DP algorithm:
274  *
275  *  v <--- u ---> w  ==> v    w  In the original graph, u has 0 incoming edges, and multiple outgoing edges.
276  *  In addition, v and w have other complicated connections, resulting in v and w can not be performed other
277  *  eliminations. After the StarElimination, u is merged into v, and the resulting graph is split into multiple
278  *  connected components.
279  *  NOTE: this elimination MUST be performed only when the above 5 operation cannot be applied.
280  */
281 struct StarEliminationDecision : public Decision {
StarEliminationDecisionStarEliminationDecision282   StarEliminationDecision(StrategyPtr elimi_op_stra, CostPtr elimi_op_cost, CostPtrList succ_edges_clist,
283                           std::vector<StrategyPtr> succ_ops_stra_list, CostPtrList succ_ops_clist)
284       : eliminated_op_strategy_(std::move(elimi_op_stra)),
285         eliminated_op_cost_(std::move(elimi_op_cost)),
286         succ_edges_cost_list_(std::move(succ_edges_clist)),
287         succ_ops_stra_list_(std::move(succ_ops_stra_list)),
288         succ_ops_cost_list_(std::move(succ_ops_clist)) {
289     type_ = DecisionType::STAR_ELIMINATION;
290   }
291 
292   StrategyPtr eliminated_op_strategy_;
293   CostPtr eliminated_op_cost_;
294   CostPtrList succ_edges_cost_list_;
295   std::vector<StrategyPtr> succ_ops_stra_list_;
296   CostPtrList succ_ops_cost_list_;
297   MS_DECLARE_PARENT(StarEliminationDecision, Decision);
298 };
299 
300 // This data structure records the decision for the graph which contains two nodes: u --> v. This includes
301 // the strategy 'u_strategy_' for 'u', the strategy 'v_strategy_' for 'v', the cost 'left_cost_' for 'u'.
302 struct FinalDecision : public Decision {
FinalDecisionFinalDecision303   FinalDecision(StrategyPtr u_stra, StrategyPtr v_stra, CostPtr l_cost, CostPtr m_cost, CostPtr r_cost)
304       : u_strategy_(std::move(u_stra)),
305         v_strategy_(std::move(v_stra)),
306         left_cost_(std::move(l_cost)),
307         middle_cost_(std::move(m_cost)),
308         right_cost_(std::move(r_cost)) {
309     type_ = DecisionType::FINAL_TYPE;
310   }
311 
312   StrategyPtr u_strategy_;
313   StrategyPtr v_strategy_;
314   CostPtr left_cost_;
315   CostPtr middle_cost_;
316   CostPtr right_cost_;
317   MS_DECLARE_PARENT(FinalDecision, Decision);
318 };
319 
320 // This data structure records the final decision for the graph containing a single node: u. This includes
321 // the strategy 'u_strategy_' for 'u', the cost 'u_cost_' for 'u'.
322 struct FinalSingleDecision : public Decision {
FinalSingleDecisionFinalSingleDecision323   FinalSingleDecision(StrategyPtr u_stra, CostPtr u_cost) : u_strategy_(std::move(u_stra)), u_cost_(std::move(u_cost)) {
324     type_ = DecisionType::FINAL_SINGLE;
325   }
326 
327   StrategyPtr u_strategy_;
328   CostPtr u_cost_;
329   MS_DECLARE_PARENT(FinalSingleDecision, Decision);
330 };
331 
332 using DecisionPtr = std::shared_ptr<Decision>;
333 using OpEliminationDecisionPtr = std::shared_ptr<OpEliminationDecision>;
334 using EdgeEliminationDecisionPtr = std::shared_ptr<EdgeEliminationDecision>;
335 using MergeEliminationDecisionPtr = std::shared_ptr<MergeEliminationDecision>;
336 using ContractEliminationDecisionPtr = std::shared_ptr<ContractEliminationDecision>;
337 using SourceEliminationDecisionPtr = std::shared_ptr<SourceEliminationDecision>;
338 using TriangleEliminationDecisionPtr = std::shared_ptr<TriangleEliminationDecision>;
339 using StarEliminationDecisionPtr = std::shared_ptr<StarEliminationDecision>;
340 using FinalDecisionPtr = std::shared_ptr<FinalDecision>;
341 using FinalSingleDecisionPtr = std::shared_ptr<FinalSingleDecision>;
342 
343 void Simplify(CostPtrList *clist);
344 void SimplifyForDecreasingCommunicationForward(CostPtrList *clist);
345 void SimplifyForDecreasingCommunicationWithPartialPara(CostPtrList *clist);
346 void RefineForPracticalCost(const CostPtr &, bool is_redistribution);
347 }  // namespace parallel
348 }  // namespace mindspore
349 
350 #endif  // MINDSPORE_CCSRC_FRONTEND_PARALLEL_AUTO_PARALLEL_COSTMODEL_H_
351