想象你走进一家五星级酒店,要办一场三百人的晚宴。你不需要知道厨房的燃气灶是哪个品牌、电工用的电线是哪个国家的标准——你只需要在前台说清需求,前台自会通过内部系统把“煎牛排”派给厨房、把“调灯光”派给电工。Android 的 NNAPI(Neural Networks API,神经网络 API)就是手机里这家酒店的前台。 今天的 Android 手机,芯片五花八门:有灵活的 CPU、并行的 GPU、专为 AI 设计的 NPU、低功耗的 DSP。如果每个 App 都要分别适配每一种芯片,开发者的工作量将是一场噩梦。NNAPI 的出现,让开发者只需对着统一接口“下单”,底层究竟由哪颗芯片执行、怎么执行,全由前台和各部门自行协调。 本文就用这家“酒店前台”的视角,带你读懂 NNAPI 的硬件抽象层原理、厂商驱动集成、算子加速分工、量化支持和性能调优,以及它如何在端侧大模型部署中扮演统一加速的关键角色。

岗位关联

掌握 NNAPI 抽象层原理,你就能在碎片化的 Android 芯片生态中“一次适配、处处加速”,成为端侧 AI 部署中不可替代的调优专家。

目录
  1. 可视化演示
  2. NNAPI初识
  3. 抽象层原理
  4. 驱动集成
  5. 算子加速
  6. 量化支持
  7. 性能调优
  8. 大模型落地
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示NNAPI作为硬件抽象层的架构原理:应用层到硬件的分层调用、算子编译加速流程、INT8量化精度管理、跨芯片设备性能调优,交互切换四种模式深入理解端侧加速。

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

HAL架构:NNAPI分层抽象原理 应用通过ML框架调用NNAPI,NNAPI作为HAL将请求路由到厂商驱动,最终在NPU/GPU/DSP硬件上执行 App → Framework → NNAPI HAL → Driver → NPU 统一抽象层让框架无需关心底层硬件差异,实现跨芯片兼容。

NNAPI初识

酒店的客人,大多不关心后厨有几位厨师、用的是燃气还是电磁炉。他们只认一个入口——前台。Android 诞生之初,AI 开发者面对的却是另一番景象:同样一个“识别猫”的模型,在高通芯片上要写一种代码,在联发科芯片上要换一种写法,在华为 NPU 上又要重新适配。这就是硬件碎片化——每家芯片都有自己的“方言”,开发者被迫成为“八国翻译”。

NNAPI 正是为了终结这种混乱而生的。它从 Android 8.1(API 27)开始随系统提供,位于应用与芯片驱动之间,扮演“总前台”的角色。开发者只需通过 NDK 提供的 ANeuralNetworks 系列 C 接口描述模型、提交任务,至于底层是 CPU、GPU 还是 NPU 在执行,完全不用关心。像 TensorFlow Lite、PyTorch Mobile 这样的推理框架,也通过 delegate(委托)机制把算子转交给 NNAPI,进一步降低了接入门槛。

一次完整的 NNAPI 推理,前台内部要走四个动作:构建模型(把算子图登记成菜单)、编译(把菜单交给合适的部门形成执行方案)、执行(各部门按方案出菜)、等待结果(收拾台面)。这四步分别对应创建 Model、Compilation、Execution 三个核心对象的过程。理解了这条主链路,后面谈抽象层、驱动、调优就都有了坐标系。

在前台出现之前,客人得自己跑到后厨、电工房、洗衣房分别打招呼;前台出现之后,一切只需一个入口。NNAPI 存在的意义,就是把“找谁干活”这件事从开发者手里收走,变成系统内部的日常。

S=TCPUTNPU\displaystyle S = \frac{T_{\text{CPU}}}{T_{\text{NPU}}}
加速比公式:NPU 相比 CPU 快多少倍,是衡量硬件加速价值的第一个指标。
  1. S加速比:衡量使用 NPU 相比纯 CPU 推理快了多少倍,大于 1 表示确实加速了。
    S\displaystyle S
  2. T_CPUCPU 基线耗时:整个模型完全在 CPU 上执行所需的时间,是性能对比的基准。
    TCPU\displaystyle T_{\text{CPU}}
  3. T_NPUNPU 执行耗时:同一模型经 NNAPI 派发到 NPU 后完成推理的时间,通常远小于前者。
    TNPU\displaystyle T_{\text{NPU}}
  4. 比值关系两者相除得到加速倍数,实际中还需扣除切分、拷贝等调度开销。
    TCPUTNPU\displaystyle \frac{T_{\text{CPU}}}{T_{\text{NPU}}}

