假设你是一位小说家,写了一部长篇小说(PyTorch 模型),想把它推向全世界——手机、汽车芯片、可穿戴设备就是一个个语言不同的国家。可各国读者的文化习惯、词汇量、语法体系天差地别,怎么办?你找到了 Torch-MLIR 这家“跨国翻译社”。它先为手稿扫描留档(捕获成静态计算图),再让译者直译成包罗万象的“世界语”(torch 方言),原意一字不改,只做格式规范化。接下来,编辑们按各国口味把世界语意译成当地语言(Linalg、TOSA 等底层方言),最后印刷发行(生成目标代码)。更妙的是:无论将来接到多少新语言订单,那份“世界语直译稿”只需准备一次。今天这篇文章,就带你把这家翻译社的流水线从头到尾走一遍。

岗位关联

Torch-MLIR 是 AI 编译器工程师的“跨硬件桥”,掌握它,你才能在模型部署、算子优化、新芯片适配等岗位上真正理解“一次编译、处处运行”的工程智慧。

目录
  1. 可视化演示
  2. 前端捕获
  3. Torch方言
  4. 降级管线
  5. Linalg衔接
  6. TOSA衔接
  7. 后端扩展
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

动态展示Torch-MLIR将PyTorch图逐步lowering为MLIR各层dialect的编译过程,可视化算子从Torch到Linalg、TOSA、LLVM-IR的转换链路。

本节配有交互动效(进入视口后自动加载,约 3KB)。

Torch-MLIR编译流水线 PyTorch Torch Linalg TOSA LLVM-IR dialect(n)→dialect(n+1) 逐步lowering将高层算子转换为硬件可执行代码

前端捕获

想象你是一位小说作者,拿着刚完稿的手稿走进跨国翻译社。前台没有直接开译,而是先给手稿扫描留档、登记语言方向、确认目标读者。这套“接单流程”看似繁琐,却是后面所有翻译工作的地基。Torch-MLIR 面对 PyTorch 模型同样如此:第一步不是翻译,而是捕获。

这里的“扫描留档”就是 TorchScript 捕获。PyTorch 模型本质是 Python 动态代码,里面充满 if、for 和各种 Python 对象——编译器读不懂这种“活蹦乱跳”的稿子。于是 Torch-MLIR 借道 TorchScript,把模型的前向计算固化成一张静态计算图,图上的每个节点都是明确可枚举的算子。

固化之后,torch_mlir.compile() 这部“专车”会把静态图直接送进 MLIR 世界。它有三大关键参数:模型本身、示例输入(确定输入形状)、output_type(决定翻译到哪一站下车)。在入口处,计算图被转换成 torch 方言的 MLIR 模块,模块内包含若干 func.func,每个函数体就是一层层 torch 算子。

至此,翻译社完成了接单和扫描留档。稿子内容一个字没动,只是从“作者手写体”变成了“统一版式的电子稿”。接下来,才是真正逐句翻译的时刻。

Mpytorch→TorchScript 捕获Gscript→torchscript_to_torchMtorch\displaystyle \mathcal{M}_{\text{pytorch}} \xrightarrow{\text{TorchScript 捕获}} \mathcal{G}_{\text{script}} \xrightarrow{\text{torchscript\_to\_torch}} \mathcal{M}_{\text{torch}}
这条“捕获→图→方言模块”的流水线,就是翻译社把作者手稿变成电子稿的过程。字体变了,内容一字未动。
  1. PyTorch 模型 M_pytorch用户定义的模型对象,是一个装满权重和 forward 逻辑的容器,翻译社要处理的原稿。
    Mpytorch\mathcal{M}_{\text{pytorch}}
  2. TorchScript 捕获用 torch.jit.script 或 trace 把动态的 Python 模型变成静态图,类似手稿扫描成统一的电子文档。
    →TorchScript 捕获\xrightarrow{\text{TorchScript 捕获}}
  3. 静态计算图 G_script图中节点是算子、边是张量流动,编译器才能稳定地遍历和改写。
    Gscript\mathcal{G}_{\text{script}}
  4. 图导入器 torchscript_to_torchTorch-MLIR 自带的导入 pass,把计算图逐节点翻译成 torch 方言。
    →torchscript_to_torch\xrightarrow{\text{torchscript\_to\_torch}}
  5. torch 方言模块 M_torch输出的 MLIR 模块,是所有后续降级工作的公共起点,相当于世界语直译稿。
    Mtorch\mathcal{M}_{\text{torch}}

