大規模部署特性¶
本注意事項討論了在較大系統內執行 PyTorch 或在大型組織中使用 PyTorch 操作多個系統時可能有用的一些擴充套件點和技巧。
本注意事項不涉及模型投入生產部署的主題。請檢視 torch.jit 或相應的教程之一。
本注意事項假設您要麼在組織內部從原始碼構建 PyTorch,要麼能夠在 PyTorch 使用時靜態連結要載入的附加程式碼。因此,許多鉤子都作為 C++ API 公開,可以在集中位置觸發一次,例如在靜態初始化程式碼中。
全艦隊(Fleet-wide)運算元分析¶
PyTorch 提供了 torch.autograd.profiler,能夠按需測量單個運算元花費的時間。可以使用相同的機制對執行 PyTorch 的任何程序進行“始終開啟”的測量。這對於收集有關給定程序或整個機器叢集中執行的 PyTorch 工作負載的資訊非常有用。
可以使用 torch::addGlobalCallback 為任何運算元呼叫新增新的回撥函式。鉤子將透過描述呼叫上下文(例如 name)的 torch::RecordFunction 結構體進行呼叫。如果啟用,RecordFunction::inputs() 包含表示為 torch::IValue 變體型別的函式引數。請注意,輸入日誌記錄相對昂貴,因此必須顯式啟用。
運算元回撥函式還可以訪問 c10::ThreadLocalDebugInfo::get() 介面,該介面返回指向儲存除錯資訊的結構體的指標。此除錯資訊可以使用 at::DebugInfoGuard 物件提前設定。除錯資訊會透過前向(包括非同步 fork 任務)和後向傳播,對於將應用程式更高層的一些執行環境額外資訊(例如模型 ID)傳遞給運算元回撥函式非常有用。
呼叫回撥函式會增加一些開銷,因此通常只隨機抽樣運算元呼叫是有用的。這可以透過將可選的取樣率傳遞給 torch::addGlobalCallback,針對每個回撥函式啟用。
請注意,addGlobalCallback 不是執行緒安全的,只能在沒有 PyTorch 運算元執行時呼叫。通常,最好在初始化期間呼叫它們一次。
這是一個例子
// 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 key”,例如,對於 PyTorch 擴充套件匯入是 python.import,如果觸發了 TorchScript 編譯,則是 torch.script.compile。
SetAPIUsageLogger([](const std::string& event_name) {
std::cerr << "API was used: " << event_name << std::endl;
});
開發者注意事項:可以在程式碼中使用 C++ 中的 C10_LOG_API_USAGE_ONCE("my_api") 或 Python 中的 torch._C._log_api_usage_once("my.api") 新增新的 API 觸發點。
為儲存的 TorchScript 模型附加元資料¶
TorchScript 模組可以儲存為存檔檔案,該檔案將序列化的引數和模組程式碼捆綁為 TorchScript(參見 torch.jit.save())。將附加資訊(例如模型生產者描述或輔助工件)與模型捆綁在一起通常很方便。
這可以透過將 _extra_files 引數傳遞給 torch.jit.save() 和 torch::jit::load 來實現,以便在儲存過程中儲存和檢索任意二進位制大物件。由於 TorchScript 檔案是常規的 ZIP 存檔,額外資訊將作為常規檔案儲存在存檔的 extra/ 目錄中。
還有一個全域性鉤子,允許將額外檔案附加到當前程序中生成的任何 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++ 實現自定義運算元 - 詳情請參閱教程。
自定義資料讀取通常可以透過呼叫相應的 Python 庫直接整合。可以透過擴充套件
torch.utils.data的現有功能來利用Dataset或IterableDataset。