想象这样一个场景:你要去爬一座雪山,面前摆着一个塞满 60 升装备的豪华登山箱——帐篷、炊具、冰镐、备用绳索,应有尽有。可你的手机、智能门锁、摄像头只是一个小小的随身背包。把整个登山箱原封不动背在身上显然不现实,于是你学会了一门手艺:只带路上真正用得到的装备,把羽绒服抽成真空压缩片,到了山脚再请一位熟悉路线的本地向导。ONNX Runtime Mobile 干的就是这件事。它是专为手机、IoT 设备设计的轻量推理引擎,能把原本动辄 30MB 的完整框架,通过“算子裁剪”和“模型量化”压缩到几 MB,再借力 NNAPI、CoreML 等硬件加速接口,让模型在巴掌大的设备上跑得又快又省。这篇文章会用“整理登山背包”的故事,带你从零看懂它的包体优化、算子裁剪、硬件加速和量化部署全流程。

岗位关联

掌握 ONNX Runtime Mobile,你就能把云端大模型真正“装进”手机和 IoT 设备,这是端侧 AI 落地工程师的核心竞争力,也是从“会训练”走向“会部署”的关键一步。

目录
  1. 可视化演示
  2. 端侧部署挑战
  3. 轻量架构设计
  4. 算子裁剪机制
  5. 包体优化策略
  6. 硬件加速引擎
  7. 模型量化部署
  8. 部署工具链
  9. 端侧应用场景
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

展示ONNX Runtime Mobile的架构分层、算子裁剪按需打包机制与硬件加速EP路由,直观理解移动端轻量推理引擎的包体优化原理。

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

ONNX Mobile引擎架构 模型加载层解析ONNX格式,按需注册算子构建计算图 执行层通过EP路由到NNAPI/CoreML等硬件加速器 包体 = 基础库 + 算子集 + EP 移动端按需裁剪

端侧部署挑战

同样是登山,60 升登山箱和 20 升随身背包的差距,比想象中大得多。手机的内存通常只有几个 GB,还要分给系统和各种 App;智能门锁的芯片可能只有几十 MB 可用内存;摄像头的主控更是省着花。设备越小,能背的装备就越少,这是端侧部署一切问题的起点。

深度学习模型在云端 GPU 上跑,好比装备库管理员,随便调用几千瓦电力和几十 GB 显存;到了端侧,供电、内存、存储全部受限。部署工程师至少要面对四个硬约束:内存不足、包体敏感(App 多 1MB 都影响用户下载意愿)、硬件碎片化(安卓、苹果、各类 IoT 芯片架构各不相同)、以及毫秒级延迟要求。而这其中,内存占用是最容易用公式讲清楚的。

模型驻留内存由参数总量和位宽共同决定:

看清了“背包容量”的账,再来想怎么省地方:要么减少带的东西(裁剪算子),要么把东西压扁(量化权重),要么让向导带路走最顺的路线(硬件加速)。这正是 ONNX Runtime Mobile 的全部智慧。

M=N×b8\displaystyle M = \frac{N \times b}{8}
通俗地说:N 是模型记事的条目数,b 是每条笔记用的“墨水浓度”(位宽),两者相乘再除以 8,就是占用的字节数。
  1. N(参数量)模型里所有可学习参数(权重)的个数。参数越多,模型“记性”越好,占的地方也越大。
    NN
  2. b(位宽)每个参数用多少比特存储。常见 FP32 是 32 位,INT8 是 8 位,位宽直接决定“墨水浓度”。
    b∈{32,16,8}b \in \{32, 16, 8\}
  3. 乘号 \times把参数量与位宽相乘,得到模型权重的总比特数。
    N×bN \times b
  4. 除以 88 比特等于 1 字节,把比特换算成字节;再除以两次 1024,就得到以 MB 为单位的体积。
    N×b8\frac{N \times b}{8}

轻量架构设计