抽象层原理

前台要对各部门派活,前提是有一套统一的“内部工单”——不管你是西餐部还是中餐部,工单上“桌号、菜品、忌口”三栏必须填齐。这个工单格式,就是硬件抽象层(HAL,Hardware Abstraction Layer)的精神。

NNAPI 下层与厂商驱动之间,隔着一层 HAL 接口。它规定了驱动必须实现的最小功能集:设备发现、模型编译、执行、能力上报。任何硬件,只要把这套接口实现完整,就能被 NNAPI 调度。HAL 的好处是双向的——对系统,它不用知道某芯片内部如何取指令;对厂商,它只需按约定实现接口,不必为每个 App 定制,更不必泄露芯片机密。

技术细节上有三个关键点。设备发现:系统服务启动时枚举所有注册的 IDevice(HIDL/AIDL 版本的驱动接口),应用可通过 ANeuralNetworks_getDeviceCount 拿到设备列表和名称,就像前台先盘点今天哪些部门在岗。能力声明:每个设备上报自己支持的算子集合和性能参数,NNAPI 据此制定编译策略。共享内存:输入输出通过 AHardwareBuffer 等内存域在 App 与驱动之间零拷贝传递——就像工单直接钉在厨房案板上,不必再抄一遍。

前台最重要的资产不是菜,而是那张所有部门都认的工单格式。抽象层真正的价值,正在于把“硬件差异”压缩进一张小小的能力名单里,让上层世界保持简单。

Fd={f1, f2, …, fn}\displaystyle F_{d} = \{ f_{1},\ f_{2},\ \dots,\ f_{n} \}
设备能力集合公式:每个硬件能干什么,用一张“算子名单”说清楚,NNAPI 才能准确派单。
  1. F_d设备能力集合:某个硬件驱动向 NNAPI 上报的“擅长算子名单”,决定哪些算子能交给它。
    Fd\displaystyle F_{d}
  2. f_i单个算子能力:集合中的每个元素代表该设备支持的一种算子,如 Conv、ReLU。
    fi\displaystyle f_{i}
  3. 集合列举大括号表示把多个能力放在一起,n 表示该设备支持的算子总数。
    {f1, f2, …, fn}\displaystyle \{ f_{1},\ f_{2},\ \dots,\ f_{n} \}

驱动集成

部门主管们各有性格:西餐主厨脾气大但手艺精,工程队只接大活儿。前台不强求他们改脾气,只要求他们学会看工单。厂商驱动就是这么一位“翻译官”,把 NNAPI 的标准请求翻译成自家芯片的指令。

在 Android 系统中,高通负责骁龙芯片的 Hexagon DSP/NPU 驱动,联发科负责天玑的 APU 驱动,ARM 提供 Mali GPU 驱动,Google 自己还维护了一份 CPU 参考实现。每份驱动都实现了 android.hardware.neuralnetworks 接口(早期用 HIDL,新版本迁移到 AIDL),并且运行在独立的 vendor 进程中——即便驱动崩溃,也不会拖垮整个系统,这是进程隔离带来的安全边界。

驱动需要实现的核心方法不多:prepareModel 对应“把菜单预演一遍,形成内部执行计划”;execute 对应“正式出菜”;异步回调则对应“边做边汇报进度”。驱动还会上报性能等级(performanceInfo),NNAPI 用这些数字计算哪些算子交给谁最划算。驱动质量直接影响真实性能——同一个算子,优化到位的驱动可能比粗糙实现快一个数量级,这也是同一颗芯片在不同手机上跑分差异巨大的原因之一。

前台不必懂每个部门内部的火候与刀工,它只需确认:这位主管看得懂工单。这就是厂商驱动的全部修养——站在系统与芯片之间,把两边的话都说得明明白白。

