[{"data":1,"prerenderedAt":783},["ShallowReactive",2],{"content-query-EnYZp5WCcw":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":777,"_id":778,"_source":779,"_file":780,"_stem":781,"_extension":782},"/technology-blogs/zh/3592","zh",false,"","重生之大腿带我征服 MindSpore（一）： IR 图再多也吃得下！","开场白","2025-01-27","https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2025/02/21/9776eedcbc6d4f2f874cad9e5fc23f12.png","technology-blogs","开发者分享",{"type":15,"children":16,"toc":754},"root",[17,25,118,123,158,163,169,186,191,196,201,218,223,233,244,254,259,264,269,274,285,290,295,299,304,309,314,326,334,339,385,389,394,399,404,461,465,477,489,499,512,517,522,527,532,536,541,559,584,609,614,619,624,647,652,657,662,667,680,687,700,708,712,716,720,724,729],{"type":18,"tag":19,"props":20,"children":22},"element","h1",{"id":21},"重生之大腿带我征服-mindspore一-ir-图再多也吃得下",[23],{"type":24,"value":8},"text",{"type":18,"tag":26,"props":27,"children":28},"ol",{},[29,34,62,67,108,113],{"type":18,"tag":30,"props":31,"children":32},"li",{},[33],{"type":24,"value":9},{"type":18,"tag":30,"props":35,"children":36},{},[37,39],{"type":24,"value":38},"访谈环节\n",{"type":18,"tag":26,"props":40,"children":41},{},[42,47,52,57],{"type":18,"tag":30,"props":43,"children":44},{},[45],{"type":24,"value":46},"为什么我们总是找用户拿 IR 图？",{"type":18,"tag":30,"props":48,"children":49},{},[50],{"type":24,"value":51},"基于 IR 图的简单问题分析",{"type":18,"tag":30,"props":53,"children":54},{},[55],{"type":24,"value":56},"更进一步 - 探索 IR图",{"type":18,"tag":30,"props":58,"children":59},{},[60],{"type":24,"value":61},"IR 的功能是什么？",{"type":18,"tag":30,"props":63,"children":64},{},[65],{"type":24,"value":66},"自由提问环节",{"type":18,"tag":30,"props":68,"children":69},{},[70,72],{"type":24,"value":71},"大腿带躺环节\n",{"type":18,"tag":26,"props":73,"children":74},{},[75,80],{"type":18,"tag":30,"props":76,"children":77},{},[78],{"type":24,"value":79},"功能分析",{"type":18,"tag":30,"props":81,"children":82},{},[83,85],{"type":24,"value":84},"功能实现\n",{"type":18,"tag":26,"props":86,"children":87},{},[88,93,98,103],{"type":18,"tag":30,"props":89,"children":90},{},[91],{"type":24,"value":92},"基于脚手架搭建项目",{"type":18,"tag":30,"props":94,"children":95},{},[96],{"type":24,"value":97},"实现语法高亮",{"type":18,"tag":30,"props":99,"children":100},{},[101],{"type":24,"value":102},"实现定义查找",{"type":18,"tag":30,"props":104,"children":105},{},[106],{"type":24,"value":107},"实现引用查找",{"type":18,"tag":30,"props":109,"children":110},{},[111],{"type":24,"value":112},"免责声明",{"type":18,"tag":30,"props":114,"children":115},{},[116],{"type":24,"value":117},"致谢",{"type":18,"tag":119,"props":120,"children":121},"h2",{"id":9},[122],{"type":24,"value":9},{"type":18,"tag":124,"props":125,"children":126},"p",{},[127,129,135,137,142,144,149,151,156],{"type":24,"value":128},"【",{"type":18,"tag":130,"props":131,"children":132},"strong",{},[133],{"type":24,"value":134},"主持人致辞",{"type":24,"value":136},"】: 大家好，欢迎大家莅临本期的《重生之大腿带我征服 mindspore》栏目。今天，我们很荣幸地邀请到并行组的大佬-->首座带领我们阅读关于IR图信息的学习和实践，欢迎首座！！ 【",{"type":18,"tag":130,"props":138,"children":139},{},[140],{"type":24,"value":141},"首座",{"type":24,"value":143},"】: 谢谢大家~ 呵呵呵。 【",{"type":18,"tag":130,"props":145,"children":146},{},[147],{"type":24,"value":148},"观众",{"type":24,"value":150},"】：掌声鼓励！ ============",{"type":18,"tag":130,"props":152,"children":153},{},[154],{"type":24,"value":155},"【快速进入正题】",{"type":24,"value":157}," ==========",{"type":18,"tag":119,"props":159,"children":161},{"id":160},"访谈环节",[162],{"type":24,"value":160},{"type":18,"tag":164,"props":165,"children":167},"h3",{"id":166},"为什么我们总是找用户拿-ir-图",[168],{"type":24,"value":46},{"type":18,"tag":124,"props":170,"children":171},{},[172,173,178,180,184],{"type":24,"value":128},{"type":18,"tag":130,"props":174,"children":175},{},[176],{"type":24,"value":177},"问题1",{"type":24,"value":179},"】: 首座，咱们定位问题的时候，老找用户拿 IR 图，那这个IR图到底是什么呢？ 【",{"type":18,"tag":130,"props":181,"children":182},{},[183],{"type":24,"value":141},{"type":24,"value":185},"】 ：IR 图本质上是描述源代码的程序表示，在 mindspore 中，其以静态单赋值形式(SSA)的形式表现。 具体到 mindspore 来说，就是描述咱们写的程序经过程序解析后的中间形态，通过这个中间形态，可以看到源代码被转换成什么样子。也就是说，我们可以从这个 IR 图上看到算子（计算、通信）的输入和输出，以便和源程序的逻辑进行比对，看是否符合咱们的预期。 【主持人】：哦哦，那我明白了，其实就是把咱们的源程序转换成一种通用的形式，所以它的逻辑肯定要和源程序一致。 【首座】：是的。",{"type":18,"tag":124,"props":187,"children":188},{},[189],{"type":24,"value":190},"=============== 我是分割线 =================",{"type":18,"tag":164,"props":192,"children":194},{"id":193},"基于-ir-图的简单问题分析",[195],{"type":24,"value":51},{"type":18,"tag":124,"props":197,"children":198},{},[199],{"type":24,"value":200},"============【举例分析】============",{"type":18,"tag":124,"props":202,"children":203},{},[204,205,210,212,216],{"type":24,"value":128},{"type":18,"tag":130,"props":206,"children":207},{},[208],{"type":24,"value":209},"问题2",{"type":24,"value":211},"】：咱们的观众很多都是工程师，擅长从问题入手，首座你可以举一个使用 IR 图进行问题分析的例子吗？ 【",{"type":18,"tag":130,"props":213,"children":214},{},[215],{"type":24,"value":141},{"type":24,"value":217},"】 ：呵呵呵，让我浅浅思考一下。既然我来自并行组，我就举一个简单关于并行的简单报错吧。",{"type":18,"tag":124,"props":219,"children":220},{},[221],{"type":24,"value":222},"这是一个由 Matmul 构建的简单网络，其两个参数由输入传入。",{"type":18,"tag":224,"props":225,"children":227},"pre",{"code":226},"class MyMatMul(nn.Cell):\n    def __init__(self):\n        super().__init__()\n        self.net = ops.MatMul().shard(((1, 1), (1, 1)))\n \n    def construct(self, input1, input2):\n        output = self.net(input1, input2)\n        return output\n \ninput1 = ms.Tensor(np.random.random([24, 48]), ms.float16)\ninput2 = ms.Tensor(np.random.random([48, 36]), ms.float16)\n \nnet = MyMatMul()\noutput = net(input1, input2)\nprint(output)\n",[228],{"type":18,"tag":229,"props":230,"children":231},"code",{"__ignoreMap":7},[232],{"type":24,"value":226},{"type":18,"tag":124,"props":234,"children":235},{},[236,238],{"type":24,"value":237},"执行该脚本出现如下报错： ",{"type":18,"tag":229,"props":239,"children":241},{"className":240},[],[242],{"type":24,"value":243},"ValueError: For 'MatMul' the input dimensions must be equal, but got 'x1_col': 48 and 'x2_row': 384.",{"type":18,"tag":124,"props":245,"children":246},{},[247,249],{"type":24,"value":248},"查看 IR 图: ",{"type":18,"tag":250,"props":251,"children":253},"img",{"alt":7,"src":252},"https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2025/02/07/297323f4f5884202a1fbf281a8000a04.png",[],{"type":18,"tag":124,"props":255,"children":256},{},[257],{"type":24,"value":258},"【首座】可以看到, MatMulNet construct 对应程序中的 construct 部分，但是两个参数的输入偷偷变成了原来的 8倍，这不符合咱们的预期啊！ 这是为什么呢？ 【观众】：mindspore 又出 bug 了 --> 笑声响起）",{"type":18,"tag":124,"props":260,"children":261},{},[262],{"type":24,"value":263},"【主持人】: 请大家请安静，咳咳咳，首座还没说完呢。",{"type":18,"tag":124,"props":265,"children":266},{},[267],{"type":24,"value":268},"=========== 【首座继续】 ==========",{"type":18,"tag":124,"props":270,"children":271},{},[272],{"type":24,"value":273},"这是因为在 mindspore 中，假定从数据集获取的网络 shape 为 (A,B)(A,B), 其需要从数据集中取 (A×N,B)(A×N,B)条数据，而每张卡都取(A,B)(A,B)条数据。 这里 MatMul 的输入就是被当成了数据输入，进行了扩增，从而导致了 Tensor 变成原来的 N 倍，这里的 N 就是 卡数。",{"type":18,"tag":124,"props":275,"children":276},{},[277,279],{"type":24,"value":278},"这里的解决方案就是让数据导入策略不使用数据并行导入，或者把Matmul 算子设置为 Parameter。这里给出第一种解决方法，改成 Parameter 的方式就留给大家做个探索把~。 ",{"type":18,"tag":229,"props":280,"children":282},{"className":281},[],[283],{"type":24,"value":284},"ms.set_auto_parallel_context(parallel_mode=ms.ParallelMode.SEMI_AUTO_PARALLEL, full_batch=True)",{"type":18,"tag":124,"props":286,"children":287},{},[288],{"type":24,"value":289},"【主持人、观众】：哦~ 【某观众】：这是 bug 还是 feature？ 【某观众】：嗯？还要做作业？",{"type":18,"tag":124,"props":291,"children":292},{},[293],{"type":24,"value":294},"【首座】:（内心 OS：我靠，想做作业是吧，多给你2题）",{"type":18,"tag":124,"props":296,"children":297},{},[298],{"type":24,"value":190},{"type":18,"tag":164,"props":300,"children":302},{"id":301},"更进一步-探索-ir图",[303],{"type":24,"value":56},{"type":18,"tag":124,"props":305,"children":306},{},[307],{"type":24,"value":308},"【问题3】首座刚才带我们做了一点热身，但是大家看起来才刚刚入门，首座能不能提供更详细的一些入门资料，帮助大家理解呢？ 【首座】没问题",{"type":18,"tag":124,"props":310,"children":311},{},[312],{"type":24,"value":313},"在座的各位都是攻城狮，都有自己擅长的编程语言，每个编程语言有自己的语法，IR 图也是。",{"type":18,"tag":124,"props":315,"children":316},{},[317,319,324],{"type":24,"value":318},"MindIR 是一种基于",{"type":18,"tag":130,"props":320,"children":321},{},[322],{"type":24,"value":323},"图表示的函数式IR",{"type":24,"value":325},"，其最核心的目的是服务于自动微分变换。而自动微分采用的是基于函数式编程框架的变换方法，ANF是函数式编程中常用且简洁的中间表示。借鉴于ANF 语法，MindIR 的文法长这样：",{"type":18,"tag":224,"props":327,"children":329},{"code":328}," ::=  | \n ::= Parameter\n ::= Scalar | Named | Tensor | Type | Shape | Primitive | MetaFuncGraph | FuncGraph \n ::= ( …)\n ::=  | \n",[330],{"type":18,"tag":229,"props":331,"children":332},{"__ignoreMap":7},[333],{"type":24,"value":328},{"type":18,"tag":124,"props":335,"children":336},{},[337],{"type":24,"value":338},"左侧可以简单地理解为父类，右侧是它的子类。--》除了第4条。 第4条表示CNode 是一个包含多个 AnfNode 的列表。",{"type":18,"tag":340,"props":341,"children":342},"ul",{},[343,367],{"type":18,"tag":30,"props":344,"children":345},{},[346,348,353,355],{"type":24,"value":347},"MindIR中 CNode 对应于ANF的复合表达式，表示一次",{"type":18,"tag":130,"props":349,"children":350},{},[351],{"type":24,"value":352},"函数调用",{"type":24,"value":354},"。",{"type":18,"tag":340,"props":356,"children":357},{},[358],{"type":18,"tag":30,"props":359,"children":360},{},[361,363],{"type":24,"value":362},"像MatMul 的计算，其就是一个函数调用。第一个参数是 MatMul 这个算子，第二个、第三个参数是输入，其他输入则是相关属性。 ---》 这里调通之前的用例就可以拿到这个 IR ",{"type":18,"tag":250,"props":364,"children":366},{"alt":7,"src":365},"https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2025/02/07/9a35e2f6ae6c41d0ab76236a2338ce35.png",[],{"type":18,"tag":30,"props":368,"children":369},{},[370,372],{"type":24,"value":371},"MindIR中的 Anode 对应于ANF的原子表达式，ANode有两个子类分别为 ValueNode 和 ParameterNode。",{"type":18,"tag":340,"props":373,"children":374},{},[375,380],{"type":18,"tag":30,"props":376,"children":377},{},[378],{"type":24,"value":379},"ValueNode表示常数节点，可承载一个常数值（标量、符号、张量、类型、维度等），也可以是一个原语函数（Primitive）或一个元函数（MetaFuncGraph）或一个普通函数（FuncGraph），因为在函数式编程中函数定义本身也是一个值。",{"type":18,"tag":30,"props":381,"children":382},{},[383],{"type":24,"value":384},"ParameterNode 是参数节点，表示函数的形参。",{"type":18,"tag":124,"props":386,"children":387},{},[388],{"type":24,"value":190},{"type":18,"tag":164,"props":390,"children":392},{"id":391},"ir-的功能是什么",[393],{"type":24,"value":61},{"type":18,"tag":124,"props":395,"children":396},{},[397],{"type":24,"value":398},"【问题】首座，现在大家对 IR 图的概念有一定的了解，但是有同学在存图后，发现对应目录下有很多 ir，这些 ir 图的功能分别是什么呢？ 【首座】这个问题问得很好，我们组内很多新员工也有这样的疑问。首先，大家在存图的时候是设置的图模式，另外一个模式是 Pynative。 图模式的好处之一就是能够在编译的时候，获取到完整的图信息，以便我们根据整图结构进行更好地优化，而在动态图的时候，就无法拿到这些信息。",{"type":18,"tag":124,"props":400,"children":401},{},[402],{"type":24,"value":403},"那么，对于图进行处理，就需要分为多个阶段，不同的阶段会对图进行相关的处理。这里只说几个大家关注度比较高的（其实是其他的阶段，作者不懂）",{"type":18,"tag":340,"props":405,"children":406},{},[407,417,427,437],{"type":18,"tag":30,"props":408,"children":409},{},[410,415],{"type":18,"tag":130,"props":411,"children":412},{},[413],{"type":24,"value":414},"ParseAction",{"type":24,"value":416},": 解析用户脚本，这对应了 parse_xxx.ir",{"type":18,"tag":30,"props":418,"children":419},{},[420,425],{"type":18,"tag":130,"props":421,"children":422},{},[423],{"type":24,"value":424},"abstact specialize",{"type":24,"value":426},": 这里会对用户脚本中不同算子的 abstract 进行推导，abstract包含（shape/type/value)。在 Python/C++ 侧的算子就有 InferShape 和 InferType 等函数用于实现该功能。",{"type":18,"tag":30,"props":428,"children":429},{},[430,435],{"type":18,"tag":130,"props":431,"children":432},{},[433],{"type":24,"value":434},"inline",{"type":24,"value":436},"：在网络脚本中，通常我们是以 Cell 为单位进行解析，那么这个图的信息太多，因此这里会把若干张小图 inline 成若干个大图。",{"type":18,"tag":30,"props":438,"children":439},{},[440,445,447],{"type":18,"tag":130,"props":441,"children":442},{},[443],{"type":24,"value":444},"optimize",{"type":24,"value":446},": 这里主要做的是设备无关的相关优化，设备无关指的是通用类优化，和不同的后端(如ascend、gpu)无关。这里会执行大量的 pass 对整图结构进行调整，用于优化性能。并行的相关处理也在这个阶段，大家跑多机多卡的时候，通常都会挂在这个阶段。\n",{"type":18,"tag":340,"props":448,"children":449},{},[450],{"type":18,"tag":30,"props":451,"children":452},{},[453,455,459],{"type":24,"value":454},"由于并行调整幅度比较大，所以在执行前后分别会保存 step_parallel_begin 和 step_parallel_end 这两张图，用于比对关于图的调整是否正确。 ",{"type":18,"tag":250,"props":456,"children":458},{"alt":7,"src":457},"https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2025/02/07/045e540318544ac5a2b0b747221863a5.png",[],{"type":24,"value":460},"大家看上面的这些截图，其实这些图前面的序号就是按照不同阶段的执行顺序。",{"type":18,"tag":119,"props":462,"children":463},{"id":66},[464],{"type":24,"value":66},{"type":18,"tag":124,"props":466,"children":467},{},[468,470,475],{"type":24,"value":469},"============= 【",{"type":18,"tag":130,"props":471,"children":472},{},[473],{"type":24,"value":474},"提问环节",{"type":24,"value":476},"】 ============【问题一】：首座，您好，我是小来。Mindspore 主要推行的是静态图模式，而torch 类似动态图模式，我想请问下静态图相较于动态图，它的优劣势分别是什么？",{"type":18,"tag":124,"props":478,"children":479},{},[480,482,487],{"type":24,"value":481},"【首座】：",{"type":18,"tag":130,"props":483,"children":484},{},[485],{"type":24,"value":486},"优势",{"type":24,"value":488},"大概是这样的：静态图能够获得图的全局信息，包含节点的顺序和数据类型，可以有针对性的进行优化，这里的优化可以是算子执行顺序的调整、内存优化等，最终的目的都是为了更快的执行速度。",{"type":18,"tag":124,"props":490,"children":491},{},[492,497],{"type":18,"tag":130,"props":493,"children":494},{},[495],{"type":24,"value":496},"劣势",{"type":24,"value":498},"主要还是在于开发/调试方面：",{"type":18,"tag":340,"props":500,"children":501},{},[502,507],{"type":18,"tag":30,"props":503,"children":504},{},[505],{"type":24,"value":506},"首先，torch 是单算子下发执行的，调测效率比较高。例如，torch 需要打印数据的时候，可以直接 print 对应的数据，而 mindspore 在这方面支持还比较有限（据可靠消息，在最新的 2.3 版本上已经支持了）。",{"type":18,"tag":30,"props":508,"children":509},{},[510],{"type":24,"value":511},"其次，静态图里面的图，意味着固定的 pattern，这也就意味着自由度受限。如果出来一种新模式，有比较大的概率可能是无法处理的。所以这就对 静态图框架的开发者有较高的要求，如果相关的 pass 没有处理好一些 corner case，可能会出现意料之外的错误。",{"type":18,"tag":124,"props":513,"children":514},{},[515],{"type":24,"value":516},"【接着提问】：那是不是基于动态图开发，然后转换为静态图训练或者部署？这样鱼与熊掌兼得啊！",{"type":18,"tag":124,"props":518,"children":519},{},[520],{"type":24,"value":521},"【首座】：是的，咳咳咳，但是你知道的，理想与现实总是会存在 gap 的。据我所知，在2.3及后续版本，会逐步聚焦易用性的开发，构建好生态，敬请大家期待。",{"type":18,"tag":119,"props":523,"children":525},{"id":524},"大腿带躺环节",[526],{"type":24,"value":524},{"type":18,"tag":124,"props":528,"children":529},{},[530],{"type":24,"value":531},"本章节，大腿带我们实现基于 IR 图的解析功能",{"type":18,"tag":164,"props":533,"children":534},{"id":79},[535],{"type":24,"value":79},{"type":18,"tag":124,"props":537,"children":538},{},[539],{"type":24,"value":540},"在 IR 图中，主要有如下定义:",{"type":18,"tag":340,"props":542,"children":543},{},[544,549,554],{"type":18,"tag":30,"props":545,"children":546},{},[547],{"type":24,"value":548},"Parameter: 以 %para 开头",{"type":18,"tag":30,"props":550,"children":551},{},[552],{"type":24,"value":553},"算子：以 %开头",{"type":18,"tag":30,"props":555,"children":556},{},[557],{"type":24,"value":558},"子图：通常以数字开头",{"type":18,"tag":124,"props":560,"children":561},{},[562,566,568,574,576,582],{"type":18,"tag":250,"props":563,"children":565},{"alt":7,"src":564},"https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2025/02/07/f51ae485c31b4abeb1a42e9a101f756f.png",[],{"type":24,"value":567},"如上图所示，",{"type":18,"tag":229,"props":569,"children":571},{"className":570},[],[572],{"type":24,"value":573},"%22",{"type":24,"value":575}," 就是被标记的 Load 算子，它用于加载 ",{"type":18,"tag":229,"props":577,"children":579},{"className":578},[],[580],{"type":24,"value":581},"para69",{"type":24,"value":583}," 开头的 embedding_table。",{"type":18,"tag":124,"props":585,"children":586},{},[587,589,595,597,603,605],{"type":24,"value":588},"如下图所示，在 subgraph instance 这个属性后跟着的就是子图的名称 ",{"type":18,"tag":229,"props":590,"children":592},{"className":591},[],[593],{"type":24,"value":594},"43_CR_CR_model_pangu_alpha_PanGUAlphaWithLoss_construct_27676",{"type":24,"value":596},", 其使用通常以 ",{"type":18,"tag":229,"props":598,"children":600},{"className":599},[],[601],{"type":24,"value":602},"call @43_CR_CR_model_pangu_alpha_PanGUAlphaWithLoss_construct_27676",{"type":24,"value":604}," 的形式存在 ",{"type":18,"tag":250,"props":606,"children":608},{"alt":7,"src":607},"https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2025/02/07/95a3a1c3e3e34e21bbc92667bf021378.png",[],{"type":18,"tag":124,"props":610,"children":611},{},[612],{"type":24,"value":613},"对于某一个参数/算子/子图，查找它的定义和引用是一个很常见的需求。 例如，在并行的 pass 中，需要确认算子 shape 是否符合预期，如果不符合预期，就需要沿着当前算子，找到第一个不符合预期的算子，分析根因。",{"type":18,"tag":124,"props":615,"children":616},{},[617],{"type":24,"value":618},"查找引用则是需要确认当前参数/算子/子图的调用，常用于特性开发的情况。",{"type":18,"tag":124,"props":620,"children":621},{},[622],{"type":24,"value":623},"另外，IR 图是没有颜色的，而在平时编程时，是会对变量、函数等做高亮，方便识别。因此对于 IR 图，我们需要对关注的信息进行高亮，方便快速识别, 这些包含：",{"type":18,"tag":340,"props":625,"children":626},{},[627,632,637,642],{"type":18,"tag":30,"props":628,"children":629},{},[630],{"type":24,"value":631},"变量： 参数",{"type":18,"tag":30,"props":633,"children":634},{},[635],{"type":24,"value":636},"函数： 算子名、子图",{"type":18,"tag":30,"props":638,"children":639},{},[640],{"type":24,"value":641},"关键字：call、Partial",{"type":18,"tag":30,"props":643,"children":644},{},[645],{"type":24,"value":646},"其他： 算子信息（Shape，type）",{"type":18,"tag":164,"props":648,"children":650},{"id":649},"功能实现",[651],{"type":24,"value":649},{"type":18,"tag":653,"props":654,"children":655},"h4",{"id":92},[656],{"type":24,"value":92},{"type":18,"tag":124,"props":658,"children":659},{},[660],{"type":24,"value":661},"这里主要基于官方脚手架进行基础搭建",{"type":18,"tag":124,"props":663,"children":664},{},[665],{"type":24,"value":666},"注意，这里还需要安装 npm。",{"type":18,"tag":124,"props":668,"children":669},{},[670,672,678],{"type":24,"value":671},"当前 IR 图只支持 .ir 类型，我们需要在 ",{"type":18,"tag":229,"props":673,"children":675},{"className":674},[],[676],{"type":24,"value":677},"package.json",{"type":24,"value":679}," 文件的 contributes 中添加 languages，来支持 .ir 文件，否则无法触发。",{"type":18,"tag":124,"props":681,"children":682},{},[683],{"type":18,"tag":250,"props":684,"children":686},{"alt":7,"src":685},"https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2025/02/07/776565653ab348d7851ad3ccb17b7751.png",[],{"type":18,"tag":124,"props":688,"children":689},{},[690,692,698],{"type":24,"value":691},"这里还需要配置 ",{"type":18,"tag":229,"props":693,"children":695},{"className":694},[],[696],{"type":24,"value":697},"language-configuration.json",{"type":24,"value":699},":",{"type":18,"tag":224,"props":701,"children":703},{"code":702},"{\n    \"comments\": {\n        // symbol for single line comment\n        \"lineComment\": \"//\",\n        // symbol for a block comment\n        \"blockComment\": [\"/*\", \"*/\"]\n    },\n    \"brackets\": [\n        [\"{\", \"}\"],\n        [\"[\", \"]\"],\n        [\"(\", \")\"]\n    ],\n    \"autoClosingPairs\": [\n        { \"open\": \"{\", \"close\": \"}\" },\n        { \"open\": \"[\", \"close\": \"]\" },\n        { \"open\": \"(\", \"close\": \")\" },\n        { \"open\": \"\\\"\", \"close\": \"\\\"\" },\n        { \"open\": \"'\", \"close\": \"'\" }\n    ],\n    \"surroundingPairs\": [\n        { \"open\": \"{\", \"close\": \"}\" },\n        { \"open\": \"[\", \"close\": \"]\" },\n        { \"open\": \"(\", \"close\": \")\" },\n        { \"open\": \"\\\"\", \"close\": \"\\\"\" },\n        { \"open\": \"'\", \"close\": \"'\" }\n    ]\n}\n",[704],{"type":18,"tag":229,"props":705,"children":706},{"__ignoreMap":7},[707],{"type":24,"value":702},{"type":18,"tag":653,"props":709,"children":710},{"id":97},[711],{"type":24,"value":97},{"type":18,"tag":653,"props":713,"children":714},{"id":102},[715],{"type":24,"value":102},{"type":18,"tag":653,"props":717,"children":718},{"id":107},[719],{"type":24,"value":107},{"type":18,"tag":119,"props":721,"children":722},{"id":112},[723],{"type":24,"value":112},{"type":18,"tag":124,"props":725,"children":726},{},[727],{"type":24,"value":728},"本文中提到的人物对话【纯属虚构】的，如有雷同，纯属巧合，请【勿对号入座】。",{"type":18,"tag":124,"props":730,"children":731},{},[732,734,739,741,746,748,752],{"type":24,"value":733},"感谢本期",{"type":18,"tag":130,"props":735,"children":736},{},[737],{"type":24,"value":738},"特邀嘉宾",{"type":24,"value":740},"：首座 感谢本栏目的",{"type":18,"tag":130,"props":742,"children":743},{},[744],{"type":24,"value":745},"常驻嘉宾",{"type":24,"value":747},"：xxx、xxx。 感谢以下工作人员：我自己。 感谢",{"type":18,"tag":130,"props":749,"children":750},{},[751],{"type":24,"value":148},{"type":24,"value":753},"。。。",{"title":7,"searchDepth":755,"depth":755,"links":756},4,[757,759,766,767,776],{"id":9,"depth":758,"text":9},2,{"id":160,"depth":758,"text":160,"children":760},[761,763,764,765],{"id":166,"depth":762,"text":46},3,{"id":193,"depth":762,"text":51},{"id":301,"depth":762,"text":56},{"id":391,"depth":762,"text":61},{"id":66,"depth":758,"text":66},{"id":524,"depth":758,"text":524,"children":768},[769,770],{"id":79,"depth":762,"text":79},{"id":649,"depth":762,"text":649,"children":771},[772,773,774,775],{"id":92,"depth":755,"text":92},{"id":97,"depth":755,"text":97},{"id":102,"depth":755,"text":102},{"id":107,"depth":755,"text":107},{"id":112,"depth":758,"text":112},"markdown","content:technology-blogs:zh:3592.md","content","technology-blogs/zh/3592.md","technology-blogs/zh/3592","md",1776506131813]