
Kanana-2-3B 第一次在 ROCK 5C 上跑起來的時候,雞兔同籠它回我「共 4 個 8 頭」,玉山高度是「四千多米」,問它 WireGuard 的優點,它就一直吐「步步步步……」。轉檔過程完全沒報錯,模型檔大小也正常,rkllm-toolkit 一路綠燈。
結果問題出在 rkllm 默默忽略了 config 裡的 YaRN。把一個 1.369 的倍數摺進兩組 norm 權重之後,同一個模型拿到 5.5 分(滿分 7),全程繁中。
這種「轉得過、但答案是錯的」坑,這批模型裡我踩了好幾個。現在這 8 個我自己在 RK3588 上轉好、實測過的模型,已經全部公開在 Hugging Face(oliver0804 ),每個 repo 都附板子上的實測分數、速度、轉檔腳本和授權檔。這篇整理一下有哪些模型、該挑哪個,還有轉檔時那些不會報錯的坑。
環境與前置條件
測試平台
- 板子:Radxa ROCK 5C (RK3588S 、8GB RAM),NPU 驅動 0.9.8
- Runtime:RKLLM runtime 1.3.1;混合版另外需要 rknn-toolkit2 的 runtime 2.5.0(rknnlite)
- 轉檔機:RTX 3090 的 Windows 主機,WSL2 Ubuntu 22.04,rkllm-toolkit 1.3.1、rknn-toolkit2 2.5.0
- 鎖頻:除了表格中標「未鎖頻」的兩筆,數字都在官方fix_freq_rk3588.sh鎖頻下量測(CPU 1.8/2.3GHz、DDR 2112MHz、NPU 1GHz)。其他模型鎖頻前後重測的差距都在 ±5% 內,未鎖頻的數字仍可參考,但不算嚴格同條件
評分用的是我一直在用的 7 題:雞兔同籠、玉山海拔、9.11 和 9.9 誰大、strawberry 有幾個 r、三段論、寫 is_prime、WireGuard 三點優點(每點 15 字內)。全部 greedy、關閉思考、最多 768 token。題目不多,差 0.5~1 分不一定是真的有差,這點先講清楚。
8 個模型的 Hugging Face 連結
先上清單,懶得看後面的可以直接挑:
| Repo | 跑法 | 7 題 | 生成速度 | 記憶體 | 一句話 |
|---|---|---|---|---|---|
| MiniCPM5-2B-RK3588-rkllm-w8a8 | rkllm w8a8 | 6 | 10.9 tok/s | 2.5GB | CP 值最高,但常混簡體 |
| Kanana-2-3B-Instruct-RK3588-rkllm-w8a8 | rkllm w8a8(YaRN 摺疊) | 5.5 | 8.1 tok/s | 3.8GB | 繁中穩,3B 首選 |
| Granite-4.2-3B-RK3588-rkllm-w8a8 | rkllm w8a8(摺成 Llama) | 5 | 7.1 tok/s | 3.7GB | 全程繁中、格式最乖 |
| RWKV7-G1j-2.9B-RK3588-rkllm-w8a8 | rkllm w8a8(fla 格式) | 5 | 7.1 tok/s | 2.9GB | 沒有 KV cache,長對話不漲記憶體 |
| Nanbeige4.1-3B-RK3588-rkllm-w8a8 | rkllm w8a8 | 4.5 | 7.5 tok/s(未鎖頻) | 3.8GB | 推理型,簡體多、不太聽格式指令 |
| WeVisOne-VL-2B-RK3588-rkllm | rkllm+視覺 RKNN | — | 14.1 tok/s | 4.3GB | 框物件最準,GUI 定位弱 |
| LFM3-1.7B-RK3588-hybrid-rknn | 混合 RKNN(12 段) | 5 | 5.6 tok/s(未鎖頻) | 約 3.5GB | rkllm 轉不了,自己寫引擎搬上 NPU |
| Kanana-2-1.3B-Instruct-RK3588-hybrid-rknn | 混合 RKNN(33 段) | 3 | 2.2 tok/s | 約 4GB | 驗證用,不建議日常 |
拿來對照的話,同一套題目下 Qwen3-4B-2507 是 7 分但只有 3.4 tok/s、吃 5.4GB;Gemma4-E2B 是 6 分、9.3 tok/s、2.6GB。Qwen3-4B 分數最高,但慢到對話會等得很煩,還吃掉板子大半記憶體;MiniCPM5-2B 跟 Gemma4 同分、比它快、還省一點記憶體,所以是我目前在 8GB 板子上最推的小模型。要繁中乾淨就選 Kanana-2-3B 或 Granite。
下載與執行
rkllm 版就是一個 .rkllm 檔,用 HF 的 CLI 抓下來,丟給官方範例或你自己的 API 就能跑:
# 需要 huggingface_hub(pip install -U huggingface_hub)
hf download oliver0804/MiniCPM5-2B-RK3588-rkllm-w8a8 --local-dir ~/models/minicpm5-2b
# 在板子上用 rknn-llm 官方 examples 編出來的 llm_demo 跑(參數依官方範例)
./llm_demo ~/models/minicpm5-2b/MiniCPM5-2B_RK3588_w8a8.rkllm 768 4096
混合版是一整個資料夾(每段一個 .rknn、embedding、meta2.json、tokenizer),repo 裡的 runtime/ 就是我評測用的同一套程式:
hf download oliver0804/LFM3-1.7B-RK3588-hybrid-rknn --local-dir ~/models/lfm3-1.7b-rknn
pip install numpy tokenizers # rknnlite 隨 rknn-toolkit2 的 runtime 安裝
python ~/models/lfm3-1.7b-rknn/runtime/chat.py ~/models/lfm3-1.7b-rknn --tok lfm3
Runtime 版本要對
這批.rkllm是用 toolkit 1.3.1 轉的,板子上的librkllmrt.so也要 1.3.1。版本不合時不一定會報錯,可能載入成功但輸出亂碼,所以出問題時先查版本。
坑一:rkllm 會默默忽略 YaRN(Kanana-2-3B)

