Ubuntu18.04安装与使用Cuda

一、驱动部分
$ sudo apt remove --purge nvidia*        #卸载已有的驱动
##禁用驱动nouveau,否则肯能安装后会卡在登录界面
$ sudo vim /etc/modprobe.d/blacklist.conf     #最后一行添加blacklist nouveau

$ sudo update-initramfs -u               #更新内核,使上面的命令生效

$ sudo reboot                       #系统还有一块集成intel显卡能正常驱动,所以可以正常进入图形界面

$ lsmod | grep nouveau                 #查看nouveau禁用是否生效,无输出则有效

##开始安装NVIDIA驱动
$ sudo add-apt-repository ppa:graphics-drivers/ppa $ sudo apt update

$ ubuntu-drivers devices                  #查看可以安装的驱动版本  不同的驱动需要不同的gcc $ sudo ubuntu-drivers autoinstall            #或者只安装推荐(recommend)的那一个(sudo apt install xxx) $ sudo apt install nvidia-cuda-toolkit gcc-6

# 或者手动下载.run驱动包,手动安装——参考
$ nvcc --version

$ sudo reboot                        #驱动重启生效
$ sudo nvidia-smi                      #查看驱动是否生效

1. 我的是GTX 950m,给我安装的cuda9.1,如果要安装指定版本的可能还是要用传统方法;——用图形界面装,还不如用ssh连接,在另一台机器的命令行里面安装(如xshell)

2. 驱动与cuda的对应关系 官方参考

3. 不同的驱动需要不同的gcc——gcc管理

 

GPU及nvidia-smi命令内容含义 参考。 

由于官方源下载很慢,可以去网上找官网下,官网只有最新版的,如最新版为450,下载地址为

https://cn.download.nvidia.cn/XFree86/Linux-x86_64/450.57/NVIDIA-Linux-x86_64-450.57.run

要下载415旧版本的,先到网上去找nvidia-driver-415的信息,得到具体的版本为415.xx,将上面的450.57替换为415.xx即可进行下载,会快很多

 

但是旧版本的安装可能有些问题,可以用apt-fast加快安装(需要添加apt-fast的库)

 

** 已安装驱动,但nvidia-smi出现问题:NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver。。。

解决:470.74换位原来已安装驱动的版本号即可  ——参考

sudo apt install dkms
sudo dkms install -m nvidia -v 470.74

 

 

二、cuda与cudnn部分 

一个完整的参考

 版本查看方式——参考

 

 

注意:conda中安装的cudatoolkit只是使python可以正常使用cuda,但是如果其它包是用到了cuda编译生成的,那么它们调用的将是系统中的cuda和cudnn,需要版本符合要求。

 

三、其它问题

1. 非root用户安装自己版本的 方法

 

2. 查看占用gpu的进程

$ fuser -v /dev/nvidia*

 3. 如果电源功率不够,GPU功率大了的话,GPU超频时可能电源过载导致电脑重启,可能有效的方法

a)降低GPU功率—— 参考源;b)在BIOS关闭超频模式(turbo mode)——参考,;c)更新BIOS;d)换更大功率电源

GPU功率与电源功率的 参考;下面是降低GPU功率的操作

sudo nvidia-smi -pm 1     # 开启持久模式,允许调节
sudo nvidia-smi -pl 220    # 设置功率为220W(原250W),nvidia-smi是为它管理的所有GPU一起设置的
sudo nvidia-smi -pm 0

降低功率后性能下降很小的。其它

sudo nvidia-smi -i 1 -pl 220    # -i 可以指定第几个显卡
显卡共有p0-p12这些模式,p0是最大性能,它会自动调节(初始状态应该是P0或P8)

1)新建一个开机自启动的服务,否则重启后上面的设置就失效了。

sudo vim /etc/systemd/system/nvidia-setpower.service

内容如下:

[Unit]
Description=Nvidia SetPower Service
After=network.target
Wants=network.target

[Service]
Type=simple
PIDFile=/run/nvidia-setpower.pid
ExecStart=sh /usr/bin/nvidia-setpower.sh
Restart=on-failure
# Don't restart in the case of configuration error
RestartPreventExitStatus=23

[Install]
WantedBy=multi-user.target

2)新建nvidia-setpower.sh

sudo vim /usr/bin/nvidia-setpower.sh

内容如下:

sudo nvidia-smi -pm 1 
sudo nvidia-smi -pl 220
sudo nvidia-smi -pm 0

3)设置开机启动服务

systemctl daemon-reload
systemctl start nvidia-setpower.service
systemctl enable nvidia-setpower.service

 

四、 进行单机多卡训练(单卡测试)——使用pytorch中的DistributedDataParallel

主要有几部分需要修改(添加)如下:  ——以下代码主要参考自 参考;原理 参考

1)初始化使用多卡
import torch.distributed as dist

