PyTorch 效能分析(第一部分):torch.profiler 入門指南
本文是 PyTorch 效能分析系列的第一篇,從最簡單的矩陣乘加操作開始,引導讀者學習如何使用 torch.profiler 進行效能分析,包括設定分析器、解讀分析表和追蹤資料,以及理解 CPU 和 GPU 活動之間的時間關係。文章還討論了預熱和最佳化開銷等問題。
文章情報
要點
- torch.profiler 可以生成效能分析表和時間線追蹤,幫助識別熱點和瓶頸。
- 小矩陣乘法容易導致開銷受限,增大矩陣規模可轉為計算受限。
- 預熱步驟對於消除啟動開銷至關重要,確保分析結果準確。
- CPU 和 GPU 活動之間存在時間偏移,反映了核心啟動和同步的延遲。
為什麼重要
這條新聞值得關注,因為torch.profiler 可以生成效能分析表和時間線追蹤,幫助識別熱點和瓶頸。
技術影響
可能影響模型選型、推理成本、產品能力和評測基準。
在最佳化 PyTorch 模型時,效能分析是不可或缺的一步。無論你是想提高大語言模型(LLM)的每秒 token 數,縮短推理時間,還是僅僅想了解訓練迴圈為何比預期慢,最終都需要透過效能分析來定位問題。然而,效能分析有著較高的學習門檻:追蹤資料是密集的彩色矩形,事件名稱令人望而生畏,大多數教程假設讀者已經具備讀取能力。因此,即使我們知道應該進行效能分析,開啟追蹤檔案也常常被推遲或交給他人處理。本文旨在降低這一門檻。
本系列文章將從 PyTorch 效能分析的基礎開始,逐步培養讀者讀取分析追蹤資料並用其指導最佳化的能力。本部分(第一部分)從最簡單的操作——矩陣乘法加偏置——開始,教你如何理解分析器返回的資訊。後續部分將擴充套件到 nn.Linear 和小型 MLP,並最終應用於大語言模型中的 Transformer。
準備工作:核心概念
在開始之前,需要了解兩個定義:
- GPU 核心(kernel):是在 GPU 上並行執行的程式。
- CPU 排程並啟動這些核心。
當使用 PyTorch 操作時,它會被自動轉換為一個或多個在 GPU 上執行的核心。
建立效能分析程式碼
我們從最簡單的操作開始:一個矩陣乘法加一個偏置加法。程式碼如下:
def fn(x, w, b):
return torch.add(torch.matmul(x, w), b)使用 torch.profiler 進行效能分析的步驟如下:
- 準備好要分析的程式碼(如上)。
- 用
torch.profiler.record_function標註演算法(可選但推薦)。 - 將程式碼包裝在
torch.profiler.profile上下文管理器中。 - 匯出分析結果。
分析器產生兩個不同的產物:
- 分析表:提供事件的統計摘要,回答“什麼佔用了最多時間”。
- 追蹤資料:提供時間維度的執行檢視,回答“操作何時發生以及為何發生”。
解讀分析表
執行指令碼時,會生成包含分析表的 .txt 檔案和包含追蹤資料的 .json 檔案。分析表的第一列是觸發的事件,其他列是 CPU、GPU 等裝置上的時間。透過觀察事件消耗的時間,可以直觀地瞭解哪些是熱點。注意“自 CPU/CUDA 時間”與“總 CPU/CUDA 時間”的區別:前者僅包括事件本身的時間,後者包括其所有子事件。
例如,對於 64×64 的矩陣,自 CUDA 時間僅為 23.104 微秒,而自 CPU 時間為 2.314 毫秒,說明 GPU 大部分時間空閒,這是典型開銷受限的情況。透過將矩陣大小增加到 4096×4096,自 CUDA 時間變為 4.495 毫秒,CPU 時間為 4.908 毫秒,GPU 時間顯著增加,說明從開銷受限轉向了計算受限。
解讀追蹤資料
追蹤資料可以用 Perfetto UI 開啟。CPU 和 GPU 有各自的泳道,條形寬度表示事件持續時間,垂直巢狀表示呼叫層次。在 64×64 的追蹤中,可以觀察到以下現象:
- ProfileStep#2 耗時明顯更長:這是因為沒有預熱 GPU,導致啟動開銷被記錄。預熱步驟(先執行幾次程式碼再進行分析)可以消除這種一次性開銷。
- CPU 和 GPU 泳道之間存在約 2.5 毫秒的偏移:這是 CPU 啟動核心後,GPU 實際開始執行之前的延遲,可能涉及記憶體傳輸、核心排隊等。
總結與展望
本部分介紹了 torch.profiler 的基本用法以及如何解讀分析表和追蹤資料。透過調整矩陣大小和預熱,可以觀察到從開銷受限到計算受限的轉變。在後續部分中,我們將擴充套件這些概念到更復雜的網路,並利用分析結果指導最佳化。
透過本部分的學習,你應該能夠:
- 設定 torch.profiler 並理解其輸出。
- 讀取分析表和時間線追蹤(CPU 泳道、GPU 泳道以及兩者之間的間隙)。
- 跟蹤從 Python 呼叫到 CUDA 核心的完整事件鏈。
- 理解 torch.compile 帶來的變化。