回到開頭那個「步步步」。Kanana-2-3B 是 Qwen3 架構,RoPE 用的是 YaRN (factor 40、原始長度 4096)。HF transformers 實作 YaRN 時除了改 inv_freq,還會把 cos/sin 乘上一個 attention_scaling,公式在 modeling_rope_utils.py 裡是 0.1 * ln(factor) + 1,factor 40 算出來是 1.369。q 和 k 都乘一次,等於 attention logits 被放大 1.369² 倍。
rkllm-toolkit 1.3.1 看到 rope_scaling 不會報錯,也不會警告,就直接當一般 RoPE 算。少了那個倍數,attention 分佈整個變平,模型就開始胡言亂語。
解法是利用 Qwen3 的一個特性:它對 q、k 各做一次 RMSNorm(q_norm、k_norm),而 RoPE 是線性旋轉,所以「cos/sin 乘 s」可以完全等價地改成「q_norm、k_norm 的權重乘 s」:
# 概念示意;完整版(含 GPU 驗證)在 repo 的 conversion/fold_yarn.py
import math
def fold_yarn(state_dict, config):
rs = config.pop("rope_scaling") # 拿掉之後 rkllm 就當一般 RoPE
s = 0.1 * math.log(rs["factor"]) + 1.0 # attention_scaling,factor 40 → 1.369
for name, w in state_dict.items():
if name.endswith(("q_norm.weight", "k_norm.weight")):
state_dict[name] = w * s
return state_dict, config
YaRN 對 inv_freq 的修改沒辦法用一般 RoPE 表示,但它主要動的是低頻維度,4096 以內影響很小。我在 GPU 上跟官方 YaRN 實作比對 600 個 token:
| 做法 | 跟官方 YaRN 的 argmax 一致率 |
|---|---|
| 直接當一般 RoPE(rkllm 的預設行為) | 12.5% |
| 一般 RoPE,再把 1.369 摺進 q_norm、k_norm | 99.83% |
12.5% 的一致率代表每 8 個 token 就有 7 個跟原版不同,模型等於壞掉了,轉檔工具卻一聲不吭,是在哈囉。config 裡有任何 rope_scaling 的模型,丟進 rkllm 之前都要先查清楚。
坑二:Granite 的四個倍數,和 RWKV7 的六關
Granite-4.2-3B 其實就是 Llama 多了四個純量:embedding、attention、殘差、logits 各乘一個倍數。四個都是線性的,可以直接乘進權重。這顆模型實際上只有 attention_multiplier 不是標準值:它是 1/64,標準 Llama 是 1/√64 = 1/8,所以把 q_proj 乘 0.125 就變成一顆標準 Llama。摺完跟原版比,logits 最大差 0.00001,argmax 100% 一致,之後 rkllm 照 Llama 轉就好(conversion/fold_granite.py)。
RWKV7 就沒這麼好打發了,前後過了六關:
- 官方 requirements 要 transformers 4.51.3,但 rkllm-toolkit 1.3.1 本身要 5.8:toolkit 用
--no-deps裝,再補 5.8。 - bf16 初始化時的正交初始化會呼叫 QR 分解(
geqrf),bf16 不支援:config 的 dtype 改 float32。 - RWKV 官方最新的 HF 格式(
rwkv7.blocks.N.att.*)rkllm 不認:改用 fla-hub 格式 。 - flash-linear-attention 註冊模型時跟 transformers 撞名:包一層跳過重複註冊,再把
RWKV7ForCausalLM掛到 transformers 底下讓 rkllm 找得到。 - rkllm 要的是把 x_r、x_w、x_k、x_v、x_a、x_g 疊成一個
x_x(順序 r,w,k,v,a,g),fla 的 fused LayerNorm 也不認:疊權重、fuse_norm: false。 - 轉好之後套 ChatML 模板,模型會把
<|im_start|>當文字照抄:改用 RWKV 自己的User: …\n\nAssistant: <think></think>\n格式。
六關過完,RWKV7 拿 5 分、7.1 tok/s、2.9GB,全程繁中。它是 RNN,沒有 KV cache,對話再長記憶體都不會漲,這是 transformer 模型給不了的。修權重的腳本和模板說明都在 repo 的 conversion/ 裡,你不用再踩一次。
坑三:rkllm 轉不了的,就自己寫引擎(LFM3)

