资讯动态

端侧大模型部署实战:从量化压缩到推理优化

发布时间:2026/10/21 21:43:35 来源:尧图企业网站定制
“端侧大模型部署”这个说法最近两年已经被聊得很多了但真正动手把模型塞进手机、开发板、甚至嵌入式设备的人其实没那么多。我更喜欢用标题里那个比喻把大象塞进冰箱。第一步是想办法压缩体积让它能进得去第二步是保证它进去之后冰箱还能正常制冷也就是模型在设备上要流畅运行而不是卡到风扇狂转、App直接闪退。这个“先压缩、再优化、最后调到丝般顺滑”的过程说它是工程艺术一点都不夸张。这篇文章要分享的内容是我在一款国产SoC开发板上部署开源大模型的完整实战记录。项目目标很直接把一个7B级别的对话模型塞进内存仅有8GB的设备并让对话输出速度从最初每秒两三个字提升到接近可商用水平。整个过程涉及模型选型、量化压缩、推理引擎适配、算子优化、真机调参等一系列工作。适合正在做算法落地、移动端推理、边缘计算的朋友参考也可以给准备在自己的产品里接入大模型但还没有理清思路的独立开发者一些借鉴。1. 端侧部署的整体思路与方案选型1.1 先算“预算”为什么说要先看硬件天花板很多同学拿到一个开源大模型第一反应就是“下载权重、装个推理框架、跑起来试试”。如果你只是在电脑上玩一下那无所谓但做端侧部署第一步永远是算账算的是硬件资源的三笔账内存、内存带宽、算力。先说内存。大模型的权重是占内存的大头。一个7B参数模型权重如果用FP16存储差不多要14GB如果是FP32那直接28GB普通手机根本不用想。即使在8GB内存的开发板上14GB的权重连加载都做不到。而当我们把权重量化到INT4同样7B模型只需要大约3.5GB再加上推理过程中需要的K/V cache、激活值、中间缓冲区总内存占用才会在6GB左右。所以第一步必须搞清楚设备的可用内存到底有多少、推理运行时能容忍多大的峰值。再说内存带宽。大模型解码阶段有个特点每生成一个token都要把全部权重从内存搬到计算单元。所以生成速度的物理上限约等于内存带宽除以每token需要读取的权重字节数。听起来抽象我拆开说假设开发板的内存带宽是20GB/s。如果模型权重是FP16约为14GB那么每生成一个token从内存读一遍所有权重就需要14GB数据理论最高只能跑20 ÷ 14 ≈ 1.4 token/s。如果把模型量化到INT4权重变成3.5GB理论最高就可以跑到20 ÷ 3.5 ≈ 5.7 token/s。这个计算虽然粗糙但能帮你看清一件很重要的事端侧大模型的瓶颈往往不是算力不够而是“喂数据”的速度跟不上。压缩模型不只是为了省内存更是为了提速。最后是算力。PreFill阶段处理你输入的那段文字是稠密计算对算力要求很高Decode阶段逐个吐字则变成访存密集型对带宽更敏感。如果目标设备有NPU或GPU一定要把算子尽量跑到这些加速单元上否则单靠CPU小模型可能还能忍7B模型基本就是漫长等待。1.2 模型选型的“量级红线”怎么定硬件预算算清楚之后再回来选模型你会发现选择范围其实很小。市面上的开源模型从0.5B到几十B都有但能真正塞进端侧设备的基本只有三档1B~3B级别适合闲聊、意图识别、轻量摘要这类简单任务。INT4量化后权重只要0.5GB~1.5GB手机和开发板都容易跑起来。7B~8B级别适合通用对话、中等复杂度的文本理解。INT4量化后权重约3.5GB~4GB需要设备至少有6GB以上可用内存且要有较充裕的带宽。13B以上在平板、PC级设备上也有可能部署但手机和开发板会很吃力。我的经验是除非设备内存很大否则不建议硬塞。有一个很容易踩的坑看到模型评测榜单里某个7B模型得分很高就直接选它结果发现任务其实用3B模型就够白占了大量资源。我建议在下决定之前先用自己的数据做一个简单的效果对比。如果3B模型在目标任务上的指标跟7B模型差距在可接受范围内优先选小模型把省下来的资源留给更长的上下文、更大的并发这比追求单个模型的能力上限要明智得多。另外模型结构也会影响部署难度。有些模型的代码里用了特殊算子比如自定义注意力机制、非线性函数这会增加移植和优化成本。同一参数量级下尽量选择结构规整、主流推理框架已经支持良好的模型。做工程不是搞科研目标是用最低成本把产品跑起来没必要跟算子兼容性过不去。2. 压缩到能塞进去量化、剪枝、蒸馏的组合拳2.1 量化把精度换成内存与速度如果只做一件事就压缩模型那一定是量化。量化就是把模型里原本用高精度表示的数换成低精度表示。大模型的权重一般用FP32或者FP16存储数值分布近似一个以零为中心的钟形曲线集中在小数值附近。量化做的事情就是给这组数找一个缩放比例把连续浮点映射到离散的整数集合。我自己的项目里主要用的是两种量化方式训练后量化和量化感知训练。训练后量化字面意思就是模型训练完之后拿一批校准数据统计权重和激活值的分布然后计算出量化参数。这个方法速度快不需要重新训练但需要在校准集上多花点心思。校准集不用很大但要能覆盖模型可能见到的数据分布。我试过随便拿几句话做校准结果模型量化后输出质量明显变差换成任务相关的几百条样本之后就好了很多。量化感知训练则是在训练阶段就模拟量化误差让模型自己去适应低精度带来的噪声。效果通常比训练后量化好但需要额外的训练资源和数据。如果手头没有训练条件还是优先做训练后量化。量化精度这块有几个直观的规律INT8量化绝大多数任务上损失很小可以当作无感优化。INT4量化会有一定精度损失尤其是复杂推理、数学题、代码生成这类任务。INT3/INT2量化端侧很少用精度崩的太快一般只在极端内存受限时才考虑。注意量化不只是把权重变成低精度激活值也可以量化。权重量化省内存激活值量化则能减少计算中间结果的存储量。在算子实现里如果权重是INT4激活是FP16读写权重省了带宽但激活值还是原始大小速度上会打折扣。更理想的是INT4权重配INT8激活能进一步减少访存但激活量化对校准集的要求更高。我在项目里碰到过一个典型问题量化完某个模型发现模型回答开始胡言乱语后面一查是某些敏感层对精度特别敏感一旦量化误差稍大整个输出的token概率分布就乱了。解决办法是混合精度把一部分敏感层保留为FP16其余层用INT4。具体哪些层敏感不是拍脑袋猜的可以逐层做量化并观察loss变化也可以看每层权重的数值分布是不是存在特别大的离群值。分布越不规整越要谨慎量化。2.2 剪枝与蒸馏从源头减重量化是“把大象压缩后放进去”还有一种思路是“把大象本身变小一点”。这里就涉及剪枝和蒸馏。剪枝分非结构化剪枝和结构化剪枝。非结构化剪枝是把模型里那些“重要性较低”的权重直接置零大部分参数变成稀疏矩阵。稀疏矩阵虽然在算法理论上有加速比但在端侧的实际硬件上如果不配合特殊的稀疏计算库经常跑不出真正的加速收益有时候反而因为存储格式转换变慢。所以端侧项目里我更推荐结构化剪枝。结构化剪枝是直接剪掉某些完整的结构块比如Transformer里的某几个注意力头、FeedForward层的某几个维度。剪掉之后模型变成更瘦的结构每层的参数量和计算量都实打实地减少部署时可以直接受益。剪枝思路很简单操作却不轻松要计算每个结构的重要性剪完了还需要微调恢复精度。如果项目时间紧建议剪枝率控制在20%以内否则精度恢复会越来越难。蒸馏则是让一个“大老师”模型教一个“小学生”模型。具体做法是用大模型在大量数据上生成输出然后用这些输出去训练小模型让小模型学会模仿大模型的行为。这个方法的优点是小模型的架构可以完全按部署要求重新设计参数量更小、结构更规整比单纯压缩一个现成模型要稳得多。缺点是训练数据、训练卡资源都要跟上不是所有团队都有条件做。量化、剪枝、蒸馏这三者不是非此即彼的关系。如果要从头做一个端侧模型我建议的顺序是先用蒸馏拿到一个适中的小模型再对小模型做适度的结构化剪枝最后用INT4量化收尾。每一步改动都会损失一点精度但要尽量把损失控制在每步可接受范围内别三步叠加之后模型变傻子。2.3 组合策略与精度回退经验端侧项目的时间线往往非常紧最佳组合往往不是理论上的“最优”而是“当前资源下的最稳方案”。我这次部署的方案组合是直接用原版模型不做蒸馏和剪枝对权重做INT4量化对激活值保持FP16K/V cache单独做了低精度缓存。为什么这样选因为原模型是现成的蒸馏和微调的流程太长项目等不起。INT4权重量化带来的内存收益最明显7B权重从14GB降到3.5GB内存压力立刻解决。激活值没有量化是因为这部分精度敏感度更高而且端侧NPU对INT4激活的支持不一定好。K/V cache在长对话时增长特别快把它压缩一个等级能在同样的内存预算下塞进更长的上下文。我给自己留了一条精度回退路径如果INT4效果不达标就换成“INT4/FP16混合精度”只把最敏感的若干层调回FP16。这个方案比全量INT4内存多占几百MB但效果提升明显。实测下来混合精度方案最终成为了我的默认配置。这张表是我在实际对比后整理的参考组合可以帮大家快速决定路径方案内存收益速度收益精度影响适用场景仅INT8量化中等中等很小设备内存较紧张层度一般INT4权重FP16激活大大较小通用端侧部署的首选INT4权重INT4激活最大最大较大内存极受限且任务容错度高混合精度量化较大较大最小对输出质量要求高的项目剪枝INT4量化很大大中等有足够时间微调恢复精度蒸馏小模型量化最大大可控有训练资源可重塑模型结构3. 推理引擎与算子优化真正把它跑起来3.1 推理引擎怎么选把模型压缩完之后下一步要解决的是“怎么让它跑起来”。端侧推理不是拿通用的深度学习框架直接推理就完事因为框架通用性强但针对具体硬件优化不足。这时候就需要选一个端侧推理引擎。市面上的端侧推理引擎针对不同硬件做了很多优化但选择标准其实可以归纳成四点算子覆盖面、硬件加速支持、多线程调度、内存管理灵活性。我自己的选择方法是先列清单优先级从高到低这么排算子覆盖面是否包含模型里的主要算子。如果模型里有一个很冷门的自定义算子引擎不支持就只能被迫回退到CPU通用实现性能会掉一大截。是否支持目标硬件的NPU或GPU加速。同一个模型在NPU上跑的功耗和速度通常远好于CPU。但要注意NPU支持往往是碎片化的不是说一句“支持NPU”就能所有算子都跑上去。多线程调度能力。端侧CPU通常是大核小核的架构怎么分配推理线程、怎么避免和系统UI抢资源引擎要能灵活配置。内存管理能力。能不能手动控制内存池、能不能提前分配K/V cache这直接影响长对话场景下的稳定性。合规提醒一句具体引擎品牌我不展开说大家在选型的时候自己多跑benchmark没有完美的引擎只有适合你设备的引擎。实操中还有一个很容易忽略的坑模型格式转换。很多开源大模型在训练时留下的格式是面向训练框架的并不适合推理引擎直接加载。你需要先转成引擎支持的通用格式。转换过程看似简单实际上模型里的各种自定义算子都会跳出来让你处理。我在这个环节被一个很简单的窗口函数卡了两天因为引擎的算子库不支持最后只能改模型代码把窗口函数替换成等价的多种基础算子组合才顺利转换。所以给新手的建议是在下模型之前先确认推理引擎对这类模型结构的支持已经成熟尽量选那些社区适配热度高的模型。等整个pipeline跑通了再考虑换更小众但效果更好的模型。3.2 内存池、K/V Cache与线程调度模型权重是静态的加载之后占用的内存还算稳定真正让你措手不及的是动态内存。Transformer在推理时每一个token都要更新K/V cache而且随着对话长度变长K/V cache大小线性增长。如果你的实现里是每生成一个token都重新申请一块内存用完了再释放内存碎片会越来越多到后面可能直接OOM。我处理这个问题的方式很朴素预先分配一个足够大的K/V cache缓冲区上限就是模型支持的最大上下文长度。比如设定最大上下文长度为2048那就在初始化阶段把对应长度的K/V cache统一申请好之后的每一次推理都在这块缓冲区里读写不再重复分配。这样做之后内存峰值下降了约30%长对话也不再出现越跑越卡的问题。激活值的内存峰值出现在PreFill阶段特别是你输入一大段文字时中间计算会同时产生很多临时张量。解决思路是复用内存池把不同算子的输入输出缓冲区抽象成统一的内存分配器上一层的输出如果能被下一层消费完就直接供下一层复用而不是每层都开新内存。线程调度也要重视。端侧设备不是一个“无人值守”的服务器设备上还有系统UI、后台通知、其他App在运行。我见过一个方案把CPU所有核心都绑给推理线程结果推理速度确实上去了但整个系统卡成PPT用户界面基本没法操作这是不可接受的。更好的做法是只占用部分核心跑推理留一到两个核心给系统同时给推理线程设置优先级。如果设备有大小核架构尽量让推理线程跑在大核上但也要限制最高频率防止发热降频。3.3 算子融合与访存优化端侧推理引擎里有一些看起来不起眼、但实际效果很大的优化手段最典型的就是算子融合。算子融合的理念很简单减少中间张量在内存和计算单元之间的来回搬运。举个例子Transformer里的LayerNorm或RMSNorm如果单独实现那它的输出必须完整写回内存下一个矩阵乘法再把它读出来。而如果把Norm和后面紧跟着的矩阵乘法融合在一起可以一边计算归一化一边直接把结果送到矩阵乘法单元省掉一次全量写回读取。别小看这一步大模型里每个Transformer层都有Norm累积起来能省下大量访存时间。另外还有一个很常见的优化把多个算子合并成一个大算子。比如Q、K、V三个线性变换原本是三个独立的矩阵乘如果把它们拼成一个大的权重矩阵一次矩阵乘就能同时算出Q、K、V三个结果。这样不仅减少了一次遍历权重的时间还能减少三次内核启动的开销。这类优化在各家推理引擎里很多是自动完成的但如果你发现引擎优化得不彻底也可以自己动手改计算图。做算子优化时要注意精度问题。融合之后由于浮点运算顺序改变结果和原始逐算子实现会有细微差别。正常情况下差别很小不影响结果。但如果你的模型对数值非常敏感或者某些中间值非常接近0那就得谨慎评估。我的经验是在量化模型上做算子融合融合前后多跑几条测试用例对比输出分布宁可少赚一点性能也别让效果崩掉。4. 实测调优从“能跑”到“流畅”的关键瓶颈4.1 延迟、功耗、内存怎么平衡模型能加载、能出字并不代表它好使。“流畅”这个标准在LLM场景里要拆成两个指标首token延迟从用户输入结束到模型吐出第一个token的时间。这个指标直接决定对话的“响应感”一般建议控制在1秒以内能做到500ms左右就很舒服。生成速度之后每秒生成多少个token。对阅读体验来说每秒5个token是及格线10个以上就比较流畅了。除了延迟和速度端侧还有第三个约束功耗。设备是电池供电的模型推理如果长时间让CPU/GPU跑满手机会发热降频反而导致速度越来越慢。我建议在调优时把功耗作为一等公民来考虑。用开发板的功耗计或手机的电池统计功能记录不同配置下的平均功耗。性能再好如果让设备温度冲到红线系统会自动锁频最终体验还不如一开始就限制频率来得稳定。这张表是我在实际项目中用到的调优目标参考指标可接受良好优秀首token延迟 1.5s 800ms 400ms生成速度 5 token/s 10 token/s 20 token/s平均功耗无限制 4W 2.5W峰值内存不触发OOM 设备内存70% 设备内存50%4.2 一次典型的调优路径实录这里整理一下我那次部署3B模型的实测过程数据来自开发板的真实日志。设备是某国产SoC8核CPU集成NPU板载8GB内存Linux系统。初始状态我把模型原始FP16权重直接加载发现光是权重就占了6GB再加上系统占用内存已经红了。系统的做法是把一部分内存交换到存储设备导致模型加载完成后首次推理慢得离谱基本没法用。第一步做INT4量化。权重降到1.8GB左右系统内存占用顺利降到4GB左右模型能稳定运行了。但生速度只到2 token/s比理论值还低很多因为大部分算子还在CPU上跑默认实现没有做图优化。第二步开启推理引擎的图优化和算子融合。生成速度从2 token/s拉到4 token/s左右提升明显但当时首token延迟仍然很高主要卡在PreFill阶段没有利用上NPU。第三步把支持的算子尽量切到NPU执行然后调整线程数。这一步收益很大生成速度直接到7 token/s首token延迟降到900ms。但设备发热明显跑了十分钟后频率下降速度又掉回5 token/s。第四步限制NPU/CPU最高频率打开功耗模式同时把最大上下文长度从4096调整到2048减少K/V cache占用。最终的数字是生成速度稳定在10 token/s首token延迟约400ms峰值内存占用约4.3GB平均功耗控制在4W以内。对我来说这个结果已经跨过了“可用”门槛。每次改动之后我都会跑一组固定测试集记录输出质量和性能数据而不是凭感觉做判断。如果没有这套数据记录你很难说清楚是哪一步优化真正起了作用。4.3 端侧部署常见问题速查表做端侧部署会遇到很多细碎问题我把最常见的几个列出来方便大家排查现象可能原因排查方向与解法模型加载很慢大文件从存储读入没有做内存映射或缓存改用内存映射方式加载权重或把模型文件放到更快存储分区输出乱码/胡言乱语量化校准集不合适、量化精度太低、tokenizer配置错误换校准集检查tokenizer敏感层回退FP16内存溢出OOM没有限制K/V cache、激活值峰值过大、内存碎片严重设置最大上下文长度预分配KV缓存使用内存池设备发热严重线程绑核过多、CPU频率没有限制限制大核频率减少线程数开启功耗模式NPU算子不支持模型里有冷门算子引擎未适配改写/替换为等价通用算子或回退CPU并接受性能下降首次推理特别慢引擎在做初始化算子编译/加载尚未完成启动时做预热推理把初始化耗时挪到用户感知之前长对话越跑越卡历史消息导致K/V cache增长触发反复分配或超限控制上下文长度用滑动窗口丢弃早期token5. 工程化打磨模型管理、隐私保护和更新机制5.1 模型动态加载与热切换把模型跑通之后更考验人的是上线环节。端侧App不能每次都靠发版更新模型尤其模型文件动辄几百MB甚至几GB必须建立一套模型管理机制。我的做法是把模型文件拆成“引导模型”和“完整模型”两级。用户首次安装只携带一个最小的引导模型等真正需要使用大模型功能时再做后台下载。下载要支持断点续传和完整性校验。大文件传输很容易因为弱网中断如果没有断点续传用户每中断一次就要重新下几GB体验极差。完整性校验也很关键用哈希校验确保模型文件和服务器发布的版本一致避免文件损坏导致推理结果异常。模型热切换则要解决内存占用问题。如果旧模型还在内存里直接加载新模型内存会瞬间翻倍很容易OOM。正确顺序应该是先加载新模型到临时区然后做模型切换释放旧模型。加载新模型期间不要让用户触发推理请求可以通过消息队列把请求挂起等切换完成后再处理。5.2 端侧部署带来的隐私红利与安全挑战端侧部署最大的吸引力除了省流量和低延迟就是隐私。用户的输入和模型的输出都不需要离开设备这直接避免了把聊天数据送到云端带来的合规风险。在面向企业客户的项目里这个卖点甚至比性能更重要。但模型文件放进端侧之后也面临被提取的风险。模型权重是投入了大量训练资源得到的资产不能随随便便被扒走。我的做法是给模型文件做加密封装推理引擎在加载时先解密再映射到内存。加密会增加启动耗时但可以接受毕竟比起模型泄露还是值得的。这里也要提醒大家端侧模型本身的输出安全性也需要做一层保障。模型能力再强如果被输入一些恶意构造的内容也可能产生不合规的回答。常规做法是在模型前后各加一道轻量的内容过滤前端过滤危险输入后端过滤不合规输出。不要图方便省掉这步否则上线后可能被各种意外输入打得措手不及。5.3 版本管理与回滚机制模型上线后一旦发现问题版本必须能快速回滚。我习惯在模型文件名里带版本号并在配置中心记录当前线上使用的版本。如果新模型在真实数据上表现不佳通过配置中心一键切回旧版本不需要用户重新下载大文件因为设备上会长期保留最近两个版本。清理策略也很重要只保留当前版本和上一个版本更老的模型要自动清理避免设备存储被版本堆满。这个听起来简单但如果不做时间长了会发现设备空间被一堆旧模型残骸占光用户开始卸载App。写在最后的一个实用技巧如果大家正准备做端侧大模型部署我强烈建议从第一天就建立性能基线表把每次改动记录成一条日志。不要只在出问题时才想到去看数据。我采用的方式是每次调整模型、引擎参数、线程数、量化策略之后都跑同一组测试集记录首token延迟、生成速度、内存峰值、平均功耗四个指标。哪怕只是调整了一个缓存大小的参数也要记录。这招在项目后期帮了我大忙很多“改了也看不出变化”的改动最后都是靠历史日志复盘才有结论。最后再分享一个小技巧端侧推理引擎的首次调用往往会做大量初始化包括算子编译、内存池预分配、模型加载。所以正式测性能之前一定要先做一次“预热推理”让模型先生成几个token再开始计时。不预热的话你会把初始化的几百毫秒算进首token延迟里然后被误导去优化一个根本不是真实瓶颈的方向。预热之后再测数字才代表用户在正常使用时的真实感受。端侧大模型部署这件事本质上就是不断和“硬件资源有限”这一现实做博弈。只要把每一步的选择依据吃透哪怕手头设备很普通也有机会把模型调到一个可用的状态。希望这篇实战记录能帮你少走一些弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