好的登山背包不是一块整布,而是主仓、侧袋、顶包、外挂点各司其职,并且侧袋和顶包可以拆卸。ONNX Runtime 本身也是模块化设计:完整版把一千多个算子内核全部编译进去,Mobile 版则只保留“骨架 + 你要的那几个口袋”。

这个“骨架”包含会话管理、图优化、内存池等公共组件,体积通常在 2~4MB;“口袋”是各个算子内核,每个口袋大小不一,比如 Conv 内核约 4MB,Relu 不到 1MB。你选择裁剪配置时,本质上是在决定哪些口袋被缝上背包。除了算子裁剪,Mobile 版还通过按需加载机制避免一次链接全部符号,并精简掉桌面版才需要的平台依赖,只保留最必要的运行库,最终以静态库或动态库形式打包进 App。

裁剪后的引擎包体可以写成一条清晰的加法:

骨架不可省,口袋可增减——这就是“轻量”二字的架构来源。

S=Sbase+∑i=1ksi\displaystyle S = S_{\text{base}} + \sum_{i=1}^{k} s_i
S_base 是骨架(基础运行环境),s_i 是第 i 个被选中的算子内核体积,k 是选中算子的数量。
  1. S_base(基础骨架)会话执行、图调度、内存池等公共代码,这部分无论如何都要保留。
    SbaseS_{\text{base}}
  2. 求和符号 \sum把选中的 k 个算子的体积逐一累加起来。
    ∑i=1k\sum_{i=1}^{k}
  3. s_i(第 i 个算子)每个算子内核编译后的产物体积,不同算子差异很大。
    sis_i
  4. k(算子数量)由裁剪清单决定的值,清单越短,包体越小。
    kk

算子裁剪机制

出发前你会写装备清单:帐篷、睡袋、炉头,逐项打勾。ONNX Runtime Mobile 也是这么干的:先把模型计算图完整扫一遍,统计每个节点用到的算子类型,整理成“必带清单”,然后只编译清单里的算子内核。

具体机制分三步:第一步,离线分析模型,遍历全部算子节点并提取类型;第二步,生成裁剪配置文件,交给构建系统;第三步,构建时按注册表剔除未选中的算子内核。这样生成的 .so 或 .a 库只含必需代码,从源头控制包体大小。

“必带清单”可以用集合公式表达:

装备清单越准,背包越轻;但漏掉任何一个必需品,到山上才发现没带炉头,就只能接受冷饭的代价——部署前务必用真实模型做一次完整扫描。

Oneed=⋃l=1LOpType(opl)\displaystyle O_{\text{need}} = \bigcup_{l=1}^{L} \mathrm{OpType}(op_l)
模型有 L 个算子节点,把每个节点的类型提取出来,再用“并集”合并去重,就是必须保留的算子集合。
  1. op_l(第 l 个算子节点)计算图中每个算子节点,比如一次卷积、一次矩阵乘法。
    oplop_l
  2. OpType()(类型提取函数)读取该节点属于哪种算子,例如 Conv、Gemm、Relu。
    OpType(opl)\mathrm{OpType}(op_l)
  3. 并集 \bigcup把 L 个节点的类型合并,相同类型只保留一个,避免重复计算体积。
    ⋃l=1L\bigcup_{l=1}^{L}
  4. O_need(必带集合)最终得到模型真正依赖的算子类型集合,也就是裁剪后的“装备清单”。
    OneedO_{\text{need}}

包体优化策略

收拾完行李,站上体重秤。不同的打包方案,重量天差地别。一个常见 CNN 分类模型的实测数据(示意)就很有说服力:完整 ONNX Runtime 框架约 30MB;只保留 Conv、Gemm、Relu、Softmax 等必需算子后,包体降到约 12MB;再对权重做 INT8 量化,包体进一步逼近 4MB。

从 30MB 到 4MB,压缩比超过 85%。第一刀“裁剪”砍掉的是用不上的算子内核,第二刀“量化”压缩的是权重本身,两刀方向不同、互不冲突。这也是很多团队把“裁剪”和“量化”同时纳入发布流水线的原因。