Peff=ηdriver×Pchip\displaystyle P_{\text{eff}} = \eta_{\text{driver}} \times P_{\text{chip}}
驱动效率公式:芯片理论算力再高,也要乘上驱动效率系数,才是你能真正用到的性能。
  1. P_eff实际有效性能:开发者最终在真机上感受到的推理吞吐,单位如 FPS 或毫秒/次。
    Peff\displaystyle P_{\text{eff}}
  2. η_driver驱动效率系数:取值在 0 到 1 之间,反映驱动把硬件算力转化为真实速度的百分比。
    ηdriver\displaystyle \eta_{\text{driver}}
  3. P_chip芯片理论峰值:芯片规格书上标注的最大算力,如 TOPS 指标,现实中几乎无法打满。
    Pchip\displaystyle P_{\text{chip}}

算子加速

一场三百人的宴会只靠一个部门做不完。前台会把菜单拆开:凉菜给冷菜间、热菜给热灶、甜点给烘焙房。NNAPI 干的正是拆菜单的活——模型切分(partitioning)。

神经网络模型本质是一张算子图(conv、relu、fc、softmax……)。NNAPI 编译器会检查每个算子是否在某硬件的能力集合里,把“同一硬件能连续吃下的算子”打包成一个子图(partition),分配给对应驱动执行。切分的结果往往不是单硬件独占,而是 CPU、GPU、NPU 各领一段,像流水线一样接力完成推理。

切分时有三个原则。一是尽量把相邻算子分给同一硬件,减少交接成本——换部门就要递盘子,递一次就有一次开销。二是每个算子在目标硬件上必须真实可用,否则会回退到 CPU 参考实现,速度反而更慢。三是融合优化:像 Conv+ReLU 这类连续小算子,很多驱动支持融合成单个算子,一次内存读取、一次计算,省掉中间结果的写回与读取。融合做得好的模型,往往比盲目“堆更多硬件”更有效。

聪明的前台从不让一位大厨从头到尾做整桌菜,而是让最拿手的人各领一盘。算子加速的本质,就是“合适的人干合适的活”。

Tpart=Ncvc+Ngvg\displaystyle T_{\text{part}} = \frac{N_{c}}{v_{c}} + \frac{N_{g}}{v_{g}}
切分耗时公式:总耗时等于各硬件分到的任务量除以各自速度之和,派单要算清这笔账。
  1. T_part切分后总耗时:模型被切成多个子图、分配给不同硬件后推理一次的总时间。
    Tpart\displaystyle T_{\text{part}}
  2. N_c 与 v_cCPU 段:CPU 分到的算子个数除以它的处理速度,得到这一段的耗时。
    Ncvc\displaystyle \frac{N_{c}}{v_{c}}
  3. N_g 与 v_gGPU 段:同理计算 GPU 段的耗时,两段串行或流水衔接。
    Ngvg\displaystyle \frac{N_{g}}{v_{g}}

量化支持

“七分熟和牛、黑椒汁、配芦笋”——报菜名给后厨既费时又容易出错。前台干脆把常用菜品编号成套餐:7 号套餐,一秒钟说清楚。量化,就是给神经网络模型编“套餐号”。

训练好的模型权重通常是 FP32(32 位浮点),而在手机芯片上,用 8 位整数(INT8)表示不仅能省 75% 的带宽和存储,还能在支持 INT8 的 NPU/DSP 上获得数倍加速。NNAPI 从早期版本就支持 8 位量化张量的传递,驱动负责把整数还原成近似浮点值参与计算。FP16 则是另一种折中:精度损失极小、模型体积减半,适合 GPU 这类原生支持半精度的硬件。

量化核心是缩放因子 s 与零点 z:把浮点范围线性映射到 0~255 的整数区间。NNAPI 支持 per-tensor(整个张量共用一个缩放参数)和 per-channel(每个输出通道各用一组参数,精度更好)两种方式。开发者通常先用训练后量化(PTQ)快速压测,模型偏差偏大时再用量化感知训练(QAT)恢复精度——前者像直接给老菜谱编号,后者像让厨师按编号重新试菜。

菜单编号这件事看似不起眼,但正是它,让招牌菜从“主厨限定”变成了“流水线量产”。量化让大模型从云端落地到手机,靠的就是这组简单的整数映射。

