[折腾]编译pytorch

前言

最好全程科学上网,预计需要5~7GB的下载量。 本教程尝试在 Windows 的 Docker 环境下编译给 Ubuntu20.04 的 torch=2.3.0 CUDA11.7 。(至于为什么是这个详见LLM在CUDA11.7安装经历)

零、准备工作

⚠⚠⚠记住一定要先检查目标机器是否有NVIDIA驱动和CUDA环境,CUDNN最好也检查一下,否则编译好了在那边也装不上。 1. 从github/pytorch处获得最新的pytorch源代码,之后的命令执行是参考DockerFile来编写的。 2. 从NVIDIA CUDA 11.7处获得 11.7 CUDA 的toolkit包。在开始前需要下载这个文件。 3. 基础镜像参考Dockerfile使用的是Ubuntu:22.04(MD从头开始还不如直接下一个 CUDA 11.7 的镜像,记住要使用和目标计算机一样的环境,例如本次使用Ubuntu:20.04)也需要提前安装完毕。 4. 仔细观察目标环境的配置,包括但不限于CUDA安装位置、CUDNN头文件位置、安装Python等等,需要在容器中复现。

一、开始编译

1、配置docker

建议使用以下命令启动ubuntu:22.04镜像,默认的内存空间可能不够用,需要额外扩充一部分swap空间。