压缩幅度可以用一个比例公式衡量:

但“最轻”不等于“最好”——如果为了极致小,把模型要用的算子也裁掉,模型根本跑不起来。包体小是手段,能跑且够快才是目的,权衡才是打包的哲学。

R=Sfull−StrimSfull×100%\displaystyle R = \frac{S_{\text{full}} - S_{\text{trim}}}{S_{\text{full}}} \times 100\%
R 表示裁剪加量化后节省下来的体积占比。
  1. S_full(完整框架包体)包含全部算子和完整依赖的原始体积,这里是 30MB。
    SfullS_{\text{full}}
  2. S_trim(裁剪后包体)经过算子裁剪和量化后的实际体积,这里是 4MB。
    StrimS_{\text{trim}}
  3. 差值(分子)完整包减去裁剪包,就是省下来的空间。
    Sfull−StrimS_{\text{full}} - S_{\text{trim}}
  4. 乘 100%把比值转换成百分比,方便团队之间沟通压缩效果。
    ×100%\times 100\%

硬件加速引擎

到了山脚,与其自己摸索路线,不如请一位本地向导。向导知道哪条路最近、哪段坡最滑。NNAPI 和 CoreML 就是这样的向导:前者熟悉安卓设备上的 NPU、DSP、GPU,后者熟悉苹果的神经网络引擎。

ONNX Runtime 用 EP(Execution Provider,执行提供商)抽象层管理这些向导。推理时,模型被拆成一个个算子:支持硬件加速的算子交给 EP,不支持的算子自动回退 CPU。这个“会就带路、不会就自己走”的机制,保证了任何模型在任何设备上都能正确运行。

硬件加速到底快多少,可以这样衡量:

向导并非万能:在小模型上,向导的“问路开销”可能超过带路收益。所以哪些算子交给向导,必须用基准测试数据来拍板,而不是凭感觉。

Speedup=TCPUTEP\displaystyle \text{Speedup} = \frac{T_{\text{CPU}}}{T_{\text{EP}}}
加速倍数等于纯 CPU 推理耗时除以硬件加速 EP 的推理耗时。
  1. T_CPU(CPU 耗时)同一个算子或整个模型在 CPU 上推理所用的毫秒数。
    TCPUT_{\text{CPU}}
  2. T_EP(加速耗时)把计算交给 NNAPI 或 CoreML 后所用的毫秒数。
    TEPT_{\text{EP}}
  3. 比值(Speedup)两者相除,结果大于 1 说明加速有效,越大越好。
    TCPUTEP\frac{T_{\text{CPU}}}{T_{\text{EP}}}

模型量化部署

羽绒服蓬松时占半个箱子,塞进真空压缩袋一抽气,就变成薄薄一片。量化就是模型的“真空压缩袋”。FP32 用 32 位存一个权重,INT8 只用 8 位,体积直接除以 4,带宽压力也跟着下降。

动态量化只压缩权重、推理时临时还原,实现简单,适合快速上线;静态量化还会统计激活值的范围,压缩更彻底,但需要一份校准集来“量尺寸”。无论哪种,部署前都要用验证集做精度回归,确认模型没有“掉点”。

量化的数学本质是把连续浮点值映射到有限整数刻度:

真空压缩省空间,但如果被子原本就不蓬松(权重分布异常),压缩后可能失真。量化的精度损失必须用真实任务验证,不能只看体积数字。