Torch方言

译者拿到电子稿后,开始直译。特别注意:他翻译的是“世界语”——专有名词保留原样、句子结构照搬、修辞手法一律不动。这样做的目的是确保任何人看到直译稿,都能精确反推出原稿的每一处细节。torch 方言就是这份世界语直译稿。

torch 方言的算子集完整刻印了 PyTorch 的 ATen 算子库,名字都带着 torch.aten. 前缀,例如 torch.aten.conv2d、torch.aten.relu。一个 PyTorch 算子进来,就有一个 torch 方言算子接住,几乎一一对应。正因为映射如此直接,PyTorch 里任何一眼看不透的行为都被原样保留:inplace 修改、隐式广播、动态形状,统统写进这张稿子。

除了算子,torch 方言还引入了自己的张量类型 !torch.vtensor<[形状],dtype>。它把“运行期才知道的形状”变成了编译期可查的签名。比如 !torch.vtensor<[1,3,224,224],f32> 就清清楚楚写着这是一张 1×3×224×224 的浮点张量,为后续推导优化提供了线索。

直译稿的价值在于“保真”。它或许不够精炼,却让每个下游编辑都能放心引用:无论最终翻译成哪国语言,遇到疑问时回查这份稿子,永远能找到最原始的答案。

torch.aten.conv2d ⁣:R[N,C,H,W]×R[F,C,k,k]→R[N,F,H′,W′],H′=⌊H+2p−ks⌋+1\displaystyle \texttt{torch.aten.conv2d} \colon \mathbb{R}^{[N,C,H,W]} \times \mathbb{R}^{[F,C,k,k]} \to \mathbb{R}^{[N,F,H',W']},\quad H'=\left\lfloor\frac{H+2p-k}{s}\right\rfloor+1
torch 方言的算子签名与 PyTorch 完全一致,形状关系原样保留。它不做任何简化或融合,先把“原意”钉死。
  1. 算子名torch.aten.conv2d 对应 PyTorch 的 torch.nn.Conv2d,命名也照搬 ATen 体系,方便追溯。
    torch.aten.conv2d\texttt{torch.aten.conv2d}
  2. 输入张量形状 [N,C,H,W] 分别表示批量大小、通道数、高、宽,是卷积输入的四个维度。
    R[N,C,H,W]\mathbb{R}^{[N,C,H,W]}
  3. 权重张量[F,C,k,k] 表示输出通道 F、输入通道 C、卷积核尺寸 k×k。
    R[F,C,k,k]\mathbb{R}^{[F,C,k,k]}
  4. 输出形状推算H' 由输入高 H、padding p、步长 s、卷积核 k 共同算出,与 PyTorch 的公式逐符号一致。
    ⌊H+2p−ks⌋+1\left\lfloor\frac{H+2p-k}{s}\right\rfloor+1

降级管线

直译稿里“断肠人在天涯”如果直愣愣交给国外读者,没人看得懂。编辑组决定意译,但不能一步到位——先统一语法、再补全缺省信息、最后才按目标语言逐句改写。Torch-MLIR 的降级管线正是这样一组按顺序执行的小型重写工序。

第一道工序是函数化(Functionalize)。PyTorch 里许多算子会原地修改张量,比如 add_ 把值直接写回输入。这类副作用让编译器不敢随意调整执行顺序。函数化 pass 把所有原地算子改写成“输入不变、返回新张量”的纯函数形式,图就变成了无副作用的函数式表达。

