手机上跑扩散模型,难的不是算力,是内存和编译
天玑 9400 的 NPU 峰值在 2 TFLOPS 量级,算 2B 的 DiT 本来就够。 真正卡住的是三件事:权重放不下、图编译不出来、编出来的东西没法带给别人。 下面这三条是这个项目解决它们的方式。
直连 Neuron,不走通用推理框架
模型被导出成 .npug 计算图,由 MediaTek Neuron Adapter 在设备上编译成 MDLA 指令后直接执行。
没有 CPU 回退层,也没有 TFLite / ONNX 这类中间运行时。
28 层 DiT 被切成 4 张图分别编译执行,VAE 解码也在 NPU 上。文本编码器(Qwen3-0.6B + LLMAdapter)目前跑在 CPU,约 5 秒 —— 同一段提示词只算一次,连续出图不重复付。
W8A16:int8 权重 × int16 激活
直接量化会崩在两个地方:激活里的离群通道,和残差主干高达 44000× 的逐通道动态范围。 处理办法是 SmoothQuant 把离群迁到权重、主干改存缩放后的量、LayerNorm 全程在缩放域里算 —— 三项都折进权重和调制表,图里零额外算子。
结果是资产从 3.5 GB 降到 1.8 GB,而画质与 fp16 持平:同种子同提示词下高频占比 0.3482 对 0.3481。
预编译缓存跟着模型一起发
.npug 只是图的描述,真正的 NPU 指令要在你的机器上编译。冷编译实测 249 秒 一张图,四张就是 17 分钟,而且起跑要 6 GB 可用内存 —— 没 root 的人清不掉后台,基本必被系统杀掉。
所以每一档都把已经编好的产物一起下发,装载时直接命中,实测 510 ms。
五档,按分辨率和精度分
下面的耗时全部取自一台天玑 9400(MT6991 / PLC110 / Android 15)的运行日志, 口径是采样 + VAE 解码 + 存图,引擎已装载。有多次记录的给出区间。 步数是那几次实测用的值,不是限制 —— 每档都能在 6–12 之间调。
| 档位 | 精度 | 出图耗时 | 其中 NPU | 装载需要 | 下载量 |
|---|---|---|---|---|---|
| 512 × 512 | W8A16 | 6 步 9.4 s12 步 16.0 – 16.4 s | 8.6 s2.17 TFLOPS | 3.7 GB可用内存 | 3.3 GB+ 1.6 GB 缓存 |
| 576 × 1024 | W8A16 | 10 步 42.1 – 43.1 s12 步 49.7 – 50.1 s | 40.3 s1.78 TFLOPS | 4.0 GB | 3.3 GB+ 1.5 GB 缓存 |
| 768 × 768 | W8A16 | 同 576×1024共用同一套计算图,L 相同 | — | 4.0 GB | + 26 MB只多一张 VAE 和位置表 |
| 768 × 1024 | W8A16 | 6 步 42.0 – 42.6 s12 步 77.3 – 79.4 s | 39.2 s1.62 TFLOPS | 4.8 GB | 3.3 GB+ 1.7 GB 缓存 |
| 768 × 1024 | W8A8 | 12 步 70.5 – 72.6 s | 68.3 s1.74 TFLOPS | 3.9 GB | 3.3 GB+ 1.4 GB 缓存 |
← 表格可横向滑动 →
换一段新提示词,首张还要加约 5–6 秒的文本编码(跑在 CPU 上,同一提示词连续出图不重复付)。
首次进入某一档另有一次装载,实测 512² 在 9–82 秒之间,跨度几乎全来自当时的可用内存。
同一台机器上热状态是最大的变量:都是 512² 这一档,凉机跑出 2.33 TFLOPS,连跑几张热起来之后只有 1.80,所以上面给的是区间不是单点。
各档共用同一份 1.46 GB 的文本编码器权重和 VAE,只下一次;所以第一档约 3.3 GB,之后每加一档约 1.9 GB,全部下齐大约 14 GB。
「装载需要」指的是点开那一档时系统的可用内存 —— 不够会被拦下并提示清后台,不会跑到一半被系统杀掉。
768×1024 的两档是同一分辨率的两种取舍:W8A8 快约 10%、更省内存,但颜色断层和小物件细节的损失肉眼可见;W8A16 画质与 fp16 持平。
先确认你的芯片,再决定要不要下这 8 GB
「已验证」表示有人在这颗芯片的真机上完整跑通过。没列出来的联发科型号可以试 —— App 会现场编译,第一次装载慢一些,但跑得起来。这张表在 App 里是从云端拉的,会持续更新。
| 芯片 | 型号号 | 状态 | 说明 |
|---|---|---|---|
| 天玑 9400 / 9400+ | MT6991 | 已验证 | 开发与调优的基准机型,预编译缓存就是在它上面烧的 |
| 天玑 9500 | MT6993 | 已验证 | Neuron 9.x,需要走另一套运行时库;0.2.x 起已自动识别 |
| 天玑 9400+(平板) | MT8799 | 已验证 | 用户实测跑通 |
| 天玑 8300 / 8350 | MT6897 | 已验证 | 用户实测,全部计算图编译通过 |
| 天玑 8400 | MT6899 | 已验证 | 用户实测,并已上传该芯片的编译缓存 |
| 其它联发科天玑 | MT6xxx / MT8xxx | 可以试 | 图会在你的机器上现场编译。建议从 512² 那档开始 —— 它最小、最容易成功 |
| 高通 / 三星 / 海思 | — | 跑不了 | 整条链路依赖 MediaTek Neuron(APU / MDLA)接口,不是通用推理,装了也用不了 |
← 表格可横向滑动 →
装载失败时,对话框里有「复制错误详情」,内容包含芯片型号、机型、系统版本、档位、编到第几张图和错误原文。 把它发到群里就能判断这颗芯片是缺什么。设置页还有一个兼容性自检,会逐个探测这颗 NPU 能不能编出各类算子。
装 App,挑一档,点下载,出图
- 大小
- 20.3 MB
- 系统
- Android 12+
- 架构
- arm64-v8a
- 包名
- com.anima.npu
fea11c2ed2ea2e241fc72296bf4ed8cd99541c292d2b10b929a6052fe5ddb779
主源走魔搭(ModelScope),国内直连,实测单连接 18.8 MB/s。
想永远拿最新版可以直接用固定地址
…/models/anima.apk。
模型资产在 App 里下载,不用手动填地址。
-
装包
下载上面的 APK 并安装。系统提示「来源未知」时允许一次即可 —— 这个包是自签名的,不走应用商店。
-
挑一档
打开 App 进「模型库」。第一次建议选 512²:它最小、最快、内存门槛最低。顶部会显示你这颗芯片的适配状态。
-
下模型
点下载。第一档约 4.9 GB(模型 3.3 GB + 预编译缓存 1.6 GB),下载在后台进行,可以息屏。
-
出图
进画图工作台,写提示词,点生成。第一次要花几十秒把图搬进 NPU(缓存全部命中的情况下),之后连续出图不用重装。
这是测试版,不是正式版。
绝大部分调优和验证是在一台天玑 9400(ColorOS)上做的,其它机型的覆盖来自群里的反馈,一颗一颗加进来。 版本号还在 0.2.x,界面和档位都可能改。遇到装不上、跑不动、出图不对,把错误详情复制出来发群里 —— 这是目前推进适配最有效的方式。
更新日志
2026-08-29
已适配的芯片不再误报「没人验证过」
上一版没修干净:那段判断读的不是界面状态,云端信息拉回来之后界面根本不会刷新,于是永远停在「还没拉到」那一刻的结论上。现在拉到之前不下任何判断。
找到 rc=6 的真因:冷编译峰值是各图之和
决定性证据是同一台平板的对照 —— 自检逐张编、编完就放,五张图全过;真装载时 DiT 四张过、VAE 挂。同机、同图、同运行时,差别只有「编这张的时候还剩多少内存」。
装载因此改成两趟:先只编译并写缓存、每编完一张立刻整张放掉,第二趟才真装载。冷编峰值从各图之和降到单张最大值。
天玑 9500 跑通
目录扫描找到真凶:那台机器的 /system_ext/lib64 里有两个 adapter,我们一直加载的是不带版本号的兼容壳(报设备 0 个,连最小的加法都编不出来),而它实际上是 Neuron 9.x。加上带版本号的候选库之后,设备认出来了,算子一个不缺。
遇到问题、想报个芯片、或者只是想看看别人出的图
新机型的适配基本都是从群里的一份错误详情开始的。装不上、编不出、画质不对,发进来就行。