大規模部署的功能¶
此筆記討論了幾個擴充點和技巧,這些點和技巧在較大的系統中運行 PyTorch 或在較大的組織中使用 PyTorch 運行多個系統時可能會很有用。
它不涵蓋將模型部署到生產環境的主題。請查看 torch.jit
或相關的教學文件。
此筆記假設您在組織內部從原始碼建置 PyTorch,或者能夠靜態連結額外的程式碼,以便在使用 PyTorch 時載入。因此,許多 hook 都以 C++ API 的形式公開,可以在一個集中位置觸發,例如在靜態初始化程式碼中。
全伺服器群組 Operator 分析¶
PyTorch 內建 torch.autograd.profiler
,能夠按需測量個別 operator 所花費的時間。可以使用相同的機制,針對任何執行 PyTorch 的進程進行「始終開啟」的測量。這對於收集有關在給定進程中或跨整個機器集合運行的 PyTorch 工作負載的資訊可能很有用。
可以使用 torch::addGlobalCallback
新增任何 operator 調用的新回呼。Hook 將使用 torch::RecordFunction
結構呼叫,該結構描述了調用上下文(例如 name)。如果啟用,RecordFunction::inputs()
包含以 torch::IValue
變體類型表示的函數參數。請注意,輸入記錄的開銷相對較高,因此必須明確啟用。
Operator 回呼還可以存取 c10::ThreadLocalDebugInfo::get()
介面,該介面傳回指向保存除錯資訊的結構的指標。此除錯資訊可以稍早使用 at::DebugInfoGuard
物件設定。除錯資訊會透過正向傳遞(包括非同步 fork
任務)和反向傳遞傳播,並且可用於將有關執行環境(例如,模型 ID)的額外資訊從應用程式的較高層傳遞到 operator 回呼。
調用回呼會增加一些開銷,因此通常僅隨機取樣 operator 調用會很有用。可以使用傳遞到 torch::addGlobalCallback
的可選取樣率在每個回呼的基礎上啟用此功能。
請注意,addGlobalCallback
不是執行緒安全的,只能在沒有 PyTorch operator 運作時呼叫。通常,在初始化期間呼叫它們一次是個好主意。
這是一個範例
// Called somewhere in the program beginning
void init() {
// Sample one in a hundred operator runs randomly
addGlobalCallback(
RecordFunctionCallback(
&onFunctionEnter,
&onFunctionExit)
.needsInputs(true)
.samplingProb(0.01)
);
// Note, to enable observers in the model calling thread,
// call enableRecordFunction() in the thread before running a model
}
void onFunctionEnter(const RecordFunction& fn) {
std::cerr << "Before function " << fn.name()
<< " with " << fn.inputs().size() << " inputs" << std::endl;
}
void onFunctionExit(const RecordFunction& fn) {
std::cerr << "After function " << fn.name();
}
API 使用記錄¶
在更廣泛的生態系統中運行時,例如在託管的作業排程器中,追蹤哪些二進位檔案調用特定的 PyTorch API 通常很有用。存在簡單的檢測,注入到幾個重要的 API 點,會觸發給定的回呼。因為通常 PyTorch 是在一次性的 Python 腳本中調用,所以對於每個 API,回呼僅針對給定進程觸發一次。
c10::SetAPIUsageHandler
可用於註冊 API 使用檢測處理常式。傳遞的參數將會是識別已使用點的「API 金鑰」,例如 python.import
用於 PyTorch 擴充匯入,或 torch.script.compile
如果觸發了 TorchScript 編譯。
SetAPIUsageLogger([](const std::string& event_name) {
std::cerr << "API was used: " << event_name << std::endl;
});
開發人員注意事項:可以在程式碼中使用 C10_LOG_API_USAGE_ONCE("my_api")
在 C++ 中或 torch._C._log_api_usage_once("my.api")
在 Python 中新增新的 API 觸發點。
將元資料附加到已儲存的 TorchScript 模型¶
TorchScript 模組可以儲存為歸檔檔案,該檔案將序列化的參數和模組程式碼捆綁為 TorchScript(請參閱 torch.jit.save()
)。將額外資訊與模型捆綁在一起通常很方便,例如,模型生產者的描述或輔助成品。
這可以透過將 _extra_files
參數傳遞給 torch.jit.save()
和 torch::jit::load
來儲存和檢索儲存過程中的任意二進位 Blob 來實現。由於 TorchScript 檔案是常規 ZIP 歸檔,因此額外資訊會以常規檔案的形式儲存在歸檔的 extra/
目錄中。
還有一個全域 hook 允許將額外檔案附加到目前進程中產生的任何 TorchScript 歸檔。將模型標記為生產者元資料可能很有用,類似於數位相機產生的 JPEG 元資料。範例用法可能如下所示
SetExportModuleExtraFilesHook([](const Module&) {
ExtraFilesMap files;
files["producer_info.json"] = "{\"user\": \"" + getenv("USER") + "\"}";
return files;
});
建置環境考量¶
TorchScript 的編譯需要存取原始的 Python 檔案,因為它使用 Python 的 inspect.getsource
呼叫。在某些生產環境中,可能需要明確地將 .py
檔案與預先編譯的 .pyc
一起部署。
常見的擴充點¶
PyTorch API 通常是鬆散耦合的,並且很容易用專門的版本替換元件。常見的擴充點包括
用 C++ 實作的自訂 operator - 請參閱 教學文件以取得更多詳細資訊。
通常可以透過調用相應的 Python 函式庫直接整合自訂資料讀取。可以透過擴充
Dataset
或IterableDataset
來利用torch.utils.data
的現有功能。