把大模型塞进手机:一份端侧LLM部署全流程
2026-10-13 05:00:00  腾讯   [查看原文]

ON-DEVICE LLM · 端侧部署全流程

手机上真正跑得动的,从来不是你在云端用的那个模型。-- 从选型、压缩、装箱,到编译、集成、调优的完整链路拆解。

把 LLM 部署到手机,本质是一场资源预算的博弈:你只有几 GB 可用内存、几十 GB/s 的内存带宽、几瓦的功耗预算,却要塞进一个参数量以十亿计的模型。好消息是这件事已经不需要自研推理框架 —— llama.cpp、MLC-LLM、MNN-LLM、ExecuTorch、LiteRT-LM 已经把最脏的工程活干完了。坏消息是选错路线,你会在「内存不足 → 被杀进程 → 速度只有个位数 → 跑一分钟就掉速」里反复挣扎。

这篇不推销任何单一框架,而是把链路拆成六步:选型 → 压缩 → 转换 → 编译 → 集成 → 调优。每一步都给出可执行的命令、能直接抄的参数,以及判断「这一步做没做对」的验收标准。

量化 PTQ / QATGGUFKV Cache内存带宽墙llama.cppMLC-LLMMNN-LLMExecuTorch + QNNLiteRT-LM

目标读者

想在 App 里跑本地 LLM 的开发者

前置知识

会 Python 与命令行,了解 Transformer 大致结构

硬件前提

一台开发机 + 一台 arm64 真机(≥ 8GB 内存更好)

读完收获

在真机跑通 1–4B 本地模型,并知道下一步往哪优化

目录

01

四道墙:端侧推理的物理约束06

选引擎:五大运行时横评02

六步流水线:全局地图07

动手:三条可复制的路线03

选型:什么模型配进手机08

榨干 NPU:QNN 与 ExecuTorch04

压缩:量化、蒸馏与剪枝09

上架前:工程细节清单05

装箱:内存预算怎么算10

数据、坑与资源清单

01四道墙:端侧推理的物理约束

这一章回答:为什么「手机上跑 7B」听起来很近,做起来却处处碰壁?

先把结论放前面:端侧推理的瓶颈,和你熟悉的任何 ML 部署都不一样。云端你关心 FLOPs 和显存,端侧你要同时对付四个互相拉扯的物理约束 —— 内存容量、内存带宽、算力、功耗与散热。

内存容量。模型权重必须整体常驻 RAM。Android 对单个 App 的内存上限通常只有 4–8GB(即便手机标称 12GB / 16GB),一旦越界,进程会被 LMKD 直接杀掉,用户看到的现象是「App 莫名闪退」。

内存带宽。自回归解码一次只吐一个 token,而每生成一个 token,都必须把全量权重从 DRAM 完整读一遍。这一步的算术强度极低 —— 每个权重只参与约 2 次浮点运算,算力单元大部分时间在等内存。于是解码速度的上限可以直接写成一句话:

解码速度天花板

解码速度上限 ≈ 内存带宽 ÷ 每 token 读取字节数一部带宽 60 GB/s 的旗舰机跑 3.5GB 的 INT4 模型,理论上限就是 60 ÷ 3.5 ≈ 17 tok/s —— 不管 NPU 标着多少 TOPS。

算力。反直觉的是,算力通常不是瓶颈。1B 模型在 INT4 下生成一个 token 只需要约 2 GFLOPs,任何一颗现代 NPU 都绰绰有余。真正吃算力的是 Prefill 阶段 —— 你一次性丢进去两千个 token 的长文档时,很短时间里要做大量矩阵乘法,这才是 NPU 算力真正起作用的地方。

同一颗芯片,为什么提速感觉不一致?

Prefill 是计算密集型,Decode 是访存密集型。把计算从 CPU 挪到 GPU / NPU,对「首字延迟」的改善远大于对「出字速度」的改善。所以你会看到「开了 NPU 首字快了 3 倍,但每秒出字只快了两成」这种看似矛盾的结果。

功耗与散热。手机是被动散热。持续推理时 SoC 功耗可以到 5–10W 量级,大约 90 秒后就开始热降频,NPU 时钟可能掉三成以上。实验室里测到的峰值 TOPS,要按 5–6 折来预估持续性能。

图 1端侧 LLM 的四道墙四者互相牵制:降量化档位救容量,却未必救速度;上 NPU 救首字,却压不住热。