LFM3-1.7B 是另一個等級的問題:rkllm 兩條路都轉不了。原生的 lfm2 少了 sandwich norm、attention 輸出的 sigmoid gate、只轉一半維度的部分 RoPE、sliding window;custom_config 又要求每一層都是 attention,但 LFM3 有一半是卷積層。gate 和 norm 都是非線性,摺不進權重,toolkit 又是閉源的。
所以我改用 rknn-toolkit2,把模型切成 12 段計算圖自己串。第一版全部丟 NPU,結果雞兔同籠在第 35 個字翻車:「每隻雞有 2 個頭」。GPU 上 fp32、bf16、fp16 都答對,所以不是「fp16 不夠準」。
拿真實激活值逐個運算子量,答案很清楚:
| 運算 | NPU 最大相對誤差 | 理想 fp16 誤差 | 倍數 |
|---|---|---|---|
| Softmax(16×1025,有 mask) | 1.07e-2 | 7.5e-4 | 14 倍 |
| Sigmoid | 1.95e-3 | 1.0e-4 | 20 倍 |
| matmul 2048→7680 | 3.4e-4 | 8.1e-5 | 4 倍 |
而且用 op_target=cpu、手動拆成 exp(x-max)/sum、換編譯最佳化等級,誤差都一模一樣,在 RKNN 裡面根本控制不了。這邊要講清楚範圍:我只量了 rknn runtime 2.5.0 下的這兩個運算,rkllm 自己的 attention kernel 是另一套,這次沒測。
最後的「混合 RKNN」架構長這樣:
Embedding(CPU 查表)
│
▼
┌──────────── NPU(fp16)────────────┐
│ 段 k:o_proj + FFN / 卷積 │
│ + 下一層 q, k, v, gate 投影 │
└────────────────────────────────────┘
│ q, k, v, gate ▲ attention 輸出
▼ │
┌──────────── CPU(numpy fp32)──────┐
│ q·Kᵀ → softmax → ·V → × sigmoid(gate) │
│ KV cache 常駐 CPU │
└────────────────────────────────────┘
│(最後一段)
▼
lm_head → 下一個 token
矩陣乘法全部留在 NPU,真正怕精度的 softmax 和 sigmoid 改由 CPU 用 fp32 算。KV cache 一直放在 CPU,不用每步搬進搬出 NPU,結果反而快了約 56%(3.6 → 5.6 tok/s,兩次都是未鎖頻量測),7 題 5 分,跟 PyTorch fp32 同分,greedy 前 40 個 token 逐字一致。精度修好、速度還變快,原因就是少了 KV cache 的搬運。
同一套 engine2.py 後來也吃下了 Kanana-2-1.3B(Qwen3 的 sliding/full 雙 RoPE 架構)。它能跑、輸出正確,但 24 層切成 33 段,每個 token 要依序打 33 次 NPU,NPU 只佔 35% 的時間,其他都在等 Python,只剩 2.2 tok/s。我把它放上 HF,主要是當成「這套引擎可以移植 Qwen3 系架構」的範例,日常用請選 rkllm 版的 Kanana-2-3B。
混合 RKNN 的定位
rkllm 有 w8a8、KV cache 在 NPU、整段 prefill,它轉得了的模型一定比較快。混合 RKNN 只適合兩種情況:rkllm 轉不了的架構,或對 attention 精度很敏感的任務。
坑四:檔案大小對,內容是錯的

