前言
作為最受歡迎的深度學(xué)習(xí)框架,Pytorch如今已擁有極大的用戶群體以及開發(fā)者。但對于開發(fā)者而言,針對日益臃腫的pytorch框架進(jìn)一步更新迭代已經(jīng)成為了較大的問題,特別是對剛想要上手對pytorch底層框架進(jìn)行理解的初學(xué)者而言丹诀。
因此本系列主要針對于pytorch底層框架中的核心部分進(jìn)行解讀,為讀者展現(xiàn)其背后工作機(jī)理的同時也能使得讀者在閱讀完本系列的文章后翁垂,能夠?qū)ytorch框架有個基本的了解铆遭,甚至可以做到對其進(jìn)行修改、優(yōu)化沿猜。
本文以pytorch 2.0.1作為參考進(jìn)行講解枚荣。
Pytorch框架概覽
pytorch工作原理
絕大部分朋友應(yīng)該都聽說過前端、后端的概念啼肩,但是很多人對其的理解可能僅限于網(wǎng)頁前端橄妆、服務(wù)器后端這類。實際上祈坠,前后端的概念可以進(jìn)一步拓展害碾。
在編譯過程中,像llvm這類的工具可以將不同的語言如C++赦拘、Rust等轉(zhuǎn)化成中間代碼慌随,這部分中間代碼是與語言無關(guān)的,也就是說通過這類工具可以解決不同語言的異構(gòu)問題,實現(xiàn)這個過程的工具在編譯原理中稱為前端阁猜。在我們拿到與語言無關(guān)的中間代碼后丸逸,我們再通過一個工具將中間代碼翻譯為針對于不同指令集的匯編語言,這樣便可以實現(xiàn)不同語言在不同cpu架構(gòu)上運(yùn)行了剃袍,而實現(xiàn)這個過程的工具在編譯原理中就稱為后端黄刚。
這里我們引用一下網(wǎng)上對于llvm的相關(guān)圖片,可以從中看出llvm將不同的語言通過一系列處理生成了可以在不同的架構(gòu)上執(zhí)行的匯編語言民效,這里的前端就是C憔维、C++等,后端就是llvm在不同架構(gòu)上的backend研铆。
事實上,pytorch框架也是借鑒了這個思路州叠,針對于該框架而言棵红,python便是前端,而用c++實現(xiàn)的框架完成了后端的工作咧栗,后面涉及到相關(guān)概念時再做具體說明逆甜。
目錄樹概覽
打開pytorch
源碼,從目錄樹上可以看到致板,pytorch框架十分龐大交煞,但實際上其中最核心的部分占比較小,對于入門而言斟或,只需要掌握以下兩個部分即可:
-
torch
目錄:這個部分主要存放的是是pytorch的前端代碼素征,也包括了C++的實現(xiàn),為了實現(xiàn)C++與python的混合開發(fā)萝挤,在這里使用了pybind
御毅、ctypes
等python包。 -
aten
目錄:A Tensor Library的縮寫怜珍,這個目錄下主要包括了與Tensor
相關(guān)的內(nèi)容端蛆,例如Tensor
的定義、存儲酥泛、操作等今豆。可以看到在aten/src/Aten
目錄下柔袁,算子實現(xiàn)都在native/目錄
中呆躲。其中有CPU的算子實現(xiàn),以及CUDA的算子實現(xiàn)(cuda/)等捶索。
除了上述兩個部分以外的其他目錄歼秽,基本上都暫時不用了解,當(dāng)然不是說這些目錄不重要情组,比如c10
燥筷、caffe2
這些移植了caffe后端箩祥,但是我們在入門階段不用去了解這些內(nèi)容,把目光主要放在torch
和aten
兩個目錄即可肆氓。
torch解讀
當(dāng)然袍祖,細(xì)心的讀者應(yīng)該可以發(fā)現(xiàn),torch
目錄下的文件結(jié)構(gòu)有些眼熟谢揪,我們不妨打開安裝好的pytorch包的目錄蕉陋,就會發(fā)現(xiàn)其實源代碼下的torch目錄下的文件與最終安裝的pytorch包目錄下幾乎是一一對應(yīng)的,除了少部分源代碼中出現(xiàn)的.h頭文件不存在以外拨扶。至于為什么會出現(xiàn)這個情況凳鬓,寫過python包的讀者大概也了解,其實這就是python包(package
)的結(jié)構(gòu)患民。
要編寫一個python包首先需要定義python包的目錄結(jié)構(gòu)缩举,一個python包結(jié)構(gòu)往往具有一個主模塊和若干個子模塊,然后通過__init__.py
文件對某個目錄進(jìn)行進(jìn)行標(biāo)記匹颤,被標(biāo)記的目錄便識別為python包仅孩。我們也注意到,在torch文件夾下便存在這么一個文件印蓖,事實上辽慕,torch
文件夾下的這部分代碼就是pytorch的前端,用戶在import torch
的時候就是引入的這個目錄赦肃。
對于相當(dāng)一部分python包而言溅蛉,它們的__init__.py
文件為空,這也可以理解他宛,因為該文件的主要作用是標(biāo)記一個目錄為python包温艇,因此即使什么也不寫仍然是可以的。但是也存在部分python包會在該文件下插入一部分代碼堕汞,pytorch便是這么做的勺爱。
在討論這么做的好處之前,我們先來引入一個新的概念:import
關(guān)鍵字的執(zhí)行原理讯检。
首先我們要知道琐鲁,python和c最大的不同在于python是解釋型語言,而c是編譯型語言(雖然官方的python底層是用c實現(xiàn)的)人灼,那么python中的import
自然也不能與c中的#include
劃上等號围段。#include
實際上只是很單純地在編譯期間將一個文件引入到了另一個文件里,而python的import
卻是一個運(yùn)行時的概念投放。當(dāng)python程序執(zhí)行到某個文件的import
時奈泪,如果需要導(dǎo)入的文件是一個.py
文件,那么解釋器會將其作為一個Module
對象進(jìn)行導(dǎo)入。如果需要導(dǎo)入的是一個python包涝桅,即package
拜姿,那么解釋器會直接去執(zhí)行需要導(dǎo)入的模塊的__init__.py
文件,然后將其作為一個 Module
對象給放在當(dāng)前的全局變量中(通過globals()
函數(shù)返回)冯遂,這樣就實現(xiàn)了Module
和package
的統(tǒng)一蕊肥。
后續(xù)的具體細(xì)節(jié)本文不再深究,我們先來看看torch\__init__.py
里有什么蛤肌。
__init__.py
解讀
首先是__all__
部分壁却,從中我們可以看到很多熟悉的字眼,如rand
裸准、is_tensor
等展东,這些都是我們平時常用的函數(shù)。__all__
是針對模塊公開接口的一種約定炒俱,比起雙下劃線的方式(私有變量或者私有函數(shù))盐肃, __all__
以提供了”白名單“的形式暴露接口。具體的意思就是我們可以直接通過torch.xxx
的方式向胡,使用__all__
中給定的函數(shù)恼蓬。
__all__ = [
'typename', 'is_tensor', 'is_storage', 'set_default_tensor_type',
'set_rng_state', 'get_rng_state', 'manual_seed', 'initial_seed', 'seed',
'save', 'load', 'set_printoptions', 'chunk', 'split', 'stack', 'matmul',
'no_grad', 'enable_grad', 'rand', 'randn', 'inference_mode',
'DoubleStorage', 'FloatStorage', 'LongStorage', 'IntStorage',
'ShortStorage', 'CharStorage', 'ByteStorage', 'BoolStorage',
'_TypedStorage',
'DoubleTensor', 'FloatTensor', 'LongTensor', 'IntTensor',
'ShortTensor', 'CharTensor', 'ByteTensor', 'BoolTensor', 'Tensor',
'lobpcg', 'use_deterministic_algorithms',
'are_deterministic_algorithms_enabled',
'is_deterministic_algorithms_warn_only_enabled',
'set_deterministic_debug_mode', 'get_deterministic_debug_mode',
'set_float32_matmul_precision', 'get_float32_matmul_precision',
'set_warn_always', 'is_warn_always_enabled',
]
加載庫文件
接下來是第58行至第142行惊完,這部分代碼主要是處理在windows平臺上運(yùn)行pytorch會遇到的問題僵芹。在windows平臺上,如果使用者創(chuàng)建了一個虛擬環(huán)境用于執(zhí)行pytorch代碼小槐,那么在執(zhí)行前需要將pytorch依賴的庫目錄插入到windows的dll搜索目錄中拇派,否則將會出現(xiàn)依賴問題。
一個題外話凿跳,代碼中的win32
其實指的并不是windows系統(tǒng)件豌,而是其底層架構(gòu),不過不管是windows的64位系統(tǒng)還是32位系統(tǒng)控嗜,其底層架構(gòu)均為win32
茧彤,以免讀者混淆,在此額外說明疆栏。
另外曾掂,關(guān)于這部分代碼,對于沒有涉及過python與C壁顶、C++混合編程的讀者而言其實并不是很容易看懂珠洗,因為它使用了ctypes
庫,這是一個可以在python中調(diào)用由C若专、C++編寫并導(dǎo)出的dll
動態(tài)鏈接庫的包许蓖。如下代碼中給出的ctypes.CDLL('vcruntime140.dll')
這部分,其實就是加載了用C、C++編寫一個名為vcruntime140.dll
的文件膊爪。另外自阱,動態(tài)鏈接庫在windows系統(tǒng)中的后綴是.dll
,而在linux中的后綴是.so
蚁飒,pytorch代碼中也加載了不少.so
文件以適配linux系統(tǒng)动壤,這在后面的解析中可以看到。關(guān)于ctypes
的介紹網(wǎng)上有很多相關(guān)的資料淮逻,本文不再進(jìn)行闡述琼懊。
if sys.platform == 'win32':
pfiles_path = os.getenv('ProgramFiles', 'C:\\Program Files')
...
try:
ctypes.CDLL('vcruntime140.dll')
ctypes.CDLL('msvcp140.dll')
ctypes.CDLL('vcruntime140_1.dll')
except OSError:
print('''Microsoft Visual C++ Redistributable is not installed, this may lead to the DLL load failure.
It can be downloaded at https://aka.ms/vs/16/release/vc_redist.x64.exe''')
...
kernel32.SetErrorMode(prev_error_mode)
第146行到154行提供了根據(jù)不同的平臺加載了一個叫做libtorch_global_deps
的庫的函數(shù),這個函數(shù)將在下面進(jìn)行調(diào)用爬早。
def _load_global_deps():
if platform.system() == 'Windows' or sys.executable == 'torch_deploy':
return
lib_name = 'libtorch_global_deps' + ('.dylib' if platform.system() == 'Darwin' else '.so')
here = os.path.abspath(__file__)
lib_path = os.path.join(os.path.dirname(here), 'lib', lib_name)
ctypes.CDLL(lib_path, mode=ctypes.RTLD_GLOBAL)
第157行到202行的代碼為加載libtorch_global_deps
和其他一些庫提供了一些方法哼丈。
if (USE_RTLD_GLOBAL_WITH_LIBTORCH or os.getenv('TORCH_USE_RTLD_GLOBAL')) and \
platform.system() != 'Windows':
...
from torch._C import * # noqa: F403
細(xì)心的朋友之前或許已經(jīng)發(fā)現(xiàn)了,在pytorch的源碼中存在的torch\csrc
并沒有在安裝好的torch
目錄下出現(xiàn)筛严,這是因為這部分c++內(nèi)容以編譯好的動態(tài)庫文件代替了醉旦,第204行到第207行就是將其引入的代碼。
# Appease the type checker; ordinarily this binding is inserted by the
# torch._C module initialization code in C
if TYPE_CHECKING:
import torch._C as _C
當(dāng)然桨啃,實際上從55行到255行的代碼對于我們理解pytorch的底層原理而言并不重要车胡,一般而言這部分代碼都不會進(jìn)行改動,這部分代碼我們可以統(tǒng)一的概括為根據(jù)不同平臺加載pytorch所需要的適配的庫文件照瘾。
定義基本工具
從261行到640行的代碼實際上就是在__all__
中給出的部分的實現(xiàn)匈棘,這部分代碼被視為pytorch的一些基本工具。
def typename(o):
if isinstance(o, torch.Tensor):
return o.type()
...
return _C._get_warnAlways()
不過這部分代碼其實有相當(dāng)一部分很難讓對python了解不深入的人看懂析命,比如從379行到502行的use_deterministic_algorithms
函數(shù)主卫,這個函數(shù)用了幾乎所有的篇幅寫了一段很長的注釋,但是具體的實現(xiàn)確實只用了一行代碼鹃愤。
def use_deterministic_algorithms(mode, *, warn_only=False):
r""" Sets whether PyTorch operations must use "deterministic"
algorithms. That is, algorithms which, given the same input, and when
run on the same software and hardware, always produce the same output.
When enabled, operations will use deterministic algorithms when available,
and if only nondeterministic algorithms are available they will throw a
:class:`RuntimeError` when called.
...
# Backward mode nondeterministic error
>>> torch.randn(10, requires_grad=True, device='cuda').index_select(0, torch.tensor([0], device='cuda')).backward()
...
RuntimeError: index_add_cuda_ does not have a deterministic implementation...
"""
_C._set_deterministic_algorithms(mode, warn_only=warn_only)
根據(jù)最后一行_C._set_deterministic_algorithms(mode, warn_only=warn_only)
簇搅,可以很容易的知道這部分代碼其實是調(diào)用了torch._C
下的_set_deterministic_algorithms
函數(shù),但是當(dāng)我們打開這個torch._C
這個包對應(yīng)的__init__.pyi
文件時卻發(fā)現(xiàn)這個函數(shù)是這樣的:
def _set_deterministic_algorithms(mode: _bool, *, warn_only: _bool=...) -> None: ... # THPModule_setDeterministicAlgorithms
好像什么也沒有寫软吐。不過如果你往上翻代碼瘩将,你會發(fā)現(xiàn)在669行有如下的一段注釋:
# Defined in torch/csrc/Module.cpp
def _initExtension(shm_manager_path: str) -> None: ... # THPModule_initExtension
...
毫無疑問,在這個.pyi
文件中出現(xiàn)的函數(shù)凹耙,它們的具體實現(xiàn)其實是在torch/csrc
文件夾下的姿现,這也是為什么本文從一開始便提出僅需掌握這個目錄下的文件即可。另外使兔,.pyi
文件是python中的類型提示文件建钥,也被叫做存根文件stub file
,用于提供代碼的靜態(tài)類型信息虐沥,也可以用來表示公共的接口熊经。事實上這也很好理解泽艘,python是一個動態(tài)類型語言,它的類型推斷是根據(jù)賦值操作實現(xiàn)的镐依,而C匹涮、C++都是靜態(tài)類型語言,它們需要給定變量或者函數(shù)的類型槐壳,因此.pyi
文件給出了其靜態(tài)類型然低,這樣便做到了python和C、C++的綁定务唐。關(guān)于其原理這里不再過多闡述雳攘,筆者將在這個系列后續(xù)的文章中做進(jìn)一步解讀和說明,現(xiàn)在我們只需要認(rèn)為這部分代碼通過C枫笛、C++實現(xiàn)了可以被python調(diào)用的函數(shù)即可吨灭。
定義數(shù)字常量
毫無疑問,這部分以拓展__all__
的方式實現(xiàn)了對幾個數(shù)字常量的定義刑巧。
from math import e , nan , inf , pi
__all__.extend(['e', 'pi', 'nan', 'inf'])
定義Storage和Tensor 類
從655行開始到760行的這部分代碼就是重中之重了喧兄,它們的具體實現(xiàn)將在下一章進(jìn)行講解,本章僅針對于它們在__init__.py
文件中起到的作用進(jìn)行闡述啊楚。
from ._tensor import Tensor
from .storage import _StorageBase, _TypedStorage, _LegacyStorage, _UntypedStorage
# NOTE: New <type>Storage classes should never be added. When adding a new
# dtype, use torch.storage._TypedStorage directly.
class ByteStorage(_LegacyStorage):
@classproperty
def dtype(self):
return torch.uint8
...
_storage_classes = {
_UntypedStorage, DoubleStorage, FloatStorage, LongStorage, IntStorage,
ShortStorage, CharStorage, ByteStorage, HalfStorage, BoolStorage,
QUInt8Storage, QInt8Storage, QInt32Storage, BFloat16Storage,
ComplexFloatStorage, ComplexDoubleStorage, QUInt4x2Storage, QUInt2x4Storage,
_TypedStorage
}
# The _tensor_classes set is initialized by the call to _C._initialize_tensor_type_bindings()
_tensor_classes: Set[Type] = set()
從上方給出的代碼中可以看到吠冤,在本文件中引入了_tensor
模塊的Tensor
類,又從storage
模塊引入了一些storage類恭理,并實現(xiàn)了一些特定的storage類拯辙,諸如ByteStorage
。其實從名稱上可以看出該類是一個用于存儲字節(jié)類型數(shù)據(jù)的存儲對象蚯斯,那么什么是存儲對象呢薄风?
實際上在pytorch中饵较,每一個Tensor
對象都對應(yīng)著一個Storage
對象拍嵌,而每一個Storage
對象都對應(yīng)著一個或多個Tensor
對象,這個知識點(diǎn)在pytorch的官方文檔中其實是提到過的循诉。Tensor
對象好理解横辆,因為所有使用者都使用過torch.tensor()
或者torch.Tensor()
這種函數(shù)創(chuàng)建過Tensor
對象。tensor的中文名叫張量茄猫,這實際上是一個數(shù)學(xué)上的概念狈蚤。正如本文在一開始提到的,Tensor
相關(guān)的定義與實現(xiàn)都在aten
目錄下划纽,在本章節(jié)中脆侮,我們不刻意去解讀Tensor
的具體的c++實現(xiàn),我們將在下一節(jié)對其展開講述勇劣。
我們根據(jù)導(dǎo)入的Tensor
去查看這部分代碼在python中的實現(xiàn)靖避,從中我們可以看到潭枣,在_tensor.py
這個文件中的第84行到1190行都是Tensor
在python中的定義。
class Tensor(torch._C._TensorBase):
def __deepcopy__(self, memo):
if has_torch_function_unary(self):
return handle_torch_function(Tensor.__deepcopy__, (self,), self, memo)
if not self.is_leaf:
raise RuntimeError("Only Tensors created explicitly by the user "
"(graph leaves) support the deepcopy protocol at the moment")
...
device_type = DLDeviceType.kDLCPU
else:
raise ValueError('Unknown device type {} for Dlpack'.format(self.device.type))
return (device_type, idx)
__module__ = 'torch'
我們不細(xì)究Tensor
當(dāng)中的具體實現(xiàn)細(xì)節(jié)幻捏,先從宏觀上來看盆犁,這個類首先繼承了torch._C._TensorBase
這個類,我們剛才提到torch._C
是由C++代碼生成的篡九。因此可以知道的是谐岁,在python中的這個Tensor
繼承的是C++后端的TensorBase
類的實現(xiàn),而python中的這個Tensor
類可以視為對C++中的TesorBase
的再度封裝榛臼,因為它在這里重寫了一些python對象自帶的函數(shù)伊佃,諸如深拷貝函數(shù)__deepcoy__
。
值得注意的是沛善,這些重寫是很有必要的锭魔,比如我們在上文提到的一個Storage
對應(yīng)一個或多個Tensor
,那么自然地路呜,想要實現(xiàn)這個特性迷捧,我們就必須得重寫__deepcopy__
這個深拷貝函數(shù),因此我們可以看到在第110行有這么一段代碼:
new_storage = self.storage().__deepcopy__(memo)
我們再來看Tensor
類的storage
方法:
def storage(self):
r"""
storage() -> torch.Storage
Returns the underlying storage.
"""
if has_torch_function_unary(self):
return handle_torch_function(Tensor.storage, (self,), self)
return torch._TypedStorage(wrap_storage=self._storage(), dtype=self.dtype)
從上面兩個代碼中我們可以看到Tensor
類的__deepcopy__
方法其實是用的Storage
對象的__deepcopy__
方法胀葱,這也直接印證了一個Storage
對象對應(yīng)多個Tensor
對象漠秋。然后我們再一層層的套娃去尋找,最后我們發(fā)現(xiàn)其實這個深拷貝函數(shù)返回的是這么一個對象:
class _TypedStorage:
is_sparse = False
dtype: torch.dtype
def fill_(self, value):
self[0:len(self)] = value
return self
...
這個類并不是Storage
的基類抵屿,但是它卻有很多子類庆锦,接下來我們將來講解這個類,至于Tensor
類的剩下部分主要是對C++中的TensorBase
的封裝轧葛,用以實現(xiàn)在python端調(diào)用C++后端搂抒,這里就不再深入解讀,畢竟真要詳解尿扯,恐怕這篇文章的篇幅得翻幾番求晶,對于入門者想要了解pytorch框架而言,我們只需要知道python中的Tensor
類實現(xiàn)了對后端的TensorBase
的進(jìn)一步封裝即可衷笋。
首先我們看到storage.py
這個文件芳杏,它是我們需要關(guān)注的重點(diǎn),也是在__init__.py
中引入過的部分(上文提到的)辟宗。我們看到storage.py
的第16行到210行爵赵,這個部分是_StorageBase
的定義颠锉,我們從名稱可以看出者其實就是Storage
的基類住诸。
T = TypeVar('T', bound='Union[_StorageBase, _TypedStorage]')
class _StorageBase(object):
_cdata: Any
is_cuda: bool = False
is_sparse: bool = False
is_sparse_csr: bool = False
device: torch.device
def __init__(self, *args, **kwargs): ... # noqa: E704
...
def _untyped(self):
return self
我們首先可以注意到的一點(diǎn)是翁都,在這個類的最上方有一個泛型的類型注釋柠掂,有的讀者對TypeVar
中的bound
參數(shù)不了解横堡,這其實意味著所有屬于bound
參數(shù)對應(yīng)的類型及它的子類都可以通過類型檢查冀泻,Union[_StorageBase, _TypedStorage]
的意思就是既可以是_StorageBase
類型黔姜,也可以是_TypedStorage
類型粗悯。
在213行我們可以看到,它定義了一個新的類_UntypedStorage
如捅,從名稱上我們可以知道其實就是和_TypedStorage
相對的一個類棍现,它繼承了兩個父類,但沒有繼續(xù)實現(xiàn)或定義一些成員方法镜遣,說明這兩個父類提供的方法已經(jīng)可以實現(xiàn)_UntypedStorage
的要求了己肮。
class _UntypedStorage(torch._C.StorageBase, _StorageBase):
pass
我們再往下看,從第286行到第810行是_TypedStorage
的定義悲关,其實我們不難發(fā)現(xiàn)這個類的定義和_UntypedStorage
還是有不小的出入的谎僻,它的定義相比于_UntypedStorage
要更具象一些。
class _TypedStorage:
is_sparse = False
dtype: torch.dtype
def fill_(self, value):
self[0:len(self)] = value
return self
...
從第824行開始到最后則是_LegacyStorage
的定義寓辱,從中我們可以發(fā)現(xiàn)這個類實際上是繼承了_TypedStorage
艘绍。
class _LegacyStorage(_TypedStorage, metaclass=_LegacyStorageMeta):
@classmethod
def _new_shared(cls, size):
"""Creates a new storage in shared memory with the same data type"""
untyped_storage = torch._UntypedStorage._new_shared(size * cls().element_size())
return cls(wrap_storage=untyped_storage)
我們還記得我們是怎么一步步從__init__.py
分析到這個階段的嘛,現(xiàn)在讓我們回到定義Storage和Tensor 類的這個部分秫筏,我們可以看到__init__.py
導(dǎo)入的幾個Storage
類中诱鞠,用的最多的其實就是_LegacyStorage
了,下方是__init__.py
的截取部分这敬。
...
class QInt8Storage(_LegacyStorage):
@classproperty
def dtype(self):
return torch.qint8
class QInt32Storage(_LegacyStorage):
@classproperty
def dtype(self):
return torch.qint32
class QUInt4x2Storage(_LegacyStorage):
@classproperty
def dtype(self):
return torch.quint4x2
class QUInt2x4Storage(_LegacyStorage):
@classproperty
def dtype(self):
return torch.quint2x4
綜上所述航夺,我們可以得到如下的一個關(guān)系圖,當(dāng)然崔涂,這個繼承圖并不完整阳掐,比如對于Storage
對象在不同的設(shè)備上的實現(xiàn)是不同的,因此后面還會有_CudaLegacyStorage
這些類冷蚂,它繼承了_LegacyStorage
類缭保,實現(xiàn)了對GPU設(shè)備上的顯存管理。
現(xiàn)在我們可以對
Tensor
和Storage
的實現(xiàn)思想有大致的了解了蝙茶,實際上就是由一個python的基類繼承C++的基類艺骂,然后再由這些基類去派生其他類,pytorch其他代碼的思想也基本就是遵循這個理念尸闸。__init__.py
后續(xù)的代碼就是些細(xì)枝末節(jié)的東西了彻亲,這里不再贅述孕锄。
目錄回顧與簡介
通過對__init__.py
的解讀吮廉,我們已經(jīng)對pytorch的框架的核心部分有了一定的了解,現(xiàn)在我們再來對pytorch源碼的所有目錄進(jìn)行初步的了解(盡管當(dāng)中很大一部分可能不是核心)畸肆,但是本文將會對它們做一個簡要的介紹宦芦,之后的文章將只會圍繞當(dāng)中的核心部分展開。
1.android
是pytorch對安卓的支持庫轴脐,準(zhǔn)確地說是在安卓端編譯pytorch需要用到的调卑,寫過安卓APP的應(yīng)該都知道gradle
這個構(gòu)建工具抡砂,pytorch官方提供了支持gradle
的pytorch編譯方案。
2.aten
文章最開始已經(jīng)說過了恬涧,這里不贅述注益。
3.benchmarks
該文件夾包含可生成各種 PyTorch 功能的可重復(fù)計時的腳本,它還提供了將 PyTorch 與其他框架進(jìn)行比較的機(jī)制溯捆。
4.binaries
這個目錄其實挺讓人迷惑的丑搔,看上去像是基準(zhǔn)測試相關(guān)的工具文件。
5.c10
提揍,caffe2
這兩個目錄下的文件在之前已經(jīng)提到過了啤月,它們移植了caffee
的后端,關(guān)于caffee
后端劳跃,本文不做討論谎仲,讀者可自行搜索。
6.cmake
該目錄下有許多.camke
文件刨仑,本質(zhì)上就是對pytorch
的C++代碼進(jìn)行編譯的文件郑诺。
7.docs
該目錄下存放了一些文檔。
8.functorch
杉武,提到這個目錄就得提到另一個項目JAX
间景,本質(zhì)上這個目錄是pytorch
框架對該項目一些功能的模仿。
9.ios
作用類似于android
目錄艺智。
10.moudles
一些已經(jīng)定義好了的模型倘要。
11.mypy_plugins
沒啥用的目錄。
12.scripts
顧名思義十拣,其中包含了很多sh腳本文件封拧,作用面非常廣泛,有在各種系統(tǒng)上進(jìn)行編譯的sh腳本夭问,也有導(dǎo)出模型的腳本等等泽西。
13.test
存放了一堆測試文件,在對pytorch
源碼進(jìn)行修改后缰趋,用于測試是否有效會用到捧杉。當(dāng)然,大部分比較小的修改其實不需要使用這里的測試文件秘血。
14.third-party
第三方依賴味抖。
15.utils
一些常用的工具文件。
16.torch
上文已經(jīng)提到過灰粮。
17.torchgen
用于生成代碼仔涩。
總結(jié)
截止到這里,對pytorch框架的初步了解就到此結(jié)束粘舟,我們先是從__init__.py
文件了解了pytorch框架的前端做了哪些核心的工作熔脂,然后對整個pytorch項目的目錄進(jìn)行了粗略的解釋佩研。下一篇文章將針對pytorch的Tensor
展開討論,主要解讀其在后端所做的工作霞揉。