[{"data":1,"prerenderedAt":593},["ShallowReactive",2],{"content-query-FLHEkHVpX6":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"cover":11,"type":12,"category":13,"body":14,"_type":587,"_id":588,"_source":589,"_file":590,"_stem":591,"_extension":592},"/technology-blogs/zh/746","zh",false,"","实现一个昇思MindSpore 图层 IR 融合优化 pass","暑期2021｜项目经验分享","2021-10-09","https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2021/10/09/541ffee306324f4d82360aace76c3484.png","technology-blogs","开发者分享",{"type":15,"children":16,"toc":584},"root",[17,25,34,54,59,76,85,92,100,108,113,121,129,134,142,147,157,164,169,177,185,190,195,202,207,212,220,225,232,237,242,249,254,262,267,277,282,290,295,303,308,321,326,331,336,341,346,354,359,367,372,380,385,390,398,403,408,416,429,437,445,450,455,460,468,476,481,486,491,496,504,517,528,536,541,546,551,558,563,574,579],{"type":18,"tag":19,"props":20,"children":22},"element","h1",{"id":21},"实现一个昇思mindspore-图层-ir-融合优化-pass",[23],{"type":24,"value":8},"text",{"type":18,"tag":26,"props":27,"children":28},"p",{},[29],{"type":18,"tag":30,"props":31,"children":33},"img",{"alt":7,"src":32},"https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2021/10/09/7a13f1c00f114830b0583624cf2951ea.gif",[],{"type":18,"tag":26,"props":35,"children":36},{},[37,39,45,47,52],{"type":24,"value":38},"暑期2021结项审核正在进行中，项目经验分享也未停止。本期分享来自",{"type":18,"tag":40,"props":41,"children":42},"strong",{},[43],{"type":24,"value":44},"MindSpore 社区",{"type":24,"value":46},"的",{"type":18,"tag":40,"props":48,"children":49},{},[50],{"type":24,"value":51},"胡秋越",{"type":24,"value":53},"同学带来的项目经验：实现一个 MindSpore 图层 IR 融合优化 pass。",{"type":18,"tag":26,"props":55,"children":56},{},[57],{"type":24,"value":58},"欢迎大家持续投喂编辑部信箱，积极分享项目经验以及开源心得！",{"type":18,"tag":26,"props":60,"children":61},{},[62,67,69],{"type":18,"tag":40,"props":63,"children":64},{},[65],{"type":24,"value":66},"邮箱",{"type":24,"value":68},"：",{"type":18,"tag":70,"props":71,"children":73},"a",{"href":72},"mailto:summer@iscas.ac.cn",[74],{"type":24,"value":75},"summer@iscas.ac.cn",{"type":18,"tag":26,"props":77,"children":78},{},[79,84],{"type":18,"tag":40,"props":80,"children":81},{},[82],{"type":24,"value":83},"微信",{"type":24,"value":68},{"type":18,"tag":26,"props":86,"children":87},{},[88],{"type":18,"tag":30,"props":89,"children":91},{"alt":7,"src":90},"https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2021/10/09/782bb8d2f1804b949288cbf2e41ee90c.jpg",[],{"type":18,"tag":26,"props":93,"children":94},{},[95],{"type":18,"tag":40,"props":96,"children":97},{},[98],{"type":24,"value":99},"项目信息",{"type":18,"tag":26,"props":101,"children":102},{},[103],{"type":18,"tag":40,"props":104,"children":105},{},[106],{"type":24,"value":107},"项目名称",{"type":18,"tag":26,"props":109,"children":110},{},[111],{"type":24,"value":112},"实现一个 MindSpore 图层 IR 融合优化 pass",{"type":18,"tag":26,"props":114,"children":115},{},[116],{"type":18,"tag":40,"props":117,"children":118},{},[119],{"type":24,"value":120},"项目背景",{"type":18,"tag":26,"props":122,"children":123},{},[124],{"type":18,"tag":40,"props":125,"children":126},{},[127],{"type":24,"value":128},"MindSpore 简介",{"type":18,"tag":26,"props":130,"children":131},{},[132],{"type":24,"value":133},"随着近年来深度学习的快速发展，国外大的互联网公司谷歌（Google）和脸书（Facebook）分别推出了自己的深度学习框架：采用静态计算图的Tensorflow与采用动态图的Pytorch,二者都受到了广泛的应用。国内华为公司推出的“昇思”(MindSpore)，结合了动静态图，发挥了二者的优势。",{"type":18,"tag":26,"props":135,"children":136},{},[137],{"type":18,"tag":40,"props":138,"children":139},{},[140],{"type":24,"value":141},"MindSpore 架构",{"type":18,"tag":26,"props":143,"children":144},{},[145],{"type":24,"value":146},"MindSpore总体架构如下图所示：",{"type":18,"tag":26,"props":148,"children":149},{},[150],{"type":18,"tag":70,"props":151,"children":155},{"href":152,"rel":153},"https://www.mindspore.cn/tutorials/zh-CN/r1.5/introduction.html",[154],"nofollow",[156],{"type":24,"value":152},{"type":18,"tag":26,"props":158,"children":159},{},[160],{"type":18,"tag":30,"props":161,"children":163},{"alt":7,"src":162},"https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2021/10/09/e271743fbbdd4bed8a3facf1f969d5e6.jpg",[],{"type":18,"tag":26,"props":165,"children":166},{},[167],{"type":24,"value":168},"图1.MindSpore架构图",{"type":18,"tag":26,"props":170,"children":171},{},[172],{"type":18,"tag":40,"props":173,"children":174},{},[175],{"type":24,"value":176},"I****R(Intermediate Representation)简介",{"type":18,"tag":26,"props":178,"children":179},{},[180],{"type":18,"tag":40,"props":181,"children":182},{},[183],{"type":24,"value":184},"IR本质上是一种中间表示形式，是一个完整编译工具的一部分:",{"type":18,"tag":26,"props":186,"children":187},{},[188],{"type":24,"value":189},"中间表示（IR）是编译器或虚拟机内部用于表示源代码的数据结构或代码。IR旨在有助于进一步处理，如优化和翻译。“良好”的IR必须准确——能够在不丢失信息的情况下表示源代码——并且独立于任何特定的源语言或目标语言。IR可以采取以下几种形式之一：内存中的数据结构，或程序可读的基于元组或堆栈的特殊代码。在后一种情况下，它也被称为中间语言。",{"type":18,"tag":26,"props":191,"children":192},{},[193],{"type":24,"value":194},"随着不同的应用场景和需求，出现了大量不同的编程语言和不同的处理器架构，深度学习有如此多不同的前后端，如何找到一个桥梁更有效实现他们之间的优化和影射，这时体现出IR的重要性。",{"type":18,"tag":26,"props":196,"children":197},{},[198],{"type":18,"tag":30,"props":199,"children":201},{"alt":7,"src":200},"https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2021/10/09/65a57c074fd34e139aa92f9b0837286d.jpg",[],{"type":18,"tag":26,"props":203,"children":204},{},[205],{"type":24,"value":206},"图2.IR桥梁图",{"type":18,"tag":26,"props":208,"children":209},{},[210],{"type":24,"value":211},"基于图层IR的实际应用价值，我们有必要对图层进行IR融合优化，对应的应用方案即本项目课题-编写识别特定结构的图层 IR融合优化pass",{"type":18,"tag":26,"props":213,"children":214},{},[215],{"type":18,"tag":40,"props":216,"children":217},{},[218],{"type":24,"value":219},"方案描述",{"type":18,"tag":26,"props":221,"children":222},{},[223],{"type":24,"value":224},"根据项目要求，实现一个图层 IR 融合优化 pass。在图的编译阶段，通过各个 pass 进行优化，每个 pass 将识别到的图中特定结构，识别成功后进一步进行算子替换，将原网络 图中特定的结构中的算子进行融合，优化替换为相应更简单结构，从而实现网络图结构的优化。本次项目的图层融合优化 pass 是实现一个 prelu 的融合优化 pass，将 neg,relu,mul,add 算子组成的特定结构进行融合优化为 prelu 算子结构，具体的优化前特定算子结构如下图所示。",{"type":18,"tag":26,"props":226,"children":227},{},[228],{"type":18,"tag":30,"props":229,"children":231},{"alt":7,"src":230},"https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2021/10/09/b9688a83fde54a9ab4265043c152b6c1.jpg",[],{"type":18,"tag":26,"props":233,"children":234},{},[235],{"type":24,"value":236},"图3.优化前结构图",{"type":18,"tag":26,"props":238,"children":239},{},[240],{"type":24,"value":241},"为实现上图结构的优化，在 ir_fusion 文件中添加编写的优化 pass,即 prelu_fusion,实现的功能具体为识别上图结构，将输入 x,weight 通过算子 prelu 运算从而转换为新的网络结构，并输出新的网络图结点。在图编译的过程中，通过 compilegrahimpl 函数的调用，将运行各类优化 pass，将编写的 prelu_fusion 优化 pass 添加在 ascend_backend_optimization.cc 调用的pass 序列中，即可实现 prelu 的优化 pass。具体的优化后的网络图结构如下图所示。",{"type":18,"tag":26,"props":243,"children":244},{},[245],{"type":18,"tag":30,"props":246,"children":248},{"alt":7,"src":247},"https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2021/10/09/139933e23dcd411f87490e82279e2e8a.jpg",[],{"type":18,"tag":26,"props":250,"children":251},{},[252],{"type":24,"value":253},"图4.优化后结构图",{"type":18,"tag":26,"props":255,"children":256},{},[257],{"type":18,"tag":40,"props":258,"children":259},{},[260],{"type":24,"value":261},"编写文件",{"type":18,"tag":26,"props":263,"children":264},{},[265],{"type":24,"value":266},"依照方案编写文件，按照优化前网络结构图，对指定识别结构进行识别并替换,这里的代码偏向底层，各个pass的结构差别都不大，能产出代码的前提就是能看懂各个pass的数据结构及其依赖关系：",{"type":18,"tag":268,"props":269,"children":271},"pre",{"code":270},"namespace mindspore {\nnamespace opt {\nconst BaseRef PReluFusion::DefinePattern() const {\n  VectorRef x_pattern({prim::kPrimRelu, VectorRef({prim::kPrimNeg, x_})});\n  VectorRef mul_pattern({prim::kPrimMul, VectorRef({prim::kPrimNeg, weight_}), x_pattern});\n  VectorRef pattern({prim::kPrimAdd, VectorRef({prim::kPrimRelu, x_}), mul_pattern});\n  return pattern;\n}\n",[272],{"type":18,"tag":273,"props":274,"children":275},"code",{"__ignoreMap":7},[276],{"type":24,"value":270},{"type":18,"tag":26,"props":278,"children":279},{},[280],{"type":24,"value":281},"在识别到对应算子结构后，需要将其替换为优化后的算子结构，这里即为prelu算子，相关代码如下:",{"type":18,"tag":268,"props":283,"children":285},{"code":284},"const AnfNodePtr PReluFusion::Process(const FuncGraphPtr &graph, const AnfNodePtr &node, const\nEquivPtr &equiv) const {\n  MS_EXCEPTION_IF_NULL(graph);\n  MS_EXCEPTION_IF_NULL(node);\n  MS_EXCEPTION_IF_NULL(equiv);\n\n\n  BaseRef &x_gnode = (*equiv)[x_];\n  BaseRef &weight_gnode = (*equiv)[weight_];\n\n\n  auto x = utils::cast(x_gnode);\n  auto weight = utils::cast(weight_gnode);\n\n\n  MS_EXCEPTION_IF_NULL(x);\n  MS_EXCEPTION_IF_NULL(weight);\n\n\n  auto prim = std::make_shared(kPReluOpName);\n  MS_EXCEPTION_IF_NULL(prim);\n  std::vectorinputs = {NewValueNode(prim), x, weight};\n  auto fusion_node = graph->NewCNode(inputs);\n  MS_EXCEPTION_IF_NULL(fusion_node);\n  fusion_node->set_abstract(node->abstract());\n  fusion_node->set_scope(node->scope());\n  return fusion_node;\n}\n",[286],{"type":18,"tag":273,"props":287,"children":288},{"__ignoreMap":7},[289],{"type":24,"value":284},{"type":18,"tag":26,"props":291,"children":292},{},[293],{"type":24,"value":294},"其中这里的kPReluOpName是自己定义的，指向“PReLU”这个算子，在测试过程中也因为这个算子而掉过一个坑，也就是下文分享的问题。",{"type":18,"tag":26,"props":296,"children":297},{},[298],{"type":18,"tag":40,"props":299,"children":300},{},[301],{"type":24,"value":302},"问题处理经验分享",{"type":18,"tag":26,"props":304,"children":305},{},[306],{"type":24,"value":307},"完成代码的编写后，在进行测试的过程中遇到一些 bug，一个主要错误为运行测试用例时发生错误：",{"type":18,"tag":26,"props":309,"children":310},{},[311,315,317],{"type":18,"tag":30,"props":312,"children":314},{"alt":7,"src":313},"https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2021/10/09/e599480ac72b4009bbc2eaad212a36eb.jpg",[],{"type":24,"value":316}," ",{"type":18,"tag":30,"props":318,"children":320},{"alt":7,"src":319},"https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2021/10/09/5c69ae3b4a31443482a2412b7a359bc9.jpg",[],{"type":18,"tag":26,"props":322,"children":323},{},[324],{"type":24,"value":325},"我根据错误信息按照以下步骤进行错误排查：",{"type":18,"tag":26,"props":327,"children":328},{},[329],{"type":24,"value":330},"查看编写代码是否出错",{"type":18,"tag":26,"props":332,"children":333},{},[334],{"type":24,"value":335},"查看出错测试用例代码，分析可能出错点",{"type":18,"tag":26,"props":337,"children":338},{},[339],{"type":24,"value":340},"逐层加深到更多文件，查看与编写的代码可能存在冲突的文件",{"type":18,"tag":26,"props":342,"children":343},{},[344],{"type":24,"value":345},"按照以上步骤，进行检查，排除问题。",{"type":18,"tag":26,"props":347,"children":348},{},[349],{"type":18,"tag":40,"props":350,"children":351},{},[352],{"type":24,"value":353},"1. 首先对编写文件进行检查",{"type":18,"tag":26,"props":355,"children":356},{},[357],{"type":24,"value":358},"在这方面由于编写前已经将相关文件查阅较为熟悉，编译过程与demo测试过程都没有问题，我主观上便将其排除了。",{"type":18,"tag":26,"props":360,"children":361},{},[362],{"type":18,"tag":40,"props":363,"children":364},{},[365],{"type":24,"value":366},"2. 查看出错测试用例代码",{"type":18,"tag":26,"props":368,"children":369},{},[370],{"type":24,"value":371},"在仔细查看其模型代码后，发现其与我所编写的文件并未存在直接冲突，可能是其中调用的文件中与我所编写的文件存在冲突，接下来便是一一查看与其相关的文件，检查可能存在的冲突。",{"type":18,"tag":26,"props":373,"children":374},{},[375],{"type":18,"tag":40,"props":376,"children":377},{},[378],{"type":24,"value":379},"3. 检查冲突文件",{"type":18,"tag":26,"props":381,"children":382},{},[383],{"type":24,"value":384},"在对涉及文件一一查阅的过程中，发现其中涉及的文件延伸更广，这让我发现要通一一查阅文件来判断冲突文件几乎是不可能的，这让我不得不另找出路；",{"type":18,"tag":26,"props":386,"children":387},{},[388],{"type":24,"value":389},"既然查阅所有文件不可取，我想到先对编写文件涉及的代码文件进行查阅，在其中mindspore/ mindspore / ccsrc / utils / utils.h 中我发现编写pass及其附近pass的涉及算子如下",{"type":18,"tag":268,"props":391,"children":393},{"code":392},"namespace mindspore {\nconstexpr auto kSquareSumV1OpName = \"SquareSumV1\";\nconstexpr auto kSquareSumV2OpName = \"SquareSumV2\";\nconstexpr auto kClipByNormNoDivSumOpName = \"ClipByNormNoDivSum\";\nconstexpr auto kPReluOpName = \"PReLU\";\nconstexpr auto kGreaterOpName = \"Greater\";\nconstexpr auto kSqrtOpName = \"Sqrt\";\n",[394],{"type":18,"tag":273,"props":395,"children":396},{"__ignoreMap":7},[397],{"type":24,"value":392},{"type":18,"tag":26,"props":399,"children":400},{},[401],{"type":24,"value":402},"这让我想到会不会是在pass中替换算子的定义错误，怀着这个想法，我在分配的昇腾910环境下对出错的测试用例进行测试，神奇的发现竟然并没有报错，这让我思考推送到社区代码与本地代码的差别，最终发现是由于优化后算子的定义错误：自定义的prelu算子与实际存在的PReLU算子不匹配，导致了测试用例的错误。而实际上我们需要将自定义算子与已有的算子进行匹配，将匹配到的算子结构替换为已有的优化的算子结构。",{"type":18,"tag":26,"props":404,"children":405},{},[406],{"type":24,"value":407},"最终终于解决了错误，最后在导师的指导下在 gitee 上提出 issue 与 pr，在导师审查后进行修改优化，也让我进一步学习了为社区贡献代码的规范与进一步优化代码。",{"type":18,"tag":26,"props":409,"children":410},{},[411],{"type":18,"tag":40,"props":412,"children":413},{},[414],{"type":24,"value":415},"经验总结",{"type":18,"tag":26,"props":417,"children":418},{},[419,421,427],{"type":24,"value":420},"作为一个初识MindSpore（",{"type":18,"tag":70,"props":422,"children":425},{"href":423,"rel":424},"https://www.mindspore.cn",[154],[426],{"type":24,"value":423},{"type":24,"value":428},"）的小白，这次的项目开发经验无疑让我受益匪浅，迈出面向MindSpore的第一步。",{"type":18,"tag":26,"props":430,"children":431},{},[432],{"type":18,"tag":40,"props":433,"children":434},{},[435],{"type":24,"value":436},"沟通是最好的桥梁",{"type":18,"tag":26,"props":438,"children":439},{},[440],{"type":18,"tag":40,"props":441,"children":442},{},[443],{"type":24,"value":444},"项目的完成离不开与导师的沟通交流：",{"type":18,"tag":26,"props":446,"children":447},{},[448],{"type":24,"value":449},"初期学习方案的制定多亏导师的建议与帮助，让我对项目开发有了一定方向；",{"type":18,"tag":26,"props":451,"children":452},{},[453],{"type":24,"value":454},"按照计划，完成每一阶段及时向导师反馈，并将其中遇到的未解决的问题咨询导师，导师也很耐心地为我寻找解决的方案提供帮助；",{"type":18,"tag":26,"props":456,"children":457},{},[458],{"type":24,"value":459},"在社区仓库代码的合并过程中与导师沟通交流，规范代码，减少冗余操作，经过导师审查后代码成功并入仓库。",{"type":18,"tag":26,"props":461,"children":462},{},[463],{"type":18,"tag":40,"props":464,"children":465},{},[466],{"type":24,"value":467},"心得体会",{"type":18,"tag":26,"props":469,"children":470},{},[471],{"type":18,"tag":40,"props":472,"children":473},{},[474],{"type":24,"value":475},"本次项目的开发偏底层，在项目开发的过程中我更多的时间是在查看相关文件，弄懂编写一个优化pass涉及的文件及其依赖，知道了代码该怎么写，实际的编写过程就显得相对容易，开发的过程中，让我印象深刻的有几点：",{"type":18,"tag":26,"props":477,"children":478},{},[479],{"type":24,"value":480},"**公共环境要慎重操作：**在操作分配的公共环境时，由于自己的疏忽操作，影响了整个公共环境的正常运行，这点让我印象尤为深刻，幸好问题并不大，及时得到了解决；",{"type":18,"tag":26,"props":482,"children":483},{},[484],{"type":24,"value":485},"**与导师及时沟通，积累经验：**在进行项目开发时，经验显得尤为重要，项目开发初期，由于缺乏经验，让我不知从何下手，好在通过导师的沟通帮助，让我的开发方向明朗了起来，按照计划稳步推进项目；",{"type":18,"tag":26,"props":487,"children":488},{},[489],{"type":24,"value":490},"**深入理解项目内容，确定开发方向后，再进行实际开发：**经过一段时间的学习，我认为已经明确了开发方向，进行实际开发后，因为理解的错误，导致了不少问题，如上述中的问题④，便是对相关算子的替换的理解失误造成的；事实上，在编程中因为思考或理解的不到位导致的错误屡见不鲜。",{"type":18,"tag":26,"props":492,"children":493},{},[494],{"type":24,"value":495},"**规范化代码与减少冗余操作：**在将代码归并进社区的过程中，我深刻感觉到因为自己编写过程中代码的规范问题与冗余操作问题，当然这些问题不可能完全规避，但这也让我感受到规范化与精简化的社区标准，在平时就应该有意识的将其作为自己的标准。",{"type":18,"tag":26,"props":497,"children":498},{},[499],{"type":18,"tag":40,"props":500,"children":501},{},[502],{"type":24,"value":503},"自我评价",{"type":18,"tag":26,"props":505,"children":506},{},[507,509,515],{"type":24,"value":508},"完成了项目的要求与目标，解决了对应issue：",{"type":18,"tag":70,"props":510,"children":513},{"href":511,"rel":512},"https://gitee.com/mindspore/mindspore/issues/I44PH8?from=project-issue",[154],[514],{"type":24,"value":511},{"type":24,"value":516},"，将产出代码以pr：",{"type":18,"tag":26,"props":518,"children":519},{},[520,526],{"type":18,"tag":70,"props":521,"children":524},{"href":522,"rel":523},"https://gitee.com/mindspore/mindspore/pulls/21572",[154],[525],{"type":24,"value":522},{"type":24,"value":527},"的形式合并到社区仓库，实现了一个 MindSpore 图层 IR 融合优化 pass。虽然项目的总体难度并不难，但在开发的过程中遇到的困难也不少，收获也很多，让我受益匪浅。",{"type":18,"tag":26,"props":529,"children":530},{},[531],{"type":18,"tag":40,"props":532,"children":533},{},[534],{"type":24,"value":535},"致谢",{"type":18,"tag":26,"props":537,"children":538},{},[539],{"type":24,"value":540},"这次活动促进了开源软件的发展，也为开源社区贡献了新的活跃度，推进MindSpore开源生态的发展，也推动了在校学生积极参与开源社区并做出贡献；感谢 @开源之夏主办方 为这次活动提供的平台与机会；感谢俞老师、苑老师与王老师对我的帮助，使得我能顺利完成项目。",{"type":18,"tag":26,"props":542,"children":543},{},[544],{"type":24,"value":545},"本文为华南理工大学胡秋越同学的原创文章，欢迎更多小伙伴投稿分享。",{"type":18,"tag":26,"props":547,"children":548},{},[549],{"type":24,"value":550},"扫描下方二维码加入MindSpore项目↓",{"type":18,"tag":26,"props":552,"children":553},{},[554],{"type":18,"tag":30,"props":555,"children":557},{"alt":7,"src":556},"https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2021/10/09/20f111ea6168429ba6a94bb8c0880f9f.jpg",[],{"type":18,"tag":26,"props":559,"children":560},{},[561],{"type":24,"value":562},"MindSpore官方资料",{"type":18,"tag":26,"props":564,"children":565},{},[566,568],{"type":24,"value":567},"GitHub : ",{"type":18,"tag":70,"props":569,"children":572},{"href":570,"rel":571},"https://github.com/mindspore-ai/mindspore",[154],[573],{"type":24,"value":570},{"type":18,"tag":26,"props":575,"children":576},{},[577],{"type":24,"value":578},"Gitee : https : //gitee.com/mindspore/mindspore",{"type":18,"tag":26,"props":580,"children":581},{},[582],{"type":24,"value":583},"官方QQ群 : 8715434",{"title":7,"searchDepth":585,"depth":585,"links":586},4,[],"markdown","content:technology-blogs:zh:746.md","content","technology-blogs/zh/746.md","technology-blogs/zh/746","md",1776506140499]