q=round(r−zs)\displaystyle q = \text{round}\left( \frac{r - z}{s} \right)
量化公式:把浮点数映射成整数,关键在于算对缩放因子和零点。
  1. q量化后的整数:FP32 浮点值经过映射后得到的 INT8 表示,范围通常在 0~255。
    q\displaystyle q
  2. r原始浮点值:量化前的真实数值,来自模型权重或中间激活。
    r\displaystyle r
  3. s 与 z缩放与零点:s 由浮点范围除以 255 得到,z 是浮点最小值对应的整数偏移。
    r−zs\displaystyle \frac{r - z}{s}
  4. round四舍五入取整:映射结果可能带小数,取整后才能存进整数张量。
    round\displaystyle \text{round}

性能调优

老练的酒店在大堂设了“预开台”:客人落座前,餐具、茶水、冷盘全部就位;重复来的熟客,口味偏好直接存档。性能调优,就是把这套旺季管理经验搬进推理链路。

第一次调用 NNAPI 执行某个模型时,驱动要做编译,往往很慢;后续执行会快很多。所以线上推理前要做“预热”(warmup)——先用一次推理把驱动唤醒、缓存建好,计时只统计稳定后的执行。此外,模型权重和输入输出尽量都放进 NNAPI 的共享内存对象,避免每次执行在 Java 层和 Native 层之间反复拷贝,这好比让餐具直接留在备餐间,不用每次从仓库搬。

还有三个常用手段。一是编译缓存(Compilation caching):把 prepareModel 生成的编译产物序列化落盘,下次启动直接加载,省掉几十到几百毫秒的编译时间,相当于把熟客口味偏好存档。二是异步执行:主线程不阻塞在等待上,CPU 在驱动计算的同时继续调度其他工作。三是批量输入:一次喂多条输入,摊薄固定开销。调优时用 systrace 抓调度时间线,黄色等待块往往比红色计算块更值得优化——因为等待意味着某个硬件在空转。

旺季里决定口碑的往往不是厨师颠勺的速度,而是前台把等待时间藏起来的本事。性能调优到极致,用户感知到的不是“某次很快”,而是“每次都很快”。

S=TbaseTopt+Toverhead\displaystyle S = \frac{T_{\text{base}}}{T_{\text{opt}} + T_{\text{overhead}}}
调优收益公式:优化的目标是让计算更快,同时把调度开销压到最低,收益比才会高。
  1. S调优收益比:优化前后耗时的比值,表示性能提升的倍数。
    S\displaystyle S
  2. T_base基线耗时:未做任何调优时一次推理的总时间,是优化的起点。
    Tbase\displaystyle T_{\text{base}}
  3. T_opt优化后计算耗时:经过切分、融合、量化等手段后,纯计算部分的时间。
    Topt\displaystyle T_{\text{opt}}
  4. T_overhead额外开销:预热、拷贝、调度等非计算时间,优化要让它与 T_opt 之和尽量小。
    Topt+Toverhead\displaystyle T_{\text{opt}} + T_{\text{overhead}}

大模型落地

今天最风光的宴会,是端侧大模型——几亿到几十亿参数的 LLM 要在手机上跑起来。这好比一场千人婚宴,任何单一部门都扛不下来,必须全店总动员:冷菜、热灶、烘焙、酒水、传菜,所有部门并行接单。

端侧大模型流行 4bit 量化,把权重压到极低位数。内存公式 M = n×b/8 给出了底线:一个 7B 模型,4bit 量化后约 3.5GB,手机勉强装得下。但推理时还有 KV Cache、中间激活值,内存压力远超权重本身,所以端侧适配不止是量化,还要做算子精简、层剪枝和内存换入换出。

跨芯片协同是 NNAPI 大显身手的舞台:Transformer 解码时,QKV 投影这类 GEMM 算子是计算大头,适合 NPU/GPU;LayerNorm、Softmax 这类小算子调度成本高,CPU 反而游刃有余。NNAPI 根据能力表自动切分,让三种芯片流水线并行。新兴 NPU 开始原生支持 GQA、RoPE 等 LLM 算子,进一步把更多子图从 CPU 手里抢过来。对开发者来说,写好模型格式转换与量化管线,剩下交给 NNAPI 这个“总调度”,就能实现一套代码跨芯片统一加速。