图 2解码速度被带宽锁死带宽 ÷ 读取量就是硬上限,真机还要再打七折。

02六步流水线:全局地图

这一章回答:从 Hugging Face 上的一个仓库,到手机上点开就聊的 App,中间要做哪些事?

整条链路可以拆成六步,前三步在 PC 上完成,后两步回到手机上。每一步都有明确的输入、输出和验收标准 —— 卡住的时候,先确认上一步的产物是不是真的合格。

图 3端侧 LLM 的六步流水线前三步是「离线加工」,编译产物跨设备 adb push 之后,才进入 App 集成与调优。

表 1六步流水线的输入输出与验收标准

步骤输入输出验收标准01 选型

使用场景(中文 / 英文 / 推理 / 多模态)一个 0.5–4B 的候选模型Q4 权重体积 ≤ 3GB02 压缩原始权重(FP16 / BF16)INT4 / INT8 量化权重体积降 4×,PPL 增量 2 字节 ; q8_0 -> 1 字节# 乘 2 是因为 Key / Value 两份

注意 kv_heads 是 KV 头数,不是注意力头数。现代模型大多用了 GQA,所以这个数字比 query 头数小得多。以 Llama 3 8B 为例:32 层、8 个 KV 头、head_dim 128、fp16,代入就是每个 token 128KB。

把上下文长度代进去:8K → 1.0GB,32K → 4.0GB,128K → 16GB。一个 8B 的 Q4 模型权重才 4.3GB,但在 128K 上下文下你需要 16GB 的 KV Cache,是权重的三倍多。这就是「模型能加载,上下文一拉长就 OOM」的全部真相。

图 6KV Cache 随上下文线性增长到 32K 时它已经超过模型权重本身,成为内存账单上的第一大户。三把缰绳

第一把是 KV 缓存量化。把 K / V 从 fp16 降到 q8,内存直接减半,质量损失几乎不可感知 —— 在 llama.cpp 里就是两个参数的事。

把 KV 缓存量化到 q8

llama-server \  -m model-q4_k_m.gguf \  --ctx-size 32768 \  --cache-type-k q8_0 \  --cache-type-v q8_0

第二把是 显式限制上下文。手机上从 -c 4096 起步,不要照抄模型卡上的 128K —— 那是在数据中心硬件的预算下写的。第三把是优先选 KV 头少(GQA 充分)的模型,这是架构层面就省下来的钱。

更省的两条路

滑动窗口注意力只保留最近 N 个 token 的 KV;KV Cache 驱逐(eviction)策略则按重要性保留历史。两者都能把长对话的内存从线性压成近似常数,代价是实现复杂度上升,且需要针对你的任务做验证。

06选引擎:五大运行时横评

这一章回答:llama.cpp、MLC-LLM、MNN-LLM、ExecuTorch、LiteRT-LM,到底选哪个?

五个引擎的核心差异不在「谁更快」,而在两件事的取舍:模型格式的生态广度,和目标硬件的覆盖深度。你不可能同时拿满这两头,所以第一步是先确定你的设备分布。

表 4五大端侧推理运行时对比

运行时模型格式主要后端一句话优势主要代价llama.cppGGUF

CPU / Vulkan / Metal / QNN生态最大,什么模型都能跑NPU 支持仍在演进MLC-LLMMLC 权重 + .so

Metal / Vulkan / CUDAAOT 编译,同芯片快 1.5–2×每个模型都要重编译MNN-LLM.mnn

CPU / OpenCL / NNAPICPU 与中文优化强,App 现成生态偏阿里系ExecuTorch.pte

XNNPACK / CoreML / Vulkan / QNN

PyTorch 原生,NPU 性能最好QNN 需 Linux + SDKLiteRT-LM.task / .litertlmCPU / GPU / NPU

Google 官方,Gemma 系开箱即用可支持的模型面窄

← 左右滑动查看完整表格 →

MLC-LLM 走的是 AOT(预先编译)路线:它在编译时针对目标设备生成 Metal / Vulkan 着色器,做算子融合与共享内存优化,因此同一颗芯片上通常比 llama.cpp 快 1.5–2 倍。代价是每换一个模型、每换一类设备都要重新编译一次。

llama.cpp 则是运行时解释 GGUF 计算图,牺牲一点峰值性能换来极大的灵活性 —— 社区里几万个现成 GGUF 模型开箱即用,这是它成为事实标准的根本原因。

