问题背景:
实验室新买了两张4090D,在装好机器后出现了若干问题,主要包括Xorg占用显卡显存、分布式训练报错、显存分配等问题,本人主要的工作是在Pytracking框架中实现,记录一下问题及解决方案,希望能帮助遇到相同问题的朋友们。
- 服务器系统:Ubuntu
- GPU:2张 nvidia-4090D
- CPU:i7-13700K
- 主板:华硕
问题描述
-
问题1:独立显卡显存被占用(资源浪费)
装好显卡驱动后,使用
nvidia-smi
命令检查,发现显存被Xorg占用约400M。
排查及解决方案:
因为之前在3090的机器上跑实验的时候,未存在上述显存占用现象,所以认为该情况是可以避免的,可以节约显存资源。
Xorg是Linux的GUI图形化进程,可以将其部署在核显上,我使用的13700K是带核显的,CPU没有核显的只能将Xorg部署在独立显卡上。
有的主板是默认禁用核显的,以使用的华硕主板为例:需要在BIOS菜单中,找到Advanced、Chipset、Northbridge或IntegratedPeripherals的子菜单, 在这个部分,找到InternalGraphicsModeSelect,将其从禁用状态改为Auto或Enabled,以启用核显功能。
网上的教程说可以通过命令或配置文件将Xorg重新部署,但是我没有成功,并且将图像界面也搞崩溃了。最后,简单粗暴的重装系统了,先用核显部署完Xorg,再装独立显卡驱动,装显卡驱动的时候一定别选将Xorg转移部署的选项!问题解决。 -
问题2:启动分布式训练报错及显存分配不均衡
单卡训练正常,多卡训练报错,多卡训练显存占用有问题(一个卡占满一个卡不占用/一张卡占用多一张卡占用少)。
排查及解决方案:
以下是我的代码中启动分布式训练的命令,其中torch.distributed.launch
在2.0版本被弃用,之后的版本都是用torch.distributed.run
启动分布式训练。
直接使用launch或直接将launch改成run都会存在错误,主要错误都是由 local_rank 未正常分配 引起的。
--local_rank
是获取当前进程在本机上的rank,一般是动态获取的。在官方的说明文档中对此参数有详细解释,“–local_rank"这个命令行参数是必须声明的,但不由用户填写,是由pytorch自动填写的。如果用户声明了这个参数,则会覆盖掉pytorch为用户生成的值,就会产生错误。
elif args.mode == "multiple":
train_cmd = "python -m torch.distributed.launch --nproc_per_node %d --master_port %d lib/train/run_training.py " \
"--script %s --config %s --save_dir %s --use_lmdb %d --script_prv %s --config_prv %s --use_wandb %d " \
"--distill %d --script_teacher %s --config_teacher %s" \
% (args.nproc_per_node, random.randint(10000, 50000), args.script, args.config, args.save_dir, args.use_lmdb, args.script_prv, args.config_prv, args.use_wandb,
args.distill, args.script_teacher, args.config_teacher)
在我的代码中并未声明该参数,这就是引起错误的原因。
elif args.mode == "multiple":
train_cmd = "CUDA_VISIBLE_DEVICE=0,1 python -m torch.distributed.launch --nproc_per_node %d --master_port %d --use-env lib/train/run_training.py " \
"--script %s --config %s --save_dir %s --use_lmdb %d --script_prv %s --config_prv %s --use_wandb %d " \
"--distill %d --script_teacher %s --config_teacher %s " \
% (args.nproc_per_node, random.randint(10000, 50000), args.script, args.config, args.save_dir,
args.use_lmdb, args.script_prv, args.config_prv, args.use_wandb,
args.distill, args.script_teacher, args.config_teacher)
以上是修改后的代码,其中 CUDA_VISIBLE_DEVICE=0,1
能解决程序对显存占用不均衡的问题,添加了 --use_env
参数,声明了此参数后,pytorch会将当前进程在本机上的rank自动添加到环境变量 LOCAL_RANK
中,并不再添加到 args.local_rank
。
上述改动在 torch.distributed.launch
可以生效,但是在 torch.distributed.run
中 --use_env
已经被废弃,用户中只能从LOCAL_RANK中获取当前进程在本机上的rank,所以需要加入以下代码。
args.local_rank = int(os.environ['LOCAL_RANK'])
最终,我是继续使用 torch.distributed.launch
启动分布式训练,在命令行中加入 CUDA_VISIBLE_DEVICE=0,1
和 --use_env
,同时加入了从环境变量中获取local_rank的代码行,解决问题。
- 问题3:分布式训练对CPU内核占用
解决上述两个问题后,我的实验就能正常跑起来了,过程中也没有问题。但是实验室后续又组了一台新的4090D双卡机器,根据上述过程能跑起来分布式训练,但是同门反应分布式训练速度明显比之前的单张4090变慢了。
排查及解决方案:
在使用htop
检查时,发现CPU只有两个核跑满,这部分实际应该受num_worker控制。在调试过程中,多次更改num_worker值无效后,在隔壁组师兄的帮助下最终将问题定位在 run_training.py中,import cv 应该在 import torch 和 import numpy之后,修改完num_worker就能正常控制CPU内核分配了。