q=round(r−rmin⁡rmax⁡−rmin⁡×255)\displaystyle q = \mathrm{round}\left( \frac{r - r_{\min}}{r_{\max} - r_{\min}} \times 255 \right)
把一个 FP32 权重值 r,按它所在层的取值范围,映射到 0 到 255 的整数上。
  1. r(原始权重)模型里一个 FP32 浮点权重,比如 0.7321。
    rr
  2. r_max - r_min(取值范围)该层所有权重的最小值与最大值之差,决定压缩的“标尺”。
    rmax⁡−rmin⁡r_{\max} - r_{\min}
  3. 归一化(分子除以范围)把任意区间里的值映射到 0 到 1 之间。
    r−rmin⁡rmax⁡−rmin⁡\frac{r - r_{\min}}{r_{\max} - r_{\min}}
  4. 乘 255 并取整把 0 到 1 的小数放大到 0 到 255 的整数刻度,得到 INT8 存储值。
    round(⋯×255)\mathrm{round}\left( \dots \times 255 \right)

部署工具链

完整打包流程像一条流水线:列清单、装箱、称重、试走计时。每一步都有对应的工具和产出物,缺一不可。

第一步,把 PyTorch、TensorFlow 模型导出为 ONNX 格式;第二步,用裁剪工具生成精简版引擎,并链接上 .ort 模型文件;第三步,在真实设备上跑基准测试,记录延迟、内存峰值、功耗;第四步,根据数据迭代调优——更换 EP、调整线程数、决定是否量化。整个流程的核心是“先测后调”,不能靠猜。

端侧性能最常用的指标是每秒帧数:

测出来的数据才是打包的“体检报告”。没有实测,裁剪和量化都只是纸上谈兵。

FPS=1000tinfer\displaystyle \text{FPS} = \frac{1000}{t_{\text{infer}}}
每秒能处理多少帧,取决于单次推理的毫秒耗时。
  1. t_infer(单帧耗时)模型处理一帧输入(如一张图片)所用的毫秒数。
    tinfert_{\text{infer}}
  2. 1000(毫秒换算)1 秒等于 1000 毫秒,是分子。
    10001000
  3. 除法(帧率)用 1000 除以单帧耗时,得到 1 秒内能跑多少帧。
    1000tinfer\frac{1000}{t_{\text{infer}}}

端侧应用场景

城市轻装出行和雪山重装攀登,背的包完全不同。不同设备、不同场景,对“轻量”的定义也完全不同。

手机美颜 App 追求又小又快,走“裁剪包 + CoreML/NNAPI + INT8 量化”路线;智能门锁内存极小,走“纯 CPU + 极简算子”路线,包体控制在 3MB 左右;摄像头端侧检测则倾向“裁剪 + 动态量化”,在体积和精度之间取平衡。设备越受限,打包手艺越重要。

如何比较不同方案的性价比?可以用一个综合效率公式:

没有万能的背包,只有合适的打包方案。ONNX Runtime Mobile 的价值,就是给你一套标准化的打包手艺,让你面对任何“小背包”都能从容应对。

E=1S×L\displaystyle E = \frac{1}{S \times L}
综合效率等于包体大小与推理延迟乘积的倒数,用来衡量端侧方案的“性价比”。
  1. S(包体大小)引擎加模型在设备上占用的存储空间,单位 MB。
    SS
  2. L(推理延迟)单次推理的耗时,单位毫秒。
    LL
  3. 乘积(综合代价)S 与 L 相乘,体积越大、延迟越长,代价越高。
    S×LS \times L
  4. 倒数(效率)取倒数后,代价越小效率越高,方便横向比较不同方案。
    1S×L\frac{1}{S \times L}

AI 应用场景

手机端离线美颜相机

阶段:模型部署与推理优化

解决的问题:传统做法把完整 ONNX Runtime 拷进 App,包体增加 30MB 以上,用户下载意愿下降;同时 GPU 和神经网络引擎完全闲置,CPU 推理又慢又费电。使用 ONNX Runtime Mobile 后,按需裁剪算子、INT8 量化权重,再接入 CoreML/NNAPI 加速,包体和延迟双双下降。

具体案例:某美颜 App 在 iPhone 上部署人像分割模型,先用 PyTorch 导出 ONNX,再裁剪掉模型中未用到的算子并做 INT8 量化,最后绑定 CoreML EP。包体从 35MB 降到约 5MB,单帧分割从 120ms 降到 25ms,用户好评率明显上升。

