Linux下編譯安裝PyTorch源碼
前言
本篇記錄在Linux下編譯安裝PyTorch源碼的流程,以及編譯過程中電腦當機的解決方式。
Prerequisite
首先確定環境中已安裝了對應版本的CUDA及cudnn,筆者是使用打包好的docker環境。使用如下指令拉取docker image:
docker pull nvidia/cuda:11.8.0-cudnn8-devel-ubuntu20.04
# docker pull nvidia/cuda:11.3.0-cudnn8-devel-ubuntu18.04 # older version
接著啟動並進入docker container:
docker run --name <name> -td -p 8888:8888 -v /home/xxx/Documents:/root/Documents --restart always nvidia/cuda:11.8.0-cudnn8-devel-ubuntu20.04
docker exec -it <name> bash
上述docker image中並未安裝Anaconda,完成在Ubuntu中安裝Anaconda後,再繼續以下步驟。
conda install astunparse numpy ninja pyyaml mkl mkl-include setuptools cmake cffi typing_extensions future six requests dataclasses
使用nvcc --version
查看cuda版本,在筆者機器下運行的結果為:
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2021 NVIDIA Corporation
Built on Sun_Mar_21_19:15:46_PDT_2021
Cuda compilation tools, release 11.3, V11.3.58
Build cuda_11.3.r11.3/compiler.29745058_0
可以得知CUDA版本為11.3,到pytorch/repo查找並安裝對應版本的magma-cuda*
:
conda install -c pytorch magma-cuda113
注:nvidia/cuda:11.8.0-cudnn8-devel-ubuntu20.04
應安裝magma-cuda118
Ubuntu 22.04
在Ubuntu 22.04中預設只有gcc 11,但PyTorch目前只能用gcc 9編譯,所以在此環境下需要另外安裝gcc 9:
apt install gcc-9 g++-9
另外在Ubuntu 20.04中編譯時會出現如下錯誤:
ninja: error: '/usr/lib/x86_64-linux-gnu/libpthread.so', needed by 'lib/libtorch_cpu.so', missing and no known rule to make it
ninja: error: '/usr/lib/x86_64-linux-gnu/libdl.so', needed by 'lib/libtorch_cpu.so', missing and no known rule to make it
ninja: error: '/usr/lib/gcc/x86_64-linux-gnu/9/libgomp.so', needed by 'lib/libtorch_cpu.so', missing and no known rule to make it
表示在系統中找不到上述so檔。但實際去該路徑下找,卻可以找到同名的so.x檔。
參考libpthreads.so missing in Ubuntu 21.10 (amd64),只要自己手動create soft link即可解決:
ln -s libpthread.so.0 libpthread.so
ln -s libdl.so.2 libdl.so
ln -s libgomp.so.1 libgomp.so
下載PyTorch源碼
git clone --recursive https://github.com/pytorch/pytorch
cd pytorch
# if you are updating an existing checkout
git submodule sync
git submodule update --init --recursive --jobs 0
編譯安裝PyTorch
設定環境變量:
export CMAKE_PREFIX_PATH=${CONDA_PREFIX:-"$(dirname $(which conda))/../"}
pytorch/From Source中給出的編譯(安裝)指令為:
python setup.py install
如果想要自行修改PyTorch中的Python源碼,可以改用以下指令。如此一來,每次改動.py
檔後,不必重新安裝,改動的部分便會自動生效。
python setup.py develop
參考Dispatcher Structured Kernels Lab,為了更好地trace code,可以開啟下列選項編譯:
REL_WITH_DEB_INFO=1 USE_PER_OPERATOR_HEADERS=0 USE_DISTRIBUTED=0 USE_CUDA=0 MAX_JOBS=2 python setup.py develop
在USE_CUDA=1
的情況下可以額外加上:
TORCH_CUDA_ARCH_LIST="8.6"
以避免安裝過程中出現nvcc fatal : Unsupported gpu architecture 'compute_89'
的錯誤。
將編譯過程記錄到log檔
如果想要將編譯過程記錄到log檔,可以使用以下指令:
REL_WITH_DEB_INFO=1 USE_PER_OPERATOR_HEADERS=0 USE_DISTRIBUTED=0 USE_CUDA=0 MAX_JOBS=2 python setup.py develop >> build_log.txt 2>&1
設定編譯線程數
在編譯開始時,筆者的電腦對鍵盤和滑鼠的反應漸漸變得遲緩,後來又變成完全沒有反應,最後只得強制重開機解決。
如果機器的性能不是特別好,可以手動將編譯源碼的線程數調低,避免出現上述情況。
首先設定MAX_JOBS
環境變量:
export MAX_JOBS=2
其中2是筆者自行選擇的數字,根據電腦的性能,也可以選擇大一點的數字。
在預期中,做完這個設定後,編譯的線程數就不會多於2了。但是ninja在編譯PyTorch中的nccl時,仍然是使用默認的6個線程,參考Compilation hangs: too many threads和Compiling NCCL does not obey MAX_JOBS, makes machine unresponsive這兩篇討論,這是由於pytorch/cmake/External/nccl.cmake
中的bug造成。解決方式如下:
將pytorch/cmake/External/nccl.cmake
中36,37行附近的代碼由:
"VERBOSE=0"
"-j"
$ENV{MAX_JOBS}
BUILD_BYPRODUCTS "${__NCCL_BUILD_DIR}/lib/libnccl_static.a"
修改為:
"VERBOSE=0"
"--jobs=2"
BUILD_BYPRODUCTS "${__NCCL_BUILD_DIR}/lib/libnccl_static.a"
之後就能順利地編譯了。
注1:其中2是筆者自行選擇的數字
注2:在2022/8/19的NCCL: Re-enable parallel builds這個PR後不需要修改pytorch/cmake/External/nccl.cmake
,直接用export MAX_JOBS=2
設定即可
筆者電腦的CPU為Intel® Core™ i5-6300HQ,GPU為GeForce GTX 950M,編譯PyTorch的過程約花了十個小時。
錯誤排除
libstdc++.so.6: version `GLIBCXX_3.4.30’ not found
編譯完成後,如果import torch
時出現以下錯誤:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/root/Documents/pytorch/torch/__init__.py", line 229, in <module>
from torch._C import * # noqa: F403
ImportError: /root/anaconda3/bin/../lib/libstdc++.so.6: version `GLIBCXX_3.4.30' not found (required by /root/Documents/pytorch/torch/lib/libtorch_python.so)
參考’GLIBCXX_3.4.30’ not found for librosa in conda virtual environment (after trying out a lot of solutions)?,首先檢查該so檔是否包含GLIBCXX_3.4.30
:
strings /<anaconda3_install_path>/envs/<your_conda_env_name>/lib/libstdc++.so.6.0.29 | grep GLIBCXX_3.4.30 # 未輸出任何東西
上述指令未輸出任何東西,再來檢查系統中的libstdc++.so.6
:
strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBCXX_3.4.30 # GLIBCXX_3.4.30
發現有包含GLIBCXX_3.4.30
。所以此處的做法便是將conda路徑下的libstdc++.so.6
的soft link改為指向/usr/lib/x86_64-linux-gnu/libstdc++.so.6
。
cd /<anaconda3_install_path>/envs/<your_conda_env_name>/lib
mv libstdc++.so.6 libstdc++.so.6.old
ln -s /usr/lib/x86_64-linux-gnu/libstdc++.so.6 libstdc++.so.6