這批模型最陰的坑其實不在模型本身,在傳輸。
Kanana-2-3B 第一次轉出來全是韓文亂碼「명명명…」,連在 GPU 上用官方 transformers 跑都是亂碼。查到最後是第一個 4.96GB 的分片壞了:下載時剛好碰上 WSL 的 C 槽塞滿,後來 curl -C - 續傳,檔案大小完全正確,內容是錯的。拿去跟 HF 上的 LFS sha256 一比就抓到了。
模型從轉檔機經 frp 多條並行傳到板子和 NAS 的時候,又有兩份 .rkllm 傳壞,一樣是大小正確、sha 不符。後來我寫了一個逐段比對的小腳本,只重傳壞掉的那幾段,不用整個 4GB 重來。
上傳 HF 前,我也是每個檔案都先跟 NAS 比對過 sha256 才送出去。所以你下載這些 repo 時,可以用 HF 頁面上每個檔案的 SHA256 對一下:
sha256sum ~/models/minicpm5-2b/*.rkllm
# 跟 HF 網頁上該檔案的 "SHA256" 欄位比對
上傳本身倒是很順。huggingface_hub 現在走 Xet 儲存後端 ,4GB 的模型大約 3 分半,8 個 repo 全部傳完約 20 分鐘。唯一要注意的是 upload_folder 只會帶資料夾裡的東西,我第一次把共用的 runtime/ 放在外面,兩個混合版就漏了推理引擎,後來補傳才齊。
授權:能放,但要照規矩放
會不會被告是放模型前一定要想的事。這 8 個的授權分三類:
| 模型 | 授權 | 我怎麼處理 |
|---|---|---|
| MiniCPM5、Granite、RWKV7、Nanbeige、WeVisOne | Apache-2.0 | 附 LICENSE 原文,卡片註明權重已修改 |
| Kanana 兩個 | Kanana Open License(Kakao 自訂) | license: other,附全文與 NOTICE,卡片寫 Powered by Kanana;商用限制對下載者一樣適用 |
| LFM3 | LFM Open License v1.0(Liquid AI) | 附全文;年營收 1,000 萬美元以上不可商用 |
如果你要拿去做產品,記得回去看原始模型的授權(Kanana-2-3B 、LFM3 、MiniCPM5 ),我轉檔不會讓授權變寬鬆。別人轉好的 Qwen3、Gemma4 我就沒放,那不是我的東西。
Troubleshooting
Q:載入成功,但輸出亂碼或一直重複同一個字?
先查三件事:runtime 版本是不是 1.3.1;對話模板對不對(RWKV7 不吃 ChatML);檔案 sha256 有沒有跟 HF 一致。
Q:自己轉別的模型,答案「差不多對但怪怪的」?
打開 config.json 找 rope_scaling、attention_multiplier、logits_scaling 這類欄位。rkllm 不一定處理它們,而且不會告訴你。能摺進權重的就先摺,摺完在 GPU 上跟原版比 argmax。
Q:混合版好慢,NPU 使用率很低?
正常,瓶頸在 Python 呼叫的固定開銷,段數越多越慢。下一步我打算把 engine2 改寫成 C++、用 rknn_create_mem 做零拷貝,到時候再更新 repo。
結語:挑一個開始玩

如果你手上剛好有一塊 RK3588 的板子,我的建議很簡單:先抓 MiniCPM5-2B 試試,2.5GB、10.9 tok/s,8GB 的板子還有空間跑別的;在意繁中就換 Kanana-2-3B ;想看 rkllm 轉不了的架構怎麼硬搬上 NPU,就去翻 LFM3 混合版 的 runtime/。
跑出不同的數字、或是遇到我沒寫到的坑,歡迎到 HF 的 Community 分頁留言。你的板子、你的題目,可能會讓這張排名表換個樣子。
參考資料
- airockchip/rknn-llm — RKLLM toolkit 與 runtime
- airockchip/rknn-toolkit2 — RKNN 轉檔與 runtime
- YaRN: Efficient Context Window Extension of Large Language Models
- transformers modeling_rope_utils.py — YaRN 的 attention_scaling 實作
- fla-org/flash-linear-attention — RWKV7 的 fla 實作
- Hugging Face Hub 上傳指南
- Xet on the Hub
- Radxa ROCK 5C 、Rockchip RK3588
沒有留言:
張貼留言