第二道工序是类型精化(RefineTypes)。原始 torch 方言里很多张量只有松散约束,比如“三维张量”或“未知形状”。RefineTypes 沿着算子语义把每个中间结果的形状和 dtype 精确推导出来,让隐性的信息显性化。

第三道工序是后端转换(ConvertToBackend)。这道工序根据 output_type 把 torch 算子映射到目标方言:Linalg 或 TOSA。每个 torch 算子可能有各自的改写规则,有的一个变一个,有的一个拆成多个,有的直接消失。

经过这三道工序,世界语直译稿变成了一本“通俗意译稿”。它不再保留原文的修辞痕迹,却让目标读者能顺畅理解。接下来,就看目的地在哪里了。

torch 方言→函数化无副作用→类型精化形状精确→后端转换Linalg/TOSA 方言\displaystyle \text{torch 方言} \xrightarrow{\text{函数化}} \text{无副作用} \xrightarrow{\text{类型精化}} \text{形状精确} \xrightarrow{\text{后端转换}} \text{Linalg/TOSA 方言}
降级管线就像编辑部流水线:语法编辑先改病句,资料编辑再补背景,最后责任编辑按出版方向定稿。每道工序只动一小步,合起来完成整个意译。
  1. 函数化(Functionalize)把 add_ 这类原地修改算子改写成 add 并返回新张量,让计算图变成纯函数。
    →函数化\xrightarrow{\text{函数化}}
  2. 无副作用每个算子只读输入、返回新输出,编译器可以放心做交换、融合、删除等优化。
    无副作用\text{无副作用}
  3. 类型精化(RefineTypes)从松散的形状约束推导出每个张量的精确形状和 dtype,相当于给所有名词补上“确切所指”。
    →类型精化\xrightarrow{\text{类型精化}}
  4. 后端转换(ConvertToBackend)把 torch.aten 算子逐一映射为 linalg 或 tosa 算子,是意译中最关键的一步。
    →后端转换\xrightarrow{\text{后端转换}}

Linalg衔接

有位编辑负责“学术精装版”:所有章节结构固定,逻辑链条完整,方便学者做文本比对和算法研究。Linalg 方言就是这种风格——算子不多,但每个算子都“结构化”得一丝不苟,把循环计算的三要素全部显式写出。

Linalg 的核心是 linalg.generic 这类结构化算子。它不写“我做了一次卷积”这样含糊的话,而是明确声明:迭代空间长什么样(iterator_types)、输入输出如何对齐(indexing_maps)、内部标量计算是什么(region body)。比如矩阵乘法被描述成三重循环,前两维是 parallel,最后一维是 reduction。

这种结构化表达对编译器极其友好。因为循环边界和索引关系全部摊开,多面体编译、循环融合、向量化、tiling 等优化都能批量自动实施。相比之下,一个封装严密的"conv2d"黑盒反而让优化无处下刀。

精装版图书让学者可以做严格的文本考据,Linalg 的标准化也让编译器可以做系统的循环变换。选择这个方向,等于把“性能优化”放在了首要位置。

MatMul⇔linalg.generic{iterator_types=[parallel,parallel,reduction]}\displaystyle \text{MatMul} \Leftrightarrow \texttt{linalg.generic}\{ \text{iterator\_types} = [\text{parallel}, \text{parallel}, \text{reduction}]\}
Linalg 像学术出版:结构标准、逻辑外露、便于理论分析。它牺牲了“看着舒服”,换来了“可以被系统性优化”。
  1. 矩阵乘法 MatMul语义是三重循环,C[i][j] = Σ A[i][k] × B[k][j],是深度学习里最常见的基础计算。
    MatMul\text{MatMul}
  2. 结构化算子 linalg.genericLinalg 统一模板,用声明式字段描述整类循环计算,而不是写死某个具体算子。
    linalg.generic\texttt{linalg.generic}
  3. 迭代类型 iterator_types前两维是并行迭代(每个输出独立),最后一维是归约迭代(需要累加),全部在循环空间显式声明。
    [parallel,parallel,reduction][\text{parallel}, \text{parallel}, \text{reduction}]