千人婚宴之所以能成,前台未必认识每位宾客,但它一定知道:哪个部门现在闲着,哪道菜需要排多久。这就是抽象层在端侧大模型时代不可替代的理由。

M=n×b8\displaystyle M = \frac{n \times b}{8}
权重内存公式:参数量 × 位宽,再除以 8 换算成字节,是端侧部署的第一道门槛。
  1. M权重内存占用:模型参数在内存里占用的字节数,决定手机装不装得下。
    M\displaystyle M
  2. n参数量:模型的参数个数,如 7B 表示 70 亿个参数。
    n\displaystyle n
  3. b位宽:每个参数用多少位存储,FP32 是 32,INT8 是 8,4bit 量化是 4。
    b\displaystyle b
  4. 除以 8 转字节8 位等于 1 字节,把比特数换算成字节数。
    n×b8\displaystyle \frac{n \times b}{8}

AI 应用场景

手机端侧大模型助手

阶段:端侧推理部署 / 性能优化

解决的问题:传统云端 LLM 有网络延迟、隐私泄露和服务成本问题;端侧部署则要面对内存紧张、芯片碎片化。NNAPI 把同一个 3B 模型自动切分到 NPU/GPU/CPU,让开发者无需为每颗芯片单独移植,就能在手机本地流畅对话。

具体案例:某翻译 App 的离线对话助手基于 3B 模型,4bit 量化后约 1.8GB。接入 NNAPI 后,Attention 的 QKV 投影交由 NPU 执行,LayerNorm 与 Softmax 留在 CPU,首字延迟从 1.2 秒降至 400 毫秒,且全程不联网,敏感句子不出手机。

安防摄像头目标检测

阶段:算子加速 / 功耗调优

解决的问题:摄像头要 7×24 小时实时检测,纯 CPU 跑 YOLO 功耗高、发热大,单路就占满算力。借助 NNAPI 把 Conv 骨干网络派发到 Hexagon DSP/NPU,CPU 只做后处理,兼顾帧率与功耗。

具体案例:某智能门铃产品在骁龙平台用 NNAPI 调度 YOLOv5s:Convolution 算子全部落在 DSP,检测帧率从 8 FPS 提升到 25 FPS,整机功耗下降约 55%,电池续航接近翻倍。

电商图像搜索特征提取

阶段:端到端部署

解决的问题:拍照搜商品需要把图片转成 embedding 向量,传统方案上传云端,单张成本高、响应慢。在手机上用 NNAPI 加速特征提取网络,可以做到本地秒级返回。

具体案例:潮流电商 App 在商品拍照搜索中,用 MobileNet 提取 512 维特征。打开 NNAPI delegate 后,特征提取从 CPU 的 45ms 降到 GPU 的 12ms,且可覆盖同年发布的十余款中端机型,无需逐个适配。

Python 演示

