c++ 构造函数调用方法_torch._C

本文详细解析了PyTorch中的torch._C模块,它是Python前端与C++后端交互的关键。介绍了Python与C++性能差异的原因,以及torch._C如何通过Setuptools和C++扩展实现。通过宏定义和源码编译过程,展示了torch._C模块中函数的生成机制,阐述了PyTorch如何利用C++提升性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我在简书上写了关于torch._C的文章,现将地址和原文贴上来。

torch._C​www.jianshu.com
35702d44ebe7469f240bf42819748ecc.png

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内容。

4ecae24667ab29807c4aba107dfcbef7.png

其中ext_modules指定扩展模块,torch._C就是通过这样指定的。

通过指定ext_modules,Setuptools处理torch._C的编译过程。

关键细节

ext_modules被指定为extensions,extensions(与torch._C相关的实现)如下所示:

0cf258961aecfe72dc1bd714b051db19.png

其中libraies = main_libraries指定的torch._C的来源,main_libraries定义如下

99246bd312ef4bd724f939033ec73fed.png

stub.c如下所示

745614079a15a6c36d20c13ead7b4390.png

PyMODEINIT_FUNC为链接说明,关键在于initModule()函数,该函数位于torch/csrc/Module.cpp中,如下:

5b8e9777494b01166cdf0f010616a331.png


initModule

以上图中691为例,函数通过THPUtils_addPyMethodDefs( )

d1d3432454a4fbdd63086a62d359146e.png

添加到methods(static std::vector<PyMethodDef> methods)中,在获取一些方法的定义之后,则可根据这些方法创建torchmodle。

30c4430e654123adc4ad147b2df257a2.png

,然后通过TH***_init()进行一些对象的初始化,以THPGenerator_init(PyObject *module)为例:

1d86980eac214008085a28c8a5a46ced.png


THPGenerator_init

通过PyModule_AddObject()添加到torchmodule中, 并增加PyTypeObject THPGeneratorType的引用计数。

对于以下的这些对象的初始化:

9ab0de7478b40fb46b598e7045708cc4.png


THDoubleStorage_init()

,在pytorch源码工程中搜索不到它们的具体定义,那这些函数是如何生成的呢?

我们看到torch/csrc/Storage.h

7a7c46c1a1893e658c2ad94b30617eae.png


torch/csrc/Storage.h

上图中第6行#define THPStorage_(NAME) TH_CONCAT_4(THP,Real,Storage_,NAME)中的TH_CONCAT_4的宏定义在aten/src/TH/http://THGeneral.h.in中

f5e155cd0718db6f8af05885f797e4ef.png

http://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

a01e768a8be637ac78cf89f96c475c07.png


torch/csrc/generic/Storage.h

在上图中看到了THPStorage_(init)从而可被替换成THP##Real##Storage_##init

28854d5270ba0cd85e440e340be77748.png


TH/THGenerateAllTypes.h

edbba3fae771e0acc8170b7793b55c98.png


TH/THGenerateFloats.h

4d75c5c29066c79a9cfc7221e7546ae8.png


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中对所有类型的相应文件进行上述操作,即可生成所有类型的相应函数)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值