智能门锁人脸识别

阶段:端侧推理与资源优化

解决的问题:门锁主控芯片内存不足 100MB,没有独立 GPU,完整推理框架根本装不下。通过 ONNX Runtime Mobile 的算子裁剪机制,只保留 Conv、Relu、Gemm 等少量内核,生成约 3MB 的静态库,让离线人脸识别成为可能。

具体案例:某厂商在低功耗 MCU 上部署人脸特征提取模型,裁剪后引擎包体 3.2MB,单次识别耗时 180ms,整机功耗控制在 1W 以内。断网也能工作,隐私数据不出设备。

智能摄像头周界检测

阶段:模型量化与性能评测

解决的问题:摄像头 SoC 集成了 GPU 但显存很小,FP32 模型推理帧率只有个位数,误报漏报率高。采用“算子裁剪 + 动态量化 + NNAPI 加速”组合方案后,在包体几乎不增加的条件下,帧率大幅提升。

具体案例:某安防厂商在智能摄像头上部署行人检测模型,量化为 INT8 后配合 NNAPI 调用 GPU,FPS 从 8 提升到 25,检测距离和准确率满足商用标准,单设备硬件成本未增加。

Python 演示

python48 行
operator_code_mb = {    "Conv": 4.2, "Gemm": 3.1, "Relu": 0.5, "Softmax": 0.4,    "Add": 0.8, "BatchNorm": 1.2, "Reshape": 0.3, "MatMul": 2.5,    "Split": 0.5, "Gather": 0.9, "Cast": 0.6, "LSTM": 8.5,} RUNTIME_BASE_MB = 3.0FULL_FRAMEWORK_MB = 30.0  def trace_needed_ops(layer_list):    """遍历模型全部算子, 去重得到必带清单"""    return sorted(set(layer_list))  def calc_package_mb(needed_ops):    """包体 = 基础运行环境 + 清单内算子代码体积"""    code_mb = sum(operator_code_mb[op] for op in needed_ops)    return RUNTIME_BASE_MB + code_mb  def calc_model_mb(param_count, bits):    """权重体积 = 参数量 x 位宽 / 8, 换算成 MB"""    return param_count * bits / 8 / 1024 / 1024  def quantize_model_mb(fp32_mb, bits):    """把 FP32 权重体积按位宽等比缩放"""    return fp32_mb * bits / 32  def main():    model_ops = ["Conv", "Relu", "Conv", "Relu", "Conv", "Relu", "Gemm", "Softmax"]    needed_ops = trace_needed_ops(model_ops)    trimmed_pkg_mb = calc_package_mb(needed_ops)     weights_fp32_mb = calc_model_mb(12_000_000, 32)    weights_int8_mb = quantize_model_mb(weights_fp32_mb, 8)     print("模型算子清单: %s" % (needed_ops,))    print("完整框架包体: %.1f MB" % FULL_FRAMEWORK_MB)    print("裁剪后包体:   %.1f MB" % trimmed_pkg_mb)    print("FP32 权重:    %.2f MB -> INT8: %.2f MB" % (weights_fp32_mb, weights_int8_mb))    print("端侧总占用:   %.1f MB" % (trimmed_pkg_mb + weights_int8_mb))  if __name__ == "__main__":    main()
目的:用一组简化数据演示“算子裁剪 + 权重量化”如何共同压缩端侧包体与内存占用。
  1. def trace_needed_ops(layer_list): return sorted(set(layer_list))把计算图里出现的算子类型去重排序,生成“必带装备清单”
  2. code_mb = sum(operator_code_mb[op] for op in needed_ops)只累加清单内算子的代码体积,没被用到的算子一律不算钱
  3. return RUNTIME_BASE_MB + code_mb包体 = 基础运行环境(背包骨架)+ 清单算子(实际装备)
  4. def calc_model_mb(param_count, bits):权重体积由参数量和位宽共同决定,对应公式 M = N×b/8
  5. return param_count * bits / 8 / 1024 / 1024比特先除以 8 转字节,再除两次 1024 变成 MB
  6. weights_int8_mb = quantize_model_mb(weights_fp32_mb, 8)位宽从 32 降到 8,相当于把羽绒服抽成真空
  7. print("端侧总占用: %.1f MB" % (trimmed_pkg_mb + weights_int8_mb))引擎包体 + 权重体积加起来,才是真正落在设备上的总负担

