【TVM 教程】Python Target 參數(shù)化 原創(chuàng)
Apache TVM 是一個(gè)深度的深度學(xué)習(xí)編譯框架,適用于 CPU、GPU 和各種機(jī)器學(xué)習(xí)加速芯片。更多 TVM 中文文檔可訪問 →https://tvm.hyper.ai/
摘要
對(duì)于任何支持的 runtime,TVM 都應(yīng)該輸出正確的數(shù)字結(jié)果。因此,在編寫驗(yàn)證數(shù)字輸出的單元測試時(shí),這些單元測試應(yīng)該在所有支持的 runtime 上都能正常運(yùn)行。由于這是一個(gè)非常常見的用例,TVM 的輔助函數(shù)可以對(duì)所有單元測試進(jìn)行參數(shù)化,從而便于單元測試在所有啟用并具有兼容設(shè)備的 target 上運(yùn)行。
測試套件的單個(gè) Python 函數(shù),可以擴(kuò)展為幾個(gè)參數(shù)化單元測試,每個(gè)單元測試一個(gè) target 設(shè)備。為了保證測試正常運(yùn)行,以下所有條件必須為 True:
- 測試存在于已經(jīng)傳遞給?pytest?的文件或目錄中。
- 應(yīng)用于函數(shù)的 pytest 標(biāo)記,無論是顯式還是通過 target 參數(shù)化,都必須與傳遞給 pytest 的?-m?參數(shù)的表達(dá)式兼容。
- 對(duì)于使用 target fixture 的參數(shù)化測試,target 必須出現(xiàn)在環(huán)境變量?TVM_TEST_TARGETS?中。
- 對(duì)于使用?target?fixture 的參數(shù)化測試,config.cmake 中的構(gòu)建配置必須啟用相應(yīng)的 runtime。
單元測試文件內(nèi)容
在多個(gè) target 上運(yùn)行測試,推薦方法是通過參數(shù)化測試。對(duì)于一個(gè)固定的 target 列表,可以通過用?@tvm.testing.parametrize_targets('target_1', 'target_2', ...)?修飾同時(shí)接受?target?或?dev?作為函數(shù)參數(shù)來顯式地完成。
該函數(shù)將為列出的每個(gè) target 都運(yùn)行一遍,并單獨(dú)報(bào)告每個(gè) target 的運(yùn)行結(jié)果(成功/失敗)。如果一個(gè) target 因?yàn)樵?config.cmake?中被禁用而無法運(yùn)行,或者因?yàn)闆]有合適的硬件存在,那么這個(gè) target 將被報(bào)告為跳過。
# 顯式列出要使用的 target
@tvm.testing.parametrize_target('llvm', 'cuda')
def test_function(target, dev):
# 測試代碼寫在這里
對(duì)于在所有 target 上都能正常運(yùn)行的測試,可以省略裝飾器。任何接收?target?或?dev?參數(shù)的測試,都將自動(dòng)在?TVM_TEST_TARGETS?指定的所有 target 上進(jìn)行參數(shù)化。參數(shù)化為每個(gè) target 提供了相同的成功/失敗/跳過報(bào)告,同時(shí)允許輕松擴(kuò)展測試套件,以覆蓋額外的 target。
# 隱式參數(shù)化以運(yùn)行在所有 target 上
# 在環(huán)境變量 TVM_TEST_TARGETS 里
def test_function(target, dev):
# 測試代碼寫在這里
@tvm.testing.parametrize_targets?也可以用作裸裝飾器(bare decorator)來顯式地進(jìn)行參數(shù)化,但沒有額外的效果。
# 隱式參數(shù)化以運(yùn)行在所有 target 上
# 在環(huán)境變量 TVM_TEST_TARGETS 里
@tvm.testing.parametrize_targets
def test_function(target, dev):
# 測試代碼寫在這里
可以使用?@tvm.testing.exclude_targets?或?@tvm.testing.known_failing_targets?裝飾器,將特定 target 排除或標(biāo)記為預(yù)期失敗。更多信息,請(qǐng)參閱文檔字符串。
在某些情況下,可能需要跨多個(gè)參數(shù)進(jìn)行參數(shù)化。例如,可能存在一些待測試的 target-specific 實(shí)現(xiàn)方法,其中一些 target 的實(shí)現(xiàn)方法還不止一個(gè)。這可以通過顯式地參數(shù)化參數(shù)元組來完成,如下所示。在這種情況下,只有顯式地列出的 target 會(huì)運(yùn)行,但它們?nèi)詴?huì)應(yīng)用適當(dāng)?shù)?@tvm.testing.requires_RUNTIME?標(biāo)記。
pytest.mark.parametrize('target,impl', [
('llvm', cpu_implementation),
('cuda', gpu_implementation_small_batch),
('cuda', gpu_implementation_large_batch),
])
def test_function(target, dev, impl):
# 測試代碼寫在這里
參數(shù)化功能是在 pytest 標(biāo)記之上實(shí)現(xiàn)的。每個(gè)測試函數(shù)都可以用?pytest 標(biāo)記?裝飾以包含元數(shù)據(jù)。最常用的標(biāo)記如下:
@pytest.mark.gpu?- 將函數(shù)標(biāo)記為使用 GPU 功能。這本身是沒有效果的,但可以與命令行參數(shù)?-m gpu?或?-m 'not gpu'?搭配使用,從而限制 pytest 要執(zhí)行哪些測試。這不應(yīng)該單獨(dú)調(diào)用,而應(yīng)該是單元測試中使用的其他標(biāo)記的一部分。@tvm.testing.uses_gpu?- 應(yīng)用?@pytest.mark.gpu。用于標(biāo)記可能使用 GPU 的單元測試(如果有)。只有在顯式循環(huán)?tvm.testing.enabled_targets()?的測試中,才需要這個(gè)裝飾器,不過這已經(jīng)不是編寫單元測試的首選方法了(見下文)。使用?tvm.testing.parametrize_targets()?時(shí),此裝飾器對(duì)于 GPU target 是隱式的,不需要顯式地應(yīng)用。@tvm.testing.requires_gpu?- 應(yīng)用?@tvm.testing.uses_gpu,如果沒有 GPU,還要標(biāo)記這個(gè)測試應(yīng)該被跳過(@pytest.mark.skipif)。@tvfm.testing.requires_RUNTIME?- 幾個(gè)裝飾器(例如?@tvm.testing.requires_cuda),如果指定 runtime 不可用,每個(gè)裝飾器都會(huì)跳過測試。runtime 如果在?config.cmake?中被禁用,或是不存在兼容設(shè)備時(shí),則該 runtime 不可用。對(duì)于使用 GPU 的 runtime,包含?@tvm.testing.requires_gpu。
使用參數(shù)化 target 時(shí),每個(gè)測試運(yùn)行都是用跟正在使用的 target 相對(duì)應(yīng)的?@tvm.testing.requires_RUNTIME?修飾的。因此,如果某個(gè) target 在?config.cmake?中被禁用,或沒有合適的硬件可以運(yùn)行,它將被顯式列為跳過。
還有?tvm.testing.enabled_targets(),根據(jù)環(huán)境變量?TVM_TEST_TARGETS、構(gòu)建配置和存在的物理硬件,返回所有在當(dāng)前機(jī)器上啟用和可運(yùn)行的 target。大多數(shù)當(dāng)前測試顯式循環(huán)是?enabled_targets()?返回 target,但它無法應(yīng)用于新測試。這種類型的 pytest 輸出會(huì)自動(dòng)跳過在?config.cmake?中禁用,或者沒有運(yùn)行設(shè)備的 runtime。此外,測試會(huì)在第一個(gè)失敗的 target 上停止,這對(duì)于判斷錯(cuò)誤是發(fā)生在某一個(gè)還是所有 target 上,都很困難。
# 老的風(fēng)格, 已棄用。
def test_function():
for target,dev in tvm.testing.enabled_targets():
# 測試代碼寫在這里
本地運(yùn)行
要在本地運(yùn)行 Python 單元測試,可以使用?${TVM_HOME}?目錄中的命令?pytest。
-
環(huán)境變量
-
TVM_TEST_TARGETS?應(yīng)該是一個(gè)用分號(hào)分隔的待運(yùn)行 target 列表。如果未設(shè)置,默認(rèn)是?tvm.testing.DEFAULT_TEST_TARGETS?中定義的 target。注意:如果?
TVM_TEST_TARGETS?不包含任何已啟用且具有該類型可訪問設(shè)備的 target,則測試將回退到僅在?llvm?target 上運(yùn)行。 -
TVM_LIBRARY_PATH?應(yīng)該是?libtvm.so?庫的路徑。例如,這可以用來借助調(diào)試版本運(yùn)行測試。如果未設(shè)置,將搜索相對(duì)于 TVM 源目錄的?libtvm.so。
-
-
命令行參數(shù)
-
傳遞文件夾或文件的路徑,將僅在該文件夾或文件中運(yùn)行單元測試。這一點(diǎn)很實(shí)用,例如,避免在未安裝特定前端的系統(tǒng)上,運(yùn)行位于?
tests/python/frontend?中的測試。 -
-m?參數(shù)僅運(yùn)行帶有特定 pytest 標(biāo)記的單元測試。最常見的用法是使用?m gpu?僅運(yùn)行標(biāo)有?@pytest.mark.gpu?的測試,并使用 GPU 運(yùn)行。通過傳遞?m 'not gpu',它也可以用于僅運(yùn)行不使用 GPU 的測試。注意:此過濾發(fā)生在基于?
TVM_TEST_TARGETS?環(huán)境變量選定 target 之后。即使指定了?-m gpu,如果?TVM_TEST_TARGETS?不包含 GPU target,也不會(huì)運(yùn)行任何 GPU 測試。
-
在本地 Docker 容器中運(yùn)行
與在 CI 中的用法類似,docker/bash.sh?腳本可用于在同一 Docker 鏡像中運(yùn)行單元測試。第一個(gè)參數(shù)應(yīng)指定要運(yùn)行的 Docker 鏡像(例如?docker/bash.sh ci_gpu)。允許的鏡像名稱在位于 TVM 源目錄的 Jenkinsfile 頂部定義,并映射到?tlcpack?中的鏡像。
如果沒有給出額外的參數(shù),Docker 鏡像將被載入一個(gè)交互式 bash 會(huì)話。如果腳本作為可選參數(shù)傳遞(例如?docker/bash.sh ci_gpu tests/scripts/task_python_unittest.sh),則該腳本將在 Docker 鏡像中執(zhí)行。
注意:Docker 鏡像包含所有系統(tǒng)依賴項(xiàng),但不包括這些系統(tǒng)的?build/config.cmake?配置文件。 TVM 源目錄用作 Docker 鏡像的主目錄,因此這將默認(rèn)使用與本地配置相同的 config/build 目錄。一種解決方案是單獨(dú)維護(hù)?build_local?和?build_docker?目錄,并在進(jìn)入/退出 Docker 時(shí),創(chuàng)建從?build?到相應(yīng)文件夾的符號(hào)鏈接。
在 CI 中運(yùn)行
CI 中的所有內(nèi)容都從 Jenkinsfile 中的任務(wù)定義開始的。這包括定義使用哪個(gè) Docker 鏡像,編譯時(shí)配置是什么,以及哪些階段都各自包含哪些測試。
-
Docker 鏡像
Jenkinsfile 的每個(gè)任務(wù)(例如 ‘BUILD: CPU’)都會(huì)調(diào)用?
docker/bash.sh。調(diào)用 docker/bash.sh 后面的參數(shù)定義了 CI 中的 Docker 鏡像,就本地類似。 -
Compile-time 配置
Docker 鏡像沒有內(nèi)置?
config.cmake?文件,因此這是每個(gè)?BUILD?任務(wù)的第一步。這一步是使用?tests/scripts/task_config_build_*.sh?腳本完成的。使用哪個(gè)腳本取決于正在測試的構(gòu)建,還需要在 Jenkinsfile 中指定。每個(gè)?
BUILD?任務(wù)都以打包一個(gè)供以后測試使用的庫而結(jié)束。 -
運(yùn)行哪些測試
Jenkinsfile 的?
Unit Test?和?Integration Test?階段決定了如何調(diào)用?pytest。每個(gè)任務(wù)都是先解壓一個(gè)編譯庫,這個(gè)庫在先前的?BUILD?階段已經(jīng)編譯過了。接下來運(yùn)行測試腳本(如tests/script/task_python_unittest.sh)。這些腳本可以設(shè)定文件/文件夾,以及傳遞給?pytest?的命令行選項(xiàng)。其中一些腳本包含?
-m gpu?選項(xiàng),該選項(xiàng)將測試限制為僅運(yùn)行包含?@pytest.mark.gpu?標(biāo)記的測試。

