TOSA衔接

另一位编辑负责“口袋书版”:面向地铁通勤读者,用词固定、句式短小、杜绝一切歧义。TOSA 方言正是这种风格。TOSA 全称是 Tensor Operator Set Architecture,为嵌入式设备和移动端量身定做。

TOSA 拥有一份固定的张量算子集:卷积、池化、全连接、逐元素运算、拼接、reshape 等。每个算子的语义都有唯一官方解释,不依赖运行时上下文。它不允许隐式广播——需要改变形状时必须显式写出 reshape,这样硬件在看到算子时就能确定每个维度的物理意义。

TOSA 对量化也极其友好。量化参数(零点、缩放因子)作为算子属性显式携带,定点逻辑可以一步映射到硬件指令。这让 TOSA 成为连接 ML 框架与低功耗硬件 IP 的理想中间站:芯片厂商可以直接针对 TOSA 算子做硬件综合。

口袋书虽然词汇有限,却在手机、IoT 和专用芯片的世界里畅行无阻。选择 TOSA,等于把“部署确定性”放在了首要位置。

TOSA⊆{语义确定∧形状严明∧量化显式}\displaystyle \text{TOSA} \subseteq \{\text{语义确定} \wedge \text{形状严明} \wedge \text{量化显式}\}
TOSA 像口袋书出版:词汇量小、语法规则单一、含义零歧义。它不追求最优性能表达,但保证硬件能可靠地消化。
  1. 语义确定每个 TOSA 算子行为有唯一官方解释,不依赖运行时上下文,硬件可按固定逻辑展开。
    语义确定\text{语义确定}
  2. 形状严明张量维度规则固定,隐式广播必须显式写 reshape,避免硬件遇到意外形状。
    形状严明\text{形状严明}
  3. 量化显式量化参数随算子属性携带,定点逻辑可直接映射到硬件指令,无需运行时推导。
    量化显式\text{量化显式}

后端扩展

翻译社想接新语种订单,最妙的是它不需要重译原稿和世界语直译稿,只需新配一位目标语言的意译编辑,再安排排版印刷。Torch-MLIR 的后端扩展机制正是这样设计的。

后端抽象给每个目标硬件定义一个“编辑部”。在 Python 层面,开发者用注册装饰器把后端名称和编译函数绑定起来。新增一个后端只需要:确定目标方言集合(比如 Linalg-on-Tensors、TOSA 或自定义方言)、实现 torch 算子到目标方言的降级管线、然后注册接入 compile 入口。

注册完成后,torch_mlir.compile(..., output_type="my_backend") 就能直接调用这条新产线。前端捕获和 torch 方言直译稿完全不用动——这正是“翻译社”架构的红利:所有后端共享同一份世界语底稿,任何前端改进(比如新增算子支持)自动惠及所有后端。

每一次扩展都让这家翻译社的覆盖版图更大,而成本只是“再招一位编辑”。理解了这套可插拔后端机制,你就能设计出适应未来硬件生态的编译器架构。

新后端=方言集选择⏟目标方言+降级管线定制⏟lowering+代码生成器⏟codegen\displaystyle \text{新后端} = \underbrace{\text{方言集选择}}_{\text{目标方言}} + \underbrace{\text{降级管线定制}}_{\text{lowering}} + \underbrace{\text{代码生成器}}_{\text{codegen}}
新后端像为新语言配备的编辑部,只处理“世界语→当地语言”这一段。稿子在前面怎么采写、怎么直译,编辑部一概不用操心。
  1. 方言集选择决定从 torch-backend 降级到哪组目标方言,Linalg、TOSA 或自研方言皆可。
    方言集选择\text{方言集选择}
  2. 降级管线定制编写把 torch 算子逐一改写为目标方言算子的 pass 序列,是后端工作量的主体。
    降级管线定制\text{降级管线定制}
  3. 代码生成器目标方言如何变成可执行代码,通常复用 LLVM 或专用硬件工具链完成。
    代码生成器\text{代码生成器}

