英伟达APEX,多GPU分布式训练,同步Batchnorm,自动混合精度训练法宝指南

本文主要是介绍英伟达APEX,多GPU分布式训练,同步Batchnorm,自动混合精度训练法宝指南,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上一篇博客我讲解了APEX如何配置,以及简单的使用。这一篇主要讲一下注意细节。
英伟达(NVIDIA)训练深度学习模型神器APEX使用指南

多GPU,同步BN,自动混合精度

结合当前时代背景,这三个可以说是能训练好网络的基本条件。多GPU重要性不多说,既然都使用了多GPU,同步BN自然缺不得,还不知道同步BN(Sync BN)的同学,赶紧去查查吧。自动混合精度(amp)是干啥的,点击上面的链接,上一篇博客我也说明了。今天就带来一篇结合这三个技巧,具体介绍一下如何使用。

一般情况下的训练代码

  • 导入数据结构dataloader
  • 定义模型, 迁移到GPU上
  • 定义损失函数和优化器
  • 把模型用nn.dataParallel迁移到多GPU上。

大致就像下面这样

net = xxxNet()
net.train()
net.cuda()dataset = xxxDataset()
loader = torch.utils.data.Dataloader(dataset)opt = SGD(net.parameters())
crit = nn.BCELoss()net = torch.nn.DataParallel(net)for data in dataloader:......

接下来,我们就在上面的基础上改动,如何结合apex支持的分布式训练,同步bn,以及混合精度,同时我还会讲解几个我自己遇到的坑。

正文开始

假设我们的训练代码叫做"train.py",导入

import argparse
from apex import amp
from apex.parallel import convert_syncbn_model
from apex.parallel import DistributedDataParallel as DDP

先罗列自己网络的超参数。

def parse():parser = argparse.ArgumentParser()parser.add_argument('--local_rank', type=int, default=0)......args = parser.parse_args()return args

local_rank指定了输出设备,默认为GPU可用列表中的第一个GPU。这里这个是必须加的。原因后面讲

在主函数中开头写

def main():args = parse()torch.cuda.set_device(args.local_rank)  # 必须写!,还必须在下一句的前面,#torch.utils.launch也需要set_device, 所以必须写torch.distributed.init_process_group('nccl',init_method='env://')

导入数据接口,这里有一点不一样。需要用一个DistributedSampler

	dataset = DAVIS2017(root, 'training')num_workers = 4 if cuda else 0# 多了一个DistributedSampler,作为dataloader的samplertrain_sampler  = torch.utils.data.distributed.DistributedSampler(dataset)loader = DataLoader(dataset,batch_size=batchsize,shuffle=False, num_workers=num_workers,pin_memory=cuda,drop_last=True, sampler=train_sampler)

之后定义模型。

	net = XXXNet(using_amp=True)net.train()net = convert_syncbn_model(net)  # 用apex支持的方法,使得普通bn成为同步bn。# 切记在网络实现中,不要使用torch自带的SyncBatchnorm。device = torch.device('cuda:{}'.format(args.local_rank))net = net.to(device)  # 把模型搬运到第一块GPU上

定义优化器,损失函数,定义优化器一定要在把模型搬运到GPU之后。

	opt = Adam([{'params': params_low_lr, 'lr': 4e-5},{'params': params_high_lr, 'lr': 1e-4}], weight_decay=settings.WEIGHT_DECAY)crit = nn.BCELoss().to(device)

多GPU设置

  net, opt = amp.initialize(net, opt, opt_level="O1")  # 字母小写o,不是零。# 关于initialize用法,见上一篇博客。net = DDP(net, delay_allreduce=True)  # 必须在initialze之后

记得loss要这么用

	opt.zero_grad()# loss.backward()with amp.scale_loss(loss, opt) as scaled_loss:scaled_loss.backward()opt.step()

然后在代码底部加入

if __name__ == '__main__':main()

代码部分就修改完毕了。但是不能直接用python train.py的形式去使用它。

根据官方文档所写,无论是apex支持的DDP,还是pytorch自身支持的DDP(torch.nn.parallel.DistributedDataParallel),都需要使用torch.distributed.launch 来使用,方法是:

  • CUDA_VISIBLE_DEVICES=1,2,4 python -m torch.distributed.launch --nproc_per_node=3 train.py

注意, 1,2,4是你想用的GPU编号,nproc_per_node指定你用了几块GPU。nproc是开启几个进程,设置为和GPU数目相同的值,就意味着每一个进程要负责一块gpu,per_node代表了你只有一个主机服务器。 记得开头说必须要加入local_rank,是因为torch.distributed.launch 会调用这个local_rank.


update on 2019.11.26
在做resume训练的时候,发现resume模型需要设置在to(device)之前,就是以CPU模型导入模型才行。
否则会报显存不够的错误。
在这里插入图片描述
可能是由于设置的多进程问题吧,具体原因没搞清楚。总之记录步骤就行了。于是resume的写法可以视作这样

	# 定义模型net = SiamCo(using_amp=True)net.train()# resume 旧的训练模型resume = './model_ranet_17/65000.pth'checkpoint = torch.load(resume, map_location='cpu')  # CPU modenet.load_state_dict(checkpoint['model'])# 转同步bnnet = convert_syncbn_model(net)# 搬到GPU上去, local_rank虽然默认为0,但是torch.distributed.launch# 会给每个进程分配单独的GPU,local_rank就是被这个lauch脚本重新指定了。device = torch.device('cuda:{}'.format(args.local_rank))net = net.to(device)# 定义优化器params_low_lr = []params_high_lr = []for n, p in net.named_parameters():if 'encoder' in n:params_low_lr.append(p)else:params_high_lr.append(p)opt = Adam([{'params': params_low_lr, 'lr': 1e-5},{'params': params_high_lr, 'lr': 5e-5}], weight_decay=settings.WEIGHT_DECAY)# 分布式训练net, opt = amp.initialize(net, opt, opt_level="O0")net = DDP(net, delay_allreduce=True)