1
docker run --name torch_compile --privileged -it ubuntu:20.04 /bin/bash
或者
1
docker run -it –cap-add SYS_ADMIN ubuntu:20.04 /bin/bash
进入ubuntu:22.04后第一件事情是更新环境,安装必备工具(最好科学上网)。
1
2
3
4
5
6
7
8
9
10
11
sudo apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
build-essential \
ca-certificates \
ccache \
cmake \
curl \
git \
wget \
libjpeg-dev \
libpng-dev && \
rm -rf /var/lib/apt/lists/*
另外建议先安装 NVIDIA CUDA 11.7 toolkit

2、安装python环境

指定一些运行变量,下载 Miniconda 包安装 Python 环境。Python和目标机器上的一致(这里因为目标机器上的Python是3.11版本的,这里指定PYTHON_VERSION为3.11)。

1
2
3
4
5
6
/usr/sbin/update-ccache-symlinks
mkdir /opt/ccache && ccache --set-config=cache_dir=/opt/ccache
export PATH=/opt/conda/bin:$PATH
export PYTHON_VERSION=3.11
export MINICONDA_ARCH=x86_64
curl -fsSL -v -o ~/miniconda.sh -O "https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-${MINICONDA_ARCH}.sh"

找到github/pytorch文件夹中的requirements.txt文件。并复制到docker中存放pytorch源码的文件夹下。

1
cp [path-to-pytorch-source-code]/requirements.txt .

然后执行 python 环境的安装,这里就安装到/opt/conda这个位置了,添加环境变量以保证conda命令的正确识别。不建议改动安装位置,因为本教程之后许多指令基于这个安装位置编写。

1
2
3
4
5
6
7
8
chmod +x ~/miniconda.sh && \
bash ~/miniconda.sh -b -p /opt/conda && \
/opt/conda/bin/conda install -y python=${PYTHON_VERSION} cmake conda-build pyyaml numpy ipython && \
/opt/conda/bin/python -mpip install -r requirements.txt && \
/opt/conda/bin/conda clean -ya
export PATH=/opt/conda/bin:$PATH
# conda install mkl
# conda install mkl-include

3、补齐代码

下载下来的pytorch源码仅包含pytorch,而pytorch自己的依赖还需要二次下载。 把github/pytorch所有文件下载到/opt/pytorch这个位置,最好使用 git 命令来获得,直接下载获得的包缺少第三方库,需要使用以下命令进行库文件的补齐。

1
2
3
4
5
cd /opt
git clone https://github.com/pytorch/pytorch.git
cd /opt/pytorch
git checkout v2.3.0
git submodule update --init --recursive

建议多次执行,以确保所有的库都能下载下来。如果编译时报库文件的错,需要删掉整个对应的库文件,重新下载。

4、设置编译参数

PYTHON_VERSION很好理解,目标机器上安装什么版本的python就指定什么。CUDA_VERSION根据目标机器上实际的CUDA版本决定(机器上只有CUDA11.7)。

1
2
3
4
5
6
7
8
9
export PYTHON_VERSION=3.11
export CUDA_VERSION=11.7
export CUDA_CHANNEL=nvidia
export INSTALL_CHANNEL=pytorch-nightly
# Automatically set by buildx
/opt/conda/bin/conda update -y -n base -c defaults conda
#/opt/conda/bin/conda install -c "${INSTALL_CHANNEL}" -y python=${PYTHON_VERSION}
#/opt/conda/bin/conda install -c "${INSTALL_CHANNEL}" -c "${CUDA_CHANNEL}" -y "python=${PYTHON_VERSION}" pytorch torchvision torchaudio "pytorch-cuda=$(echo $CUDA_VERSION | cut -d'.' -f 1-2)"
/opt/conda/bin/conda clean -ya

编译,具体有哪些参数可选可以检查 setup.py 文件,另外以下代码中的CUDA_HOME变量需要自行确定。 > ⚠在执行下面命令前先检查GPU使用章节是否正确安装。 > ⚠编译过程需要较多内存空间,提前分配较大的swap空间或者加上MAX_JOBS=1来限制同时编译的数量防止OOM错误。但是会显著降低编译速度,如果内存够大,建议按照CPU核心数量来设置。 > ⚠正式开始编译前最好检查一次生成的编译配置,是否正确开启了 USE_CUDA

1
2
3
4
5
6
7
8
9
10
11
12
cd /opt/pytorch
make triton
export USE_CUDA=ON
export PYTORCH_BUILD_NUMBER=2.3.0
export USE_NUMPY=ON
export USE_QNNPACK=ON
export USE_NNPACK=ON
export USE_DISTRIBUTED=ON
export BLAS=MKL # 出现 mkl_gemm_bf16bf16f32: ATen not compiled with MKL support 问题
export USE_CUDNN=OFF # 超算中心没有(我TM……)一定要注意,有CUDA不等于有CUDNN
# TORCH_CUDA_ARCH_LIST="7.0 7.2 7.5 8.0 8.6 8.7 8.9 9.0 9.0a" TORCH_NVCC_FLAGS="-Xfatbin -compress-all" CMAKE_PREFIX_PATH="/opt/conda/bin" USE_MPI=1 USE_OPENMP=1 USE_FLASH_ATTENTION=1 USE_LMDB=1 PYTORCH_BUILD_NUMBER=2.3.0 CUDA_HOME=
python setup.py bdist_wheel

然后可以在/opt/pytorch/dist目录下找到刚刚编译好的可以直接安装的模块。 安装后执行下面的指令可以检查torch是否支持调用CUDA

1
python -c 'import torch ; print(torch.cuda._is_compiled())'

二、GPU使用

❗以下指令均需要root权限,如果是docker环境可以无视。 忽然发现运行从NVIDIA CUDA 11.7这里获得的包时,不需要安装 Driver 可以直接安装 toolkit ,反正只是跑编译而已,那么有没有 Driver 都无所谓了。(亏我还搞了好久弄 WSL 安装 NVIDIA Driver,艹)

1
2
chmod +x cuda_11.7.0_515.43.04_linux.run
sh cuda_11.7.0_515.43.04_linux.run
当你看到下面的内容时,说明 CUDA 已经安装完毕,需要向PATH变量加入cuda的可执行文件位置,以及lib位置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
root@2345f5f46b09:~# sh cuda_11.7.0_515.43.04_linux.run
===========
= Summary =
===========

Driver: Not Selected
Toolkit: Installed in /usr/local/cuda-11.7/

Please make sure that
- PATH includes /usr/local/cuda-11.7/bin
- LD_LIBRARY_PATH includes /usr/local/cuda-11.7/lib64, or, add /usr/local/cuda-11.7/lib64 to /etc/ld.so.conf and run ldconfig as root

To uninstall the CUDA Toolkit, run cuda-uninstaller in /usr/local/cuda-11.7/bin
***WARNING: Incomplete installation! This installation did not install the CUDA Driver. A driver of version at least 515.00 is required for CUDA 11.7 functionality to work.
To install the driver using this installer, run the following command, replacing <CudaInstaller> with the name of this run file:
sudo <CudaInstaller>.run --silent --driver

Logfile is /var/log/cuda-installer.log
⚠注意这里只安装了CUDA,没有CUDNN,仍然需要到CUDNN这里下载相关文件,或者使用指令。
1
2
3
4
5
6
7
wget https://developer.download.nvidia.com/compute/cudnn/9.2.1/local_installers/cudnn-local-repo-ubuntu2204-9.2.1_1.0-1_amd64.deb
dpkg -i cudnn-local-repo-ubuntu2204-9.2.1_1.0-1_amd64.deb
apt-get update
# 然后根据CUDA11还是CUDA12按照需求运行下面的指令,个人实际测试发现 dpkg 之后cudnn就能找到了
apt install cudnn-cuda-11
# 或者
apt install cudnn-cuda-12
随后利用以下指令可以检查cudnn是否成功安装。看到下图所示说明CUDNN好了:
1
cat /usr/include/cudnn_version.h | grep CUDNN_MAJOR -A 2

三、tmux多终端工具使用

在此期间会打开许多窗口用于编译和测试,在本地多开终端不仅十分繁琐,而且会忘记每个终端的功能,且不能充分利用现有终端的空间。因此tmux工具应运而生,这里简要介绍一部分其中的快捷键,足以应付本场景。 使用以下指令创建一个tmux终端服务。指定名字不仅容易复现,而且方便日后恢复工作台。这里因为我们是编译pytorch,所以取名为“torch”。

1
tmux new -s torch
简要介绍一下一些基础快捷键(⚠在进入tmux终端后才有效) 1. Ctrl+B"是垂直分割当前终端。 2. Ctrl+B%是水平分割当前终端。 3. Ctrl+Bx是关闭当前光标所在终端。 4. Ctrl+Bd是离开当前终端,日后可以利用名字回到工作台。 5. Ctrl+B,任意方向键切换激活的终端。 离开后可以使用以下指令重新连接回当前终端。
1
tmux attach-sesstion -t torch

四、错误解决

1、c++: fatal error: Killed signal terminated program cc1plus

这是因为编译过程中出现内存不足导致的。 ### a、方案一 临时扩充虚拟内存,可以按照下面的步骤进行扩充(以下均指令需要sudo权限,而且如果不按照配置docker章节来,到这里就无法扩充虚拟内存)。

1
2
3
4
5
6
mkdir -p /var/cache/swap/
# 这里的含义是swap空间大小等于 bs*count=4GB 需要自行修改
dd if=/dev/zero of=/var/cache/swap/swap0 bs=64M count=64
chmod 0600 /var/cache/swap/swap0
mkswap /var/cache/swap/swap0
swapon /var/cache/swap/swap0
如果执行第6条指令发生如下错误,需要检查启动镜像是否以特权模式运行容器。如果不是,请使用方案二,或者重新开始配置。
1
swapon failed: Operation not permitted
最后执行以下指令能看到自己添加的新 swap 分区即可
1
swapon -s

b、方案二

设置同时编译的线程数量,最好预留每个编译线程2GB的内存空间。自行调整MAX_JOBS后的数字。如果开启 CUDA 编译需要每个线程预留 4~6GB 的内存空间。

1
2
export MAX_JOBS=2
python setup.py bdist_wheel

2、ValueError: could not identify license file for third_party/opentelemetry-cpp/tools/vcpkg/ports/sigslot

出现这个错误是因为 third_party 出现了不该出现的第三方依赖。检查是否在第三步git checkout命令之前运行了git submodule。用以下命令解决冲突问题

1
2
git checkout -f v2.3.0
rm [出现错误的文件夹]

3、Import Error: …/libstdc++.so.6: version ‘GLIBCXX_3.4.30’ not found

来自conda的错误,一般是因为conda安装目录下的libstdc++.so.6没有这个标记。可以先用下面的指令检查内核版本是否有这个标记,然后再考虑是否升级内核。

1
strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBCXX
这里我很幸运的发现GLIBCXX_3.4.30存在,不用更新内核了。下一步就是更新conda的libstdc++.so.6
1
2
3
4
5
cd [path to your conda]/lib
# 备份原始文件
mv libstdc++.so.6 libstdc++.so.6.old
# 创建新的软链接
ln -s /usr/lib/x86_64-linux-gnu/libstdc++.so.6 libstdc++.so.6

4、ImportError: cannot import name ‘version’ from ‘torchvision’

问题原因:似乎是自己编译的torchvision就是有这个bug,安装目录下没有version.py这个文件。 解决方法:进入anaconda/envs/[your env]/lib/[python3.10]/site-pages/torchvision下创建文件version.py文件,然后写入一下的示例。⚠具体数值应该和你编译的版本一致。

1
__version__ = '0.18.0+cpu'


[折腾]编译pytorch
http://example.com/2024/09/18/折腾/折腾-编译pytorch/
Author
peach-water
Posted on
September 18, 2024
Licensed under