網(wǎng)站備案 視頻百度引流免費(fèi)推廣怎么做
分享自己在學(xué)習(xí) PyTorch 源碼時(shí)閱讀過(guò)的資料。本文重點(diǎn)關(guān)注閱讀 PyTorch 源碼的經(jīng)驗(yàn)和 PyTorch 的代碼結(jié)構(gòu)。因?yàn)?PyTorch 不同版本的源碼實(shí)現(xiàn)有所不同,所以筆者在整理資料時(shí)盡可能按版本號(hào)升序,版本號(hào)見(jiàn)標(biāo)題前[]。最新版本的源碼實(shí)現(xiàn)還請(qǐng)查看 PyTorch 倉(cāng)庫(kù)。更多內(nèi)容請(qǐng)參考:
- Ubuntu 22.04 LTS 源碼編譯安裝 PyTorch
- pytorch/CONTRIBUTING.md 機(jī)翻
- PyTorch 源碼學(xué)習(xí)
- PyTorch 源碼學(xué)習(xí):從 Tensor 到 Storage-CSDN博客
文章目錄
- [1.0.1] Oldpan:Pytorch源碼編譯簡(jiǎn)明指南
- 核心文件夾
- third_party
- tools
- [1.7.1] 孫港丶丶:查看 Pytorch 源碼
- [1.10.2] jhang的回答?:如何閱讀pytorch框架的源碼?
- [2.0.0]吾乃阿爾法:一點(diǎn) PyTorch 源碼閱讀心得
- [2.1.1]kiddyjinjin:pytorch 源碼解讀進(jìn)階版 - 總述
- [unknown] 小飛的回答?:如何閱讀pytorch框架的源碼?
- [unknown] 小飛?:PyTorch源碼學(xué)習(xí)系列 - 1.初識(shí)
- 我理解的PyTorch架構(gòu)
- PyTorch目錄結(jié)構(gòu)
- [unknown] clay001?:pytorch源碼閱讀
- 待更新……
[1.0.1] Oldpan:Pytorch源碼編譯簡(jiǎn)明指南
具體內(nèi)容見(jiàn)原文
以下是Pytorch源碼包展開(kāi)的目錄結(jié)構(gòu)(只展示了主要的一些文件夾),其中主要的源碼都在以下展示的文件夾中:
其中使用紅箭頭標(biāo)注的就是幾個(gè)比較重要的核心庫(kù)。下面簡(jiǎn)單介紹一下:
核心文件夾
核心文件夾主要是c10、aten、torch、caffe2.
為什么將c10放到最前面呢?
因?yàn)楣俜揭呀?jīng)表明c10目錄是最重要的源代碼文件夾,也就是幾乎所有的源代碼都與這里的代碼有關(guān)系,比如我們的類型定義,Pytorch最重要的Tensor的內(nèi)存分配方式等等,都在這個(gè)文件夾中,官方也說(shuō)到了,之后會(huì)慢慢將Aten中的代碼移至這個(gè)文件夾,也就是說(shuō)這個(gè)文件夾將包含Pytorch中最核心的代碼。
而Aten文件夾則包含了一些實(shí)現(xiàn)了Tensor的底層(和c10類似),也包括了很多的層前向代碼和后向?qū)崿F(xiàn)的代碼(例如卷積層的前向和后向操作代碼),包括CPU和GPU端,總之都是C++的核心操作代碼。
torch文件夾也同樣重要,其中主要包含了一些稍微高層些的操作函數(shù),例如torch.ones等,有C++和Python端,也包括了Python核心代碼和包裝代碼,如果我們使用python版Pytorch的話,與這些代碼接觸就比較密切了。
而Caffe2則不用多說(shuō),caffe2則主要針對(duì)移動(dòng)端設(shè)計(jì)了很多優(yōu)化后的運(yùn)算代碼,模型融合、模型量化等等的代碼,其后端有QNNPACK等一些針對(duì)移動(dòng)端的底層運(yùn)算庫(kù)(有開(kāi)發(fā)人員說(shuō)GLOW也在caffe2后端考慮之內(nèi))。
third_party
Pytorch畢竟是大型的深度學(xué)習(xí)庫(kù),所以需要的依賴庫(kù)也是有很多的,其中有很多我們耳熟能詳?shù)臄?shù)值計(jì)算庫(kù)(eigen、gemmlowp)、模型轉(zhuǎn)換庫(kù)(onnx、onnx-tensorrt)、并行訓(xùn)練庫(kù)(gloo、nccl)、自家的底層端實(shí)現(xiàn)庫(kù)(QNNPACK)以及綁定python端的pybind11等一系列所依賴的庫(kù)。
當(dāng)然還有很多庫(kù)這里就不一一介紹了,總之,我們?cè)诰幾g的時(shí)候,Pytorch的編譯代碼會(huì)根據(jù)我們的設(shè)置在編譯的時(shí)候,自動(dòng)判斷當(dāng)前系統(tǒng)中是否存在需要的第三方庫(kù)。如果不存在則使用這里的第三方庫(kù)(直接編譯并使用第三方庫(kù)的diamante),這也是為什么我們需要執(zhí)行git submodule update --init --recursive
來(lái)下載所依賴第三庫(kù)源碼的原因。
tools
tools這個(gè)文件夾中的內(nèi)容到底是做什么的,簡(jiǎn)單看一下官方的介紹:
This folder contains a number of scripts which are used as part of the PyTorch build process. This directory also doubles as a Python module hierarchy. 此文件夾包含許多用作PyTorch構(gòu)建過(guò)程一部分的腳本。該目錄還兼作Python模塊層次結(jié)構(gòu)。
其中包含了一些腳本生成代碼工具(利用python)、用于編譯一些組件的腳本和代碼,還有一些開(kāi)發(fā)人員需要的工具、以及AMD顯卡幫助編譯代碼和一些特殊情況需要使用的工具等。在我們編譯Pytorch源碼的過(guò)程中會(huì)使用到這個(gè)文件夾中的代碼。
有一點(diǎn)需要說(shuō)明,那就是Pytorch利用了很多的代碼生成,例如操作層函數(shù)的頭文件NativeFunction.h
等,所以tools中的代碼生成腳本還是比較重要的。
提一個(gè)可能會(huì)使用到的腳本build_pytorch_libs.sh
,這個(gè)腳本是用來(lái)編譯libtorch庫(kù)的,libtorch就是不需要python包裝的使用C++的Pytorch庫(kù),方便于部署階段使用。
關(guān)于tools中的文件就不具體介紹了,大家可以看一下其中的readme
。
其他的文件夾就不多說(shuō)了,相對(duì)上面的來(lái)說(shuō)并不是很重要。
[1.7.1] 孫港丶丶:查看 Pytorch 源碼
具體內(nèi)容見(jiàn)原文
該圖來(lái)自:PyTorch internals : ezyang’s blog
- “torch/” 中的代碼文件一般是pytorch python類的接口信息,其內(nèi)容可以直接在編輯器中通過(guò)查看定義得到,但其只包括了接口的參數(shù)信息和注釋,注釋與官方文檔中收到的內(nèi)容相同;
- “torch/csrc/” 中含有python和c++銜接的代碼,很多為編譯時(shí)生成;
- “aten/src/ATen/” 中包括了torch中許多操作的C++或C實(shí)現(xiàn),是我們查看pytorch許多函數(shù)實(shí)現(xiàn)需要關(guān)注的區(qū)域;
- “c10/” 中為torch最基本特性實(shí)現(xiàn)的部分,如張量的定義、數(shù)據(jù)類型的定義等。
因此,為查看torch函數(shù)的具體實(shí)現(xiàn),需要查看"aten/src/ATen/" 部分的內(nèi)核代碼。
其中"native/“為C++風(fēng)格的實(shí)現(xiàn),”/TH"等主要為C風(fēng)格的實(shí)現(xiàn),Edwards 說(shuō)開(kāi)發(fā)人員在努力將"/TH"等中的操作遷移到"native/"中,至少在我使用的pytorch1.7.1中,"native/"覆蓋了大部分的張量操作,如卷積、激活和損失等等。
如何查看"aten/src/ATen/native"中的函數(shù)操作?
- 首先可以在"aten/src/ATen/native/native_functions.yaml"這個(gè)注冊(cè)文件中查看函數(shù)的框架,可以確定這個(gè)函數(shù)是否在"native/"中實(shí)現(xiàn),這里的框架主要是用于代碼生成。
- 直接搜索大法,搜索文件夾中所有文件的內(nèi)容,找到你想要的函數(shù)。\
[1.10.2] jhang的回答?:如何閱讀pytorch框架的源碼?
具體內(nèi)容見(jiàn)原文
要想閱讀 pytorch 框架的源碼,最起碼得先了解框架的調(diào)用棧,以 pytorch v1.10.2的 torch.nn.conv2d 為例,介紹一下python api 接口到底層 c++ 接口的調(diào)用依賴關(guān)系:
Python API:
torch.nn.Conv2d:
---> class Conv2d, (torch/nn/modules/conv.py)
---> F.conv2d, (torch/nn/functional.py)
---> def conv2d(input: Tensor, ...) -> Tensor: ..., (torch/_C/_VariableFunctions.pyi)
C++ API:
---> at::Tensor conv2d(...), (aten/src/ATen/native/Convolution.cpp: 579)
---> at::convolution(...), (aten/src/ATen/native/Convolution.cpp: 586)
---> at::Tensor convolution(...), (aten/src/ATen/native/Convolution.cpp:743)
---> at::_convolution(...), (aten/src/ATen/native/Convolution.cpp:754)
---> at::Tensor _convolution(...), (aten/src/ATen/native/Convolution.cpp:769)
---> at::cudnn_convolution(...), (aten/src/ATen/native/Convolution.cpp:860)
---> Tensor cudnn_convolution(...), (aten/src/ATen/native/cudnn/ConvShared.cpp:265)
---> cudnn_convolution_forward(...), (aten/src/ATen/native/cudnn/ConvShared.cpp:273)
---> Tensor cudnn_convolution_forward(...), (aten/src/ATen/native/cudnn/ConvShared.cpp:221)
---> raw_cudnn_convolution_forward_out(...), (aten/src/ATen/native/cudnn/ConvShared.cpp:258)
---> void raw_cudnn_convolution_forward_out(...), (aten/src/ATen/native/cudnn/Conv_v7.cpp:669)
---> split_batch_dim_to_32bit_out(...,raw_cudnn_convolution_forward_out_32bit), (aten/src/ATen/native/cudnn/Conv_v7.cpp:673)
---> void raw_cudnn_convolution_forward_out_32bit(...), (aten/src/ATen/native/cudnn/Conv_v7.cpp:625)
---> cudnnConvolutionForward(...), (aten/src/ATen/native/cudnn/Conv_v7.cpp:658)
python 端接口比較容易查找,對(duì)于 c++ api 接口的查找給與一些建議:
- 常用 op c++ 接口都位于
aten/src/ATen/native
目錄,而且該目錄下有個(gè)native_functions.yaml
, 記錄了c++接口的調(diào)用依賴關(guān)系 - kernel 名搜索:通常我們也會(huì)通過(guò) nvprof 查看調(diào)用 kernel 名逆向查找 c++調(diào)用接口
- 關(guān)鍵字搜索:以conv2d為例, 我們也會(huì)去搜索 Tensor conv2d 關(guān)鍵字來(lái)查找,方便將 python 端的最后一個(gè)接口與 c++ 端的第一個(gè)接口對(duì)應(yīng)起來(lái);
- 先驗(yàn)知識(shí)搜索,還需要擁有一些cudnn api的先驗(yàn)知識(shí),比如我知道conv2d一定會(huì)調(diào)用 cudnnConvolutionForward 等接口, 然后搜該接口所在位置,然后逆向搜索 c++ api 接口即可
- c++ 接口的搜索一般只需要找到離 cuda kernel 或 cudnn/cublas API 最近的位置即可(所以方法 2,4是我們最常用的手段),從 python 接口到 c++ 接口的中間依賴關(guān)系沒(méi)必要深究,因?yàn)槠渲凶隽撕芏喾庋b,經(jīng)常依賴 vscode 跳轉(zhuǎn)時(shí)會(huì)斷了依賴關(guān)系;
- 推薦使用vscode開(kāi)發(fā)工具做好配置,方便c++/python 接口的跳轉(zhuǎn),有助于理解調(diào)用過(guò)程
[2.0.0]吾乃阿爾法:一點(diǎn) PyTorch 源碼閱讀心得
具體內(nèi)容見(jiàn)原文
PyTorch 的代碼對(duì)初學(xué)者來(lái)說(shuō)并不好讀,原因在于:
- 有很多 C++ 代碼是在編譯過(guò)程中生成的;
- PyTorch 前端充分利用了 Python 的動(dòng)態(tài)特性,比如 Python 函數(shù)可能經(jīng)過(guò) N 個(gè)裝飾器修飾;
- 混合 Python/C++ 調(diào)用,比如從 Python 調(diào) C++ 調(diào) Python 再調(diào) C++ 在 PyTorch 中是比較常見(jiàn)的事情;
以下是我讀 PyTorch 源代碼的一些經(jīng)驗(yàn),僅供參考:
-
明確目標(biāo): PyTorch代碼很多,建議每次只讀一個(gè)專題或者從一個(gè)特定的問(wèn)題出發(fā),比如 PyTorch AMP 是怎么實(shí)現(xiàn)的;
-
把握全局: 一上來(lái)直接讀代碼會(huì)有很多障礙,很多術(shù)語(yǔ)不明所以,先通讀這個(gè)專題下官方的教程、文檔,以及一些寫(xiě)的好的第三方博客,確保自己對(duì)這個(gè)專題下的內(nèi)容有初步的認(rèn)知。以下是一些初步了解 PyTorch 特定專題內(nèi)容的比較好的資源:
- PyTorch 教程
- PyTorch 文檔
- PyTorch 博客
- PyTorch 案例
- PyTorch 論壇
- PyTorch Youtube 頻道
-
Debug Build: 一定要 build debug 版的 PyTorch,并保留在編譯過(guò)程中生成的源代碼,否則很難找到 PyTorch 函數(shù)調(diào)用棧中一些函數(shù)的來(lái)源;
此處省略細(xì)節(jié),具體內(nèi)容見(jiàn)原文
-
靜態(tài)讀代碼: 有了完整的 PyTorch 源代碼之后就可以開(kāi)始讀了,網(wǎng)上有很多 VSCode 教程,設(shè)置好 VSCode 的 Python 和 C++ 插件,方便在函數(shù)之間跳轉(zhuǎn),可以解決一大部分的函數(shù)跳轉(zhuǎn);
-
動(dòng)態(tài)讀代碼: 靜態(tài)讀代碼的問(wèn)題是常常搞不清函數(shù)的執(zhí)行流程,此時(shí)在運(yùn)行過(guò)程中動(dòng)態(tài)讀執(zhí)行過(guò)的代碼就很有幫助,善用 gdb 和 pdb 可以有效輔助讀源代碼。
此處省略細(xì)節(jié),具體內(nèi)容見(jiàn)原文
-
充分利用源代碼中的日志、debug 選項(xiàng)、測(cè)試用例: 很多 PyTorch 模塊都包含了豐富的日志和 debug 開(kāi)關(guān),這些日志和用于調(diào)試的消息可以幫助我們理解 PyTorch 的執(zhí)行流程。除此之外,PyTorch 中包含了大量的測(cè)試用例,如果單純看源代碼無(wú)法理解程序的邏輯,看看其對(duì)應(yīng)的測(cè)試用例可以幫助我們理解程序在做什么。
此處省略細(xì)節(jié),具體內(nèi)容見(jiàn)原文
-
及時(shí)求助: 如果經(jīng)過(guò)上面的流程還無(wú)法了解某些代碼的邏輯,要及時(shí)向社區(qū)求助,避免浪費(fèi)過(guò)多時(shí)間。
-
學(xué)什么: 明確源代碼中哪些東西值得我們學(xué)習(xí)和借鑒,讀源代碼時(shí)要特別注意這些方面,比如:
- 特定模塊/功能的實(shí)現(xiàn)原理;
- 用到的算法;
- 一些 coding 技巧;
-
知行合一: You can’t understand it until you change it. 讀源代碼不是最終目的,充分利用從代碼中獲取的認(rèn)知才是。有效的輸出可以加深我們對(duì)代碼的理解,一些可以參考的輸出方式:
- 寫(xiě)一篇源碼剖析的博客;
- 簡(jiǎn)化自己對(duì)源代碼的認(rèn)識(shí),分享給其他人;
- 修改源代碼,改進(jìn)或添加一些功能,給 PyTorch 提交 PR;
- 親手實(shí)現(xiàn)相同功能,寫(xiě)精簡(jiǎn)版的代碼復(fù)現(xiàn)核心邏輯;
每一個(gè)讀源代碼的人都是不甘平凡的人,祝大家在這個(gè)“痛并快樂(lè)著”的過(guò)程中成長(zhǎng)得更快、更多。
[2.1.1]kiddyjinjin:pytorch 源碼解讀進(jìn)階版 - 總述
具體內(nèi)容見(jiàn)原文
pytorch官方給出的參考代碼結(jié)構(gòu):pytorch/pytorch
源碼解讀的代碼版本基于v2.1.1 版本:GitHub - pytorch/pytorch at v2.1.1
其中比較核心的4個(gè)目錄簡(jiǎn)單介紹如下:
torch
:python 代碼部分, the frontend, 我們?cè)诖a中引入并使用的Python 模塊(modules),基本都在這里torch/csrc
: python bindings, 這部分C++代碼實(shí)現(xiàn)了所謂的PyTorch前端(the frontend of PyTorch)。具體來(lái)說(shuō),這一部分主要橋接了Python邏輯的C++的實(shí)現(xiàn),和一些PyTorch中非常重要的部分,比如自動(dòng)微分引擎(autograd engine)和JIT編譯器(JIT compiler)。aten/src/ATen
: 是“A Tensor Library”的縮寫(xiě),是一個(gè)C++庫(kù)實(shí)現(xiàn)了Tensor的各種operations。ATen 內(nèi)對(duì)operators的實(shí)現(xiàn)分成兩類,一種是現(xiàn)代的C++實(shí)現(xiàn)版本(native),另一種是老舊的C實(shí)現(xiàn)版本(legacy)。c10
: 是一個(gè)來(lái)自于Caffe2 和 ATen的雙關(guān)語(yǔ)(Caffe 10),其中包含了PyTorch的核心抽象,比如 Tensor、Device、Allocator、Storage 等數(shù)據(jù)結(jié)構(gòu)的實(shí)際實(shí)現(xiàn)部分。
進(jìn)一步對(duì)c10/core
的代碼結(jié)構(gòu)進(jìn)一步介紹如下:
Allocator.h/cpp
: 提供memory管理的抽象類定義和實(shí)現(xiàn)。CPUAllocator.h/cpp
: set/get CPU Allocator, 指定DefaultCPUAllocator。Device.h/cpp
: 提供底層硬件的抽象類定義和實(shí)現(xiàn)。struct C10_API Device final
表示張量所在的計(jì)算設(shè)備, 設(shè)備由類型唯一標(biāo)識(shí)(cpu or cuda gpu, cuda 的話有index)
DeviceGuard.h
: RAII guardDeviceType.h
定義了21 種 DeviceType,包括我們常見(jiàn)的CPU,CUDA,XLA,HIP 等,應(yīng)該會(huì)是逐漸增加的狀態(tài)。DispatchKey.h
定義了40+種 dispatcherkey set,是個(gè) uint8_t,越高位優(yōu)先級(jí)越高,用來(lái)給op路由,當(dāng)調(diào)用一個(gè)op的時(shí)候,pytorch中的dispatch 機(jī)制會(huì)結(jié)合 DispatchKey 以及當(dāng)時(shí)的場(chǎng)景(在什么硬件上?是推理還是訓(xùn)練?)分配到特定的執(zhí)行算子上,這個(gè)機(jī)制保證了pytorch可以非常靈活的在不同的硬件和場(chǎng)景下切換。后面會(huì)詳細(xì)講講,比較有意思。DispatchKeySet.h
TensorOptions.h/cpp
: 提供創(chuàng)建張量時(shí)的選項(xiàng)(如設(shè)備類型、數(shù)據(jù)類型等)的定義和相關(guān)操作。TensorImpl.h/cpp
: 提供張量的具體實(shí)現(xiàn)。
其他:Backend.h
(老舊版本的 Device.h/cpp, layout 信息),提供多種新舊互相轉(zhuǎn)換接口
[unknown] 小飛的回答?:如何閱讀pytorch框架的源碼?
具體內(nèi)容見(jiàn)原文
分享下我個(gè)人學(xué)習(xí)經(jīng)驗(yàn)
- 首先自己一定要編譯源碼,學(xué)會(huì)用GDB去調(diào)試代碼。任何源碼學(xué)習(xí)的第一步永遠(yuǎn)是將源碼編譯成功并運(yùn)行起來(lái)。其次切記不要去看
setup.py
文件,不要去看torch/__init__.py
文件,不要去看C++編譯配置文件。如果你沒(méi)有豐富的相關(guān)工程開(kāi)發(fā)經(jīng)驗(yàn),從你打開(kāi)這些文件起,恭喜你,你已經(jīng)被成功勸退了。初學(xué)者就應(yīng)該老老實(shí)實(shí)先學(xué)習(xí)項(xiàng)目的設(shè)計(jì)思想和架構(gòu),忽略工程配置。 - 了解下Python語(yǔ)言如何與C/C++語(yǔ)言綁定。PyTorch底層核心代碼都是用C/C++編寫(xiě),如果你僅僅想學(xué)習(xí)的是Python部分的源碼,那本回答就到此結(jié)束了,根據(jù)你python里的模塊用到哪學(xué)到哪就行了。如果你想深入學(xué)習(xí)C/C++源碼,這是一道必須邁過(guò)的坎。不理解的話你對(duì)PyTorch的認(rèn)識(shí)永遠(yuǎn)是Python和C/C++兩個(gè)孤零零的世界,無(wú)法聯(lián)系起來(lái)。
- 先學(xué)習(xí)Tensor。Tensor是貫穿整個(gè)PyTorch最基本的數(shù)據(jù)結(jié)構(gòu),無(wú)論何時(shí)你都會(huì)遇到它。
- 了解算子。通過(guò)最簡(jiǎn)單的Tensor.Add 方法學(xué)習(xí)下Tensor函數(shù)是如何設(shè)計(jì)的。PyTorch里操作Tensor的函數(shù)被稱之為算子,算子包含前向和后向計(jì)算。這里不要求完全弄懂算子,只需要了解相關(guān)流程就行。
- 學(xué)習(xí)Autograd。先了解計(jì)算圖的概念,學(xué)習(xí)下PyTorch是如何創(chuàng)建和維護(hù)計(jì)算圖。如何反向傳播自動(dòng)求解梯度更新權(quán)重。
學(xué)到這里你基本上對(duì)PyTorch C/C++底層架構(gòu)有所了解,下面就是根據(jù)自己喜愛(ài)的方向去學(xué)習(xí)。
- 如果你想研究深度學(xué)習(xí)模型,去看Python torch.nn包里面的python源碼就行。
- 如果你想研究算子實(shí)現(xiàn),還記得我們前面學(xué)的Add方法了,找到你想了解的算子去深入,如果不關(guān)心速度,看下CPU代碼就行,如果想學(xué)習(xí)如何優(yōu)化就去了解cuda編程。
- 如果想學(xué)習(xí)分布式,就去研究下分布式相關(guān)的code。
其實(shí)從上面的流程看,只要你前5步都完成了,你自然而然就知道該如何去學(xué)習(xí)PyTorch框架源碼。現(xiàn)在PyTorch源碼很大,想在有限時(shí)間內(nèi)一下子全看完不現(xiàn)實(shí),必然要結(jié)合自己的實(shí)際情況有所側(cè)重。
[unknown] 小飛?:PyTorch源碼學(xué)習(xí)系列 - 1.初識(shí)
具體內(nèi)容見(jiàn)原文
PyTorch本身是一個(gè)Python擴(kuò)展包,按照官方說(shuō)法它主要具有以下兩種特色:
- 支持GPU加速的張量(Tensor)計(jì)算
- 在一個(gè)類似磁帶(前向和反向)的梯度自動(dòng)計(jì)算(Autograd)系統(tǒng)上搭建深度神經(jīng)網(wǎng)絡(luò)
Tensor其實(shí)本質(zhì)上就是一個(gè)多維數(shù)組。在數(shù)學(xué)上單個(gè)數(shù)據(jù)我們稱之為標(biāo)量,一維數(shù)據(jù)我們稱之為向量,二維數(shù)據(jù)我們稱之為矩陣。
如果PyTorch僅是支持GPU加速的Tensor計(jì)算框架,那它也就是NumPy的替代品而已。其最核心的功能就是Autograd系統(tǒng),目前深度學(xué)習(xí)就是基于梯度反向傳播理論來(lái)達(dá)到網(wǎng)絡(luò)的自我訓(xùn)練。PyTorch的Autograd系統(tǒng)是創(chuàng)建了一個(gè)動(dòng)態(tài)的計(jì)算圖,用戶只需要關(guān)注前向計(jì)算網(wǎng)絡(luò)搭建,PyTorch會(huì)自動(dòng)根據(jù)動(dòng)態(tài)計(jì)算圖去反向計(jì)算梯度并更新網(wǎng)絡(luò)權(quán)重。
在設(shè)計(jì)之初PyTorch并沒(méi)打算僅成為一個(gè)綁定C++框架的Python包,它緊密地將C++框架集成到python中。你可以在使用PyTorch的同時(shí)也結(jié)合使用NumPy/SciPy/scikit-learn這些優(yōu)秀的科學(xué)計(jì)算包,同時(shí)你也可以用Python編寫(xiě)你自己的神經(jīng)網(wǎng)絡(luò)層(PyTorch神經(jīng)網(wǎng)絡(luò)相關(guān)的代碼基本上都是Python編寫(xiě))。
正如前面所說(shuō),PyTorch的計(jì)算圖是動(dòng)態(tài)的,當(dāng)你寫(xiě)下一行Python代碼的時(shí)候你就可以直接運(yùn)行得到結(jié)果。對(duì)用戶來(lái)說(shuō),PyTorch的世界就是一個(gè)簡(jiǎn)單的單線程同步非阻塞世界,你可以得到實(shí)時(shí)反饋,這對(duì)于剛開(kāi)始接觸深度學(xué)習(xí)的新手來(lái)說(shuō)是非常貼心的功能,可以幫忙新手快速入門(mén)。
我理解的PyTorch架構(gòu)
根據(jù)自己的理解簡(jiǎn)單畫(huà)了下PyTorch的架構(gòu)圖,隱藏了部分細(xì)節(jié)。本系列也將主要圍繞著這張架構(gòu)圖去學(xué)習(xí)PyTorch的具體實(shí)現(xiàn)。
一共將PyTorch分成了四層,分別是
- 應(yīng)用層(Python)。這應(yīng)該是大家最熟悉的層,主要涉及到張量,Autograd以及神經(jīng)網(wǎng)絡(luò)。該層所有的源碼都是由Python編寫(xiě),這也符合前面所說(shuō)的PyTorch設(shè)計(jì)思想-——將C++框架集成到Python里
- 實(shí)現(xiàn)接口層(C++)。該層的主要功能我認(rèn)為有兩個(gè):
- Python 擴(kuò)展。通過(guò)Python提供的C API將Python應(yīng)用層與C++實(shí)現(xiàn)層綁定起來(lái),使用戶在享受Python語(yǔ)言提供的便捷優(yōu)勢(shì)時(shí)也可以同時(shí)享受到C++語(yǔ)言提供的性能優(yōu)勢(shì)
- Autograd系統(tǒng)實(shí)現(xiàn)。 PyTorch并沒(méi)有在實(shí)現(xiàn)層中實(shí)現(xiàn)Autograd系統(tǒng)。在此層中PyTorch定義了動(dòng)態(tài)有向圖的基本組件Node和Edge,以及在此基礎(chǔ)上封裝了Function類和Engine類來(lái)實(shí)現(xiàn)Autograd
- 實(shí)現(xiàn)層(C++)。該層是PyTorch的核心層,定義了PyTorch運(yùn)行過(guò)程中的核心庫(kù),包括Tensor的具體實(shí)現(xiàn),算子實(shí)現(xiàn)(前向與后向運(yùn)算)以及動(dòng)態(tài)調(diào)度系統(tǒng)(Tensor的布局,硬件設(shè)備,數(shù)據(jù)類型)。Storage類主要是針對(duì)不同硬件數(shù)據(jù)存儲(chǔ)的一種抽象。
- 硬件接口層。該層主要是硬件廠商基于自家硬件推出的運(yùn)算接口。
PyTorch目錄結(jié)構(gòu)
PyTorch的源碼托管于GitHub平臺(tái),其目前的代碼量已經(jīng)非常巨大。新手第一次接觸的時(shí)候往往會(huì)因此被勸退,但其實(shí)里面很多文件和我們學(xué)習(xí)PyTorch源碼并沒(méi)有太多的直接關(guān)系,所以我們第一步就是要理清目錄結(jié)構(gòu),專注于我們需要學(xué)習(xí)的內(nèi)容。
torch
:我們“import torch”后最熟悉的PyTorch庫(kù)。所有非csrc文件夾下的內(nèi)容都是標(biāo)準(zhǔn)的Python模塊,對(duì)應(yīng)我們架構(gòu)圖中的應(yīng)用層csrc
:該目錄下都是C++源碼,Python綁定C++的相關(guān)code都在這個(gè)目錄里面,同時(shí)也包含了對(duì)PyTorch核心庫(kù)的一些封裝,對(duì)應(yīng)我們架構(gòu)圖中的實(shí)現(xiàn)接口層csrc/autograd
:梯度自動(dòng)計(jì)算系統(tǒng)的C++實(shí)現(xiàn)autograd
:梯度自動(dòng)計(jì)算系統(tǒng)的Python前端源碼,包含torch中支持的所有自動(dòng)求導(dǎo)算子nn
:建立在autograd系統(tǒng)上的神經(jīng)網(wǎng)絡(luò)庫(kù),包含了深度學(xué)習(xí)中常用的一些基礎(chǔ)神經(jīng)網(wǎng)絡(luò)層。optim
:機(jī)器學(xué)習(xí)中用到的優(yōu)化算法庫(kù)
aten
:“a tensor library”的縮寫(xiě),對(duì)應(yīng)我們結(jié)構(gòu)圖中的實(shí)現(xiàn)層。從名字上也能知道,這個(gè)庫(kù)設(shè)計(jì)之初主要是為T(mén)ensor服務(wù)。因?yàn)樵趯?shí)現(xiàn)接口層下面,所以這里的Tensor并不支持autogradsrc/Aten/core
:aten的核心基礎(chǔ)庫(kù)。目前這個(gè)庫(kù)里面的代碼正在逐漸地遷移到c10目錄下面src/Aten/native
:PyTorch的算子庫(kù),這個(gè)目錄下面的算子都是CPU的算子。對(duì)于一些專門(mén)CPU指令優(yōu)化的算子會(huì)在子目錄里面src/Aten/native/cuda
:cuda算子實(shí)現(xiàn)
c10
:“caffe2 aten”的縮寫(xiě),PyTorch的核心庫(kù),支持服務(wù)端和移動(dòng)端。tools
:PyTorch中很多相似源碼都是腳本通過(guò)模板自動(dòng)生成的,這個(gè)文件夾下面就放著自動(dòng)生成代碼的腳本
[unknown] clay001?:pytorch源碼閱讀
具體內(nèi)容見(jiàn)原文
pytorch代碼主要由C10(Caffe Tensor Library,最基礎(chǔ)的Tenor庫(kù)代碼),ATen(A Tensor library for C++11,基于C10),torch三大部分組成。
torch.nn
中包含各種神經(jīng)網(wǎng)絡(luò)層,激活函數(shù),損失函數(shù)的類,使用時(shí)需要先創(chuàng)建對(duì)象。
torch.nn.functional
中的接口可以直接調(diào)用函數(shù)而不用創(chuàng)建對(duì)象。
算子配置文件:pytorch/aten/src/Aten/native/native_functions.yaml
中有關(guān)于各個(gè)算子的說(shuō)明,同級(jí)目錄下有這些算子的實(shí)現(xiàn)。每個(gè)算子有一些字段:func,variants,dispatch。

func
字段:表示算子的名稱和輸入輸出類型variants
字段:表示高級(jí)方法的使用方式,function
表示可以用torch.xxx()
的方式調(diào)用,method
表示在tensor a上,用a.xxx()
的方式調(diào)用
dispatch
字段:分發(fā)的設(shè)備類型,CPU,CUDA等等
算子通常成對(duì)出現(xiàn)(正向和反向)。
python_module: nn
表示將該方法自動(dòng)生成到torch.nn.functional
模塊中,可以通過(guò)torch.nn.functional.leaky_relu
的方式來(lái)調(diào)用。
反向算子配置文件:在tools/autograd/derivatives.yaml
中添加算子和反向算子的對(duì)應(yīng)關(guān)系。
算子表層實(shí)現(xiàn)文件:aten/src/Aten/native/
目錄下的h和cpp文件。有些會(huì)按照功能實(shí)現(xiàn)在一起,比如Activation.cpp中包含了多個(gè)算子。在這些cpp實(shí)現(xiàn)中,用到了封裝后的函數(shù),會(huì)再往里調(diào)一層。
算子底層實(shí)現(xiàn)文件:aten/src/ATen/native/cpu/
目錄下,通常以xxx_kernel.cpp
的形式存在。