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