保存模型需要注意

分布式训练开启多个进程,如果你在代码中写了 torch.sava 用来保存模型,那么每一个进程都会保存一次相同的模型。假设进程之间时间几乎一致,在相同的时间连续对一个文件读取以及保存会产生什么效果? 第0块GPU上开始保存模型了,文件写到一半,第1块GPU也执行到保存模型的代码,然后把同一个文件覆盖,然后xxx。反正这个模型会因为文件损坏而不能使用。亲测,遇到过。
如何避免这个问题呢?
记得local_rank吗,前面说local_rank相当于每个进程都分配不同的值。那么我们可以用local_rank == 0 来仅仅在第一个GPU上执行的进程保存模型文件,就不会遇到模型文件重复写入的问题了。

	if arg.locak_rank == 0:torch.save(xxxx)

这样就指定了代号为0的进程去保存模型。可能有人好奇,那其他进程上的模型就不要存了吗,其实虽然是多个进程,但是每个进程上模型的参数值是一样的。多个GPU之间仍在通信。而且默认代号为0的进程是主进程。所以仅要求主进程保存模型就OK啦。

这篇关于英伟达APEX,多GPU分布式训练,同步Batchnorm,自动混合精度训练法宝指南的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/251179

相关文章

Golang使用etcd构建分布式锁的示例分享

《Golang使用etcd构建分布式锁的示例分享》在本教程中,我们将学习如何使用Go和etcd构建分布式锁系统,分布式锁系统对于管理对分布式系统中共享资源的并发访问至关重要,它有助于维护一致性,防止竞... 目录引言环境准备新建Go项目实现加锁和解锁功能测试分布式锁重构实现失败重试总结引言我们将使用Go作

python实现自动登录12306自动抢票功能

《python实现自动登录12306自动抢票功能》随着互联网技术的发展,越来越多的人选择通过网络平台购票,特别是在中国,12306作为官方火车票预订平台,承担了巨大的访问量,对于热门线路或者节假日出行... 目录一、遇到的问题?二、改进三、进阶–展望总结一、遇到的问题?1.url-正确的表头:就是首先ur

Redis分布式锁使用及说明

《Redis分布式锁使用及说明》本文总结了Redis和Zookeeper在高可用性和高一致性场景下的应用,并详细介绍了Redis的分布式锁实现方式,包括使用Lua脚本和续期机制,最后,提到了RedLo... 目录Redis分布式锁加锁方式怎么会解错锁?举个小案例吧解锁方式续期总结Redis分布式锁如果追求

使用JavaScript将PDF页面中的标注扁平化的操作指南

《使用JavaScript将PDF页面中的标注扁平化的操作指南》扁平化(flatten)操作可以将标注作为矢量图形包含在PDF页面的内容中,使其不可编辑,DynamsoftDocumentViewer... 目录使用Dynamsoft Document Viewer打开一个PDF文件并启用标注添加功能扁平化

Spring使用@Retryable实现自动重试机制

《Spring使用@Retryable实现自动重试机制》在微服务架构中,服务之间的调用可能会因为一些暂时性的错误而失败,例如网络波动、数据库连接超时或第三方服务不可用等,在本文中,我们将介绍如何在Sp... 目录引言1. 什么是 @Retryable?2. 如何在 Spring 中使用 @Retryable

电脑显示hdmi无信号怎么办? 电脑显示器无信号的终极解决指南

《电脑显示hdmi无信号怎么办?电脑显示器无信号的终极解决指南》HDMI无信号的问题却让人头疼不已,遇到这种情况该怎么办?针对这种情况,我们可以采取一系列步骤来逐一排查并解决问题,以下是详细的方法... 无论你是试图为笔记本电脑设置多个显示器还是使用外部显示器,都可能会弹出“无HDMI信号”错误。此消息可能

如何安装 Ubuntu 24.04 LTS 桌面版或服务器? Ubuntu安装指南

《如何安装Ubuntu24.04LTS桌面版或服务器?Ubuntu安装指南》对于我们程序员来说,有一个好用的操作系统、好的编程环境也是很重要,如何安装Ubuntu24.04LTS桌面... Ubuntu 24.04 LTS,代号 Noble NumBAT,于 2024 年 4 月 25 日正式发布,引入了众

使用 Python 和 LabelMe 实现图片验证码的自动标注功能

《使用Python和LabelMe实现图片验证码的自动标注功能》文章介绍了如何使用Python和LabelMe自动标注图片验证码,主要步骤包括图像预处理、OCR识别和生成标注文件,通过结合Pa... 目录使用 python 和 LabelMe 实现图片验证码的自动标注环境准备必备工具安装依赖实现自动标注核心

QT实现TCP客户端自动连接

《QT实现TCP客户端自动连接》这篇文章主要为大家详细介绍了QT中一个TCP客户端自动连接的测试模型,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录版本 1:没有取消按钮 测试效果测试代码版本 2:有取消按钮测试效果测试代码版本 1:没有取消按钮 测试效果缺陷:无法手动停

Nacos集群数据同步方式

《Nacos集群数据同步方式》文章主要介绍了Nacos集群中服务注册信息的同步机制,涉及到负责节点和非负责节点之间的数据同步过程,以及DistroProtocol协议在同步中的应用... 目录引言负责节点(发起同步)DistroProtocolDistroSyncChangeTask获取同步数据getDis