☰
端侧Scaling Law实战:在固定芯片上让模型更聪明的系统方法
2026/10/2 9:47:59 网站建设 项目流程

固定芯片上,模型怎么变到最聪明?这个问题我琢磨了很久。做过端侧AI的人都有同感:云端可以堆卡堆显存,模型大了就加GPU,效果不好就上更大参数,但到了嵌入式芯片上,一切全都反过来——算力固定、内存固定、功耗固定,你只能在有限的资源里“抠”效果。所谓“端侧Scaling Law”,说白了就是在不可更换芯片的约束下,找到“效果最优化”的路径,它不是简单地堆规模,而是要在固定天花板下重新定义“什么在增长”。

这篇文章不聊虚的。我把这两年做端侧模型优化时踩过的坑、验证过的路子,以及身边同行在不同芯片上(RK3588、Jetson Orin Nano、STM32MP系列这类都算)摸索出的经验,系统拆一遍。适合三类人:刚把模型跑上板子但效果不理想的开发者、做边缘计算产品选型的技术负责人,以及想理解“端侧为什么不能直接套云端大模型”的研究者。读完你会清楚,在固定芯片上让模型变聪明,不是靠“换模型”那一锤子买卖,而是一整套从结构、训练到推理侧的系统工程。

1. 端侧Scaling Law与传统Scaling Law的本质差异

1.1 传统Scaling Law建立在“可增长”的假设上

传统Scaling Law是OpenAI那些人在2020年前后系统梳理出来的规律:模型性能随着参数量、训练数据量、算力的增长呈现出可预测的对数或幂律关系。你增加一个数量级的参数,配合相应增加的数据和算力,模型在验证集上的损失大致会按照一个平滑曲线下降。这条规律支撑了后来GPT系列的疯狂扩展,也支撑了“大力出奇迹”这条路线。

但这条规律有个隐含前提:硬件资源是可以同步增长的。训练时你可以加卡,推理时你可以换更大的服务器。模型大了,显存不够就上A100,再不够就上H100;吞吐不行就多机多卡。云端环境下,Scaling Law的“三个变量”——参数、数据、算力——基本都能绕开物理限制去放大。

到了端侧,这个前提直接崩塌。芯片是焊接在板子上的,出厂那一刻算力就定了,你不能给RK3588再插一张显卡,也不能给Jetson Orin Nano换更大的显存颗粒。更麻烦的是,端侧还多了两个云端不敏感的新约束:内存带宽和功耗墙。参数多了放得下但跑不动,或者跑得动但发热降频,效果一样拉垮。这就是为什么传统Scaling Law那一套“加参数”的玩法在端侧根本不成立。

1.2 端侧Scaling Law真正要回答的问题

固定芯片上的Scaling Law,实质上是在给定硬件架构(芯片算力、内存容量、带宽、缓存策略、功耗预算)的前提下,找出“什么样的模型结构和训练方式,能让精度逼近理论上限”。它的核心变量不再是参数量,而是**“有效计算利用率”和“信息密度”**。

我习惯用一个公式化的理解:端侧效果E = 芯片硬件能力H × 模型算法适配度A × 工程落地完整度P。芯片H是固定的,你能动的只有A和P。A指的是模型结构、算子在芯片上的映射效率、量化策略等算法层面的适配;P指的是推理引擎的调度、内存复用、算子融合、线程优化等工程层面的适配。两个都要做到极致,这个乘积才会大。

换句话说,端侧Scaling Law研究的是“在固定芯片上,通过提升每瓦性能、每毫秒性能,来换取更大的有效模型容量”。举个例子:同样是4TOPS算力的NPU,A模型直接跑标准的MobileNetV3,B模型用NAS搜出来的定制结构、再做了INT8量化感知训练,两者的推理延迟可能一样,但B的精度可以明显高出一截。这就是在固定芯片上“变聪明”的本质——不是模型变大了,而是每一份算力都被榨得更干净了。

2. 固定芯片上让模型变聪明的三条主路径

2.1 路径一:模型结构侧——用NAS和高效算子“量身定做”