AI 应用场景

多硬件部署平台

阶段:模型部署与适配

解决的问题:传统方式下,要把同一个 PyTorch 模型部署到 GPU、ARM 手机、RISC-V 芯片,需要分别对接不同的推理引擎,为每个硬件手工重写算子。Torch-MLIR 让模型只需完成一次“直译”(torch 方言),再按目标平台选择 Linalg 或 TOSA 产线,后端差异被隔离在降级管线内。

具体案例:一家 AIoT 公司需要在智能摄像头(ARM CPU)、边缘服务器(x86 GPU)和自研 NPU 上同时运行同一个手势识别模型。接入 Torch-MLIR 后,算法团队只维护一份 PyTorch 源码,硬件团队各自配置 output_type 和下游编译器,一周内完成三端部署。

算子融合与性能调优

阶段:推理性能优化

解决的问题:PyTorch 模型里 Conv 后跟 BatchNorm、ReLU 是家常便饭,逐算子执行会有大量访存开销。Torch-MLIR 在 Linalg 阶段把算子摊平成结构化循环,编译器可以自动实施算子融合和循环变换,不需要手工改模型。

具体案例:某自动驾驶团队用 Torch-MLIR 编译 3D 目标检测模型,在 Linalg 层自动完成了 conv+bn+relu 的融合,端到端延迟降低 37%,且没有改动任何 PyTorch 源码。

新 NPU 芯片快速适配

阶段:后端开发与硬件适配

解决的问题:芯片公司流片前就要把主流模型跑在自己的 NPU 上,证明算力达标。从头写一个推理引擎动辄数月,而基于 Torch-MLIR 只需定制一份“目标方言 + 降级管线 + 测试闭环”,即可复用全部前端生态。

具体案例:某 RISC-V 芯片创业公司基于 Torch-MLIR 的 TOSA 后端定义了自己的 NPU 算子方言,团队三人用六周接入了 ResNet、MobileNet 等十个模型,在仿真器上完成精度验证。

Python 演示

python28 行
import torchimport torch_mlir  class Net(torch.nn.Module):    def __init__(self):        super().__init__()        self.fc1 = torch.nn.Linear(784, 128)        self.fc2 = torch.nn.Linear(128, 10)     def forward(self, x):        x = torch.flatten(x, 1)        x = torch.relu(self.fc1(x))        return self.fc2(x)  model = Net()model.eval()example = torch.randn(1, 1, 28, 28) for output_type in ("torch", "linalg-on-tensors", "tosa"):    print("===== output_type: {} =====".format(output_type))    mlir_module = torch_mlir.compile(        model,        example,        output_type=output_type,    )    print(mlir_module)
目的:用同一个两层神经网络,分别展示 Torch-MLIR 在 torch / linalg-on-tensors / tosa 三个方言层级的编译产物,让你直观看到“翻译到不同站点”的差异。
  1. import torch_mlir引入翻译社的 API 包,它提供 compile 入口和全部降级管线。
  2. class Net(torch.nn.Module)定义小说家的“手稿”:一个两层全连接网络,结构简单但五脏俱全。
  3. model.eval()切换到推理模式,冻结 dropout 等随机行为,让捕获的图稳定可复现。
  4. example = torch.randn(1, 1, 28, 28)提供一份“样张”,用于确定输入张量的形状信息。
  5. for output_type in (...)让同一份手稿产出三个不同“国家版本”:直译稿、学术版、口袋书版。
  6. torch_mlir.compile(model, example, output_type=...)翻译社的前台,根据 output_type 决定翻译到哪一站下车。
  7. print(mlir_module)打印 MLIR 模块,相当于翻开译稿查看每一行翻译内容。

