OS: ubuntu 20.4
显卡: GeForce GT 730
结论:安装成功,但是在参考Pytorch(1.2.0+):多机单卡并行实操(MNIST识别)文章时,遇到错误 RuntimeError: No rendezvous handler for 192.168.1.6:// 暂时没有解决,有点心累。
换一个好一点的显卡,运行上MNIST识别应该会成功吧。
Slurm 搭建
Slurm的集群搭建可以参考我之前的文章:
从我的搭建Slurm集群的基础上改变为以下节点
主机名 | 用途 | IP |
---|---|---|
node1 | 管理节点/登录节点 | 192.168.1.101 |
compute1 | GPU计算节点,GPU数量1 | 192.168.1.102 |
compute2 | GPU计算节点,GPU数量1 | 192.168.1.103 |
安装显卡驱动
首先搜索可以安装什么版本的驱动, 后面显示recommended代表系统自动安装时会安装的版本,版本为470
$ ubuntu-drivers devices
== /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0 ==
modalias : pci:v000010DEd00001287sv00007377sd00000000bc03sc00i00
vendor : NVIDIA Corporation
model : GK208B [GeForce GT 730]
driver : nvidia-340 - distro non-free
driver : nvidia-driver-470 - distro non-free recommended
driver : nvidia-driver-390 - distro non-free
driver : nvidia-driver-418-server - distro non-free
driver : nvidia-driver-450-server - distro non-free
driver : nvidia-driver-470-server - distro non-free
driver : xserver-xorg-video-nouveau - distro free builtin
选择自动安装显卡驱动
$ sudo ubuntu-drivers autoinstall
安装完以后运行一下命令,出现报错信息
$ nvidia-smi
NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver.
Make sure that the latest NVIDIA driver is installed and running.
网上查找后感觉和内核版本不同导致的,首先使用命令查看当前系统内核版本
$ uname -a
Linux compute2 5.15.0-97-generic
在查看安装的驱动相对应的内核版本,其实在安装的最后会提示你安装的什么内核版本的驱动,类似以下信息
Error! Your kernel headers for kernel 5.15.0-125-generic cannot be found.
说明安装的驱动版本是5.15.0-125,而当前版本是97版本,所以需要更换内核
首先安装内核的头文件,按理说应该还需要安装一个 linux-image-5.15.0-125-generic, 但是在上面安装显卡驱动是帮我们安装过了,所以只需要安装以下一个就可以了。
apt-get install linux-headers-5.15.0-125-generic
如果是在安装过后没有注意到安装的是什么版本的驱动,可以到 /usr/lib/modules 搜索驱动以查找版本
$ cd /usr/lib/modules
$ find -name nvidia
./5.15.0-97-generic/kernel/drivers/net/ethernet/nvidia
./5.15.0-97-generic/kernel/drivers/video/fbdev/nvidia
./5.15.0-125-generic/kernel/nvidia-470/bits/nvidia
./5.15.0-125-generic/kernel/drivers/video/fbdev/nvidia
./5.15.0-124-generic/kernel/drivers/net/ethernet/nvidia
./5.15.0-124-generic/kernel/drivers/video/fbdev/nvidia
通过上面的输出可以看到安装的 nvidia-470 版本的驱动是内核125版本的。
安装好相应的内核所需要的文件后修改 grub 文件改变启动顺序,在修改之前先查看125版本的内核启动顺序是第几位,以下输出信息 Ubuntu,Linux 5.15.0-125-generic 这一行是从0开始向下依次增加,那么125版本的启动顺序是0
$ grep "menuentry " /boot/grub/grub.cfg
menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-a2f3efb3-31f9-4c54-a227-d3c5b9bc3238' {
menuentry 'Ubuntu,Linux 5.15.0-125-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.15.0-125-generic-advanced-a2f3efb3-31f9-4c54-a227-d3c5b9bc3238' {
menuentry 'Ubuntu, with Linux 5.15.0-125-generic (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.15.0-125-generic-recovery-a2f3efb3-31f9-4c54-a227-d3c5b9bc3238' {
menuentry 'Ubuntu,Linux 5.15.0-124-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.15.0-124-generic-advanced-a2f3efb3-31f9-4c54-a227-d3c5b9bc3238' {
menuentry 'Ubuntu, with Linux 5.15.0-124-generic (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.15.0-124-generic-recovery-a2f3efb3-31f9-4c54-a227-d3c5b9bc3238' {
menuentry 'Ubuntu,Linux 5.15.0-97-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.15.0-97-generic-advanced-a2f3efb3-31f9-4c54-a227-d3c5b9bc3238' {
menuentry 'Ubuntu, with Linux 5.15.0-97-generic (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.15.0-97-generic-recovery-a2f3efb3-31f9-4c54-a227-d3c5b9bc3238' {
menuentry 'UEFI Firmware Settings' $menuentry_id_option 'uefi-firmware' {
修改文件中的以下的变量值并保存
$ vim /etc/default/grub
GRUB_DEFAULT=0
$ update-grub
$ reboot
重启以后运行 nvidia-smi
命令显示以下信息证明安装驱动成功
$ nvidia-smi
Mon Nov 11 17:37:38 2024
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 470.256.02 Driver Version: 470.256.02 CUDA Version: 11.4 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 NVIDIA GeForce ... Off | 00000000:01:00.0 N/A | N/A |
| 0% 23C P8 N/A / N/A | 200MiB / 1993MiB | N/A Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
安装CUDA
安装完显卡驱动以后运行 nvidia-smi
中第一行显示的 CUDA Version: 11.4
就是可以安装的最大版本,超过这个版本就不支持了。
确认安装版本
确认最新版Pytorch
是否支持 CUDA 11.4
,可以通过此网址https://pytorch.org/get-started/locally/#start-locally确认。
如果Pytorch
支持的最低版本超过了可安装的CUDA 11.4
最大版本,则需要安装以前版本的Pytorch
,可通过 https://pytorch.org/get-started/previous-versions/ 网址进行寻找相应的CUDA
版本可支持的PyTorch
版本。
查找过后并没有 CUDA 11.4
版本的 PyTorch
,找到了支持 CUDA 11.3
版本的,所以安装 CUDA
的版本只能是11.3或者更低的。
通过 CUDA 存档下载 找到11.3.1
版本链接后选择自己相应的系统和版本后会给出一个下载方式。
后续因为PyTorch
高版本不支持GT 730
显卡的原因下载了CUDA 10.0
版本,而在Ubuntu 20.4
中安装CUDA 10.0
需要gcc7 g++7
所以需要提前安装,以下操作参考 Ubuntu20.04安装cuda10.1
$ 因为Ubuntu20.04自带的gcc版本为9.3,而cuda10.1不支持gcc-9,因此要手动安装gcc-7,命令如下:
$ sudo apt-get install gcc-7 g++-7
#安装完gcc-7,系统中就存在两个版本的gcc,因此要设置默认的gcc,命令如下:
$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 9
$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 1
# 此命令可以通过update-alternatives设置gcc各版本的优先级,优先级最高的为系统默认版本,可以用下述命令显示其优先级:
$ sudo update-alternatives --display gcc
# 设置默认的g++也是如此:
$ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-7 9
$ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-9 1
# 显示g++优先级:
$ sudo update-alternatives --display g++
安装
#$ wget https://developer.download.nvidia.com/compute/cuda/11.3.1/local_installers/cuda_11.3.1_465.19.01_linux.run
#$ sudo sh cuda_11.3.1_465.19.01_linux.run
$ wget https://developer.nvidia.com/compute/cuda/10.0/Prod/local_installers/cuda_10.0.130_410.48_linux
$ mv cuda_10.0.130_410.48_linux cuda_10.0.130_410.48_linux.run
$ sudo sh cuda_10.0.130_410.48_linux.run
运行命令后,会提示你现在这个系统中已经有显卡驱动了,建议你卸载驱动后再安装CUDA
,不用管直接选择 accept
,并且除了 CUDA Toolkit
其他选项全部使用空格
取消安装
不同于 11.3
版本的是,10.0
操作是通过输入 y
or n
来选择安装或者不安装的。
安装完成后配置当前用户环境变量
$ vim ~/.bashrc
export CUDA_HOME=/usr/local/cuda-11.3
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CUDA_HOME/lib64
export PATH=$PATH:$CUDA_HOME/bin
$ source ~/.bashrc
$ nvcc -V
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2018 NVIDIA Corporation
Built on Sat_Aug_25_21:08:01_CDT_2018
Cuda compilation tools, release 10.0, V10.0.130
如果想卸载可以通过以下命令
$ sudo apt-get --purge remove "*cuda*" "*cublas*" "*cufft*" "*cufile*" "*curand*" \
"*cusolver*" "*cusparse*" "*gds-tools*" "*npp*" "*nvjpeg*" "nsight*" "*nvvm*"
$ sudo apt-get autoremove --purge -V
CUDA 10.0
版本卸载可通过安装目录中的[CUDA安装目录]\bin\cuda-uninstaller
或者是uninstall_cuda_10.0.pl
脚本进行卸载
CUDA_VISIBLE_DEVICES
环境变量可以改变CUDA对GPU的可见个数,如主机中有4块显卡,那么每张显卡的默认标号为[0,1,2,3],编号0为主卡。
安装miniconda
安装用户为 ROOT
也可以选择不安装这个包管理软件
从下载网址中下载最新版Anaconda
的安装脚本
$ wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
$ bash Miniconda3-latest-Linux-x86_64.sh
运行 bash Miniconda3-latest-Linux-x86_64.sh
以后第一个暂停会提示你输入 ENTER
,直接回车即可。
第二暂停提示是否接收协议,输入 yes
即可。
第三个暂停提示你安装到哪里,我这里输入了: /usr/local/conda3
后回车。
第四个暂停提示为是否初始化conda
,输入 yes
会在 ~/.bashrc
文件中自动配置环境变量等等,还会执行 conda active root
。
在当前窗口中生效
$ source ~/.bashrc
如果选择了 no
还想初始化可以使用以下命令进行初始化,同样会在 ~/.bashrc
文件中自动添加内容
$ source [安装目录]/bin/activate
$ conda init
选择 no
并且没有执行上面两条命令就需要自己配置 conda
的环境变量了,在 ~/.bashrc
文件中添加以下内容
$ vim ~/.bashrc
export CONDA_HOME=/usr/local/conda3
export PATH=$PATH:$CONDA_HOME/bin:$CONDA_HOME:/condabin
conda init
$ source ~/.bashrc
选择 yes
的话每次登录shell
时都会进入base
环境,可以使用以下命令进行关闭
$ conda config --set auto_activate_base false
配置国内源(清华)
$ vim ~/.condarc
channels:
- defaults
show_channel_urls: true
default_channels:
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/msys2
# 以下的这个源如果官方源下载太慢可以放开以后手动下载GPU版本pytorch覆盖
#- https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/
custom_channels:
conda-forge: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
pytorch: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
$ conda clean -i
安装PyTorch
确认安装版本
在 https://pytorch.org/get-started/previous-versions/ 页面找到 CUDA 11.3
版本所支持的最高版本是 v1.12.1
,下载了这个最高版本后使用测试脚本时会提示以下信息:
/usr/local/conda3/envs/pytorch/lib/python3.10/site-packages/torch/cuda/init.py:123: UserWarning:
Found GPU0 NVIDIA GeForce GT 730 which is of cuda capability 3.5.
PyTorch no longer supports this GPU because it is too old.
The minimum cuda capability supported by this library is 3.7.
提示我的显卡 GT 730
的计算能力是 3.5
而pytorch 1.12.1
版本最小支持 3.7
,所以只能一个一个向下版本测试
可以在此 https://developer.nvidia.com/cuda-gpus 网址中查询自己相应的GPU能力
最终我安装了 CUDA 10.0
+ PyTorch 1.2.0
版本可以了。
在下面的两个链接中,解决的办法都是从源码编译PyTorch解决这个问题,有时间可以试一试
- https://discuss.pytorch.org/t/pytorch-for-tesla-k40c-with-cuda-11-2/109477/3
- https://github.com/pytorch/pytorch/issues/31285
安装
通过 conda
方式先创建一个虚拟环境 -n
或者 --name
是虚拟环境名字并进入虚拟环境
$ conda create -n pytorch
$ conda activate pytorch
如果更换了pytorch
清华源,下载的pytorch
是CPU
版本的,所以需要手动在清华源仓库中下载GPU
版本覆盖掉CPU
版本
后续实验发现如果不在 default_channels
中添加 - https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/
源的话,默认会在官方源下载GPU
版本,但可能会太慢,如果嫌慢的话可以更换源以后再手动覆盖掉也是可以额的
清华源仓库: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/linux-64/
选择 pytorch-1.12.1-py3.10_cuda11.3_cudnn8.3.2_0.tar.bz2
, 如果是其它版本则下载相应版本
如果没有配置pytorch
的清华源运行以下命令开始下载相关包,pytorch
下载的大概率是GPU
版本,可以在运行conda
命令后暂时不输入y
,可以在要安装中的包列表中找到pytorch
看一下后面是不是带有cuda
,如果携带则是GPU
版本,不携带则是CPU
版本,可能需要找到对应的GPU
版本覆盖掉
# 因为1.12.1版本不支持730显卡所以只能安装更低的版本了
# $ conda install pytorch==1.12.1 torchvision==0.13.1 torchaudio==0.12.1 cudatoolkit=11.3 numpy=1.26.4 -c pytorch
$ conda install pytorch==1.2.0 torchvision==0.4.0 cudatoolkit=10.0 -c pytorch
在1.12.1
版本中numpy
指定为 1.26.4
是因为后续运行测试脚本时报错需要<2.0
如果配置了pytorch
清华源则需要找到对应的版本文件后手动覆盖掉CPU
版本,这里使用1.12.1
版本的做个示范。
$ wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/linux-64/pytorch-1.12.1-py3.10_cuda11.3_cudnn8.3.2_0.tar.bz2
$ conda install --offline pytorch-1.12.1-py3.10_cuda11.3_cudnn8.3.2_0.tar.bz2
等待安装完毕以后可通过以下命令进行验证,返回 True
表示安装正确。
$ python3
>>> import torch
>>> torch.cuda.is_available()
True
>>> torch.zeros(1).cuda()
tensor([0.], device='cuda:0')
退出 conda
虚拟环境,使用以下命令
$ conda deactivate
Slurm + Pytorch运行
测试脚本如下
import torch
import os
print('hostname', end=' ')
os.system('hostname')
# Check if GPU is available
if torch.cuda.is_available():
device = torch.device("cuda")
print(f"GPU device name: {torch.cuda.get_device_name(0)}")
print(torch.cuda.device_count())
else:
print("No GPU available, switching to CPU.")
device = torch.device("cpu")
# Sample tensor operations
x = torch.rand(3, 3).to(device)
y = torch.rand(3, 3).to(device)
z = x + y
print(z)
使用 srun
命令调用
$ srun -N 2 /usr/local/conda3/envs/pytorch/bin/python3 test_gpus.py
torch version: 1.2.0
No GPU available, switching to CPU.
tensor([[0.0796, 1.2749, 1.2399],
[0.6618, 1.3286, 0.4182],
[1.1344, 0.5059, 1.0156]])
使用sbatch
脚本运行
$ vim run.slurm
#!/bin/bash
#SBATCH --output=info.out
#SBATCH --error=error.out
#SBATCH --job-name=test_gpu
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=1
#SBATCH --gres=gpu:1
# 在脚本中要加上这条语句,否则无法激活要使用的conda环境
eval "$(conda shell.bash hook)"
conda activate pytorch
srun python3 test_gpu.py
$ sbatch run.slurm
但这样应该是在两个节点各自执行一次,怎么才能使用同一个数据集训练呢?
Slurm和Pytorch如何管理多节点GPU设备
以下回答是ChatGPT的回答
Slurm
Slurm 主要负责在集群中的节点上分配资源,包括计算节点和GPU。它不会直接对 GPU 进行编号,而是分配节点,然后 PyTorch (或其他分布式框架) 负责在分配的节点上管理GPU。
Slurm 通过以下方式标识节点和资源:
- 节点名称 (Node Name): 每个计算节点都有一个唯一的名称,例如 node01, node02, node03 等。
- 节点序号 (Node ID): Slurm 会为每个节点分配一个整数 ID,用于内部管理。
- GPU ID (within a node): 每个节点上的 GPU 通常用从 0 开始的整数编号,例如 GPU0, GPU1, GPU2 等。这个编号是由硬件或驱动程序决定的,Slurm 不直接参与。
- 环境变量: Slurm 通过设置环境变量来传递节点信息给作业,例如
SLURM_NODEID
(当前节点的 ID),SLURM_NNODES
(节点总数),SLURM_JOB_ID
(作业 ID) 以及CUDA_VISIBLE_DEVICES
(指定哪个 GPU 可见)。
PyTorch
PyTorch 使用 torch.distributed
模块来进行多 GPU 和多节点训练。它依赖于 Slurm 提供的节点信息来确定每个进程应该使用哪个 GPU 进行计算。
PyTorch 的编号方式与 Slurm 关联,但更侧重于进程的视角:
进程的全局秩 (Global Rank): 每个 PyTorch 进程都有一个唯一的全局秩,从 0 开始,一直到
(节点数 * 每节点 GPU 数) - 1
。这个全局秩用于进程间的通信。进程的本地秩 (Local Rank): 每个 PyTorch 进程在一个节点上的本地秩,从 0 开始,一直到
每节点GPU数 - 1
。这指定了该进程在这个节点上使用的GPU。世界规模 (World Size): 表示参与分布式训练的总进程数,等于
节点数 * 每节点 GPU 数
。
两者如何协同工作
Slurm 提交脚本: 在 Slurm 提交脚本中,用户指定所需的节点数和每个节点的 GPU 数。
CUDA_VISIBLE_DEVICES
变量通常在脚本中设置,以限制每个进程可见的 GPU。 例如,CUDA_VISIBLE_DEVICES=0
只让进程访问该节点上的 GPU 0。Slurm 分配资源: Slurm 根据提交脚本的要求,分配相应的节点和 GPU。
PyTorch 初始化: PyTorch 的
torch.distributed
模块使用 Slurm 提供的环境变量来初始化分布式环境。 它会根据SLURM_NODEID
,SLURM_PROCID
等变量来计算每个进程的全局秩和本地秩。进程间的通信: PyTorch 使用全局秩来确定进程之间的通信方式,例如使用
torch.distributed.all_reduce
进行梯度同步。
slurm常用环境变量
变量名 | 描述 |
---|---|
SLURM_JOB_NAME |
任务名 默认为提交时的脚本名, 可以用-J参数进行设置 |
SLURM_JOB_NUM_NODES |
Number of nodes allocated to job |
SLURM_JOBID |
分配的任务编号 |
SLURM_NTASKS |
分配的task数 |
SLURM_TASKS_PER_NODE |
每个节点分配的task数 |
SLURM_SUBMIT_DIR |
提交作业时的工作目录 |
SLURM_NPROCS |
加载的进程数 常用,与-n参数含义相同 |
SLURM_CPUS_ON_NODE |
节点的CPU核心数 |
SLURM_JOB_NODELIST |
Nodes assigned to job |
SLURM_JOB_CPUS_PER_NODE |
每个节点的CPU核心数 |
SLURM_SUBMIT_HOST |
提交任务的节点名 通常为某个登录节点,如ln2 |
SLURM_PROCID |
Index of task relative to job / 全局编号 |
SLURM_LOCALID |
Index to core running on within node / 本地编号 |