很多人一上来就换大模型,比如从MobileNetV2换成MobileNetV3,或者从Swin-Tiny换成Swin-Small,觉得参数多点效果自然好。但结果往往是芯片算力撑不住,要么掉帧,要么内存溢出。真正常用的方法是用神经架构搜索(NAS),在目标芯片上直接搜索最优结构。

NAS听起来玄乎,实际落地时也不要求自己从零写搜索流程。像Google的NASNet、MobileNetV3的NAS搜出的结构,都是很好的基础。但针对性不够强——它们是拿GPU或TPU搜的,搜出来的算子组合在你的NPU上不一定高效。我见过一个案例,同样的ECC图像分割任务,在Jetson Orin Nano上跑一个搜索时考虑了内存访问模式的定制结构,比直接移植NNI搜出的MobileNetV3结构,在相同延迟下mIoU高了2.3个点。原因是定制结构减少了跨内存访问的张量搬移次数,把NPU的内部SRAM利用率从40%提到了70%以上。

如果暂时不想上NAS,也有更朴素的替代:手动替换低效算子。比如把常规的Conv3x3替换成可分离卷积,把LayerNorm替换成RMSNorm或在线归一化,把多头注意力替换成窗口注意力或线性注意力。这些改动不改变整体参数量级,但能显著降低芯片上的实际计算时间。再配合通道剪枝(Channel Pruning)和结构化稀疏,把不重要的通道直接减掉,精度损失可以控制在1%以内,但推理速度能翻倍。关键原则是:不要让模型结构去适配芯片,而是让芯片的算子库反过来约束模型结构搜索空间。

2.2 路径二:训练侧——蒸馏、量化感知训练、重参数化三件套

结构定好了,接下来是训练。在固定芯片上,我最推荐的是“大模型蒸馏小模型”路线。大模型在云端训练好,把它的logits输出作为软标签去监督小模型学习,小模型能学到比硬标签更多的一起语义信息。这比直接用小模型在数据集上从头训,通常能带来3~8%的相对精度提升。蒸馏时要注意温度系数的选取,我常用的区间是3~10,太低了软标签接近硬标签,没意义;太高了软标签趋于均匀,模型学不到区分度。还得兼顾软硬标签损失的比例,一般软标签损失权重可以取0.5~0.7,需要根据任务类别数调节。

训练侧还有一个绕不开的环节:量化感知训练(QAT)。很多人是训练完模型直接用工具转INT8,发现精度掉了一大截,于是反过来在模型后面加微调。正确的做法是训练时就把整数化伪操作(fake quant)插到模型里模拟量化误差,让模型自己去适应低比特表示。我们用QAT训练好一个INT8模型后,在RK3588上几乎没有掉点,而训练后量化(PTQ)掉点经常超过2%。QAT的代价是训练时间变长,好在现在很多框架(PyTorch、TensorRT、ONNX Runtime)都支持自动插入量化节点,不需要手写。

重参数化(RepVGG那种思路)也是端侧利器:训练时使用多分支结构提升表达能力,推理前把分支合并成单路卷积,减少计算开销。这个技巧配合剪枝、蒸馏,可以在相同芯片上白捡5~10%的推理加速而不掉点。我习惯把重参数化看成“训练时开挂、推理时卸载”,它让模型结构在训练和推理阶段解耦,训练模型可以更复杂,推理模型必须更简单。

2.3 路径三:推理侧——内存调度、算子融合和缓存布局

很多人在模型上花了大力气,却忽略了推理引擎的优化空间。固定芯片上,数据搬运比计算更贵。我做过一个实测:在某个NPU上跑YOLOv5s,纯计算时间只占整个推理的40%,剩下的时间都在等内存分配、张量copy和算子切换。这就意味着,即便你模型计算量减半,如果内存布局不优化,实际提速可能只有20%。