python59 行
"""模拟 NNAPI 抽象层:算子派发 + 量化加速效果"""from collections import defaultdict  class Hardware:    """一块真实存在的计算硬件,如 CPU / GPU / NPU"""     def __init__(self, name, speed, support):        self.name = name              # 硬件名        self.speed = speed            # 处理速度:算子数/毫秒        self.support = set(support)   # 支持的算子集合  class NNAPI:    """仿照 Android NNAPI 的调度中心"""     def __init__(self, devices):        self.devices = devices  # 设备列表,按优先级从高到低排列     def dispatch(self, graph):        """将算子图派发到各硬件,返回总耗时(毫秒)"""        plans = defaultdict(int)        for op in graph:            for dev in self.devices:                if op in dev.support:                    plans[dev.name] += 1                    break        total = 0.0        for dev in self.devices:            count = plans[dev.name]            cost = count / dev.speed            if count:                print(f"  {dev.name}: {count} 个算子 -> {cost:.2f} ms")            total += cost        return total     def quantize(self, graph, bits):        """模拟量化:算子数不变,计算速度按位宽比例提升"""        for dev in self.devices:            dev.speed *= 32 / bits        return self.dispatch(graph)  def main():    cpu = Hardware("CPU", 100, {"Conv", "ReLU", "FC", "Softmax"})    gpu = Hardware("GPU", 600, {"Conv", "ReLU", "FC"})    npu = Hardware("NPU", 3000, {"Conv", "ReLU"})    api = NNAPI([npu, gpu, cpu])     graph = ["Conv"] * 30 + ["ReLU"] * 20 + ["FC"] * 10 + ["Softmax"] * 2    print("FP32 推理:")    t1 = api.dispatch(graph)    print("INT8 量化后推理:")    t2 = api.quantize(graph, 8)    print(f"量化加速比: {t1 / t2:.1f}x")  if __name__ == "__main__":    main()
目的:用几十行代码模拟 NNAPI 的“算子派发 + 量化加速”过程,直观展示抽象层如何按硬件能力切分模型并量化提速。
  1. plans = defaultdict(int)用计数器记录各硬件分到的算子数,默认 0 免去判空。
  2. for dev in self.devices:按优先级从高到低依次询问,找到第一个支持该算子的硬件。
  3. if op in dev.support:检查算子是否在硬件的“能力名单”里,对应 NNAPI 的能力声明。
  4. cost = count / dev.speed单段耗时等于算子数除以处理速度,对应切分耗时公式。
  5. dev.speed *= 32 / bits量化把位宽从 32 降到 bits,硬件速度按比例提升,体现量化的收益。

常见误区

误区NNAPI 是谷歌写好的深度学习框架,把模型丢进去就能自动跑起来,甚至还能自动训练。

正解NNAPI 不是引擎也不是框架,它是一层“接口标准”(抽象层)。它自己不实现算子计算(除了 CPU 回退实现),真正干活的是各厂商驱动。就像酒店前台自己不炒菜,只负责下单。模型要先由 TFLite、PyTorch Mobile 等框架转换好,再通过 delegate 机制交给 NNAPI 调度。

为何常见:名字里带“Neural Networks API“,容易让人以为是完整框架;日常工具链的”一键接入”也掩盖了底层分工。

误区只要在代码里打开 NNAPI delegate,推理速度就一定能提升好几倍,所有算子都会被加速。

正解加速的前提是算子在目标硬件上受支持且驱动优化到位。若模型里有大量不支持的算子,相关子图会回退 CPU,甚至因为切分与拷贝开销变得更慢。加速比公式里的 T_CPU/T_NPU 只是理想值,实际要看算子支持率与驱动效率系数 η。

为何常见:厂商宣传片都在讲 NPU 算力翻倍,容易忽略“能不能接得住”这个前提。

误区模型从 FP32 换成 INT8,精度一定会崩,根本不能用。

正解有标定数据的训练后量化通常只掉 1~3 个百分点,量化感知训练可以控制在 0.5% 以内;配合 per-channel 量化损失更小。量化损失与数据分布有关,不是必然大幅下降——就像菜谱编号后味道只有细微差别,绝大多数客人尝不出来。

为何常见:直觉上“位宽少了 4 倍信息”自然担心损失;早期粗糙的量化工具确实损失大,给后人留下刻板印象。

误区NNAPI 做好了,高通、联发科、麒麟的芯片就都能自动加速,一个驱动搞定全部。

正解恰恰相反,NNAPI 只提供接口标准,每家厂商必须自己写驱动并实现能力声明。骁龙有 QNN、天玑有 NeuroPilot、Tensor 有 Edge TPU 驱动,各自支持的算子集合和性能差异很大。所以“一次适配”只在 API 层面成立,“处处加速”仍需针对芯片调优。

为何常见:抽象层给人的第一印象就是“屏蔽差异”,容易把接口统一误解为行为统一。

面试题

Q1. 关于 NNAPI 的定位,下列说法正确的是?

单选题 · easy

  • A.可训练的深度学习推理引擎
  • B.连接应用与硬件的调度接口← 正确答案
  • C.高通公司提供的闭源框架
  • D.TensorFlow 的 Android 版本

答案:B。NNAPI 是 Android 提供的调度接口层,它不亲自实现推理,而是把模型派发给厂商驱动执行。A 错在“引擎”,C 错在“高通提供”,D 把 NNAPI 与具体框架混为一谈。

Q2. NNAPI 是在哪一层解决硬件碎片化问题?