ExecuTorch 是 PyTorch 官方路线,优势是不需要做 ONNX 式的格式体操,而 QNN delegate 在骁龙 NPU 上性能最强。但请注意一个硬条件:pip 安装的 ExecuTorch wheel 不包含 QNN 的 AOT 库,想用 QNN 必须从源码构建,并在 x86_64 Linux(或 WSL)上配合高通 QNN SDK。

如果主力是 iOS 或 Apple 芯片

Apple 系直接用 Core ML + MLX。MLX 是 Apple 官方的数组框架,在 Apple Silicon 上通常是最省电、最省心的选择;在 iOS App 里走 Core ML 则能直通 Neural Engine。

图 7运行时选型决策树先看模型来源,再看目标芯片。两条都定了,答案通常只剩一个。

07动手:三条可复制的路线

这一章回答:如果今天就要跑通,最短路径是什么?路线 A:llama.cpp —— 通用、最省心

前两步在你的开发机上完成:把 HF 权重转成 GGUF,再量化到 Q4_K_M。

① 转换与量化

# 1. 转换:HF 权重 -> GGUF(FP16)python convert_hf_to_gguf.py \  ./Qwen3-4B \  --outfile qwen-f16.gguf# 2. 量化:Q4_K_Mllama-quantize qwen-f16.gguf \  qwen-q4km.gguf Q4_K_M

第三步先在主机上验证质量与速度,确认模型本身没问题,再往下走。

② 主机验证

# 3. 本机先跑通,确认质量与速度llama-cli -m qwen-q4km.gguf \  -c 2048 -n 128 -t 8 \  -p "用一句话介绍端侧推理"

第四步是用 Android NDK 交叉编译出 arm64-v8a 的原生库。注意开头那四个 -D…=OFF 都是必需的,不是可选项。

③ NDK 交叉编译

# $TC = $NDK/.../android.toolchain.cmakecmake \  -DCMAKE_TOOLCHAIN_FILE=$TC \  -DANDROID_ABI=arm64-v8a \  -DANDROID_PLATFORM=android-28 \  -DGGML_NATIVE=OFF \  -DGGML_OPENMP=OFF \  -DGGML_LLAMAFILE=OFF \  -DLLAMA_OPENSSL=OFF \  -B build-androidcmake --build build-android \  --config Release -j8

那四个 OFF 各自的原因

GGML_NATIVE=OFF:交叉编译时宿主机 CPU 不是目标 CPU,native 探测会得出错误结论。GGML_OPENMP=OFF:NDK 的 OpenMP 需要 CMake 作为依赖安装,目前不支持。GGML_LLAMAFILE=OFF:llamafile 后端不支持 Android。LLAMA_OPENSSL=OFF:OpenSSL 不在 NDK 的稳定原生 API 集合里,而这个选项默认是 ON 的。

第五步 push 到真机。Android 不会自动找到库目录,所以要显式给 LD_LIBRARY_PATH。

④ 部署到手机并跑通

adb shell "mkdir -p /data/local/tmp/llm"adb push build-android/bin /data/local/tmpadb push qwen-q4km.gguf /data/local/tmpadb shellcd /data/local/tmpLD_LIBRARY_PATH=lib ./bin/llama-cli \  -m qwen-q4km.gguf -c 1024 -t 4路线 B:MLC-LLM —— 同一颗芯片上更快

MLC-LLM:转换、配模板、AOT 编译

pip install mlc-llmmlc_llm convert_weight ./Qwen3-4B \  --quantization q4f16_1 -o weights/mlc_llm gen_config ./Qwen3-4B \  --quantization q4f16_1 \  --conv-template qwen -o cfg/mlc_llm compile \  cfg/mlc-chat-config.json \  --device android -o dist/lib.so

把生成的 .so 与 weights 目录一起放进官方 MLCChat App,或按官方 Kotlin SDK 集成。它的 API 刻意做成 OpenAI Chat Completions 的形状,engine.chat.completions.create(...) 直接可用,迁移成本很低。路线 C:MNN-LLM —— 中文与 CPU 友好

MNN-LLM:编译原生库并装到真机

