理解IR:从动态脚本到静态计算图的编译桥梁
理解IR(Intermediate Representation,中间表示)是掌握模型编译、调试和性能优化的关键所在。当我们编写深度学习脚本时,通常使用Python这样的动态语言,它提供了类型灵活、控制流自由、数据结构多样等便利。然而,真正要在GPU或Ascend这样的硬件上高效执行,模型必须转换为一张“静态计算图”:节点是算子,边是张量流动,所有形状、数据类型、内存布局都需提前确定。从动态代码到静态图的转换,本质上是一次彻底的“结构重塑”,而IR正是这一过程中的核心产物——它既保留了足够的高层语义信息,也逐步贴近底层执行逻辑。
在模型编译的各个阶段,从Python前端解析、类型推导,到算子融合、内存分配等后端优化,IR文件记录了每一环节的中间状态快照。通过在环境中设置 MS_DEV_SAVE_GRAPHS=2
,MindSpore会将编译流程完整“录制”下来,生成文本格式的 .ir
文件;设为 3
时,则进一步输出图形化的 .dot
文件,便于可视化分析。
以一个简单的Python脚本为例,当启用IR保存机制后,编译过程中会生成数量众多的中间文件。每个 .ir
文件都详细记录了该阶段的计算图结构、算子属性、输入输出类型等关键信息。
import os
import mindspore as ms
import mindspore.nn as nn
from mindspore import ops
ms.set_context(mode=ms.GRAPH_MODE)
os.environ['MS_DEV_SAVE_GRAPHS'] = '3'
os.environ['MS_DEV_SAVE_GRAPHS_PATH'] = './ir'
class Net(nn.Cell):
def __init__(self):
super().__init__()
def func(x, y):
return ops.div(x, y)
def construct(self, x, y): # x = 3, y = 2
a = ops.sub(x, 1) # x - 1 (2)
b = ops.add(a, y) # x - 1 + y (4)
if b :
b = ops.mul(b, self.func(a, b))
return b
input1 = ms.Tensor(3, ms.float32)
input2 = ms.Tensor(2, ms.float32)
net = Net()
out = net(input1, input2)
print(out)
在运行完成该脚本后(请使用python运行,而不要在jupyter notebook的cell里执行),我们可以通过命令对IR文件进行排序,以便按编译顺序依次查看:
find ./ -name '*.dot' | awk -F "_" '{print $NF " ---> " $0}' | sort -n
find ./ -name '*.ir' | awk -F "_" '{print $NF " ---> " $0}' | sort -n
以 22_execute_0728.ir 为例,我们可以查看其内容以了解模型结构:
而 .dot
文件可利用 GraphViz 工具转换为直观的图像,例如执行 dot -Tpng model.dot -o model.png
,就能将图结构渲染为图片。以 22_execute_0729.png 为例,在转换出的PNG图像中,我们能清晰看到静态图的整体架构:不同子图以黑色边框区分,图间的调用关系通过蓝色箭头标识。参数区域通常以蓝色呈现,矩形框代表参数列表,六边形和黑色箭头则指示该参数作为CNode的输入参与运算。黄色矩形代表CNode节点,其输入从下标0开始,第0位通常指向算子原语(如紫色或绿色区域,也可以是另一张图),通过虚箭头连接,表达该节点执行何种计算;后续输入则为具体参数,整个结构呈现出层层递进、逐步细化的编译轨迹。
最后,本文使用mindspore版本为2.6.0, 素材来自于 教程 (2.6.0) > [报错分析]https://www.mindspore.cn/tutorials/zh-CN/r2.6.0/debug/error_analysis.html
» [IR文件分析]https://www.mindspore.cn/tutorials/zh-CN/r2.6.0/debug/error_analysis/mindir.html
- 点赞
- 收藏
- 关注作者
评论(0)