单选题 · easy

  • A.模型训练层
  • B.数据标注层
  • C.推理加速抽象层← 正确答案
  • D.应用界面层

答案:C。硬件碎片化发生在推理加速环节,NNAPI 通过统一接口屏蔽 CPU/GPU/NPU/DSP 的差异。训练、标注、界面都与芯片派单调度无关。

Q3. NNAPI 中“设备能力声明”的主要作用是?

单选题 · mid

  • A.向用户展示芯片性能得分
  • B.上报驱动支持的算子集合← 正确答案
  • C.自动升级硬件固件版本
  • D.统计模型训练的损失值

答案:B。能力声明由驱动在注册时上报,NNAPI 据此决定算子如何切分、派给谁。A 是跑分软件的事,C 是系统升级的事,D 是训练阶段的事。

Q4. 模型切分(Partitioning)的核心思路是?

单选题 · mid

  • A.按硬件支持切分调度算子← 正确答案
  • B.将模型压缩成更小的文件
  • C.用 CPU 替代所有其他硬件
  • D.将模型分成多个训练批次

答案:A。切分把算子图中能被同一硬件连续执行的算子打包成子图,分给对应驱动。B 是压缩,C 违背加速本意,D 是训练时的 batch 概念。

Q5. INT8 量化相比 FP32 的主要收益是?

单选题 · mid

  • A.推理精度显著提升
  • B.内存占用变为四分之一← 正确答案
  • C.模型体积完全不变
  • D.推理结果完全一致

答案:B。INT8 每个参数占 1 字节,FP32 占 4 字节,内存和带宽都降为四分之一。精度不是提升而是轻微下降,结果也不可能完全一致。

Q6. 厂商驱动通过什么机制向 NNAPI 注册能力?

单选题 · hard

  • A.直接修改 Android 系统源码
  • B.编写 HAL 驱动并声明能力表← 正确答案
  • C.在应用层提供 Java 回调
  • D.在模型文件中嵌入配置

答案:B。厂商实现 HAL 层的 IDevice 接口(HIDL/AIDL),通过能力表上报支持的算子和性能,系统服务加载后即可被 NNAPI 调度。改源码、Java 回调、模型内嵌配置都不是驱动接入方式。

Q7. 推理前调用“预热”(warmup)的主要目的是?

单选题 · mid

  • A.提前分配资源并加载权重← 正确答案
  • B.降低模型输出的随机性
  • C.提高训练数据的整体质量
  • D.减少编译时产生的重复代码

答案:A。首次执行时驱动要完成编译、缓存和内存分配,预热正是把这些一次性开销提前付掉,让正式推理的耗时稳定且可测。B、C、D 与预热目的无关。

Q8. 端侧大模型部署面临的主要挑战包括?

多选题 · mid

  • A.设备内存容量非常有限← 正确答案
  • B.功耗与散热约束突出← 正确答案
  • C.网络带宽完全不受限制
  • D.单芯片算力存在瓶颈← 正确答案

答案:ABD。端侧 LLM 首先受内存约束(权重 + KV Cache),其次受功耗散热约束,最后单颗芯片算力有限,必须跨芯片协同。网络带宽在端侧推理时反而不是瓶颈,因为数据不上云。

Q9. 下列哪些属于 NNAPI 加速的有效手段?

多选题 · hard

  • A.算子融合减少调度开销← 正确答案
  • B.使用异步执行提升并发← 正确答案
  • C.将模型反复写入应用包
  • D.量化降低权重内存带宽← 正确答案

答案:ABD。算子融合减少中间结果读写,异步执行不阻塞主线程,量化降低带宽和存储。把模型重复写进应用包只会增加包体体积,没有任何加速作用。

Q10. 关于量化公式 q = round((r - z) / s),正确的说法是?

多选题 · hard

  • A.r 代表原始的浮点数值← 正确答案
  • B.s 是范围相关的缩放因子← 正确答案
  • C.z 代表量化的零点偏移← 正确答案
  • D.q 精确等价于原始 r 值

答案:ABC。r 是原始浮点值,s 由浮点范围除以 255 得到,z 是零点偏移,三者共同完成映射。D 错误,量化必然有信息损失,q 只是 r 的近似表示。