常见误区

误区我以为 torch_mlir.compile 之后拿到的是能直接运行的 .so 或二进制文件,所以在部署 CI 里直接把它当作最终编译产物。

正解compile 返回的是 MLIR 模块(torch、linalg-on-tensors、tosa 等方言),它还需要 LLVM 等下游编译器继续翻译成目标机器码。Torch-MLIR 的职责止于“方言级翻译”,类似翻译社只出译稿,印书是印刷厂的事。

为何常见:接口名字带 compile,使用门槛又低,小白很容易联想到 gcc 这类直接产出可执行文件的编译器,忽略了中间表示的存在。

误区反正最后都要变成 linalg 或 tosa,为什么还要在中间保留一份 torch 方言?直接转换不是更省事吗?

正解torch 方言把 PyTorch 语义完整保真地固化下来,是高层次优化(如算子融合、死分支消除)和调试诊断的最佳载体。同时它是所有后端共享的公共底稿,后端只需处理“torch→自己”的降级,不用各自对接不断变化的 PyTorch 运行时。

为何常见:只看到多一层就多一次工作,忽略了跨后端复用带来的整体工程收益。

误区linalg-on-tensors 和 tosa 都是 torch 的底层方言,output_type 选哪个都一样,无非格式略有差别。

正解两者定位差异很大。Linalg 以结构化循环为核心,适合在高性能 CPU/GPU 上做融合、向量化、多面体优化;TOSA 以确定性张量算子为核心,适合嵌入式/移动端以及硬件直接推断。选错方向,后续优化和部署都会很被动。

为何常见:两者都是张量方言,命名气质相近,初学者容易忽略它们各自服务的硬件场景。

误区我看资料里写“torch 降级到 linalg”,以为是一个 pass 一次性把图里所有算子都换掉了。

正解实际是一连串几十个小 pass 逐步迭代:先函数化、再精化类型、再拆分复合算子、再逐个映射到目标方言。每一步只做很小的改写,像翻译社里不同编辑各改一遍,最后合稿。

为何常见:站在高层面看流程是“一条线”,容易把漫长接力想象成瞬间移动,忽略了工程实现的迭代细节。

误区编译完成后权重就被固化在代码里了,以后想换权重就得重新编译整个模型。

正解在 Torch-MLIR 中,模型权重通常作为全局私有常量或函数参数传递,运行时由加载器读取当前数值。图的“结构”和参数的“值”被解耦——图编译一次,权重可以动态更换。

为何常见:直觉上把编译等同于“把所有代码和数据打包”,混淆了程序静态编译与深度学习中权重-结构分离的部署设计。

面试题

Q1. torch_mlir.compile 捕获模型时,第一步先生成什么?

单选题 · easy

  • A.捕获成 ONNX 图
  • B.捕获成 TorchScript 图← 正确答案
  • C.捕获成 LLVM IR 图
  • D.捕获成 Linalg 图

答案:B。compile 先借 TorchScript 把 Python 动态模型固化为静态计算图,这样后续才能稳定地转换成 torch 方言。ONNX 是另一个生态的表示,LLVM IR 和 Linalg 都是更下游的产物。

Q2. torch 方言中的算子统一以什么前缀命名?

单选题 · easy

  • A.linalg.conv 前缀
  • B.tosa.conv 前缀
  • C.torch.aten 前缀← 正确答案
  • D.func.call 前缀

答案:C。torch.aten.* 直接沿用 PyTorch ATen 算子名,如 torch.aten.add.Tensor、torch.aten.conv2d。linalg、tosa 是降级后的底层方言,func.call 是函数调用算子,都不是 torch 方言的统一前缀。

Q3. ValueTensorType(vtensor)主要记录什么?

