Pytorch底層源碼解讀(一)概覽

前言

作為最受歡迎的深度學(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)這個過程的工具在編譯原理中就稱為后端黄刚。


llvm.png

這里我們引用一下網(wǎng)上對于llvm的相關(guān)圖片,可以從中看出llvm將不同的語言通過一系列處理生成了可以在不同的架構(gòu)上執(zhí)行的匯編語言民效,這里的前端就是C憔维、C++等,后端就是llvm在不同架構(gòu)上的backend研铆。
事實上,pytorch框架也是借鑒了這個思路州叠,針對于該框架而言棵红,python便是前端,而用c++實現(xiàn)的框架完成了后端的工作咧栗,后面涉及到相關(guān)概念時再做具體說明逆甜。

目錄樹概覽

打開pytorch源碼,從目錄樹上可以看到致板,pytorch框架十分龐大交煞,但實際上其中最核心的部分占比較小,對于入門而言斟或,只需要掌握以下兩個部分即可:

  1. torch目錄:這個部分主要存放的是是pytorch的前端代碼素征,也包括了C++的實現(xiàn),為了實現(xiàn)C++與python的混合開發(fā)萝挤,在這里使用了pybind御毅、ctypes等python包。
  2. 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)容,把目光主要放在torchaten兩個目錄即可肆氓。

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)了Modulepackage的統(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è)備上的顯存管理。

Storag繼承圖.png

現(xiàn)在我們可以對TensorStorage的實現(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展開討論,主要解讀其在后端所做的工作霞揉。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末旬薯,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子适秩,更是在濱河造成了極大的恐慌袍暴,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件隶症,死亡現(xiàn)場離奇詭異政模,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蚂会,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門淋样,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人胁住,你說我怎么就攤上這事趁猴。” “怎么了彪见?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵儡司,是天一觀的道長。 經(jīng)常有香客問我余指,道長捕犬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任酵镜,我火速辦了婚禮碉碉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘淮韭。我一直安慰自己垢粮,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布靠粪。 她就那樣靜靜地躺著蜡吧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪占键。 梳的紋絲不亂的頭發(fā)上昔善,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機(jī)與錄音捞慌,去河邊找鬼耀鸦。 笑死,一個胖子當(dāng)著我的面吹牛啸澡,可吹牛的內(nèi)容都是我干的袖订。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼嗅虏,長吁一口氣:“原來是場噩夢啊……” “哼洛姑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起皮服,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤楞艾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后龄广,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體硫眯,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年择同,在試婚紗的時候發(fā)現(xiàn)自己被綠了两入。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡敲才,死狀恐怖裹纳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情紧武,我是刑警寧澤剃氧,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站阻星,受9級特大地震影響朋鞍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜妥箕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一番舆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧矾踱,春花似錦恨狈、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至贝搁,卻和暖如春吗氏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背雷逆。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工弦讽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓往产,卻偏偏與公主長得像被碗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子仿村,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348

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