git clone https://github.com/alibaba/MNN.gitcd MNN/project/androidmkdir build_64 && cd build_64../build_64.sh "-DMNN_BUILD_LLM=true \  -DMNN_SUPPORT_TRANSFORMER_FUSE=true \  -DMNN_ARM82=true -DMNN_LOW_MEMORY=true"# $JNI = ../apps/MnnLlmApp/.../jniLibsfind . -name "*.so" | \  xargs -I{} cp {} $JNI/arm64-v8a/cd ../apps/MnnLlmApp./gradlew installDebug

MNN-LLM 的招牌是 CPU 上的 Prefill 速度 —— 官方 benchmark 里比 llama.cpp 快 8.6 倍,解码快 2.3 倍;同时它对 Qwen、ChatGLM 等中文模型有专项优化,并且自带一个可用的多模态 App(MnnLlmChat),可以直接拿来做对照实验。

三条路线怎么选

要覆盖尽可能多的机型、想用现成的社区 GGUF,走 A。要在特定芯片上榨出最高吞吐、且能接受「一个模型编译一次」,走 B。中文场景 + 想把 CPU 也压到极限 + 需要现成 App 做基线,走 C。

图 8llama.cpp 的完整落地路径左边四步在开发机完成,右边三步在设备上完成,中间的 adb push 是分界线。

08榨干 NPU:QNN、ExecuTorch 与 LiteRT-LM

这一章回答:什么时候值得为 NPU 多付出一整套工具链的代价?

先说一个反直觉的事实:NPU 对解码速度的提升,远小于对首字延迟的提升。原因是前面讲的带宽墙 —— 解码阶段卡住你的是把权重从内存搬到计算单元,而 NPU 并不会让内存变快(除非它带独立的片上存储)。所以短对话、长回答的场景,NPU 收益有限;长文档、一次灌几千 token 的场景,NPU 的算力才会真正兑现。

表 5主流移动平台的端侧 LLM 能力

平台NPU内存带宽端侧 LLM 关键点骁龙 8 Elite Gen 5

Hexagon(约 75–100 TOPS)

LPDDR5X ≈ 84.8 GB/s

原生 INT2 / FP8,13B INT4 可实用天玑 9500

NPU 990(约 100 TOPS)

LPDDR5X ≈ 85.3 GB/s

硬件 Transformer 引擎 + Compute-in-MemoryApple A 系

Neural Engine(未公开 TOPS)统一内存架构

Core ML / MLX 直通,片上 32MB SRAM 缓存中端(7 系 / 天玑 8 系)10–30 TOPS30–50 GB/s

现实目标 1–2B Q4,别硬上 4B

← 左右滑动查看完整表格 →

TOPS 是会骗人的数字

不同厂商、不同精度下的 TOPS 不可直接比较,而且它几乎不能预测你的 tok/s。判断一块芯片适不适合跑 LLM,先看内存带宽与 LPDDR 配置,再看 NPU。ExecuTorch + QNN:骁龙上的最快路径

这条路的入场券比较硬:x86_64 Linux 主机(或 WSL)、高通 QNN SDK、Android NDK,而且必须从源码构建 —— 因为 pip wheel 不含 QNN 的 AOT 库。

准备 QNN 工具链(Linux / WSL)

export QNN_SDK_ROOT=$HOME/qairt/2.37.0export ANDROID_NDK_ROOT=$HOME/ndkgit clone --recurse-submodules \  https://github.com/pytorch/executorchcd executorch./install_executorch.sh./backends/qualcomm/scripts/build.sh# 读出目标 SoC,导出时必须一致adb shell getprop ro.soc.model

芯片型号到 QNN 的映射必须精确:骁龙 8 Gen 3 是 SM8650 / Hexagon v75,8 Elite 是 SM8750 / v79。导出时用错 SoC,轻则编译失败,重则跑得起来但完全用不上加速。

导出侧的核心是三步:torchao 上 int4 权重量化 → to_edge 降到 Edge dialect → to_backend(QnnBackend) 委托给 NPU,最后序列化成 .pte。对 LLM 建议只做 weight-only 的 int4 —— 激活量化在生成任务上收益小、风险大。LiteRT-LM / MediaPipe:最省事的一条

如果模型就在 Gemma 系里,这条路几乎没有工程成本:拿官方 4-bit 量化模型,推给设备,几行 Kotlin 就能出结果。

依赖(当前版本 0.10.27)

implementation(  'com.google.mediapipe:tasks-genai')

初始化并流式生成