# init mutli-gpu
num_gpus = int(os.environ['WORLD_SIZE']) if 'WORLD_SIZE' in os.environ else 1
is_distributed = num_gpus > 1    # world_size is the global process total numbers, aka the gpu numbers
if is_distributed:
    dist.init_process_group(backend='nccl')
    # print('world_size', torch.distributed.get_world_size())
2)加载模型到多卡
if is_distributed:
    local_rank = dist.get_rank()               # 对于单个进程,它就是一个介于[0, gpu_sum)范围内的值,表示当前进程号,其实也相当于GPU编号
    torch.cuda.set_device(local_rank)
    #device = torch.device("cuda", local_rank)
    self.model = self.model.cuda(local_rank)                     # equals to model.to(device)
    self.model = torch.nn.parallel.DistributedDataParallel(        # 更改了device_ids(可用的GPU卡号列表), output_device
        self.model, device_ids=[local_rank], output_device=local_rank,
        find_unused_parameters=False, broadcast_buffers=False )     # find_unused_parameters在网络中有不学习的参数时应设置为True,否则将报错
3)修改train dataloader
if is_distributed: 
   train_shuffle = False # the sampler will shuffle the data 
   train_sampler = torch.utils.data.distributed.DistributedSampler(data_train)  # data_train是DataSet api获取到的数据集 
   data_train_loader = torch.utils.data.DataLoader(data_train,            # 主要更改了samplershuffle其它为默认
       batch_size=train_batch, shuffle=train_shuffle, 
       pin_memory=True, sampler=train_sampler)
# pin_memory=True,则意味着生成的Tensor数据最开始是属于内存中的锁页内存,这样将内存的Tensor转义到GPU的显存就会更快一些 (锁业内存参考 # 在每个epoch开始set_epoch,打乱数据,(DistributedSampler的shuffle结果和epoch有关,需要set一下) train_sampler.set_epoch(epoch)
4)执行程序时,使用命令(否则还是单卡训练,并且多卡的代码执行会出错)
python -m torch.distributed.launch --nproc_per_node=3 train.py  

* 3 gpus (可以添加参数 --nnodes=k --node_rank=j 进行多机多卡训练,表示 k 个节点中的第 j 台机器, j<k)

  代码中参数的含义:

1)rank:表示进程序号,用于进程间通讯,表征进程优先级。rank = 0 的GPU为主卡;(对于单机多卡,不作其它设置(group等默认),则就是一个GPU一个进程,也就是rank == local_rank。)

2)local_rank:进程内,GPU 编号,非显式参数,由 torch.distributed.launch 内部指定。比方说, rank = 3,local_rank = 0 表示第 3 个进程内的第 1 块 GPU。(相当于,rank是概念上的一个值,在进程中我们用 local_rank 表示它)

3)group:即进程组。默认情况下,只有一个组,一个 job 即为一个组,也即一个 world。

上述代码中是用 get_rank() 获取的,也可以用下面的方法获取

parser.add_argument('--local_rank', default=-1, type=int)  # 这个参数不必显式指定,由启动器 torch.distributed.launch 内部指定
args = parser.parse_args()    # 用add_argument方式时,代码中要使用只需用 args.local_rank 获取即可

 * 这里用torch.distributed.lauch作启动器,管理多个进程;也可以用 multiprocessing  这个模块手动指定多线程,但是这样通信等问题就会比较麻烦——multiprocessing 参考

 

其它注意:

1)在DataParallel中,batch_size设置必须为单卡的n倍,,但是在使用DistributedDataParallel时,batch_size设置于单卡一样即可;如果想有单卡一样的效果,new batch size = batch size / GPU sum

总的batch实际是变大了,所有最好增大lr,防止陷入局部最优;如果还想要更大的batch size效果,可以看gradient accumulation的参考

2)由于有多个进程,每个进程都会指定打印日志等操作,所以除了网络模型之外的部分最好设置限制条件,使得其只在主卡所在的进程执行(如打印、保存模型)

3)多卡的平均loss,acc的计算

在主进程(主卡)中使用通信算子reduce、all_reduce等进行同步并计算;——这个似乎也会卡住

通信算子会根据输入的tensor找到它在其它卡中的对应tensor,使用dist.ReduceOp.xx进行操作——更多通信算子,参考

def reduce_loss(self, tens):    # tens为需要同步的tensor变量,如loss
     rt = tens.clone()
     dist.all_reduce(rt, op=dist.ReduceOp.SUM)
     rt /= torch.distributed.get_world_size()
     return rt

acc(标量)如果放到tensor里面,也用上面的reduce_loss的方法计算,会卡住,暂时没找到解决方法。

 

4)多卡训练,单卡测试——模型保存与加载方式

# save,多卡时套了一层module,要从里面取出来
torch.save(model.module.state_dict(), weight_path)
# 单卡训练时的save:torch.save(model.state_dict(), weight_path)
# load model.load_state_dict(torch.load(weight_path)) 

其它卡配置的模型保存-加载 参考

 

其它参考链接: 参考2 

posted @ 2020-06-17 17:13  谷小雨  阅读(595)  评论(0编辑  收藏  举报