CUDA_VISIBLE_DEVICES在文件指定GPU设置不生效的原因

我发现这个问题经常在深度学习模型训练或部署中遇到,针对多GPU分布式训练时,这关系学习率的设置问题,而学习率非常影响模型的优化过程,这次就让我碰到了,而且就是因为CUDA_VISIBLE_DEVICES生效与不生效导致学习率偏差,从而最终导致准确率相差两个百分点。


1、如何发现问题的?

我训练有个习惯是会保存训练的tensorboard。两次训练参数一致,分两类,唯一不同就是后面一次增加了7w的数据,其他参数均是一模一样,如下:
在这里插入图片描述
在这里插入图片描述
但是最终的准确率却相差两个百分点,我觉得虽然深度学习模型训练虽然有很多的随机性,但不至于影响这么大。于是打开了tensorboard观察两者的训练曲线区别。这就看到了两则学习率变换完全不一样。
在这里插入图片描述
明明参数设置一样,为什么最终优化器出来的学习率却不一样。于是看代码,我代码是这样写的:

import os
import sys
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import torch.optim.lr_scheduler as lr_scheduler
from torch.utils.tensorboard import SummaryWriter
from utils.distributed_utils import init_distributed_mode, dist, cleanup    # 我的utils里面写了分布式初始化相关函数
from utils.distributed_utils import reduce_value, is_main_process
from utils.utils_logging import init_logging

os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICES"] = "6"         # 我这里想只用第7张显卡来训练
os.environ['NCCL_SOCKET_IFNAME'] = 'lo'

args.lr *= args.world_size        # 学习率要根据并行GPU的数量进行倍增
if rank == 0:
    tb_writer = SummaryWriter(log_dir=args.save_dir)
dataloader = xxxxx
model = resnet18(pretrained=False, num_classes=num_classes)
optimizer = optim.AdamW(model.parameters(), lr=args.lr/torch.cuda.device_count(), betas=(0.9, 0.999), eps=1e-9, weight_decay=args.weight_decay)
scheduler = torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr=args.lr/torch.cuda.device_count(), steps_per_epoch=len(train_loader), epochs=args.epochs, last_epoch=last_epoch,
                                                        pct_start=args.warmup_epochs/args.epochs, div_factor=250, final_div_factor=200)

for epoch in range(num_epochs):
    for batch_idx, (data, target) in enumerate(tqdm(dataloader['train'])):
    	xxxx
    # eval
    # save models and write to tensorboard
    tags = ["train/accuracy", "train/loss", "val/accuracy", "learning_rate"]
    tb_writer.add_scalar(tags[0], np.mean(train_acc), epoch)
    tb_writer.add_scalar(tags[1], mean_loss, epoch)
    tb_writer.add_scalar(tags[2], float(Total_Accuracy), epoch)
    tb_writer.add_scalar(tags[3], optimizer.param_groups[0]["lr"], epoch)

可以看到,我运行训练sh,传入的参数lr会经过乘以world_size,然后输入优化器optimizer和scheduler都会除以torch.cuda.device_count(),所以差异必定是这里引起的。两次唯一不同就是我在运行sh脚本时是否在终端指定了CUDA_VISIBLE_DEVICES;前一次训练(tensorboard橙色曲线),在终端没有加;而蓝色曲线,由于不加会报错显存不足,分布式初始化失败,我就在运行sh训练脚本的时候加了CUDA_VISIBLE_DEVICES指定GPU序号运行。


2、验证猜想问题点

通过添加print打印.cuda.device_count()和world_size的值
当不在终端命令行加CUDA_VISIBLE_DEVICES指定GPU训练时(tensorboard橙色曲线):
在这里插入图片描述
当在终端命令行加CUDA_VISIBLE_DEVICES指定GPU训练时(tensorboard蓝色曲线):
在这里插入图片描述
结合两者打印消息可以证明,文件中用CUDA_VISIBLE_DEVICES指定GPU训练没有起作用。


3、修改,如何让CUDA_VISIBLE_DEVICES在文件中起作用

文件中通过CUDA_VISIBLE_DEVICES指定GPU训练失效的原因通常是因为设置和使用顺序搞反了导致的;具体如下:

  • 环境变量设置时机‌:在文件中设置CUDA_VISIBLE_DEVICES时,如果设置的位置不正确,可能会导致环境变量无效。正确的做法是在导入任何与CUDA相关的模块之前设置环境变量。例如,应该在import torch之前设置os.environ[‘CUDA_VISIBLE_DEVICES’]‌。

  • 导入顺序问题‌:如果在文件中导入了一个包含import torch的模块,且导入该模块在os.environ[‘CUDA_VISIBLE_DEVICES’]设置之前,那么在该模块导入时,os.environ[‘CUDA_VISIBLE_DEVICES’]的设置将不会生效。这是因为Python在执行文件时会优先导入其他包中的模块,如果在这些模块中已经导入了torch,那么在主文件中设置的CUDA_VISIBLE_DEVICES将无法生效‌。

我在程序中通过os.environ["CUDA_VISIBLE_DEVICES"] = "6"设置环境变量,从我列出来的程序可以看出,应该是设置环境变量和导入torch的顺序导致的,即我先import torch,后使用CUDA_VISIBLE_DEVICES设置显卡,所以这个设置没起作用。

终端设置的优势‌: 在终端设置环境变量时,通常会在启动一个新的shell会话时生效,这样确保了所有后续的命令都在新的环境变量设置下执行。而在文件中设置环境变量,可能会因为导入顺序或其他脚本的执行顺序问题而无法生效‌。

‌解决CUDA_VISIBLE_DEVICES在文件中设置不起作用的问题的方法‌:

  • 确保设置顺序‌:在文件中设置os.environ[‘CUDA_VISIBLE_DEVICES’]时,确保在导入任何CUDA相关模块之前进行设置。例如:
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0,1'
import torch
print(torch.cuda.device_count())
  • 使用bash脚本‌:可以通过bash脚本在终端中设置环境变量,然后启动Python脚本。例如:
export CUDA_VISIBLE_DEVICES=0,1
python train.py
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值