val opts = LlmInferenceOptions.builder()  .setModelPath("/data/local/tmp/m.task")  .setMaxTopK(64)  .build()val llm = LlmInference  .createFromOptions(ctx, opts)// 流式输出llm.generateResponseAsync(prompt)

注意一个变化:Google 已把 MediaPipe LLM Inference API 转为维护模式,官方建议迁移到 LiteRT-LM。AI Edge Gallery 里有现成的 Gemma 3n 多模态示例(文本 / 图像 / 音频),是抄作业的最佳起点。

图 9同一颗芯片上各后端的解码速度QNN 走 NPU 最快,但 llama.cpp 的 Vulkan 已经能覆盖绝大多数机型。

09上架前:工程细节清单

这一章回答:Demo 跑通之后,还有哪些坑会让它在真机上翻车?ABI 只留 64 位

最常见的「dlopen 失败」来自 jniLibs 里混进了 32 位的 .so。64 位进程无法加载 32 位库,而 Android 在 arm64 设备上会优先尝试加载 armeabi-v7a —— 于是库明明在,就是加载不上。

build.gradle 里显式声明 ABI

android {  defaultConfig {    ndk { abiFilters 'arm64-v8a' }  }}

做法是彻底删掉 armeabi-v7a / x86 / x86_64 目录,只保留 arm64-v8a。同时 -DANDROID_ABI=arm64-v8a 要作为 CMake 靠前的参数传入,否则后续的 -march=armv8-a+crypto+simd 之类优化可能被静默忽略。另外 -DANDROID_PLATFORM 建议 ≥ android-28:早期 API 在高负载下 clock_gettime 可能返回负值,导致推理计时错乱。内存:mmap、常驻与分级

用 mmap 加载权重(llama.cpp 里 no_alloc 的那条路径)让系统按页调入,比一次性 malloc 更快也更省 —— 实测首字延迟能省几百毫秒,而且在内存压力下更容易被系统回收,而不是被直接杀掉。

如果担心 Android 在后台清掉你的进程,真正稳的做法是分级:一个 0.5–1B 的小模型常驻提供即时响应,大模型只在用户明确触发时加载。这比试图把一个 4B 模型长期钉在内存里现实得多 —— 系统的 LMKD 在压力下不会因为你的 App 优先级高就手下留情。流式、热与下载

三件事必须在设计阶段就定下来。流式输出:不要等整段生成完再上屏,逐 token 推送是体验的分水岭。热管理:给出降级策略,检测到设备温度升高时增大 token 间隔或缩短单次输出,而不是等系统来 kill 你。模型下发:模型文件动辄 0.5–3GB,不要打进安装包,用后台下载 + 断点续传 + 明确的体积提示。

一句话

用户能容忍 1GB 的下载,但容忍不了「不知道在下载什么」。

10数据、坑与资源清单

这一章回答:真出问题时,怎么快速定位?

表 6端侧 LLM 常见故障速查

症状最可能原因处置加载即崩 / 被系统杀掉权重 + KV 超过可用内存

换更小档位;-c 降到 1024;KV 量化到 q8首字要等很久

Prefill 是算力瓶颈,没走 GPU / NPU

开 -ngl 99;或切 NNAPI / QNN 后端速度只有个位数 tok/s内存带宽已经到顶降量化档位;堆线程无效聊几句就变慢

上下文变长,KV Cache 与读取量增大限制 -c;裁剪历史;KV 缓存量化跑一分钟就掉速热降频分片生成;缩短单次输出;接受峰值折损没被前台操作却卡顿推理跑在主线程移到后台协程 / 独立线程池找不到 libllama.so

jniLibs 混入了 32 位 ABI

只留 arm64-v8a,abiFilters 显式声明

← 左右滑动查看完整表格 →几个容易被忽略的数字

一个粗略的选型经验:中端与旗舰手机在 4-bit 下跑 4B 级模型是舒适的;旗舰机可以在 sub-4bit 下勉强跑 7–8B;再往上,你需要的不是更强的 NPU,而是一台内存更大的设备。另外,人类阅读速度约为每秒 4–5 个 token,所以任何能稳定跑到这个数字以上的本地模型,用起来就已经「跟得上」了。

表 7继续深入的资源清单

项目适合拿来做什么llama.cpp

GGUF 生态与 Android 构建文档,覆盖面最广MLC-LLM

