以下大部分内容来源于Pytorch源码编译简明指南,并加上自己踩得一些坑。
获取源代码
编译首先是要获取源代码。
从官方获取源代码是最好的方式,从Pytorch的github官网可以下载最新的代码。
记住,从官方克隆最新的代码的时候要加入recursive
这个参数,因为Pytorch本身需要很多的第三方库参与编译:
1 | git clone --recursive https://github.com/pytorch/pytorch |
当然如果你想编译特定版本的Pytorch,需要如下操作:
1 | git clone --recursive https://github.com/pytorch/pytorch |
上面这条命令是下载并更新第三方库,我们要保证需要的第三方库都下载完毕,不然在编译过程中会中断。
目录结构
以下是Pytorch源码包展开的目录结构(只展示了主要的一些文件夹),其中主要的源码都在以下展示的文件夹中:
核心文件夹
核心文件夹主要是c10、aten、torch、caffe2.
为什么将c10放到最前面呢?
因为官方已经表明c10目录是最重要的源代码文件夹,也就是几乎所有的源代码都与这里的代码有关系,比如我们的类型定义,Pytorch最重要的Tensor的内存分配方式等等,都在这个文件夹中,官方也说到了,之后会慢慢将Aten中的代码移至这个文件夹,也就是说这个文件夹将包含Pytorch中最核心的代码。
而Aten文件夹则包含了一些实现了Tensor的底层(和c10类似),也包括了很多的层前向代码和后向实现的代码(例如卷积层的前向和后向操作代码),包括CPU和GPU端,总之都是C++的核心操作代码。
torch文件夹也同样重要,其中主要包含了一些稍微高层些的操作函数,例如torch.ones等,有C++和Python端,也包括了Python核心代码和包装代码,如果我们使用python版Pytorch的话,与这些代码接触就比较密切了。
而Caffe2则不用多说,caffe2则主要针对移动端设计了很多优化后的运算代码,模型融合、模型量化等等的代码,其后端有QNNPACK等一些针对移动端的底层运算库(有开发人员说GLOW也在caffe2后端考虑之内)。
third_party
Pytorch毕竟是大型的深度学习库,所以需要的依赖库也是有很多的,其中有很多我们耳熟能详的数值计算库(eigen、gemmlowp)、模型转换库(onnx、onnx-tensorrt)、并行训练库(gloo、nccl)、自家的底层端实现库(QNNPACK)以及绑定python端的pybind11等一系列所依赖的库。
当然还有很多库这里就不一一介绍了,总之,我们在编译的时候,Pytorch的编译代码会根据我们的设置在编译的时候,自动判断当前系统中是否存在需要的第三方库。如果不存在则使用这里的第三方库(直接编译并使用第三方库的diamante),这也是为什么我们需要执行git submodule update --init --recursive
来下载所依赖第三库源码的原因。
tools
tools这个文件夹中的内容到底是做什么的,简单看一下官方的介绍:
1 | This folder contains a number of scripts which are used as |
其中包含了一些脚本生成代码工具(利用python)、用于编译一些组件的脚本和代码,还有一些开发人员需要的工具、以及AMD显卡帮助编译代码和一些特殊情况需要使用的工具等。在我们编译Pytorch源码的过程中会使用到这个文件夹中的代码。
有一点需要说明,那就是Pytorch利用了很多的代码生成,例如操作层函数的头文件
NativeFunction.h
等,所以tools中的代码生成脚本还是比较重要的。
提一个可能会使用到的脚本build_pytorch_libs.sh
,这个脚本是用来编译libtorch库的,libtorch就是不需要python包装的使用C++的Pytorch库,方便于部署阶段使用。
关于libtorch的具体介绍和简单使用可以看这里:利用Pytorch的C++前端(libtorch)读取预训练权重并进行预测。
关于tools中的文件就不具体介绍了,大家可以看一下其中的readme
。
其他的文件夹就不多说了,相对上面的来说并不是很重要。
编译
编译重头戏来了,编译过程中大家可能会遇到各种各样的问题,但是其实只要我们将环境准备妥当,大部分都可以一次性编译好的:
- 确保你的cuda和cudnn安装正确,环境变量都设置正确
- 确保你的python环境纯净,最好使用anaconda创建一个环境,安装好pytorch需要的依赖包。
https://github.com/pytorch/pytorch#from-source - 确保你的C++编译器的版本不要太低,最好4.9以及以上
若在原来的Python环境下编译,可能出现一些奇怪的错误,例如因为我之前有Pytorch基于cuda10.2的,现在我在cuda9.0下编译出来的pytorch,也去调用cuda10.2了,更改环境变量也没有用。
编译选项
python的安装方式并不是单独利用Cmake进行构建的,而是结合了python端的setuptools搭配cmake进行构建,pytorch的项目还是比较庞大的,所以编译代码也是老长,我们主要看看编译过程中的环境变量即可:
1 | # Environment variables you are probably interested in: |
这些编译变量根据我们的需要在执行python setup.py install
使用,如果你不想编译CUDA,则NO_CUDA=1 python setup.py install
。另外,在编译之前,我们需要安装一些Python库,如numpy,否则编译出来的Pytorch就没法使用numpy和Pytorch的接口。完整过程如下:
1 | pip install numpy pyyaml mkl mkl-include setuptools cmake cffi typing |
执行以上语句我们就可以进行编译了。
编译出现的问题1
编译Pytorch1.0.0时,若编译过程中遇到RuntimeError: Source files: ['Type.h', 'Tensor.h', 'TensorMethods.h'] did not match generated files.
。这个问题是编译中产生的,原因是PyTorch1.0.0以后的版本aten/src/ATen/gen.py
中的第42行加入如下图的部分,也就是会创建一个core_tmp的文件夹,但是由于某种原因,Tensor.h, TensorMethods.h
并没有被拷贝过去,所以我们显式的设置GEN_TO_SOURCE就可以避免这个问题。
1 | export GEN_TO_SOURCE=/你的路径/pytorch/aten/src/ATen/core/ # 这个路径的设置也非常重要,如果不设置的话,系统会生成一个core_tmp/,会找不到文件需要链接的头文件导致编译失败~. |
编译出现的问题2
对于Pytorch0.4.1或者Pytorch0.5.0的版本中,caffe2要单独编译的。也就是在执行python setup.py install
之后(两者顺序不能调到),还需要执行一下python setup_caffe.py install
。caffe2依赖的Python包为numpy,future,hypothesis,protobuf
另外,对于Python3.7还需要更改vim pytorch/caffe2/python/pybind_state.h
的第二百行从str = PyUnicode_AsUTF8AndSize(input[i], &strSize);
改为str = const_cast<char*>(PyUnicode_AsUTF8AndSize(input[i], &strSize));
。
在gcc version 4.8.5 20150623 (Red Hat 4.8.5-4) (GCC)编译成功了caffe2和pytorch0.5.0
编译出现的问题3
在下拉Pytorch0.4.1的第三方库的时候,出现了错误:fatal: repository 'https://github.com/NervanaSystems/nervanagpu.git/' not found
,则执行下面语句:
1 | 从 .gitmodules中删除nervanagpu |
ninja
ninja可以大大加快编译速度,而且在编译过程中提示的错误信息更加完整和详细,如果我们想使用ninja来编译,那么直接在当前的python环境中pip install ninja
即可。
Pytorch的安装程序会自动查找当前环境中是否有ninja,如果有的话,则优先使用ninja进行编译。
不同的安装模式
只安装libtorch库:创建build文件夹,在里头执行python ../tools/build_libtorch.py
开发者模式:python setup.py build develop
(对Python开发有帮助)
安装后的自我检验
默认我们安装Pytorch的时候会自带上caffe2(当然也可以选择不安装caffe2,但是运行某些特定卷积操作时会报错~),因此我们在安装成功后不仅要检测Pytorch是否安装成功,同时也要检查caffe2是否安装成功。
Pytorch
检查Pytorch安装是否成功:
1 | import torch |
如果遇到报错ModuleNotFoundError: No module named 'torch._C'
,则大部分情况是因为当前在pytorch
源码文件夹下编译的,考虑使用cd ..
退出该文件夹,再进行验证。
caffe2
在安装caffe2的环境下运行python并导入caffe2.python
,如果顺利加载则证明安装成功。如果不能成功import的话,可以先看看错误信息,很有可能是一些小错误,例如:
1 | Python 3.6.6 |Anaconda, Inc.| (default, Oct 9 2018, 12:34:16) |
上方的导入出错是因为当期的虚拟环境没有安装protobuf
,简单执行命令pip install protobuf
即可,其他类似错误根据错误提示信息安装相应的库就可以了。
如果成功import
则不会出现报错信息:
1 | Python 3.6.6 |Anaconda, Inc.| (default, Oct 9 2018, 12:34:16) |
如何卸载
如果是源码安装的Pytorch,卸载需要执行:
1 | pip uninstall torch |
参考
Pytorch源码编译简明指南
如何查看pytorch对应cuda的版本
源码编译pytorch 1.0 遇到的问题
PyTorch學習筆記(16)——編寫你自己的PyTorch kernel(基於PyTorch1.2.0)
Fix the build break for python3.7 PyUnicode_AsUTF8AndSize() prototype changing #9259
NervanaSystems/nervanagpu Repository not found for 0.4.0 #20845