## Optimizing Large Language Model Inference on RISC-V Platforms Using TVM Compiler 資工四 莊翔鈞 資工四 洪子傑 指導教授:陳鵬升 note: 我們的題目是在嵌入式設備上運行大語言模型。因為嵌入式設備的算力有限,直接把大語言模型丟上去跑會很慢,所以我們用TVM BYOC 技術來優化模型,最後總體運行速度提升9.6倍。 --- ## Apache TVM ![Screenshot 2025-10-20 at 1.22.15 PM](https://hackmd.io/_uploads/HJ3zvSXCxx.png) note: 為了讓大語言模型能在資源受限的嵌入式設備上運行,我們重寫了Whisper-tiny模型的矩陣乘法運算子,並利用TVM compiler中的BYOC (Bring Your Own Codegen) 技術,將優化後的運算子整合至模型的計算圖中,大幅提升計算效率。優化過的模型與原版相比,運行速度提升9.6倍。 --- ## Goal ![Screenshot 2025-10-20 at 1.18.02 PM](https://hackmd.io/_uploads/ByHsLHX0ge.png) --- ## Banana pi f3 ![banana_pi_bpi-f3_interface_new](https://hackmd.io/_uploads/SyIoa-STeg.jpg) --- ## TVM 編譯流程 ![Screenshot 2025-11-28 at 10.27.24 AM](https://hackmd.io/_uploads/S1MQjKIZbx.png) note: 那接下來我來介紹一下我們用到的技術。首先是TVM,他是一個深度學習的編譯框架,可以把多種前端編譯到一個特定的設備上,然後BYOC允許我們在這個流程中添加自己設計的運算子,來替換AI模型原有的運算子,以此來優化模型。 --- ![Screenshot 2025-10-13 at 2.07.32 PM](https://hackmd.io/_uploads/H1oOPMqaxe.png) note: 那我們在實驗的一開始先用Netro分析模型,發現矩陣乘法佔了95%的執行時間,所以我們打算改寫這個運算子。 --- ## 如何加速矩陣乘法? 1. 使用 RVV 指令集 2. 矩陣分塊 ---- ## RISC-V RVV 指令 1. 一次處理多筆資料(SIMD) 2. 向量長度可變(Vector-Length Agnostic) 3. 提升諸如矩陣乘法、卷積、影像處理等資料密集型運算效能。 ---- ![589046276_1223913119547699_7684260658872023743_n](https://hackmd.io/_uploads/rJkHVyL-Wl.png =90%x) ---- ![324](https://hackmd.io/_uploads/H1IhmyU-be.png =75%x) ---- ## 矩陣分塊 首先,假設我們有兩個邊長為n=4的矩陣 $X = \begin{bmatrix} a_1 & a_2 & b_1 & b_2 \\ a_3 & a_4 & b_3 & b_4 \\ c_1 & c_2 & d_1 & d_2 \\ c_3 & c_4 & d_3 & d_4 \end{bmatrix}$ $Y = \begin{bmatrix} e_1 & e_2 & f_1 & f_2 \\ e_3 & e_4 & f_3 & f_4 \\ g_1 & g_2 & h_1 & h_2 \\ g_3 & g_4 & h_3 & h_4 \end{bmatrix}.$ ---- 將scalar如 $X=\begin{bmatrix} a_1 & a_2 & | & b_1 & b_2 \\ a_3 & a_4 & | & b_3 & b_4 \\ -- & -- & + & -- & -- \\ c_1 & c_2 & | & d_1 & d_2 \\ c_3 & c_4 & | & d_3 & d_4 \end{bmatrix}$ 分塊切割成邊長為n/2的方形子矩陣可以得到 $X=\left[\begin{array}{ll} A & B \\ C & D \end{array}\right], Y=\left[\begin{array}{ll} E & F \\ G & H \end{array}\right],A = \begin{bmatrix} a_1 & a_2 \\ a_3 & a_4 \end{bmatrix}$ ---- $X=\left[\begin{array}{ll} A & B \\ C & D \end{array}\right], Y=\left[\begin{array}{ll} E & F \\ G & H \end{array}\right]$ 那麼矩陣乘法就可以變成 $X Y=Z=\left[\begin{array}{ll} A E+B G & A F+B H \\ C E+D G & C F+D H \end{array}\right]$ ---- ## Proof $\begin{gathered} Z_{1,1}=\sum_{k=1}^n X_{1, k} Y_{k, 1} \\ =\sum_{k=1}^{n / 2} X_{1, k} Y_{k, 1}+\sum_{k=n / 2+1}^n X_{1, k} Y_{k, 1}\\= \sum_{k=1}^{n / 2} A_{1, k} E_{k, 1}+\sum_{k=1}^{n / 2} B_{1, k} G_{k, 1}\\=(A E)_{1,1}+(B G)_{1,1} \end{gathered}$ ---- ## 為何使用切割矩陣乘法? ---- ## Ans: 減少 cache miss ---- ## 範例 ``` void classic_matmul(double A[N][N], double B[N][N], double C[N][N]) { for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { for (int k = 0; k < N; k++) { C[i][j] += A[i][k] * B[k][j]; // A[i][k] → row-wise 存取,連續,快 // C[i][j] → row-wise 存取,內層 j 連續,快 // B[k][j] → column-wise 存取,內層 k 不連續 → cache miss } } } } ``` ---- $X=\begin{bmatrix} a_1 & a_2 & b_1 & b_2 \\ a_3 & a_4 & b_3 & b_4 \\ c_1 & c_2 & d_1 & d_2 \\ c_3 & c_4 & d_3 & d_4 \end{bmatrix},Y = \begin{bmatrix} e_1 & e_2 & f_1 & f_2 \\ e_3 & e_4 & f_3 & f_4 \\ g_1 & g_2 & h_1 & h_2 \\ g_3 & g_4 & h_3 & h_4 \end{bmatrix}. $ ---- ```cpp! #define N 2048 #define BLOCK_SIZE 64 void matmul_blockwise(double* A, double* B, double* C) { // 分塊矩陣乘法 for (int i = 0; i < N; i += BLOCK_SIZE) { for (int j = 0; j < N; j += BLOCK_SIZE) { for (int k = 0; k < N; k += BLOCK_SIZE) { // 處理一個塊 for (int ii = i; ii < i + BLOCK_SIZE && ii < N; ii++) { for (int jj = j; jj < j + BLOCK_SIZE && jj < N; jj++) { for (int kk = k; kk < k + BLOCK_SIZE && kk < N; kk++) { C[ii * N + jj] += A[ii * N + kk] * B[kk * N + jj]; } } } } } } } ``` ---- $X=\begin{bmatrix} a_1 & a_2 & | & b_1 & b_2 \\ a_3 & a_4 & | & b_3 & b_4 \\ -- & -- & + & -- & -- \\ c_1 & c_2 & | & d_1 & d_2 \\ c_3 & c_4 & | & d_3 & d_4 \end{bmatrix}$ $Y = \begin{bmatrix} e_1 & e_2 & | & f_1 & f_2 \\ e_3 & e_4 & | & f_3 & f_4 \\ -- & -- & + & -- & -- \\ g_1 & g_2 & | & h_1 & h_2 \\ g_3 & g_4 & | & h_3 & h_4 \end{bmatrix}.$ note: block 內 B 仍然 column-wise 存取 → 仍有些 cache miss 但因為每次處理的 block 很小,cache line 可以被重複利用 → miss 數量大幅降低 若 block 太大 → 無法完全放入 cache → miss 仍多 ---- ## 小規模測試 ![Screenshot 2025-10-09 at 4.28.43 PM](https://hackmd.io/_uploads/B1W8feSpxx.png) ---- ## 經典 vs 向量化 內積 ``` function dot_product_scalar(A[0..N-1], B[0..N-1]): dot = 0 for i = 0 to N-1: dot = dot + (A[i] * B[i]) return dot ``` ``` function dot_product_vector(A[0..N-1], B[0..N-1]): dot = 0 VL = vector_length # 硬體一次可處理的元素數 for i = 0 to N-1 step VL: # 每次都是 i+=VL chunkA = A[i : i+VL-1] # 取出一個 vector chunk chunkB = B[i : i+VL-1] # 取出對應元素 vtmp = vector_mul(chunkA, chunkB) # 每個元素對應相乘 (VL 個同時做) dot = dot + vector_reduce_sum(vtmp) # 將 vector 內元素加總到 scalar return dot ``` note: 一次 vector 乘法處理 VL 個元素 reduce_sum 將這 VL 個元素累加成單一標量 ---- | 項目 | 傳統 for loop | RVV 向量化 | | ----- | -------------------- | ----------------------------------- | | 單次運算量 | 1 個元素 | VL 個元素(如 8 或 16) | | 指令數 | N 乘法 + N 加法 | N/VL 次向量乘法 + N/VL 次向量累加(每次 VL 元素並行) | | 效率 | 1 個元素/時鐘週期 | VL 個元素/時鐘週期 → 潛在加速 8×、16× | note: Banana Pi BPI-F3 SpacemiT K1 RISC-V chip is of vector 256bit and float32 is 32 bit => 8 scalar in one insturction --- ## 數據分析 ![chart](https://hackmd.io/_uploads/SyEkwlB6gg.png =115%x) note: 由以上數據可見,無論單獨使用 RVV 版矩陣乘法或開啟 O3 最佳化,都能顯著提升計算速度;而兩者兼用時,效能提升更為突出。 在未開啟 O3 的情況下,經典矩陣乘法(O(n³))甚至比原版模型更慢,顯示其效率不足;但啟用 O3 後,即便使用此演算法,執行時間仍可降至原本的 66,反映出編譯器在迴圈轉換與記憶體排程上的優化效果。 若採用 RVV 向量化矩陣乘法,即使未啟用 O3,執行時間也降至原版的 42%,顯示向量化能有效提升吞吐量。 當 RVV 與 O3 同時啟用時,效能提升最為明顯——Encoder 計算時間由 1390 秒降至 69 秒(約 20 倍),Decoder Prefill 由 62 秒降至 5.3 秒(約 11.7 倍),整體速度提升達 9.6 倍,充分展現向量化與編譯器優化的協同效益。 --- $Speedup_{overall}=9.6$ --- ## 延伸討論 1. 最佳化矩陣分塊大小? 2. 為何不用strassen演算法 $O(n^{2.8})$? ---- ## Future work 1. decoder_with_past.onnx (dynamic shape) 2. 回饋開源社區 3. 拓展到其他模型 ---- ## Future work ![Mermaid Chart - Create complex, visual diagrams with text.-2025-10-20-054256](https://hackmd.io/_uploads/HyTUhHQAge.png =70%x) --- # Thanks ![Screenshot 2025-10-09 at 5.07.56 PM](https://hackmd.io/_uploads/rJlYjxSTgx.png) --- pic1 --- pic2
{"title":"專題展簡報","description":"為了讓大語言模型能在資源受限的嵌入式設備上運行,我們重寫了模型的矩陣乘法運算子,並利用TVM compiler中的BYOC (Bring Your Own Codegen) 技術,將優化後的運算子整合至模型的計算圖中,大幅提升計算效率。優化過的模型與原版相比,運行速度提升9.6倍。\n","contributors":"[{\"id\":\"3cd7f1c1-9859-4f23-a92f-aba10244f0dd\",\"add\":10410,\"del\":3770,\"latestUpdatedAt\":1764297676646}]"}
    211 views