AOT 编译路线,官方 Kotlin / Swift SDKMNN-LLM

中文与 CPU 优化,多模态 App 现成ExecuTorch

PyTorch 官方,QNN / CoreML / Vulkan 后端LiteRT-LM

Google 官方,Gemma 系最省事的落地路径GGUF 量化指南各档位体积与困惑度的权威对照

最后一句话

端侧 LLM 的工程本质,是把「模型能力」和「设备预算」做一次精确对齐。记住三条主线 —— 选一个不过 4GB 的模型、把上下文和 KV 缓存管住、在真机上而不是在纸上做 benchmark —— 大部分翻车都能提前避免。

OCR:IMG:浅色=区间上限,深色=常见中位值 ExecuTorch 18-25 QNN·NPU MNN-LLM 10-18 NNAPI·NPU llama.cpp 8-14 Vulkan·GPU ExecuTorch 6-10 XNNPACK·CPU llama.cpp 4-8 CPU·NEON Snapdragon8Elite·Llama3.21B·INT4社区实测区间

OCR:IMG:决策起点:模型从哪来?主要跑在什么芯片上? PyTorch原生模型 ExecuTorch+QNNdelegate 晓龙旗舰为主 NPU上最快,运行时体积最小 已有GGUF权重 llama.cpp (Vulkan/CPU) ↓ 要求覆盖全部机型 生态最大、机型覆盖最广 中文场景/阿里系 MNN-LLM CPU也要够快 Prefill快、中文优化好、App现成 只跑Gemma系列 LiteRT-LM(原MediaPipe) 想要最省事 官方模型开箱即用 iOs为主 CoreML+MLX ↓ Apple芯片 直通NeuralEngine最省 通Neurae公众号·深度学习之凡人修仙

OCR:IMG:浅色=区间上限,深色=常见中位值 ExecuTorch 18-25 QNN·NPU MNN-LLM 10-18 NNAPI·NPU llama.cpp 8-14 Vulkan·GPU ExecuTorch 6-10 XNNPACK·CPU llama.cpp 4-8 CPU·NEON 公众号·深度学习之凡人修仙 Snapdragon8Elite·Llama3.21B·INT4·社区实测区间

OCR:IMG:内存容量墙 带宽墙 权重必须整体常驻内存 每生成一个token,都要 Android给单App的上限 把全量权重读一遍 常只有4-8GB,大一点就OOM 速度上限=带宽÷权重字节数 功耗墙 热墙 持续推理SoC功耗5-10W 满负载约90秒开始降频 手机电池与被动散热 NPU时钟可能掉三成以上 撑不住长时间对话 峰值TOPS要按5-6折预估

OCR:IMG:7B模型在不同量化档位下的体积与困惑度增量 F16 14.0GB PPL基准 Q8_0 8.0GB PPL+0.003 Q6_K 5.8GB PPL+0.02 Q5_K_M 5.0GB PPL+0.06 Q4_K_M 4.3GB PPL+0.18 IQ4_XS 4.0GB Q4_KM Q3_K_M 3.5GB PPL+0.66 Q2_K 2.8GB PPL+3.52

OCR:IMG:PC/服务器侧 手机/App侧 装依赖 push到设备临时目录 pip install -r requirements.txt adb push lib/data/local/tmp adb ②HF→GGUF(FP16) 先在命令行跑通 push convert_hf_to_gguf.py LD LIBRARY PATH=lib ./llama-cli ③量化到Q4_K_M ①再集成进App 1lama-quantize.Q4_KM JNI →Module /LlamaEngine ④NDK交叉编译1ibllama.so

OCR:IMG:内存容量墙 带宽墙 权重必须整体常驻内存 每生成一个token,都要 Android给单App的上限 把全量权重读一遍 常只有4-8GB,大一点就OOM 速度上限=带宽权重字节数 功耗墙 热墙 持续推理SoC功耗5-10W 满负载约90秒开始降频 手机电池与被动散热 NPU时钟可能掉三成以上 撑不住长时间对话 峰值TOPS要按5-6折预估 ·公众号·深度学习之凡人修仙

OCR:IMG:N-DEVICELLM·端侧部署全流程 选型、压缩、转换,到编译、集成、调 H