算子融合是解决数据搬运的经典手段。把连续的Conv+BN+ReLU融合成一个算子,把LayerNorm的mean和var计算融合进前向过程,把相邻的split和concat都合并,都能减少中间张量的落内存次数。框架方面,TensorRT的图优化、OpenVINO的Plugin、ONNX Runtime的Execution Provider都在做这类事情,但针对特定芯片,往往还需要手动写一些融合规则。内存池复用也很关键:把中间层张量池化分配,而不是每个算子都malloc/free,能极大减少分配开销。我见过有人通过预分配一块统一的内存池,把推理端到端延迟降低了30%。

缓存布局这个点容易被忽略,但在有复杂缓存层级的多核芯片上影响很大。比如Jetson Orin Nano的GPU L2缓存有限,如果你把特征图排成通道数连续的数据格式(NHWC),可能比NCHW格式缓冲区命中率高不少。芯片不同,最优布局也不同,没有放之四海皆准的答案,一定要在目标板子上做A/B测试。

3. 实操复盘:在RK3588和Jetson Orin Nano上让模型变聪明

3.1 第一步:先做硬件瓶颈画像

拿到一个项目,别急着选模型,先把芯片的“脾气”摸清楚。需要收集的指标包括:峰值算力(TOPS)、内存带宽(GB/s)、可用内存/显存、NPU/GPU的算子支持列表、以及实测的功耗曲线。RK3588有6 TOPS NPU,内存带宽取决于所配的LPDDR4/5,支持常见卷积/池化/激活算子,但对某些大矩阵乘法和动态形状的算子支持不好。Jetson Orin Nano的GPU算力虽然不高,但支持TensorRT全集算子,内存带宽相对充裕。

我的方法是写一个“硬件探测工具”,用目标芯片依次跑一遍标准化的算子测试集,比如不同尺寸的卷积、不同头数的注意力、不同batch的矩阵乘法,记录每个算子的延迟和内存占用。这样你就知道自己的算法规划里哪些算子会拖后腿。比如有个项目想在Jetson上跑LLM量化版,结果发现7B模型即使INT4也得近4GB,Orin Nano 8G版勉强跑但生成速度极慢,于是果断换了更小的3B模型再加4-bit量化,速度提升了4倍多。这个决策不是靠感觉,而是先看懂了硬件的“账本”。

3.2 第二步:基于瓶颈选基座和替代架构

在固定芯片上做模型选型,不能只看Paper指标,得结合你的硬件画像来筛选。我给一个常用的判断思路:

先画一条“延迟-精度帕累托曲线”,把候选模型在你的芯片上实际跑出来,每个模型在相同输入分辨率下测延迟和精度,把点画在图上,只保留前沿点。比如目标延迟是30ms,你把MobileNetV3、EfficientNet-Lite、RepVGG-B0、RegNet-Y-800MF都跑一遍,看看30ms这根竖线上面谁精度最高,那就是基座。

接下来再考虑任务特殊性。如果是检测任务,你可能需要比分类模型多了检测头,这时要用更深的骨干+轻量检测头组合;如果是分割任务,编码器-解码器结构里,解码器的上采样方式对内存带宽影响很大,可以考虑用轻量ASPP或FPN替代大Feature Pyramid。如果是Transformer类任务,尽量选线性注意力变体或Swin这类窗口注意力,因为全局注意力的复杂度随分辨率平方增长,固定算力下撑不住。

这里要多说一句:不要迷信开源项目的“推荐配置”。很多开源repo默认参数量和FLOPs标称值是在没有考虑硬件算子支持的理想情况下算出来的,你在芯片上跑起来会完全不一样。我就遇到过EfficientNet-Lite标称FLOPs只有400M,但在某NPU上因为SQ-CAL算子的支持很差,实际延迟比MobileNetV3还高30%。所以务必实测。

3.3 第三步:量化、蒸馏、调优,逐步逼近精度上限

选定基座后,我建议的顺序是:先做PTQ快速验证精度底线;如果掉点可接受,就继续做推理优化;如果掉点太多,就升级为QAT。同时配合知识蒸馏在训练阶段拉高上限。

