理解PyTorch分發(fā)機制的內(nèi)部工作原理

概述

PyTorch的成功歸功于其簡單易用性(與Python的用法相似)和動態(tài)靈活性棺蛛。即使在PyTorch 2.0時代,它仍然保持著"Faster, more pythonic and dynamic as ever"的核心特性别厘。

PyTorch的動態(tài)性源自內(nèi)部的調(diào)度器(dispatcher),它可以根據(jù)不同的輸入類型自動選擇正確的運算方式拥诡。當調(diào)用Python函數(shù)時触趴,調(diào)度器會根據(jù)傳入的參數(shù)類型選擇正確的操作實現(xiàn)氮发,這個過程稱為分派(dispatch)。

例如冗懦,當執(zhí)行矩陣乘法(torch.matmul(a, b))時爽冕,調(diào)度器會根據(jù)輸入張量a和b的類型(dtype、shape披蕉、device等)選擇正確的BLAS庫(CPU還是CUDA颈畸,float還是half,是否批量計算)來進行計算没讲。對于PyTorch來說眯娱,模型的執(zhí)行過程就是將各個操作(op)分派給本地方法(native function)執(zhí)行的過程。

http://blog.ezyang.com/2020/09/lets-talk-about-the-pytorch-dispatcher/

dispatcher 為每個 op 都維護了一張?zhí)D(zhuǎn)表(它有點像 C++ 實現(xiàn)多態(tài)用的虛表)食零,如上圖所示困乒,表中每個條目存儲了一個本地方法寂屏,有些方法和輸入張量所屬的設備有關(guān)贰谣,比如 XLA/CUDA/CPU,有的和 requires_grad 有關(guān)迁霎,比如 Autograd(這圖是從 ezyang’s blog 拿來的吱抚,他這篇博客詳細講解了分派機制,建議閱讀)考廉。

當 op 被執(zhí)行時秘豹,e.g. aten::addmm,調(diào)度器會在它的跳轉(zhuǎn)表中找出一個方法來執(zhí)行昌粤,而且一個 op 執(zhí)行過程可能會調(diào)用多個方法既绕,例如,輸入張量需要求導(requires_grad = true)涮坐,那會先調(diào)用 Autograd 方法來構(gòu)建反向圖凄贩,再調(diào)用 backend(CPU/CUDA/XLA)的方法來運算。

分派規(guī)則

http://blog.ezyang.com/2020/09/lets-talk-about-the-pytorch-dispatcher/

跳轉(zhuǎn)表里的條目是以鍵值對的形式來存調(diào)度方法袱讹,其中“鍵”稱為 dispatch key疲扎,以 bit 的形式存在,bit 值越大捷雕,優(yōu)先級越高椒丧,調(diào)度器會從鍵集(dispatch key set)中選取優(yōu)先級最高的條目來執(zhí)行。

從上圖可以看到救巷,鍵集不只有一個壶熏,每個輸入張量都有自己的鍵集,還有 local(local includelocal exclude) 和 global 鍵集浦译,這些鍵集最終會合并棒假,調(diào)度器從中選取優(yōu)先級最高的鍵值對應的方法來執(zhí)行俄占。

輸入張量的鍵集是比較好理解的,張量本身具有很多屬性淆衷,如 layout (dense or sparse)缸榄、shape 和 device (CPU or CUDA),一個屬性對應一個 dispatch key(可以從 DispatchKey.h 找到所有的 key)祝拯。對于不同類型的張量甚带,我們希望能使用不同實現(xiàn)的操作以實現(xiàn)高性能計算的目標。

Local 鍵集 與張量個體無關(guān)佳头,與模型的行為有關(guān)鹰贵,表示模型運行在某模式中,比如 tracing康嘉。它可以允許用戶在某個范圍內(nèi)開啟或關(guān)閉模式碉输。要開啟模式就是往 local include 里添加鍵,要關(guān)閉模式就是往 local exclude 里添加要屏蔽的鍵亭珍。

Global 則表示無論什么操作都會添加的鍵集(圖中 autograd 已經(jīng)從 global 移到 tensor 鍵集)敷钾。

分派流程

http://blog.ezyang.com/2020/09/lets-talk-about-the-pytorch-dispatcher/

前面也提到,一個 op 的執(zhí)行是要經(jīng)歷多次分派的肄梨,上圖就展示了這個過程:

  • 首先阻荒,輸入張量需要求導(requires_grad = true),調(diào)度器就分派給 Autograd key 的本地方法众羡。它會為 op 生成一個反向計算操作侨赡,然后,再把控制權(quán)交給調(diào)度器做重新分派粱侣。
  • 接著由于輸入張量在CPU上羊壹,CPU的方法會被分派執(zhí)行。

前面提到齐婴,調(diào)度器會調(diào)用優(yōu)先級最高的 dispatch key油猫,因此,重新分派的前提是將已經(jīng)調(diào)度過的鍵從鍵集里清除尔店,否則重新分派將會重復調(diào)用相同的方法眨攘。