常见误区

误区移动端部署不就是在项目里链接 ONNX Runtime 的库吗?反正都是 C++ 写的,直接把完整 .so 拷进去最省事、最稳妥。

正解桌面完整版包含上千个算子内核和大量平台依赖,体积 30MB 起,对手机和 IoT 设备是沉重负担。ONNX Runtime Mobile 的意义恰恰在于“不要全拷”——通过算子裁剪只保留用得上的内核,体积可以降到三分之一甚至更小,同时依赖也大幅精简。

为何常见:很多人把框架理解成一个不可拆分的整体,忽略了它本质上是模块化拼装的产品,骨架固定、算子口袋可拆卸。

误区把算子裁掉,模型计算不就变了吗?精度肯定会下降吧,所以裁剪要谨慎再谨慎。

正解裁剪只影响“引擎能执行哪些算子”,不改变被保留算子的数值实现。同一个 Conv 算子在裁剪前后计算结果逐位一致。真正可能影响精度的是量化,那是另一回事,两者不能混为一谈。

为何常见:把“删算子”和“删网络层”混为一谈——前者删的是执行代码,后者删的是模型结构,完全不同的两件事。

误区INT8 模型内存占用小、带宽压力小,推理时间理应全面下降,量化就是百利而无一害。

正解对大多数算子和设备,量化确实更快;但某些设备缺少 INT8 优化内核时可能反而变慢,或者首次加载需要额外转换开销。量化后必须在目标设备上实测延迟和精度,不能只看体积数字。

为何常见:把“内存占用”和“计算速度”直接划等号,忽略了硬件对不同数据类型的支持度差异,也忽略了驱动与转换开销。

误区只要把 EP 切到 NNAPI 或 CoreML,整个模型就跑在硬件加速器上,肯定比 CPU 快好几倍。

正解EP 只接管它支持的算子,不支持的算子会整体或部分回退 CPU;在小模型、小算子上,驱动调用和内存拷贝的开销可能盖过加速收益。所以要把模型按算子拆开分析,用基准测试决定每个算子走哪个 EP。

为何常见:把“支持硬件加速”理解成“所有计算都加速”,忽略了算子分发、回退机制和调用开销这些工程细节。

面试题

Q1. ONNX Runtime Mobile 的核心定位是什么?

单选题 · easy

  • A.在服务器上训练大规模模型
  • B.为端侧设备提供轻量推理← 正确答案
  • C.替代深度学习训练框架
  • D.仅用于苹果设备的推理

答案:B。ONNX Runtime Mobile 是完整版在移动端和边缘设备上的轻量化推理引擎,核心目标是让模型“装得下、跑得快”。A 是训练场景,C 方向错误,D 范围过窄,它同时支持安卓和苹果生态。

Q2. 算子裁剪相当于整理背包时的什么操作?

单选题 · easy

  • A.把背包换成更大的型号
  • B.只带行程用到的装备← 正确答案
  • C.把所有装备全部带上
  • D.在背包外面挂更多袋子

答案:B。算子裁剪的本质是“按需打包”:完整框架把所有算子内核都装进去,Mobile 版只保留模型真正用到的算子,就像只带行程必需的装备。A、C 增加负重,D 只扩展外挂,都没有从本质上精简。

Q3. 下列属于 ONNX Runtime Mobile 硬件加速 EP 的是?

多选题 · easy

  • A.NNAPI 安卓加速接口← 正确答案
  • B.CoreML 苹果加速接口← 正确答案
  • C.CUDA 显卡加速接口
  • D.TensorRT 加速接口

