稀疏矩陣運算 練習題 (Practice - Sparse Matrices and Basic Storage Formats (COO and CSR))
Related Concepts
- 14-Sparse-Matrix-Computation/01-Sparse-Matrices-and-Basic-Formats-COO-CSR — 稀疏矩陣與基礎儲存格式 (COO 與 CSR)
- 14-Sparse-Matrix-Computation/02-Regularized-Formats-ELL-Hybrid-JDS — 正則化儲存格式 (ELL、Hybrid ELL-COO 與 JDS)
| 關鍵字 / 情境 | 答案 / 重點 |
|---|---|
| SpMV 是什麼 | A·X + Y,A 稀疏、X/Y 為 dense vector 的 matrix-vector multiply + accumulate |
| 為何不求反矩陣 | 反矩陣產生大量 fill-ins,比原矩陣更大 → 改用 iterative (conjugate gradient) |
| SpMV 為何 FLOPS 低 | OP/B ≈ 0.25 (2 ops / 8 bytes)、矩陣無 data reuse → memory-bandwidth-bound |
| COO 平行單位 / 為何 atomic | 一 thread = 一 nonzero;同 row 多 nonzero 寫同一 y[row] → 需 atomicAdd |
| CSR 如何免 atomic | 一 thread = 一 row,獨佔輸出 y[row] → 區域 sum 累加最後寫一次 |
rowPtrs 長度 / 末元素 |
長度 numRows+1;rowPtrs[numRows] = 總 nonzero 數 (界定最後 row 結尾) |
| 誰 coalesced / 誰 strided | COO、ELL、JDS coalesced;CSR 非 coalesced (連續 thread 讀相距遠的 row 起點) |
| 誰有 control divergence | CSR、ELL 嚴重;COO 無;Hybrid、JDS 減少 |
| ELL 兩步驟 | padding (補零成矩形) + transpose 成 column-major |
| ELL column-major 索引 | i = t*numRows + row;反推 row = i % numRows |
| Hybrid ELL-COO 動機 | 把超長 row 尾端多餘 nonzero 抽到 COO,抑制 ELL padding 爆量與 divergence |
| JDS 降 divergence 手法 | 依 row 長度排序,同 warp 內列長相近 → 迭代次數相近 (免 padding) |
JDS 的 row / iterPtr |
row 記原始列索引 (把解排回原序);iterPtr 標每次迭代 (欄) 起點 |
| COO→CSR 轉換 | histogram (數每 row nnz) + prefix sum (算 rowPtrs) |
| 最佳格式怎麼選 | data-dependent,取決於 nonzero 分佈,無單一最優 |
Question 1 - SpMV 與算術強度 [recall]
情境/題目:在迭代解線性系統時,最耗時的核心運算 SpMV 計算什麼?為何它在 CPU/GPU 上的 FLOPS 都遠低於峰值?
SpMV = A·X + Y 的 sparse matrix-vector multiply + accumulate (A 稀疏,X/Y 為 dense)。每個 nonzero 只做 2 ops (1 乘 1 加),卻要讀 value(4B)+colIdx(4B)=8B 且矩陣無 data reuse → OP/B ≈ 0.25,屬 memory-bandwidth-bound,故 FLOPS 偏低。
Question 2 - 為何不用反矩陣解稀疏系統 [recall]
情境/題目:解
A·X + Y = 0時,為何對大型稀疏矩陣不採直接求反矩陣 (如 Gaussian elimination),而改用 iterative method?
反矩陣運算會產生大量額外 nonzero (fill-ins),使反矩陣往往比原稀疏矩陣大很多,計算與儲存皆不切實際。改用 iterative method:當 A 為 positive-definite 時可用 conjugate gradient,反覆計算 A·X + Y 並用梯度修正 X 直到收斂。
Question 3 - COO 格式與 atomic 的必要性 [recall]
情境/題目:COO 用哪三個陣列儲存?SpMV/COO 的平行化單位是什麼,為何累加時必須用
atomicAdd?
三陣列:rowIdx[]、colIdx[]、value[] (各 nnz 長度)。平行單位是一個 thread 對應一個 nonzero。因為同一 row 的多個 nonzero 被分配到不同 thread,會同時更新同一個 y[row] → race condition → 必須 atomicAdd(&y[row], x[col]*value)。
Question 4 - CSR 如何避開 atomic [recall]
情境/題目:CSR 用什麼陣列取代 COO 的
rowIdx?SpMV/CSR 為何不需要 atomic operations?
用 rowPtrs[] 取代 rowIdx:rowPtrs[r] 是第 r 個 row 的 nonzero 在 value/colIdx 的起始 offset。平行單位是一個 thread 對應一個 row,每 thread 用區域 sum 累加該 row 的 dot product,最後寫入自己獨佔的 y[row] → 不同 thread 寫不同輸出 → 無需 atomic。
Question 5 - rowPtrs 的長度與末元素 [recall]
情境/題目:對 numRows 個 row 的 CSR 矩陣,
rowPtrs陣列長度是多少?最後一個元素rowPtrs[numRows]代表什麼、有何用途?
長度為 numRows + 1。rowPtrs[numRows] 儲存一個「不存在 row」的起點,其值 = 總 nonzero 數。它讓 kernel 能用 rowPtrs[row+1] 統一界定每一 row (含最後一 row) 的結尾 (exclusive),無需特例處理。
Question 6 - ELL 的兩步驟與索引公式 [recall]
情境/題目:從 CSR 出發,產生 ELL 格式需要哪兩個步驟?SpMV/ELL kernel 中存取第 t 次迭代、第 row 列元素的一維索引公式是什麼?
兩步驟:(1) Padding — 找出 nonzero 最多的 row,其餘 row 尾端補 0 到相同長度成為矩形 (colIdx 一併補);(2) Transposition — 以 column-major 排放 (等同轉置),不再需要 rowPtrs。索引公式:i = t*numRows + row。
Question 7 - ELL 的 accessibility 與反推公式 [recall]
情境/題目:為何說 ELL 同時擁有 CSR 與 COO 兩者的 accessibility?已知一維索引 i,如何反推它的 row?
ELL 既能「給 row → 取該 row 全部 nonzero」(如 CSR),又能「給 nonzero index i → 反推其 row/col」(如 COO)。col 直接由 colIdx[i] 取得;row 由 i = t*numRows + row 反推為 row = i % numRows (因 row < numRows,故 row % numRows == row)。
Question 8 - Hybrid ELL-COO 的動機 [recall]
情境/題目:純 ELL 在什麼情況下 padding 會爆量?Hybrid ELL-COO 用什麼手法緩解,同時解決哪兩個問題?
當少數 row 的 nonzero 數異常多時,所有 row 都被 pad 到該最大長度 → padding 爆量。Hybrid 作法:轉 ELL 前,把超長 row 尾端的多餘 nonzero 抽出放入獨立 COO,剩餘部分做 ELL,最後兩段結果相加。同時降低 ELL 的 padding 空間開銷與 control divergence (所有 thread 迭代次數變接近)。
Question 9 - 把矩陣轉成 COO 與 CSR [application]
情境/題目:將下列稀疏矩陣分別表示成 COO 與 CSR (依 row-major、row 內依 colIdx 遞增)。
1 0 7 0 0 0 8 0 0 4 3 0 2 0 0 1
nonzeros (row-major):(0,0)=1,(0,2)=7,(1,2)=8,(2,1)=4,(2,2)=3,(3,0)=2,(3,3)=1。
COO:value=[1,7,8,4,3,2,1],colIdx=[0,2,2,1,2,0,3],rowIdx=[0,0,1,2,2,3,3]。
CSR:value、colIdx 同上;每 row nnz = 2,1,2,2 → rowPtrs=[0,2,3,5,7] (長度 numRows+1=5,末元素 7 = 總 nnz)。
Question 10 - 各格式所需整數數量 [application]
情境/題目:一個整數稀疏矩陣有 m 列、n 行、z 個 nonzero。請寫出 COO、CSR、ELL、JDS 各需多少整數;若資訊不足,指出缺什麼。
設每列最大 nonzero 數為 k。
COO = 3z (rowIdx+colIdx+value)。CSR = 2z + (m+1) (value+colIdx + rowPtrs)。
ELL = 2·m·k (value+colIdx 皆 pad 成 m×k);需 k,無法只由 m,n,z 求得 (依分佈而定)。
JDS = 2z + (k+1) + m (value+colIdx + iterPtr + row 陣列);同樣缺 k (最長列長度)。
Question 11 - COO→CSR 的平行轉換 [application]
情境/題目:要在 GPU 上把 COO 轉成 CSR,需要用到哪兩個基礎平行原語?各自負責產生什麼?
(1) Histogram:掃描 rowIdx[] 數出每個 row 的 nonzero 數 (per-row count)。(2) Prefix sum / scan:對 per-row counts 做 exclusive scan 得到 rowPtrs[] (各 row 的起始 offset)。之後依 row 重排 (或散佈) value/colIdx 即完成。
Question 12 - COO coalesced vs CSR strided [analysis]
情境/題目:同一個矩陣,為何 SpMV/COO 的矩陣存取是 coalesced,而 SpMV/CSR 卻是 strided (非 coalesced)?這對記憶體頻寬效率有何影響?
COO 中連續 thread 處理連續 nonzero (t0→value[0], t1→value[1]…),同一時刻存取相鄰位址 → coalesced。CSR 中連續 thread 各負責一整 row,第一次迭代讀各 row 的起點 (value[0],[2],[5],[7]),彼此相距遠 → strided,一個 warp 的請求被拆成多個 memory transaction,浪費頻寬。由於 SpMV 是 memory-bound,這直接拖慢 CSR;ELL/JDS 用 column-major 排放正是為了把 CSR 的 strided 存取轉回 coalesced。
Question 13 - ELL、Hybrid、JDS 的取捨 [analysis]
情境/題目:ELL、Hybrid ELL-COO、JDS 三者在「control divergence」與「空間效率」上如何取捨?為何本章強調「沒有單一最優格式」?
ELL:用 padding+transpose 取得 coalescing,但每 thread 仍依自己 row 的 nnz 迭代 → divergence 未解、空間因 padding 變差。Hybrid:抽走長尾入 COO → padding 大減、divergence 降低,代價是溢位列的 accessibility 變差。JDS:依列長排序使同 warp 列長相近 → 有效降低 divergence 且免 padding (空間更省),但最不易增刪、且無 padding 故起點無法強制對齊 (coalescing 有時略遜 ELL)。因 SpMV 效能是 data-dependent——取決於 nonzero 分佈 (例如是否有少數超長列)——所以最佳格式須視資料而定,無單一通用最優。
| 格式 | 平行單位 | Space | Flexibility | Accessibility | Coalescing | Control Divergence |
|---|---|---|---|---|---|---|
| COO | 一 nonzero | 中 (3 陣列) | 最佳 (append) | 給 nonzero → row/col | ✓ | 無 (但需 atomic) |
| CSR | 一 row | 最佳 | 差 (須位移後列) | 給 row → nonzeros | ✗ (strided) | 高 |
| ELL | 一 row | 差 (padding) | 中 (換 padding) | row 與 nonzero 皆可 | ✓ | 高 (同 CSR) |
| Hybrid | row + nonzero | 中 | 中 (append COO) | 溢位列較差 | ✓ | 減少 |
| JDS | 一 row | 良 (免 pad) | 最差 (須重排) | 給 row → nonzeros | ✓ (難對齊) | 減少 (排序) |
核心訊息:compaction (壓縮去零) ↔ regularization (規則化) 的權衡;SpMV 為 memory-bound (OP/B≈0.25);最佳格式 data-dependent。