Autograd 的本地方法通過在 local exclude 鍵集中添加要屏蔽的鍵(Autograd)來避免方法的重復調(diào)用∠荩可以通過創(chuàng)建 AutoNonVariableTypeMode RAII guard 來實現(xiàn):

class MyAddFunction : public torch::autograd::Function<MyAddFunction> {
 public:
  static Tensor forward(
      AutogradContext *ctx, torch::Tensor self, torch::Tensor other) {
    at::AutoNonVariableTypeMode g;
    return myadd(self, other);
  }
  ...
};

注冊自定義操作

回想一下分派規(guī)則:調(diào)度器首先找到 op 對應的跳轉(zhuǎn)表鲫售,合并鍵集,并調(diào)用鍵值最大的條目中的函數(shù)该肴。由于 dispatch key 是 PyTorch 固定且不可擴展的情竹,因此注冊自定義操作需要注冊 op 以及跳轉(zhuǎn)表中鍵的方法。

注冊 op

TORCH_LIBRARY(myops, m) {
  m.def("myadd(Tensor self, Tensor other) -> Tensor");
}

PyTorch 提供 TORCH_LIBRARY 用于將 op(也稱作 schema stringsignature)注冊到一個庫里匀哄,用戶可以在 python 通過 c = torch._ops.myops.myadd(a, b) 調(diào)用該 op秦效。

schema 與 TensorFlow 的 op_def 和 ONNX 的 node 一樣雏蛮,都用于描述一個操作,只是由于 PyTorch 是動態(tài)圖的阱州,schema 不需要也不能承載更多信息挑秉。

注冊 dispatch function

TORCH_LIBRARY_IMPL(myops, CUDA, m) {
  m.impl("myadd", myadd_cuda);
}

注冊完 op 后,接著就可以通過 TORCH_LIBRARY_IMPL 注冊 dispatch key 對應的方法苔货。上述代碼片段通過將 myadd_cuda 注冊到鍵:CUDA犀概。

除了為每個鍵單獨注冊一個方法,還可以為所有的鍵注冊一個共同的方法夜惭,這類方法稱為 catch-all

TORCH_LIBRARY(myops, m) {
  m.def("myadd", myadd_catchall);
}

此外姻灶,還可以為所有 op 的某個鍵注冊一個共同的 fallback 方法:

TORCH_LIBRARY_IMPL(_, XLA, m) {
  m.fallback(xla_fallback);
}

除了 dispatch key 具有優(yōu)先級外,這些方法也有優(yōu)先級:impl > catch-all > fallback:

http://blog.ezyang.com/2020/09/lets-talk-about-the-pytorch-dispatcher/

END

PyTorch的調(diào)度器(dispatcher)和分派機制是其靈活性和高性能計算的關(guān)鍵诈茧。調(diào)度器根據(jù)輸入類型自動選擇適當?shù)牟僮鲗崿F(xiàn)产喉,通過分派流程將操作分派給本地方法執(zhí)行。分派規(guī)則通過 dispatch key 和 keyset 確定執(zhí)行方法的優(yōu)先級敢会。注冊自定義操作的過程允許用戶擴展PyTorch的功能曾沈。了解這些原理有助于深入理解PyTorch的內(nèi)部工作機制,并為模型開發(fā)和優(yōu)化提供指導走触。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末晦譬,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子互广,更是在濱河造成了極大的恐慌,老刑警劉巖卧土,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惫皱,死亡現(xiàn)場離奇詭異,居然都是意外死亡尤莺,警方通過查閱死者的電腦和手機旅敷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來颤霎,“玉大人媳谁,你說我怎么就攤上這事∮呀矗” “怎么了晴音?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長缔杉。 經(jīng)常有香客問我锤躁,道長,這世上最難降的妖魔是什么或详? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任系羞,我火速辦了婚禮郭计,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘椒振。我一直安慰自己昭伸,他們只是感情好,可當我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布澎迎。 她就那樣靜靜地躺著勋乾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪嗡善。 梳的紋絲不亂的頭發(fā)上辑莫,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天,我揣著相機與錄音罩引,去河邊找鬼。 笑死袁铐,一個胖子當著我的面吹牛揭蜒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播剔桨,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼屉更,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了洒缀?” 一聲冷哼從身側(cè)響起瑰谜,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎树绩,沒想到半個月后萨脑,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡饺饭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年渤早,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瘫俊。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡鹊杖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出扛芽,到底是詐尸還是另有隱情骂蓖,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布胸哥,位于F島的核電站涯竟,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜庐船,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一银酬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧筐钟,春花似錦揩瞪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至壹将,卻和暖如春嗤攻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背诽俯。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工妇菱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人暴区。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓闯团,卻偏偏與公主長得像,于是被迫代替她去往敵國和親仙粱。 傳聞我的和親對象是個殘疾皇子房交,可洞房花燭夜當晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容