具体操作可以参照这样一个流水线:

  1. 加载预训练模型(ImageNet或大规模数据集上训练过的权重),在目标任务的数据集上做迁移训练(finetune),得到一个高精度的浮点模型。
  2. 用这个浮点模型作为Teacher,训练一个结构相同但替换了部分低效算子(或者做了通道剪枝)的Student模型,用蒸馏损失约束。
  3. 在Student训练中开启QAT,插入fake quant节点,把量化误差纳入训练。
  4. 训练结束后,导出ONNX或TensorRT引擎,在目标芯片上验证精度和延迟。
  5. 如果精度还不够,回到步骤2,调整蒸馏温度、损失权重、剪枝比例。

我在RK3588上做过一个实例:目标是一个工地安全帽检测模型,原方案是YOLOv5s+PTQ,实测mAP 50只有78.2%,延迟45ms。后来改成YOLOv5s结构、但用YOLOv7-tiny做Teacher蒸馏,训练时做通道剪枝(保留70%通道)和QAT。最终mAP 50提升到84.6%,延迟降到31ms。整个过程三天搞定,没有任何特殊的魔法,就是按这条流水线走。

3.4 第四步:推理引擎层面的挤压与验证

模型训练完了,部署时选推理引擎也很有讲究。RK3588可以用RKNN Toolkit,Jetson用TensorRT,STM32MP系列用X-Linux或ONNX Runtime,ESP32这类MCU往往得手动做C代码移植。每个引擎都有自己的图优化规则,但需要你去配合它。

以TensorRT为例,建议先把模型转成ONNX,用TensorRT的Polygraphy工具查看每一层被替换成了什么plugin,有没有走低效的实现。比如有些模型里的Softmax算子,TensorRT可能用通用cbr实现,如果你换成一个在channel维度上做max difference的算子,可能延迟更低。这种细节需要用profile工具测出来才能发现。同样在RKNN上,我遇到过模型里的Split操作导致NPU算子切换频率过高,手动把Split替换成多个不同slice的拼接后,延迟降了20%。

最后还要做整链路验证:不只测模型推理延迟,还要测前后处理(图像的resize、归一化、后处理的NMS)在CPU和硬件加速单元之间搬运数据的开销。很多端侧项目最终延迟比预期高,根本不是模型问题,而是前处理拷贝和归一化的格式问题。比如输入图片是BGR,但模型需要RGB,你在CPU上先转再拷贝到NPU,如果直接通过硬件缩放器(如RK3588的RGA)去转格式和缩放,这个开销几乎可以忽略。

4. 常见问题与排查技巧实录

4.1 精度掉点严重:PTQ和QAT的现场检查

我见过太多人一上来就跑PTQ,掉点超过3%就开始怀疑芯片不行。实际上PTQ掉点大部分原因是激活值分布不均匀,尤其是有残差结构、注意力模块的网络。排查时可以输出每一层的激活分布直方图,看看是不是极端值拉宽了量化范围。解决办法也很机械:先试着只量化权重保留浮点激活,看看掉点来源;如果确认是激活分布问题,一种方案是改用逐通道量化,还有一种方案是“分布校正”,比如用少量校准数据调整量化阈值。如果都试了还是不行,就直接上QAT,一般都能救回来。

4.2 算子不支持导致转换失败

老牌芯片的算子支持列表就那么长,新模型里的算子层出不穷。转换时频繁报“Unsupported operator”。不要急着换模型,先试试算子重写。比如Transformer里的GELU可以用近似多项式替换;LayerNorm可以用RMSNorm替代;Multi-head Attention用手动reshape和matmul组合替代;Hard-Swish可以用ReLU6的组合近似。这些都是我在部署Transformer类模型时经常动刀的地方。如果重写太麻烦,也可以把包含不支持算子的小支路拆出来跑CPU,用GPU/NPU跑主体。但这种异构调度会增加内存拷贝,非必要不用。

4.3 内存溢出或推理时程序被杀

固定芯片上,内存溢出常出现在两种场景:一是模型太大,二是推理引擎为每个中间张量都分配了独立缓冲。第二种情况完全可控:打开推理引擎的内存池复用选项,或者手写一个内存分配器,按生命周期复用张量存储。另外要注意多线程与多进程的显式内存分配,端侧很多芯片的NPU驱动默认会保留一块内存给自己的context,你不去复用就会造成碎片。