OCR:IMG:横条=解码速度(tok/s) 右侧=Q4权重体积 Qwen3-0.6B 70 0.4GB R1-Distill-1.5B 55 0.9GB Qwen3-1.7B 50 1.0GB Phi-4-mini-3.8B 40 2.0GB Qwen3-4B 35 2.3GB Gemma-3-4B 32 2.4GB Qwen3-7B 18 4.2GB ≤1GB:轻量首选2-2.4GB:甜点位 4GB+:旗舰勉强

OCR:IMG:PC/服务器侧 手机侧 01 02 03 04 05 06 选型 压缩 转换 编译 集成 调优 2-4B模型 Q4KM量化 GGUF/.pte NDK交叉编译 JNI+Kotlin NPU+KV预算 公众号·深度学之凡人修仙

OCR:IMG:横条=解码速度(tok/s) 右侧=Q4权重体积 Qwen3-0.6B 70 0.4GB R1-Distill-1.5B 55 0.9GB Qwen3-1.7B 50 1.0GB Phi-4-mini-3.8B 40 2.0GB Qwen3-4B 35 2.3GB Gemma-3-4B 32 2.4GB Qwen3-7B 18 4.2GB ≤1GB:轻量首选2-2.4GB:甜点位 4GB+:旗舰勉强 公众号·深度学习之凡人修仙

OCR:IMG:7B模型在不同量化档位下的体积与困惑度增量 F16 14.0GB PPL基准 Q8_0 8.0GB PPL+0.003 Q6_K 5.8GB PPL+0.02 Q5_K_M 5.0GB PPL+0.06 Q4_K_M 4.3GB PPL+0.18 IQ4_XS 4.0GB Q4_K_M Q3_K_M 3.5GB PPL+0.66 Q2_K 2.8GB PPL+3.52 公众号·深度学习芝人修仙

OCR:IMG:PC/服务器侧 手机/App侧 装依赖 push到设备临时目录 pip install -r requirements.txt adb push 1ib/data/local/tmp adb ②HF→GGUF(FP16) 先在命令行跑通 push convert_hf_to_gguf.py LD LIBRARY PATH=lib ./llama-cli ③量化到Q4_K_M ①再集成进ApP 1lama-quantize.Q4_KM JNI →Module/LlamaEngine ④NDK交叉编译1ibllama.so 公众号·深度学习之凡人修仙

OCR:IMG:内存带宽 每token读取 解码理论上限 小 = 84.8 GB/s ~3.5GB ~24tok/s 理论上限·24tok/s 真机常见·约15tok/s 差额来自KVCache读取、框架开销与热降步

OCR:IMG:PC/服务器侧 手机侧 01 02 03 04 05 06 选型 压缩 转换 编译 集成 调优 2-4B模型 Q4KM量化 GGUF/.pte NDK交叉编译 JNI+Kotlin NPU+KV预算 adb bpush

OCR:IMG:浅色=区间上限,深色=常见中位值 ExecuTorch 18-25 QNN·NPU MNN-LLM 10-18 NNAPI·NPU llama.cpp 8-14 Vulkan·GPU ExecuTorch 6-10 XNNPACK·CPU llama.cpp 4-8 CPU·NEON Snapdragon8Elite·Llama3.21B·INT4·社区实测区间

OCR:IMG:Qwen3-4B·8K上下文示例·fp16KV缓存 模型权重2.6GB 2K上下文 0.29GB 4K上下文 0.58GB 8K上下文 1.15GB 16K上下文 2.30GB 一 32K上下文 4.61GB 一 上下文翻倍,KVCache就翻倍;32K时它已经超过权重本身。 把KV缓存量化到q8可以再砍一半,是端侧最划算的一刀。

OCR:IMG:PC/服务器侧 手机/App侧 ①装依赖 push到设备临时目录 pip install -r requirements.txt adbpushlib/data/local/tmp ②HF→GGUF(FP16) adb 先在命令行跑通 push convert_hf_to_gguf.py LD LIBRARY PATH=lib./1lama-c1i ③量化到Q4_K_M 再集成进App 1lama-quantize.Q4KM JNI→Module/LlamaEngine @NDK交叉编译1ibllama.so

OCR:IMG:内存带宽 每token读取 解码理论上限 小 = 84.8 GB/s ~3.5GB ~24tok/s 理论上限·24tok/s 真机常见·约15tok/s 公众号·深度学习之凡人修仙 差额来自KVCache读取、框架开销与热降步

