PyTorch为实现前端的易用性与灵活性,使用了user-friendly的动态语言Python作为首选前端,但对比Python语言与C++性能的性能,前者与后者的差是数量级的。部分的原因如下:
1、Python支持动态类型,Python引入了很多抽象,需要在执行时判断数据类型,带来很大的开销,C++的数据类型在编译期就已经确定。
2、Python是种解解释型语言,C++是种编译型语言,解释型语言的代码由特定的解释器边解释边执行,很难在整体的角度对代码进行优化,编译型语言先编译后执行,编译器可对代码先进行优化。
3、GIL带来的伪多线程问题,所以Python大力发展协程和异步语法
因此,在BACK-END这种对性能有严格要求的场景,不宜用Python作为开发语言。PyTorch选择大量地使用C++/C进行扩展。torch._C就是使用的C++/C写的Python扩展。
总体框架
一般来说, 当在FRONT-END进行python函数调用时,可以追踪到toch._C开头的函数调用,然后从torch._C模块中调用对应的C++代码,这些C++代码最终可追溯到ATen和C10中的C++ API的调用。因此一定程度上torch._C模块作为C++后端和Python前端的交互模块。
对于torch._C模块的实现,其代码位于torh/csrc目录中,该目录中的代码构成torch._C的实现细节。
torch/csrc目录中的代码如何形成torch._C模块,并且让该模块中的函数等内容能在Python被调用?这得从PyTroch的编译系统说起。PyTorch使用Setuptools编译toch._C模块, 它的核心是setup.py文件,该文件包含编译项目所需要的所有信息,它最重要的setup()函数作为主要切入点,setup()指定MetaData(e.g. name, description, version, author, author_mail等)和package内容。
其中ext_modules指定扩展模块,torch._C就是通过这样指定的。
通过指定ext_modules,Setuptools处理torch._C的编译过程。
关键细节
ext_modules被指定为extensions,extensions(与torch._C相关的实现)如下所示:
其中libraies = main_libraries指定的torch._C的来源,main_libraries定义如下
stub.c如下所示
PyMODEINIT_FUNC为链接说明,关键在于initModule()函数,该函数位于torch/csrc/Module.cpp中,如下:
initModule以上图中691为例,函数通过THPUtils_addPyMethodDefs( )
THPUtils_addPyMethodDefs添加到methods(static std::vector<PyMethodDef> methods)中,在获取一些方法的定义之后,则可根据这些方法创建torchmodle。
,然后通过TH***_init()进行一些对象的初始化,以THPGenerator_init(PyObject *module)为例:
THPGenerator_init通过PyModule_AddObject()添加到torchmodule中, 并增加PyTypeObject THPGeneratorType的引用计数。
对于以下的这些对象的初始化:
THDoubleStorage_init(),在pytorch源码工程中搜索不到它们的具体定义,那这些函数是如何生成的呢?
我们看到torch/csrc/Storage.h
torch/csrc/Storage.h上图中第6行#define THPStorage_(NAME) TH_CONCAT_4(THP,Real,Storage_,NAME)中的TH_CONCAT_4的宏定义在aten/src/TH/THGeneral.h.in中
THGeneral.h.in部分也就是说THPStorage_(NAME) 被替换成 TH_CONCAT_4(THP, Real, Storage_, NAME) 被替换成 TH_CONCAT_4_EXPAND(THP, Real, Storage_, NAME) 被替换成 TH_CONCAT_4_EXPAND(THP, Real, Storage_, NAME) 被替换成 THP##Real##Storage_##NAME, 如果Real可以具体为Double、Float...,NAME可以为init..., 这样就可以构造出THDoubleStorage_init()图中这些函数。
再看torch/csrc/generic/Storage.h和TH/THGenerateAllTypes.h
torch/csrc/generic/Storage.h在上图中看到了THPStorage_(init)从而可被替换成THP##Real##Storage_##init
TH/THGenerateAllTypes.h TH/THGenerateFloats.h TH/THGenerateFloat.h在上图中看到了#define Real Float,从而THP##Real##Storage_##init可被替换成THPStorage_(init)从而可被替换成THPFloatStorage_init(),对于THPDoubleStorage_init()等函数也是一样。
涉用技术
SetupTools
THPDoubleStorage_init()、THPFloatStorage_init()等所有类型的相应函数生成(如图TH/THGeneataFloat.h中用宏先将Real替换成Float,再includeTH_GENERIC_FILE生成THPFloatStorage_init(),再将Real进行undef;在torch/csrc/Storage.h中对所有类型的相应文件进行上述操作,即可生成所有类型的相应函数)。
网友评论