单选题 · mid

  • A.梯度与反向传播链信息
  • B.张量形状与数据类型信息← 正确答案
  • C.卷积核权重分布信息
  • D.算子执行字节码信息

答案:B。vtensor<[N,C,H,W],f32> 记录张量形状和 dtype,这是编译器做形状推导和算子选择的关键元数据。梯度、权重分布、字节码分别属于训练机制、数据内容和运行时产物。

Q4. 关于降级管线的说法,哪些正确?

多选题 · mid

  • A.由多个小 pass 接力完成← 正确答案
  • B.一个 pass 一步替换算子
  • C.逐步收敛到目标方言← 正确答案
  • D.不同目标对应不同管线← 正确答案

答案:ACD。lowering 由几十个小 pass 组成接力流水线,每个 pass 只做很小改写,逐步把 torch 语义收敛到 linalg/tosa 等目标;output_type 不同,选用的管线组合也不同。一步替换在工程上极难实现,B 错误。

Q5. MaximizeValueSemantics 主要做什么?

单选题 · mid

  • A.原地修改算子改成函数式返回← 正确答案
  • B.将函数式算子改成有副作用形式
  • C.删除所有影响梯度的算子
  • D.合并相邻同形状的张量

答案:A。这个 pass 让 add_、relu_ 等原地修改算子变成 add、relu 并返回新张量,使整个图变成纯函数式。纯函数式图没有副作用,编译器才能放心地做融合、交换和删除优化。

Q6. Linalg 与 TOSA 最核心的区别是?

单选题 · hard

  • A.Linalg 面向循环优化,TOSA 面向嵌入式← 正确答案
  • B.TOSA 面向高性能计算,Linalg 面向手机
  • C.Linalg 与 TOSA 完全等价可互换
  • D.TOSA 是 Linalg 的前一层表示

答案:A。Linalg 用结构化算子显式描述循环与索引映射,便于融合、向量化和多面体优化;TOSA 用确定性张量算子集服务嵌入式与硬件推断。两者各有定位,不可随意互换。

Q7. torch_mlir.compile 中 output_type 参数的作用是?

单选题 · easy

  • A.控制输出张量的数据精度
  • B.决定降级到的方言层级← 正确答案
  • C.设置编译器的优化开关
  • D.指定训练时的损失函数

答案:B。output_type 告诉翻译社“翻译到哪一站”,可选 torch、linalg-on-tensors、tosa 等。它不控制精度、不设优化等级,更与训练损失函数无关。

Q8. 为 Torch-MLIR 添加一个新后端,通常需要?

多选题 · hard

  • A.定义或选择目标方言集合← 正确答案
  • B.实现到目标方言的降级管线← 正确答案
  • C.注册后端名称接入编译入口← 正确答案
  • D.重新实现整个 PyTorch 算子库

答案:ABC。新后端需要确定目标方言、写降级管线、注册编译入口。PyTorch 算子库由 torch 方言统一接管,前端捕获也完全复用,不需要也不应该重新实现。

Q9. TOSA 为什么适合嵌入式设备?

单选题 · mid

  • A.算子语义固定且张量规则严格← 正确答案
  • B.运行时依赖复杂操作系统调度
  • C.允许任意隐式形状广播行为
  • D.需要完整 Python 解释器支持

答案:A。TOSA 每个算子的形状规则和量化参数都显式绑定,硬件可以按固定逻辑展开,无需运行时决策。隐式广播和 Python 依赖恰恰是嵌入式设备最想避免的。

Q10. 模型权重在降级后通常以什么形式存在?

单选题 · extreme

  • A.内联复制到每个算子调用处
  • B.作为全局常量或函数参数传递← 正确答案
  • C.捕获阶段直接被编译器丢弃
  • D.每次前向动态重算重新获得

答案:B。权重与计算图结构解耦,通常作为模块的全局私有常量或函数参数出现在编译产物中,运行时再加载实际数值。内联到每个调用处浪费空间,丢弃或动态重算都不符合部署语义。