OCR:IMG:内存带宽 每token读取 解码理论上限 小 = 84.8GB/s ~3.5GB 24tok/s 理论上限·24tok/s 真机常见·约15tok/s 差额来自KVCache读取、框架开销与热降步

OCR:IMG:决策起点:模型从哪来?主要跑在什么芯片上? PyTorch原生模型 ExecuTorch+QNNdelegate 晓龙旗舰为主 NPU上最快,运行时体积最小 已有GGUF权重 llama.cpp (Vulkan/CPU) → 要求覆盖全部机型 生态最大、机型覆盖最广 中文场景/阿里系 MNN-LLM CPU也要够快 Prefill快、中文优化好、App现成 只跑Gemma系列 LiteRT-LM(原MediaPipe) 想要最省事 官方模型开箱即用 ios为主 CoreML+MLX ↓ Apple芯片 直通NeuralEngine,最省电

OCR:IMG:7B模型在不同量化档位下的体积与困惑度增量 F16 14.0GB PPL基准 Q8_0 8.0GB PPL+0.003 Q6_K 5.8GB PPL+0.02 Q5_K_M 5.0GB PPL+0.06 Q4_K_M 4.3GB PPL+0.18 IQ4_XS 4.0GB Q4_K_M Q3_K_M 3.5GB PPL+0.66 Q2_K 2.8GB PPL+3.52

OCR:IMG:横条=解码速度(tok/s) 右侧=Q4权重体积 Qwen3-0.6B 70 0.4GB R1-Distill-1.5B 55 0.9GB Qwen3-1.7B 50 1.0GB Phi-4-mini-3.8B 40 2.0GB Qwen3-4B 35 2.3GB Gemma-3-4B 32 2.4GB Qwen3-7B 18 4.2GB ≤1GB:轻量首选2-2.4GB:甜点位 4GB+:旗舰勉强

OCR:IMG:PC/服务器侧 手机侧 01 02 03 04 05 06 选型 压缩 转换 编译 集成 调优 2-4B模型 Q4KM量化 GGUF/.pte NDK交叉编译 JNI+Kotlin NPU+KV预算 adb push

OCR:IMG:内存容量墙 带宽墙 权重必须整体常驻内存 每生成一个token,都要 Android给单App的上限 把全量权重读一遍 常只有4-8GB,大一点就OOM 速度上限=带宽÷权重字节数 功耗墙 热墙 持续推理SoC功耗5-10W 满负载约90秒开始降频 手机电池与被动散热 NPU时钟可能掉三成以上 撑不住长时间对话 峰值TOPS要按5-6折预估

OCR:IMG:决策起点:模型从哪来?主要跑在什么芯片上? PyTorch原生模型 ExecuTorch+QNNdelegate 晓龙旗舰为主 NPU上最快,运行时体积最小 已有GGUF权重 llama.cpp (Vulkan/CPU) ↓ 要求覆盖全部机型 生态最大、机型覆盖最广 中文场景/阿里系 MNN-LLM CPU也要够快 Prefill快、中文优化好、App现成 只跑Gemma系列 LiteRT-LM(原MediaPipe) 想要最省事 官方模型开箱即用 iOs为主 CoreML+MLX Apple芯片 直通NeuralEngine,最省电

OCR:IMG:Qwen3-4B·8K上下文示例·fp16KV缓存 模型权重2.6GB 2K上下文 0.29GB 4K上下文 0.58GB 8K上下文 1.15GB 16K上下文 2.30GB 32K上下文 4.61GB 一 上下文翻倍,KVCache就翻倍;32K时它已经超过权重本身。 把KV缓存量化到q8可以再砍一半,是端侧最划算的一刀。

OCR:IMG:Qwen3-4B·8K上下文示例·fp16KV缓存 模型权重2.6GB 2K上下文 0.29GB 4K上下文 0.58GB 8K上下文 1.15GB 16K上下文 2.30GB 32K上下文 4.61GB 一 上下文翻倍,KVCache就翻倍;32K时它已经超过权重本身。 把KV缓存量化到q8可以再砍一半,是端侧最划算的一刀。 公众号·深度学习之凡人修仙

本栏目中的所有页面均系自动生成,自动分类排列,采用联索网络信息采集、网页信息提取、语义计算等智能搜索技术。内容源于公开的媒体报道,包括但不限于新闻网站、电子报刊、行业门户、客户网站等。使用本栏目前必读