AI/ML Compiler & Runtime:從硬體 Mismatch 開始的 AI/ML Stack 重構之旅
January 18, 2026 · 閱讀時間約 8 分鐘
記錄在邊緣裝置上打造客製化 AI Compiler 與 Runtime 的實務經驗,從硬體限制到系統設計的完整歷程。
AI/ML Compiler and Runtime
我原以為只是把模型轉過去跑,現實是 Compiler 與 Runtime 與硬體規格上的假設互相打架。只好從零把假設拆開,再一個個拼回去。
前言:當「業界標準」不再是標準答案
想像一下,你拿到一顆晶片。規格書上寫著不錯的算力數字,老闆期待你讓 AI 模型在上面飛起來。
你打開 TensorFlow,照著官方文件一步步走,模型順利跑起來了。
然後你看了一眼效能數字,沉默了。
這顆晶片的算力,連一半都沒展現出來。
▉ 當「標準流程」變成成本
這不是假設情境。這是我在開發公司內部神經網路 SDK UPDL Compiler 與 UPDL Runtime 時的親身經歷。
問題的根源很簡單,也很殘酷:硬體與主流 Toolchain 之間,存在本質的不適配。
我們的晶片是一顆以 RISC-V 為核心的 CPU,搭配專為 CNN 優化的 NPU。理論上,這是邊緣 AI 的標準組合。
傳統路線:看起來很美的標準答案
一開始,我們選的是業界的標準路線:
- TensorFlow 訓練模型 (Model Authoring)
- TFLite Converter (Program Preparation)
- LiteRT / TFLite Micro 部署 (Runtime Execution)
這條路的好處是生態成熟、踩坑有社群陪。
但問題也來得很快。
硬體 Mismatch:魔鬼藏在每一層的邊界
▉ 一開始,我們也想省事
專案初期,我們很務實地選擇借助 ARM 生態:LiteRT 當 Runtime,CMSIS-NN 當 Kernel library,NPU 負責加速部分運算。
軟體吃成熟生態的紅利,硬體專心榨算力。
但當整條 Pipeline 串起來,問題開始浮現。效能不是被計算吃掉的是被那些「看起來合理的假設」一點一點侵蝕掉的。
Mismatch #1:Int8 的世界觀,撞上 Int16 的現實
CMSIS-NN 是為 Int8、Cortex-M、極度受限的記憶體環境設計的。
但我們的 NPU 原生支援 Int16。
這個 Mismatch 的後果很直接:
- Casting overhead:Int8 → Int16 的擴展無法避免
- 精度優勢吃不到:明明硬體能做更精確的運算,卻被軟體框架拖回 Int8 的世界觀
我們付出了額外成本,卻沒換到對等的回報。這筆帳怎麼算都不划算。
模型確實「能跑」。但這跟「跑得好」是兩回事。
能跑不等於能用。這是我在邊緣 AI 學到的第一課。
Mismatch #2:Tensor Layout,真正的大魔王
如果說 Precision mismatch 是慢性病,Tensor layout 就是急性發作。
CHW 還是 HWC? 這從來不是對錯問題,而是軟硬體怎麼搭配的問題。
我們的硬體為 CHW 優化。TensorFlow 整路的 Toolchain 預設 HWC。
結果?同一份 Tensor 在每一層 Kernel 的邊界被反覆重排:
- Pre-kernel: HWC → CHW
- Dispatch to NPU
- Post-kernel: CHW → HWC
效能不是輸在計算核心,是輸在資料搬來轉去。這是我在邊緣 AI 學到的第二課
轉折點:當你發現標準答案是錯的
意識到這件事之後,選擇其實很清楚。
如果想讓硬體發揮真正的能力,就不能繼續依賴為別人設計的工具。
於是我們走上了艱辛的路:專為公司硬體設計的客製化 Compiler + Runtime Stack。
這個任務,落到了我頭上。
從零開始寫 Compiler:一段沒有地圖的旅程
老實說,寫 Compiler 這件事一點都不浪漫。
專案開始時,公司沒人做過這個。每踏出一步,對公司是新技能;對我來說,是持續走進未知。
沒有前人經驗可以參考,沒有內部文件可以查。很多時候我只能反覆問自己:
這個選擇,能不能讓系統往前走一步?
能,就做。不確定,就先試。
為什麼不用 ONNX / MLIR / TFLite Convertor?
這是我被問最多的問題。
我們當然也研究過。直接改 TFLite Convertor 原始碼或是借助 ONNX 生態性的完整,又或是導入 MLIR 優雅的架構。
但當時的判斷是:現在導入,風險大於收益。
原因很現實:
- 沒人能確定我們真的吃得到它們的好處
- 對自家硬體的理解還在建立中
- 一旦架構選錯,要回頭會非常痛苦
所以我們選了一條看起來很土但很實際的路:先做 MVP,跑通再說。
MVP 的錨點:MLPerf Tiny Golden Models
我們用 MLPerf Tiny 的 Golden model 們當第一個目標。
- 技術面:打通 Compiler → Runtime → Hardware 整條路
- 組織面:產出能對外報告的 Benchmark 數字
這不是最完美的選擇。但它是當下能走得動的選擇。
Model Compiler:不只是轉模型,是重建執行邏輯
Model compiler 的工作遠比「把模型轉成另一種格式」複雜:
- TensorFlow graph re-writing
- Topological sorting
- Memory planning
- Operator lowering / mapping
- Batchnorm folding
- Quantization calibration
- Hardware-specific pattern matching
- Kernel fusion
- Dialect/Code generation
- Tensor layout transformation
這些事情如果丟給 Runtime 做,代價太高了。
Compiler 的價值不在於它能做什麼,在於它讓 Runtime 不必做什麼。
Int16 量化:一個牽一髮動全身的系統問題
Int16 量化不只是把浮點數 Float 轉成整數 int 這麼簡單。
Symmetric 還是 Asymmetric ? Scale 怎麼選? Zero-point 怎麼算? 要不要限制成 Power-of-2 Scaling ? Overflow 發生時怎麼處理 ?誤差怎麼傳播?
每一個選擇都會影響模型能不能跑、跑得準不準。
這不是單一模組的問題,是整個系統的問題。
Runtime:結構簡單,驗證困難
Runtime 的架構其實不複雜:Parser、Interpreter、Dispatcher、CPU Fallback、NPU Hook。
真正困難的是驗證。
你要確保:Python 寫的 Compiler 產出的東西,能在 C 寫的 Micro-controller Runtime 上正確執行。你要確保:FP32 世界的數學,轉到 Int16 世界還是對的。
這中間的鴻溝,比想像中寬得多。
數值驗證:確保系統是「對的」,不只是「能跑」
我建了一套驗證三個準則:
- CPU Fallback Kernel 與 NPU Kernel 結果必須一致
- 每一層 Kernel 的量化誤差必須可解釋
- 全模型的誤差傳播必須在可接受範圍
Golden Model 的價值在這裡體現,它讓我在早期就發現了 Graph execution model 的設計漏洞。
Debug 最怕的不是 Bug 很多,是 Bug 藏得很深。早期發現的 Bug 是禮物,上線後發現的 Bug 是災難。
一個 Add,推翻整個假設
原本的設計假設很簡單:Sequential execution,利用 Ping-pong Buffer 就夠了。
然後我遇到了 Residual network 的 Add operator。
這個 Operator 需要同時讀取兩個不相鄰 Layer 的輸出。原本的 Buffer 管理策略瞬間崩潰。
我被迫回頭研究業界的做法跟設計:
- Node lifetime analysis
- DAG-based graph execution model
- Memory planning algorithms
一個看起來最簡單的 Operator,推翻了整個記憶體管理的假設。
系統設計最危險的時刻,就是你以為自己已經想清楚的時候。** **但過早的引入無法掌握的複雜算法系統,更是一件危險的事。
結語:從做模型到做系統
回頭看這段經歷,我才真正理解一件事:
AI/ML 系統的瓶頸,往往不在模型本身,而是在我們如何假設它會被執行。
碩士期間我做的是自動駕駛演算法研究,關心的是模型、理論。
而在這個專案中,開始關心完全不同的議題:
- 計算怎麼映射到硬體
- 記憶體怎麼被使用
- Latency、Throughput、Power 怎麼預測跟優化
- 工具鏈的每一個設計怎麼影響最終行為
這讓我從「做模型的人」慢慢變成「設計系統的人」。
當 AI 走向 Edge、走向實體世界,Compiler 和 Runtime 不再只是工具。它們是系統設計的一部分,是決定產品能不能用的關鍵環節。
這是我想持續深耕的方向。
因為真正的挑戰,是當演算法落地到系統時的每一個細節中。