基準測試工具 - torch.utils.benchmark¶
- class torch.utils.benchmark.Timer(stmt='pass', setup='pass', global_setup='', timer=<built-in function perf_counter>, globals=None, label=None, sub_label=None, description=None, env=None, num_threads=1, language=Language.PYTHON)[原始碼][原始碼]¶
用於測量 PyTorch 語句執行時間的輔助類。
有關如何使用此類的完整教程,請參閱:https://pytorch.com.tw/tutorials/recipes/recipes/benchmark.html
PyTorch Timer 基於 timeit.Timer(實際上在內部使用了 timeit.Timer),但有一些關鍵區別:
- 執行時感知
Timer 將執行預熱(這很重要,因為 PyTorch 的某些元素是延遲初始化的),設定執行緒池大小以確保比較具有可比性,並在必要時同步非同步 CUDA 函式。
- 側重於重複測量
在測量程式碼,特別是複雜的核心/模型時,執行間的變異是一個顯著的混淆因素。期望所有測量都應包含重複測量,以量化噪聲並允許計算中位數,中位數比均值更穩健。為此,此類在概念上合併了 timeit.Timer.repeat 和 timeit.Timer.autorange,從而偏離了 timeit API。(具體演算法在方法文件字串中討論。)對於不希望採用自適應策略的情況,timeit 方法被複制過來。
- 可選元資料
定義 Timer 時,可以選擇指定 label、sub_label、description 和 env。(稍後定義)這些欄位包含在結果物件的表示中,並由 Compare 類用於分組和顯示結果進行比較。
- 指令計數
除了 wall time 外,Timer 還可以在 Callgrind 下執行語句並報告執行的指令數。
直接類似於 timeit.Timer 建構函式引數
stmt、setup、timer、globals
PyTorch Timer 特有的建構函式引數
label、sub_label、description、env、num_threads
- 引數
stmt (str) – 要在迴圈中執行並計時的程式碼片段。
setup (str) – 可選的設定程式碼。用於定義 stmt 中使用的變數。
global_setup (str) – (僅限 C++)放置在檔案的頂層用於 #include 語句等內容的程式碼。
timer (Callable[[], float]) – 一個返回當前時間的 Callable。如果 PyTorch 在沒有 CUDA 的情況下構建或不存在 GPU,則預設使用 timeit.default_timer;否則,它將在測量時間之前同步 CUDA。
globals (Optional[dict[str, Any]]) – 一個字典,定義了執行 stmt 時使用的全域性變數。這是提供 stmt 所需變數的另一種方法。
label (Optional[str]) – 概括 stmt 的字串。例如,如果 stmt 是“torch.nn.functional.relu(torch.add(x, 1, out=out))”,可以將 label 設定為“ReLU(x + 1)”以提高可讀性。
提供補充資訊,以區分 stmt 或 label 相同的測量。例如,在上面的例子中,sub_label 可以是“float”或“int”,以便於區分:“ReLU(x + 1): (float)”
“ReLU(x + 1): (int)” 當列印 Measurements 或使用 Compare 總結時。
用於區分 label 和 sub_label 相同的測量的字串。description 的主要用途是向 Compare 指示資料列。例如,可以根據輸入大小來設定它,以建立如下形式的表格:
| n=1 | n=4 | ... ------------- ... ReLU(x + 1): (float) | ... | ... | ... ReLU(x + 1): (int) | ... | ... | ...
使用 Compare。它在列印 Measurement 時也會包含。
env (Optional[str]) – 此標記表示在不同環境中運行了本應相同的任務,因此它們不等價,例如在對核心進行 A/B 測試時。Compare 在合併重複執行時,會將具有不同 env 規範的 Measurement 視為不同。
num_threads (int) – 執行 stmt 時 PyTorch 執行緒池的大小。單執行緒效能很重要,因為它既是關鍵的推理工作負載,也是衡量內在演算法效率的良好指標,因此預設設定為 1。這與嘗試利用所有核心的預設 PyTorch 執行緒池大小形成對比。
- adaptive_autorange(threshold=0.1, *, min_run_time=0.01, max_run_time=10.0, callback=None)[原始碼][原始碼]¶
類似於 blocked_autorange,但也會檢查測量的變異性,並重復直到 iqr/median 小於 threshold 或達到 max_run_time。
在高層面上,adaptive_autorange 執行以下虛擬碼:
`setup` times = [] while times.sum < max_run_time start = timer() for _ in range(block_size): `stmt` times.append(timer() - start) enough_data = len(times)>3 and times.sum > min_run_time small_iqr=times.iqr/times.mean<threshold if enough_data and small_iqr: break- 引數
- 返回
一個 Measurement 物件,包含測量的執行時間和重複次數,可用於計算統計資料(均值、中位數等)。
- 返回型別
- blocked_autorange(callback=None, min_run_time=0.2)[原始碼][原始碼]¶
測量多個重複,同時將計時器開銷降至最低。
在高層面上,blocked_autorange 執行以下虛擬碼:
`setup` total_time = 0 while total_time < min_run_time start = timer() for _ in range(block_size): `stmt` total_time += (timer() - start)請注意內層迴圈中的變數 block_size。塊大小的選擇對於測量質量很重要,必須平衡兩個相互競爭的目標:
較小的塊大小會產生更多的重複測量,通常會獲得更好的統計資料。
較大的塊大小可以更好地分攤計時器呼叫的成本,從而獲得偏差較小的測量結果。這很重要,因為 CUDA 同步時間不可忽略(大約為個位數到低兩位數微秒),否則會使測量產生偏差。
blocked_autorange 透過執行預熱期來設定 block_size,增加塊大小直到計時器開銷小於總計算量的 0.1%。然後將此值用於主測量迴圈。
- 返回
一個 Measurement 物件,包含測量的執行時間和重複次數,可用於計算統計資料(均值、中位數等)。
- 返回型別
- collect_callgrind(number: int, *, repeats: None, collect_baseline: bool, retain_out_file: bool) CallgrindStats[原始碼][原始碼]¶
- collect_callgrind(number: int, *, repeats: int, collect_baseline: bool, retain_out_file: bool) tuple[torch.utils.benchmark.utils.valgrind_wrapper.timer_interface.CallgrindStats, ...]
使用 Callgrind 收集指令計數。
與 wall time 不同,指令計數是確定性的(程式的非確定性以及 Python 直譯器帶來的少量抖動除外)。這使得它們非常適合進行詳細的效能分析。此方法在單獨的程序中執行 stmt,以便 Valgrind 可以對程式進行插裝。由於插裝,效能會嚴重下降,但透過較少的迭代次數通常足以獲得良好的測量結果,可以緩解此問題。
要使用此方法,必須安裝 valgrind、callgrind_control 和 callgrind_annotate。
由於呼叫者(當前程序)和 stmt 執行之間存在程序邊界,因此全域性變數不能包含任意記憶體資料結構。(與計時方法不同)相反,全域性變數僅限於內建型別、nn.Modules 和 TorchScript 化函式/模組,以減少序列化和後續反序列化帶來的意外因素。GlobalsBridge 類提供了有關此主題的更多詳細資訊。請特別注意 nn.Modules:它們依賴於 pickle,並且您可能需要在 setup 中新增匯入才能正確傳輸。
預設情況下,將收集並快取一個空語句的效能分析結果,以指示驅動 stmt 的 Python 迴圈有多少指令。
- 返回
一個 CallgrindStats 物件,提供指令計數以及一些用於分析和操作結果的基本功能。
- timeit(number=1000000)[原始碼][原始碼]¶
映象 timeit.Timer.timeit() 的語義。
執行主語句(stmt)number 次。https://docs.python.club.tw/3/library/timeit.html#timeit.Timer.timeit
- 返回型別
- class torch.utils.benchmark.Measurement(number_per_run, raw_times, task_spec, metadata=None)[原始碼][原始碼]¶
Timer 測量結果。
此類儲存給定語句的一個或多個測量結果。它是可序列化的,併為下游使用者提供了多種便利方法(包括詳細的 __repr__)。
- class torch.utils.benchmark.CallgrindStats(task_spec, number_per_run, built_with_debug_symbols, baseline_inclusive_stats, baseline_exclusive_stats, stmt_inclusive_stats, stmt_exclusive_stats, stmt_callgrind_out)[原始碼][原始碼]¶
Timer 收集的 Callgrind 結果的頂層容器。
操作通常使用 FunctionCounts 類完成,該類透過呼叫 CallgrindStats.stats(...) 獲得。還提供了一些便利方法;最重要的是 CallgrindStats.as_standardized()。
- as_standardized()[原始碼][原始碼]¶
從函式字串中去除庫名稱和某些字首。
比較兩組不同的指令計數時,一個障礙可能是路徑字首。Callgrind 在報告函式時會包含完整的檔案路徑(這是應該的)。然而,這在對比效能分析結果時可能會導致問題。如果在兩個效能分析結果中,像 Python 或 PyTorch 這樣的關鍵元件是在不同的位置構建的,可能會出現類似以下情況:
23234231 /tmp/first_build_dir/thing.c:foo(...) 9823794 /tmp/first_build_dir/thing.c:bar(...) ... 53453 .../aten/src/Aten/...:function_that_actually_changed(...) ... -9823794 /tmp/second_build_dir/thing.c:bar(...) -23234231 /tmp/second_build_dir/thing.c:foo(...)
去除字首可以透過規範化字串並在對比時更好地抵消等效呼叫點來緩解此問題。
- 返回型別
- delta(other, inclusive=False)[原始碼][原始碼]¶
對比兩組計數。
收集指令計數的一個常見原因是確定特定更改對執行某個工作單元所需的指令數產生的影響。如果更改增加了該數字,下一個合乎邏輯的問題就是“為什麼”。這通常涉及檢視程式碼的哪個部分增加了指令計數。此函式自動化了這一過程,以便可以輕鬆地基於包含和排除方式對比計數。
- 返回型別
- class torch.utils.benchmark.FunctionCounts(_data, inclusive, truncate_rows=True, _linewidth=None)[原始碼][原始碼]¶
用於操作 Callgrind 結果的容器。
- 它支援:
加法和減法以組合或對比結果。
類似元組的索引。
一個去噪函式,用於去除已知為非確定性且噪音很大的 CPython 呼叫。
兩個用於自定義操作的高階方法(filter 和 transform)。
- denoise()[source][source]¶
移除已知的噪聲指令。
CPython 直譯器中的一些指令相當嘈雜。這些指令涉及 Python 用於對映變數名的 Unicode 到字典查詢操作。FunctionCounts 通常是一個與內容無關的容器,但對於獲得可靠結果來說,這一點非常重要,值得作為一個例外。
- 返回型別
- class torch.utils.benchmark.Compare(results)[source][source]¶
用於在格式化表格中顯示多個測量結果的輔助類。
表格格式基於
torch.utils.benchmark.Timer中提供的資訊欄位(description、label、sub_label、num_threads 等)。表格可以使用
print()直接列印,或轉換為 str 型別。有關如何使用此類的完整教程,請參閱:https://pytorch.com.tw/tutorials/recipes/recipes/benchmark.html
- 引數
results (list[torch.utils.benchmark.utils.common.Measurement]) – 要顯示的測量結果列表。