
2025/12/17 6:18
Reverse-Engineering the RK3588 NPU: Hacking Limits to Run Vision Transformers
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
Summary:
著者は、Rockchip RK3588 NPU 上で Vision Transformer を効率的に動作させる方法を、ハードウェア固有のボトルネックを診断し修正することで示しています。主な問題点として、NPU の 32 KB SRAM によるレジスタオーバーフロー、最適なタイル化を妨げるコンパイラ融合、および量子化時に極端な活性値によって生じる精度損失が挙げられます。これらを解決するために、データを SRAM に収める「Nano‑Tiling」を実装し、正しいスケジューリングを強制する「Poison Pill」演算子を追加し、量子化誤差を減らすサンドイッチスケーリング手法を用い、メモリ管理を改善するためにグラフをシャーディングしています。これらの解決策は、レガシー rknn‑toolkit2 で SmolVLM の SigLIP モデルが失敗し、謎めいた hex エラーと遅い CPU フォールバックを引き起こしたことに端を発します。著者は、このリバースエンジニアリング手法が他の非対応ハードウェアシナリオにも一般化できると示唆しており、FP32 の完全精度を保ちつつ最大 15 倍の速度向上を実現できる可能性があります。エッジアクセラレータを扱う開発者が利用できるように、これらの手法は公開 GitHub リポジトリで提供されています。
Summary Skeleton
What the text is mainly trying to say (main message)
著者は、Rockchip RK3588 NPU 上で Vision Transformer を効率的に動作させる方法を説明し、複数のハードウェアとソフトウェア上限を克服したことを示しています。
Evidence / reasoning (why this is said)
レジスタオーバーフロー(SRAM の制限)、タイル化を破壊するコンパイラ融合、および極端な活性値による量子化損失という具体的な失敗ポイントを特定し、Nano‑Tiling、Poison Pill 演算子、サンドイッチスケーリングトリック、グラフシャーディングといったターゲット付き修正策を説明しています。
Related cases / background (context, past events, surrounding info)
問題は SmolVLM の SigLIP モデルがレガシー rknn‑toolkit2 で失敗し、謎めいた hex エラーと遅い CPU 推論を生じたことから始まりました。NPU の 32 KB L1 SRAM とデフォルトのコンパイラ動作により REGTASK Overflow エラーが発生しました。
What may happen next (future developments / projections written in the text)
著者は、このリバースエンジニアリング手法が他の「Unsupported Hardware」シナリオにも一般化できると示唆しており、さらなる最適化やエッジアクセラレータへの広範な採用を期待しています。
What impacts this could have (users / companies / industry)
NPU の警告を迂回しメモリを手動で管理する方法を公開することで、開発者は FP32 精度を維持しつつ最大 15 倍の速度向上を実現できるようになります。オープンに利用可能な GitHub リポジトリは、同様のモデルやハードウェアプラットフォームでこれらの手法を適用するコミュニティを支援します。
本文
著者のメモ
現在、CU Boulder のMS CS 学部に在籍し、Edge AI と組み込みシステムを専攻しています。2026 年夏に、制約されたシリコン上で難しいワークロードを最適化できるインターンシップを積極的に探しています。
- 📄 [履歴書] | ✉️ [メール] | 💻 [GitHub]
「サポートされていない」ハードウェアの問題
Rockchip RK3588(Orange Pi 5 に搭載されているチップ)の仕様表を見ると、まるで獣みたいに見えます。
- 6 TOPS の NPU 性能
- 価格は 100 ドル
しかし、実際に現代の AI を動かす―特に SmolVLM の Vision Encoder ―を試すと、その約束は崩れます。標準的な Computer Vision SDK(
rknn-toolkit2)は、ResNet など予測しやすい古典的 CNN 用に最適化されています。SmolVLM が使用する SigLIP Vision Transformer を投入すると、ドライバがクラッシュします。モデル自体は「スモール」ですが、大量の注意行列を生成するため、暗号化された 16 進数エラーが発生し、コンパイルを拒否します。
結果:単一画像推論に CPU が約 30 秒かかり、6 TOPS アクセラレータはアイドル状態のままでした。私はそれを受け入れませんでした。
背景:難しい方法でやる理由(ファーストプリンシプル)
エコシステムに従っている方への簡単なメモです。
- QEngineering のようなプロジェクトは、Rockchip の
SDK を使って SmolVLM‑v2 を実行しています。この SDK は Transformer 専用の「ブラックボックス」ツールチェーンです。rknn-llm - 私のプロジェクトは SmolVLM‑v1 を対象とし、レガシー
上に構築されています。rknn-toolkit2
なぜレガシースタックをハッキングするのか?
私は ファーストプリンシプル アプローチを取りたかったので、ハードウェアが注意層でクラッシュしている理由を理解し、任意の Transformer を任意の制約付きエッジアクセラレータ上で動作させるための汎用的な設計パターン(手動タイル化、グラフシャーディング)を発見したいと考えました。
探偵仕事
エラー 0xe010 は何?
Rockchip は公開 ISA を持っていません。注意層のコンパイル時にドライバは未定義のエラー REGTASK Overflow (0xe010) を吐き続けます。
私はこれをメモリオーバーフローだと仮説しました。
- モデルパラメータ:約 96 M
- 1024 トークン列に対する中間アクティベーション行列は約 25 MB
制限を調べるため、合成 ONNX グラフを生成しました。
| テンサーサイズ | 結果 |
|---|---|
| 8 KB | 通過 |
| 16 KB | 通過 |
| 32 KB | 通過 |
| 32.1 KB | クラッシュ |
発見:NPU はベクトル演算用に 32 KB の L1 SRAM スクラッチパッドをハードウェアで強制しています。標準コンパイラは 25 MB の注意行列をそのスロットに詰め込もうとしていました。
修正策:Nano‑Tiling と「ポイズンピル」
Nano‑Tiling
PyTorch で Nano‑Tiling アルゴリズムを書きました:
# 大量の 1024 トークン列を 32×32 タイルに分割し、32 KB スクラッチパッドに収まるようにする。
rknn コンパイラは「賢い」ため、タイル化されたグラフを見て非効率だと判断し、演算子を再び単一ブロックへ融合してしまいます。私はコンパイラを騙す必要がありました。
ポイズンピル
トップロジカルな障壁―ポイズンピル を導入し、融合を防止しました:
# 1. スライス(ストライドアクセスを強制) slice_x = x[..., :1] # 2. 非線形演算を適用(コンパイラの融合ヒューリスティクスを壊す) # 3. 数学的にほぼゼロになるように縮小 poison = torch.sigmoid(slice_x) * 1e-6 # 4. 依存関係を注入 out = out + poison # コンパイラは 'out' が 'poison' に依存していると認識する
このダミー演算を挿入すると、コンパイラはタイル化ロジックを尊重します。
「SigLIP Cliff」:精度崩壊の解決
NPU を動かすことがステップ1;正しく機能させることがステップ2です。最初は出力がゴミ(コサイン類似度 ≈ 0.02)でした。
問題点:SigLIP の活性化はスパイク(≈300)があり、視覚信号は非常に小さい(≈0.05)。
- INT8 量子化では –128/+127 を表現。
- もし 300 が範囲に収まれば 0.05 は 0 に丸められ、信号が失われる。
- 逆に 0.05 が範囲に収まれば 300 がオーバーフローし、計算がクラッシュする。
サンドイッチドメインシフト
CPU 前スケール:入力を 0.1 倍(最大 ≈ 30.0 – FP16 に安全) NPU 実行:この「安全ゾーン」で実行 CPU 後スケール:出力を 10.0 倍
結果:信号の忠実度が 0.02 から 0.999(ほぼビット単位で一致)に回復しました。
カスタムランタイムスケジューラ
数千個の小さな演算によるドライバタイムアウトを避けるため、私は:
- モデルグラフを 26 個の別々のバイナリファイル(シャード) に分割。
- Python でユーザー空間ランタイムを書き、
- 各シャードを RK3588 の3つの NPU コアにロード。
- シンクロナイズされたラウンドロビンスケジュールで実行:Core 0 → Core 1 → Core 2。
結果
| 指標 | CPU ベースライン(PyTorch) | SHARD(私の手法) |
|---|---|---|
| レイテンシ | ~30.0 s | < 1.8 s |
| スピードアップ | 1× | 15× |
| 精度 | 参照 0.999 (FP32 と一致) | 0.999 |
結論
このプロジェクトは「サポートされているハードウェア」という二項式の考え方に挑戦しました。
RK3588 は標準 SDK では SigLIP エンコーダをそのままサポートしていませんでしたが、シリコン自体は常に機能可能であり、レジスタオーバーフローコードを掘り下げ、メモリを手動で管理すれば実現できるということです。
完全なコード(タイル化ロジックとランタイムオーケストレーターを含む)を見るには、以下のリポジトリをご覧ください。
GitHub でソースを見る