答案:AB。NNAPI 是安卓系统提供的神经网络加速接口,CoreML 是苹果系统的加速接口,都是典型移动端 EP。CUDA 和 TensorRT 面向服务器显卡,不属于移动端硬件加速范畴。

Q4. FP32 权重量化为 INT8 后,理论体积变为原来的?

单选题 · mid

  • A.约为原来的二分之一
  • B.约为原来的四分之一← 正确答案
  • C.约为原来的八分之一
  • D.约为原来的十六分之一

答案:B。体积与位宽成正比。FP32 每个权重占 32 位,INT8 只占 8 位,32 除以 8 等于 4,所以理论体积变为原来的四分之一。这是量化作为“真空压缩袋”最直观的收益。

Q5. 为什么算子裁剪通常不会降低模型精度?

单选题 · mid

  • A.因为模型参数会自动增加
  • B.因为数值计算完全不变← 正确答案
  • C.因为显卡性能更加强劲
  • D.因为裁剪后重新训练过

答案:B。裁剪删除的是“执行算子代码”,不是模型的数值结构。被保留算子的计算方式不变,输出与裁剪前完全一致。精度变化主要来自量化或模型结构改动,而不是算子裁剪。

Q6. 关于包体和性能的权衡,下列理解正确的是?

多选题 · mid

  • A.包体越小下载越方便← 正确答案
  • B.过度裁剪可能导致缺算子← 正确答案
  • C.包体越大推理速度越快
  • D.量化可以进一步缩小体积← 正确答案

答案:ABD。包体小便于下载安装;过度裁剪可能把模型要用的算子裁掉导致部署失败;量化通过降低位宽进一步缩小体积。包体大小与推理速度没有正相关关系,C 是常见错觉。

Q7. 关于硬件加速 EP,下列说法正确的是?

单选题 · mid

  • A.它能保证任何模型都更快
  • B.它只对支持的算子生效← 正确答案
  • C.它会完全取代 CPU 内核
  • D.它无需任何模型转换支持

答案:B。EP 是“本地向导”,只负责自己熟悉的路段——支持的算子。不支持的算子要么整体回退 CPU,要么部分回退,正确性永远优先。是否加速必须实测,不能默认全能。

Q8. 裁剪后的引擎包体应该等于?

单选题 · hard

  • A.全部已实现算子的体积
  • B.基础环境加必需算子体积← 正确答案
  • C.模型权重加中间张量体积
  • D.依赖库和权重文件的体积

答案:B。裁剪后的包体 = 基础运行环境(会话、调度、内存池)+ 被选中算子的代码体积。A 漏掉基础环境;C、D 把权重和依赖库混入,但权重属于模型文件,不算引擎包体。

Q9. 部署 INT8 量化模型的正确流程包括?

多选题 · hard

  • A.用校准集统计参数分布← 正确答案
  • B.量化后做精度回归验证← 正确答案
  • C.所有算子都无损支持量化
  • D.在目标设备实测推理耗时← 正确答案

答案:ABD。静态量化需要校准集统计权重和激活的数值范围;量化后必须做精度回归防止掉点;还要在目标设备实测延迟,因为不同硬件对 INT8 的支持差异很大。并非所有算子都无损支持量化,C 过于绝对。

Q10. 某模型仅用 Conv、Gemm、Relu 三种算子,其代码体积分别为 4.2、3.1、0.5MB,基础运行环境 3MB,完整框架 30MB。裁剪后包体约为?

单选题 · extreme

  • A.约 10.8MB← 正确答案
  • B.约 8.0MB
  • C.约 12.5MB
  • D.约 7.7MB

答案:A。裁剪后包体 = 基础运行环境 3MB + Conv 4.2MB + Gemm 3.1MB + Relu 0.5MB = 10.8MB。B、D 漏算或算错组成项,C 把完整框架的冗余也算进来了,不符合公式 S = S_base + Σs_i。