简介:这份行业研究报告聚焦端侧AI在2024年的技术演进与产业落地,面向关注AI芯片、智能终端、混合AI及科技投资的从业者与研究者,帮助梳理“AI下凡”背后的软硬件基础、企业布局与商业化路径。资源包为1个PDF文件,大小约3.09MB,内容以浙商证券深度跟踪报告为主体,包含目录、图表与专题分析,便于按章节阅读和引用。报告围绕软硬融合、NPU与模型压缩、英伟达等龙头布局、云端推理成本、混合AI模式,以及手机、PC、汽车、XR和物联网等场景展开,并设相关标的及投资建议、风险提示章节。已有655人学习,适合需要快速建立端侧AI产业框架、补充研究素材或把握趋势判断的读者参考。
1. 端侧AI的临界点:为什么十亿参数模型能塞进一部手机
一份 2024 年的端侧AI行业跟踪报告里有个细节容易被跳过:某代安卓手机上,一个参数超过 10 亿的文生图模型在 15 秒内跑完了一次完整推理,全程没有联网。反直觉的地方不在于“手机能画图”,而在于 10 亿参数按 FP16 存就是 2GB 显存级别的开销,手机不但塞得下,还能在十几秒内算完——算力和带宽这两道墙,是被两套完全不同的手段同时拆掉的。搞懂这件事,就搞懂了端侧AI为什么从“演示”变成“产品”:它决定了延迟、隐私、成本这三条底线到底由谁买单。下面从算力账本、模型瘦身、NPU 微架构三层往下拆。
2. 算力账本:云端推理为什么算不过来
2.1 训练是一次性支出,推理是持续性支出
千亿、万亿参数的大语言模型需要超大规模 AI 服务器集群才能完成训练,这也是 2023 年以来 AI 芯片、通信网络和服务器整条链路被反复定价的原因。但把账算细一点,会发现一个结构性不对称:训练单个模型确实消耗巨大,可一个成熟模型一年可能只训几次;推理却是每一个用户、每一次请求都在真实发生。
日活从 100 万涨到 1000 万,训练成本几乎不变,推理成本线性翻十倍。更麻烦的是推理负载的形状——它不是均匀的,白天高峰和凌晨低谷可能差一个数量级。云侧设备极其昂贵,必须靠高利用率摊薄,而提高利用率最直接的手段是攒批(batching):把多个请求凑成一批送进 GPU,一次前向算完,吞吐上去,单请求成本下来。
攒批的代价是排队。批越大,单个请求在队列里等的时间越长,尾延迟(P99)越难看。高峰期的“卡”本质不是带宽不够,而是系统在吞吐和时延之间主动选择了吞吐。用户感受到的“转圈”,是排队策略的可预期结果。
# 云侧推理日成本的粗算骨架,价格参数按你所处环境的实际单价代入 def cloud_cost_per_day(dau, req_per_user, gpu_seconds_per_req, price_per_gpu_hour, util=0.5): total_req = dau * req_per_user # 日请求总量 gpu_seconds = total_req * gpu_seconds_per_req # util 是有效利用率:攒批能把它推高,但会因为排队牺牲尾延迟 gpu_hours = gpu_seconds / 3600 / util return gpu_hours * price_per_gpu_hour # 把 100 万 DAU 换成 1000 万 DAU,其余参数不动,成本正好乘 10 print(cloud_cost_per_day(1_000_000, 20, 0.35, 2.0)) print(cloud_cost_per_day(10_000_000, 20, 0.35, 2.0))gpu_seconds_per_req是单请求占用的 GPU 秒数,它随输出长度线性增长;util是最容易被低估的参数,工程上 0.3 到 0.5 是常态,堆到 0.7 以上往往意味着队列已经很长。这段骨架想说明的是:云端推理的成本不是常数,它随用户规模线性膨胀,而硬件采购必须按峰值来,于是大量容量在低谷期空转。
2.2 混合AI的分流账:为什么 49.88% 放端侧不掉准确率
一份端云协同推理的研究给出一组值得琢磨的数字:所有推理都在云侧做,准确率 79.31%;把 49.88% 的推理放到移动端执行、其余交给云端,仍然能拿到 79.31% 的云级准确率。将近一半的活搬走了,效果一点没掉,这不是巧合。
机制在于分流的判据。如果按比例随机分流,端侧小模型在难样本上判断错,准确率必然掉。真实可行的做法是按置信度路由:端侧先算一遍,输出分布的 top1 概率足够高、且与 top2 的差距足够大,就直接在本地给结果;否则把请求连同中间特征或原始输入转给云端。简单样本占大头,且端侧模型在简单样本上的判断和云端高度一致,所以整体准确率守住。
换个角度看,端侧在这里省下的不只是算力,更是峰值容量。云端按峰值扩容,端侧把曲线削平——削掉的那部分,恰恰是最贵的那部分。
注意:分流阈值不是拍脑袋定的,要在真实流量上做离线回放,统计“端侧高置信但判错”的比例。这个比例乘以端侧承接量,就是你为省钱付出的准确率代价。
2.3 四个优势的物理来源
隐私、低延时、可靠性、低成本这四条经常被当成营销词,但它们各有物理来源,拆开看都成立。
隐私的来源是数据不出设备。本地存储、本地计算、本地响应,数据没有经过网络传输这一环,也就没有传输环节的泄露面。对企业场景更关键:代码助手、文档摘要这类应用如果能在终端跑,保密内容根本不需要出内网。
低延时的来源不是“端侧芯片更快”,而是链路更短。云侧一次请求的时延由网络往返、排队、调度、计算四段组成,前两段抖动大且不可控;端侧时延基本只有计算一段,抖动小。高峰期云侧排队几百毫秒很常见,端侧还是那几十毫秒。
可靠性的来源同理,云端互联可能不稳定甚至断线,本地决策通路短,出错环节少。低成本的来源则是边际成本趋近于零——设备是一次性买断的,推理跑多少次都不额外付费,代价是硬件成本前置。
不同终端对这个账本的敏感度完全不同,这也解释了为什么“端侧AI”不是一个东西,而是一族东西:
| 终端品类 | 典型任务 | 算力需求 | 功耗取向 | 成本敏感度 |
|---|---|---|---|---|
| 智能驾驶 | 图像识别、多传感器融合、定位、路径规划 | 20–4000 TOPS | 中等,不极致追低功耗 | 低 |
| 智慧安防 | 图像与视频识别、检测 | 4–20 TOPS | 追求较低功耗 | 较高 |
| 消费电子 | 图像识别、拍照美化、语音助手 | 1–8 TOPS | 严格控功耗保续航 | 高 |
| 智能家居 | 图像识别、语义理解、语音交互 | <1 TOPS | 极低功耗 | 较高 |
跨度是四个数量级。给智能家居做优化的那套方法,直接搬到自动驾驶上会翻车,反过来也一样。整条算力谱系从不到 100 GOPS 的面部检测、语音触发,到 100 GOPS 至 1 TOPS 的面容识别与图像处理,再到 1 至 10 TOPS 的视觉检测与无人机,10 至 100 TOPS 的自动驾驶视觉与 AR/VR,最后到 100 至 1000+ TOPS 的目标探测、全景分割与传感器融合——每一档对应的芯片架构、内存带宽、散热方案都不同。
3. 模型瘦身:量化、剪枝、蒸馏如何把参数压下去
3.1 量化:从 4 字节到 1 字节,为什么精度只掉一点
FP32 权重占 4 字节,INT8 占 1 字节。体积压到四分之一,访存带宽压到四分之一,同样的乘加在整数单元上吞吐更高、能耗更低——这三件事同时发生,端侧才有得谈。真正让人意外的是精度:同一张图送进目标检测网络,FP32 和 INT8 的输出结果相差很小,框的位置几乎重合。
原因有三层。第一,推理只关心 argmax 的相对排序,权重上的小幅扰动经过 softmax 之后往往被概率差距吸收。第二,神经网络是过参数化的,冗余度本来就高,删掉一点信息不至于改变决策。第三,也是工程上最要紧的一层:量化粒度。
import numpy as np def quantize_symmetric(w, bits=8, per_channel=True): """对称量化:w 为 FP32 权重矩阵,返回 INT8 权重与 scale""" qmax = 2 ** (bits - 1) - 1 # INT8 时 qmax = 127,负数侧留 -127 避开溢出 if per_channel: # 每个输出通道独立算 scale,抑制离群通道 amax = np.abs(w).max(axis=1, keepdims=True) else: # 整层共享一个 scale,实现简单但误差大 amax = np.abs(w).max() scale = amax / qmax scale[scale == 0] = 1e-8 # 全零通道保护,避免除零 q = np.clip(np.round(w / scale), -qmax, qmax).astype(np.int8) return q, scale def dequantize(q, scale): return q.astype(np.float32) * scale w = np.random.randn(64, 128).astype(np.float32) q, s = quantize_symmetric(w) err = np.abs(dequantize(q, s) - w).mean() print(f"per-channel 平均量化误差: {err:.5f}") q2, s2 = quantize_symmetric(w, per_channel=False) print(f"per-tensor 平均量化误差: {np.abs(dequantize(q2, s2) - w).mean():.5f}")bits决定量化区间,per_channel决定 scale 的粒度,qmax是量化上限。关键差异在 scale 的粒度:一层权重里只要有一个通道的绝对值特别大,per-tensor 的 scale 就会被它拉大,其余通道全被压到很窄的整数区间里,误差集中爆发;per-channel 让每个输出通道在自己的动态范围内量化,离群通道不再拖累别人。
权重量化相对好办,激活量化才是真正的坑。激活值的动态范围随输入变化,而且存在少数数值极大的离群通道。常见的实现思路是对激活做 per-token 动态量化,每次推理现算一次 scale;更稳一点的做法是把离群通道单独拎出来用高精度算,其余通道走 INT8,代价是多一次分支和数据拼接。
提示:不要用权重上的量化误差评估量化方案好坏。权重误差小不代表任务指标不降,最终要看检测召回、分类准确率、生成质量这些端到端指标。
3.2 剪枝与蒸馏:删结构还是迁能力
剪枝的思路是把不重要的连接去掉。删单个权重叫非结构化剪枝,稀疏率可以做到很高,但落到硬件上收益常常接近于零——稀疏矩阵要额外存索引,访存变得不规则,通用计算单元吃不消。删整个通道、整个注意力头叫结构化剪枝,模型的张量维度真的变小了,能直接落到 NPU 上跑出加速比。
结构化剪枝有个容易被忽略的细节:剪完的通道数要满足硬件对齐。很多加速器要求通道数是 8 或 16 的倍数,剪到 37 个通道和剪到 32 个通道的速度可能一样,多出来的 5 个白剪。
蒸馏解决的是另一个问题——不是把模型变小,而是把小模型教会。云侧大模型作为教师,输出带温度的软标签,端侧小模型学这个分布。软标签比硬标签信息量大得多:一个“猫”的样本,教师可能给出猫 0.9、豹猫 0.08、其余接近零的概率分布,这个分布里藏着类别之间的相似性结构,学生学到的不只是“这是猫”,还有“猫和豹猫像在哪”。温度参数的作用是控制分布的平滑程度,温度高则类间关系暴露得多,温度低则接近 one-hot。端侧小模型从云侧大模型蒸馏,是把云的能力搬到端最直接的一条路径。
这三件事的叠加顺序有讲究。常见的顺序是蒸馏、剪枝、量化、算子对齐:先让小模型学会大模型的行为,再删结构,最后压精度。反过来先量化再剪枝,剪枝时面对的已经是带量化误差的权重,敏感层判断容易失准。
3.3 稀疏计算的收益边界
稀疏这件事最容易被误读成“稀疏率越高越快”。真实情况是:稀疏率是模型属性,加速比是硬件属性,两者中间隔着一个“硬件能不能原生吃下这种稀疏模式”。
2:4 结构化稀疏(每 4 个连续权重里固定保留 2 个)之所以能拿到接近 2 倍的理论加速,是因为张量核心的硬件数据通路就是按这个模式设计的,解码逻辑固化在电路里,不占额外周期。而随机稀疏 90% 的模型,在通用 GPU 上可能一点不快,因为每个非零元素的位置都要解码,索引开销超过省下的计算。
所以做端侧部署时,判断标准不是“我能剪到多稀疏”,而是“目标芯片有没有对应的稀疏指令和数据结构”。没有的话,老老实实做结构化剪枝,把稀疏度换成维度缩减,才是能兑现的收益。
4. NPU 的底层机制:存算一体为什么比通用核省电
4.1 冯·诺依曼瓶颈:搬运比计算贵
CPU 和 GPU 都遵循存储与计算分离的结构:指令取出来、数据搬到寄存器、算完写回。跑神经网络时这套结构特别吃亏,因为矩阵乘法里权重数量巨大,每做一次乘加都要把权重从片上缓存甚至外部内存搬到计算单元旁边。
这笔能量账很吓人。按业界常用的量级估算,一次 32 位数据从外部内存读取消耗的能量在几百皮焦,而一次 32 位整数乘加只在零点几到一皮焦的量级,中间差了两到三个数量级。也就是说,算得多快不是瓶颈,搬得多远才是。GPU 用高带宽显存加大容量片上缓存缓解,但物理上仍然在搬;CPU 的缓存层次更多、单核带宽更小,还要背通用指令译码和乱序执行的包袱,跑张量计算最不划算。
4.2 存算一体:把权重变成电导
存算一体的思路很朴素:既然搬运贵,那就别搬了,让权重待在自己该待的地方,直接把计算做在存储阵列里。
交叉阵列(crossbar)是这套思路的典型物理实现。每个交叉点放一个阻变器件或 SRAM 计算单元,其电导值就代表一个权重;行方向加输入电压,列方向收集电流。根据基尔霍夫电流定律,一条位线上流出的电流天然等于该行所有交叉点电流之和,也就是一整行的乘加结果,一次读周期就能拿到。权重不移动,移动的只有输入。
import numpy as np # 模拟一次存算阵列读操作:输入电压向量 × 电导矩阵 = 位线电流 G = np.array([[0.20, 0.50, 0.10, 0.30], # 电导矩阵,单位 mS,每个元素对应一个器件 [0.40, 0.10, 0.60, 0.20], [0.30, 0.30, 0.20, 0.70], [0.10, 0.80, 0.20, 0.40]]) v = np.array([0.10, 0.20, 0.30, 0.40]) # 输入电压,单位 V I = G @ v # 一次读周期完成 4 组点积,权重未发生搬运 print("位线电流(mA):", np.round(I, 4))G是权重的物理映射,v是激活值的物理映射,G @ v这一行在硬件上由电流求和一次完成,不需要把矩阵逐元素读出来。参数上要注意的是G的精度:器件电导通常只能稳定表示 4 到 8 比特,这是模拟存算一体精度受限的物理原因。
模拟域还有额外代价:输入要经过数模转换,输出要经过模数转换,ADC 的功耗和面积在阵列规模不够大时会吃掉全部收益。所以真实的 NPU 很少做成纯模拟存算,更常见的组合是“专用 MAC 阵列 + 固定数据流 + 片上大容量 SRAM”,用硬件固化卷积和矩阵乘的循环顺序,把数据复用做到极致,省掉通用指令发射和寄存器重命名这些跟张量计算无关的开销。
这也是 NPU 被广泛用于端侧加速的原因:专门化设计、硬件加速、高能效、低功耗、可弹性扩展,这几点不是并列的形容词,而是同一件事的不同侧面——把通用性换成效率。代价也很明确:灵活性差,算子不支持就得多绕路。
4.3 实测账本:四种执行组合的取舍
一组公开的实测数据能把这笔账算得很清楚。在搭载 NPU 的客户端处理器上跑同一个文生图扩散模型,四种执行方式的差别是这样的:
| 执行单元 | 时延 | 功耗 | 能量开销(时延×功耗) | 特征 |
|---|---|---|---|---|
| CPU | 43 s | 40 W | 约 1720 J | 指令开销和搬运占主导,最不划算 |
| GPU | 14.5 s | 37 W | 约 537 J | 单一单元里时延最低,但功耗高 |
| NPU | 20.7 s | 10 W | 约 207 J | 时延不是最低,能效最好 |
| GPU + NPU | 11.3 s | 30 W | 约 339 J | 异构并行,时延最优,能效居中 |
如果只看时延,GPU 单独跑比 NPU 快 6 秒;如果看能量,NPU 只用了 GPU 不到四成的电量,能效比大约是它的 2.6 倍。这两个结论都成立,只是回答的问题不同。
插电场景下,用户对“生成一张图等 10 秒还是 20 秒”有明确感知,选 GPU+NPU 异构并行:把计算密集的卷积和注意力留在 NPU,把 NPU 不擅长或形状动态的算子交给 GPU,两条流水线同时跑,时延压到 11.3 秒。电池场景下,能量预算才是硬约束,后台常驻的任务比如相册索引、语音唤醒,选 NPU,20 秒跑完但只花 10 瓦,设备不烫、续航不掉。
所以同一颗芯片里放 CPU、GPU、NPU 三种单元,不是简单的性能堆叠,而是给操作系统一个按能量预算调度任务的旋钮。异构并行的难点也在这里:切分点选错,两个单元之间的数据搬运会抵消并行收益,跑出来比单单元还慢。
5. 避坑:端侧部署常见问题与排查
5.1 量化后精度掉点,先别怪量化算法
现象:模型转成 INT8 之后,整体准确率只掉不到 1 个点,但某一类小目标的召回掉了 3 到 5 个点,指标表上看不出来,上线后被业务方发现。
原因:小目标在特征图上的响应本来就弱,量化噪声占响应的比例高,再叠加 per-tensor 量化把整个通道的动态范围压扁,弱响应直接被量化到同一个整数格子里,区分度没了。首尾两层尤其敏感,输入层直接量化会把原始像素的细微差异抹平,输出层量化会影响分数排序。
解决:权重量化改成 per-channel;首尾两层和检测头保留 FP16;对激活做 per-token 动态量化;改完用同一批难样本回放,专门看小目标召回,不要只看总体 mAP。
5.2 算子回退:NPU 只跑了一半的图
现象:性能分析工具显示 NPU 利用率很低,CPU 反而满载,整体时延比预期慢两三倍,但模型明明已经转成了目标格式。
原因:编译器遇到不支持的算子、不支持的属性或者动态 shape,会静默把这段子图切回 CPU 执行。切分点两侧要做布局转换和数据搬运,一次回退可能带来两次全图级别的内存拷贝,比这段算子本身贵得多。
解决:查子图切分数和每个回退算子的原因,逐条处理。常见原因是某个归一化层的属性不支持、某个 reshape 的维度是动态的。处理手段包括替换等价算子、把动态维度固定成常用档位、或者主动把这段逻辑挪到 GPU 上避免来回搬。
# 排查思路:列出所有回退到 CPU 的子图及其原因,而不是只看总耗时 def report_partition(partitions): fallback = [p for p in partitions if p.device == "CPU"] for p in fallback: # reason 一般是 shape / dtype / attr 不支持,按这个字段归类最快 print(f"回退子图: {p.op_types} | 原因: {p.reason} | 节点数: {len(p.nodes)}") return len(fallback) # 返回 0 才说明整图被目标单元接住;大于 0 就要看是哪几段在拖后腿这段逻辑的核心是先归类再优化:把所有回退原因按 shape、dtype、attr 三类统计,出现频次最高的那一类往往一改就能消掉大半回退。
5.3 功耗墙与热降频:跑三分钟就腰斩
现象:冷机启动时帧率漂亮,连续跑三五分钟后掉到一半,摸上去发烫。
原因:端侧是电池和散热受限的环境,持续满负载会触发温度阈值,系统降频保护。这不是芯片性能不够,是散热设计给不出持续功耗。
解决:把持续负载改成突发加空闲的调度,给每帧留出散热间隙;把时延预算从“最优”改成“留 30% 余量”,避免贴着温度墙跑;模型侧减少常驻内存占用,降低待机功耗。做续航评估时一定要跑长稳测试,不能只看首次推理的时延。
5.4 首帧延迟:权重加载的一次性成本
现象:第一次推理要等好几秒,之后每次都是毫秒级。
原因:权重文件存在闪存里,第一次推理要读进内存再分发到各个计算单元,这是纯粹的 IO 成本,跟模型计算量无关。模型越大、闪存带宽越低,这段越久。
解决:应用启动时做预热推理,把权重提前加载并常驻;权重文件用内存映射方式读取,避免一次性全量拷贝;多模型场景按使用频率排序,冷门模型延迟加载。
5.5 端云结果不一致:同一个问题两个答案
现象:同一个问题,端侧给出的答案和云端不一样,用户反复切换设备时感觉“这个助手有点精神分裂”。
原因:端侧跑的是量化后的小模型,云端跑的是全精度大模型,两者本来就不是同一套权重,在边界样本上必然分歧。加上端侧模型更新节奏和云端不同步,版本差异会进一步放大不一致。
解决:端云共用同一份版本号和能力清单;对高置信样本让端侧直接出结果,对低置信样本强制上云并记录分歧样本用于迭代端侧模型;对外暴露时明确标注当前由哪一侧处理,避免用户困惑。
6. 设计取舍:全端侧和全云侧为什么都活不下来
把前面的账合起来看,会得到一个不太舒服的结论:全端侧和全云侧都活不下来,只是死法不同。
全端侧的硬约束在内存和散热。模型参数的增长速度比端侧内存带宽和电池容量的提升速度快得多,十亿参数今天能塞进旗舰机,百亿参数就要在内存和功耗上做痛苦取舍,而且端侧一旦定型就没法靠扩容救场。全云侧的问题在成本和时延:推理成本随用户规模线性涨,硬件按峰值买,尾延迟在高峰期不可控,隐私敏感场景直接出局。
所以真实的产品形态只能是混合,而混合的全部复杂度集中在一个地方——谁来决策分流。这个决策不能靠人拍脑袋,得写进代码里,按置信度和时延预算动态做。
def route(logits, tau=0.9, margin=0.15, budget_ms=50): """端云分流:置信度足够高且时延可接受,就留在端侧""" p = softmax(logits) top1, top2 = topk(p, 2) confident = (top1 > tau) and (top1 - top2 > margin) if confident and estimate_latency(logits) < budget_ms: return "on-device" # 简单样本本地消化,省容量省时延 return "cloud" # 难样本上云,保住准确率上限tau控制端侧的承接比例,调高会让更多请求上云、准确率更稳但成本更高;margin是 top1 与 top2 的差距阈值,它比单纯的 top1 概率更能反映“模型是否真的分得清”;budget_ms是时延兜底,防止端侧在复杂输入上算太久反而比上云还慢。三个参数要一起调,单独调任何一个都会失衡。
这套逻辑最难的地方不在于写代码,而在于承认一件事:端侧的价值不是替代云端,而是替云端削峰。把这句话想明白,硬件的算力规划、模型的大小选择、产品的交互设计就都有了统一的判断依据。
我踩过最深的一个坑,是早期做端侧部署时把注意力全放在模型压缩上,量化、剪枝、蒸馏轮着试,指标看着漂亮,一上真机就翻车——因为回退到 CPU 的那两个算子把所有收益吃干净了。从那以后我每次做端侧落地,都强制走一遍“先看整图有没有被目标单元接住,再看压缩率”的顺序,回退不解决,压缩就是白干。希望帮到你。
本文还有配套的精品资源,点击获取