4.4 表格:端侧模型优化问题速查

问题现象可能原因排查/解决思路
INT8量化后精度掉2%以上激活分布不均、有离群值改用逐通道量化、设置合适的量化阈值、尝试QAT
推理延迟高但FLOPs很低算子不匹配、数据搬运频繁用profile工具看算子延迟排序,替换低效算子,做算子融合
转换时提示算子不支持模型结构里有芯片未实现的算子算子重写、用等价结构替代、必要时拆到CPU执行
内存占用比估算高很多推理引擎为每层开辟独立缓冲开启内存池复用、统一中间张量存储管理
多线程并发时性能下降内存带宽竞争、缓存冲突错峰调度、减少并发、绑定CPU亲和性
模型在GPU/PC上效果好但板子差分辨率或预处理方式不同在板子上用同一预处理重新测试,确认是模型还是环境导致

4.5 避坑技巧:不要忽略功耗与降频

最后这点特别想强调:固定芯片上,散热和功耗往往是隐性天花板。哪怕算力标称6 TOPS,如果板子被动散热,跑满3秒就降频,实际持续算力可能只有3.5 TOPS。我在RK3588上调模型时,一开始用NPU跑高密度的YOLOv7,性能看起来很猛,但持久化测试发现功耗高得离谱,NPU温度飙到85度后开始降频,性能衰减一半。后来改成两个小模型分时调度,反而总吞吐更高且稳定。

所以优化流程里一定要加入“长稳测试”:满载跑至少30分钟,记录每秒推理帧数和温度曲线,看有没有明显掉帧。芯片厂商给的TOPS是峰值,万万不可当成持续性能。

5. 端侧Scaling Law的边界与我自己的几点体会

5.1 它不是万能的:感知端侧智能的天花板

端侧Scaling Law能帮你把固定芯片的潜力榨到九成以上,但改变不了物理极限。如果你在2 TOPS的芯片上非想跑7B语言模型,哪怕量化到2-bit、蒸馏到极致,结果也不是“变聪明”而是“变智障”。所以做端侧AI产品前,一定要先明确场景的精度底线和时延上限,反向推导需要的算力,再筛选芯片。端侧Scaling Law本质上是在“限定芯片”这个前提下寻求最优解,但前提如果定错了,后面所有优化都白搭。

现在一些新趋势也在扩展端侧Scaling Law的边界,比如端云协同:把模型的一部分层放云端,一部分放端侧,通过分片推理来突破端侧算力限制,但这又引入了网络带宽与隐私问题。还有动态推理:根据输入难度动态选择不同深度的子网络,简单图片走浅层网络,复杂图片走深层网络,用任务难度换取平均算力的更优分配。这些方向都在尝试把“固定芯片”的天花板再用算法顶高一点,但本质还是离不开对硬件特性的精细理解。

5.2 我的个人体会

做了这么久端侧模型优化,我个人最大的体会就是:别把Scaling Law当物理定律,它更像是“资源配置策略”。在云端,你通过堆资源换能力;在端侧,你通过设计换能力。两者的目标函数完全不同。每次拿到一块新芯片,我都习惯先花半天时间做硬件探测,再花一天时间画延迟-精度曲线,然后才是训练和部署。这个前期准备看着浪费时间,却往往能省下后面好几天的返工。

另外,我也越来越觉得“在固定芯片上变聪明”不只是算法工程师的事,它需要硬件、编译器、算法三个角色并肩作战。模型结构设计师要懂芯片的内存层次,推理引擎工程师要懂模型的稀疏度分布,两者碰在一起,才能真正做到把每一毫秒、每一毫瓦都花在刀刃上。

总的来说,端侧Scaling Law没有统一公式,但有一套可靠的方法论:吃透硬件画像,在结构、训练、推理三条路径上反复迭代,用系统化的实验数据驱动每一步决策。听上去不酷,但这正是能让模型在固定芯片上“变到最聪明”的踏实路径。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询