0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

9个快速使用Pytorch训练解决神经网络的技巧(附代码

新机器视觉 来源:读芯术 作者:读芯术 2021-11-02 09:57 次阅读

这份终极指南从简单到复杂,一步步教你清除模型中所有的GP模型,直到你可以完成的大多数PITA修改,以充分利用你的网络

事实上,你的模型可能还停留在石器时代的水平。估计你还在用32位精度或GASP(一般活动仿真语言)训练,甚至可能只在单GPU上训练。如果市面上有99个加速指南,但你可能只看过1个?(没错,就是这样)。但这份终极指南,会一步步教你清除模型中所有的(GP模型)。

这份指南的介绍从简单到复杂,一直介绍到你可以完成的大多数PITA修改,以充分利用你的网络。例子中会包括一些Pytorch代码和相关标记,可以在 Pytorch-Lightning训练器中用,以防大家不想自己敲码!

这份指南针对的是谁? 任何用Pytorch研究非琐碎的深度学习模型的人,比如工业研究人员、博士生、学者等等……这些模型可能要花费几天,甚至几周、几个月的时间来训练。

本文涵盖以下内容(从易到难):

  1. 使用DataLoader
  2. DataLoader中的进程数
  3. 批尺寸
  4. 累积梯度
  5. 保留计算图
  6. 转至单GPU
  7. 16位混合精度训练
  8. 转至多GPU(模型复制)
  9. 转至多GPU节点(8+GPUs)
  10. 有关模型加速的思考和技巧

Pytorch-Lightning

文中讨论的各种优化,都可以在Pytorch-Lightning找到:https://github.com/williamFalcon/pytorch-lightning?source=post_page

Lightning是基于Pytorch的一个光包装器,它可以帮助研究人员自动训练模型,但关键的模型部件还是由研究人员完全控制。

参照此篇教程,获得更有力的范例:https://github.com/williamFalcon/pytorch-lightning/blob/master/examples/new_project_templates/single_gpu_node_template.py?source=post_page

Lightning采用最新、最尖端的方法,将犯错的可能性降到最低。

MNIST定义的Lightning模型可适用于训练器:https://github.com/williamFalcon/pytorch-lightning/blob/master/examples/new_project_templates/lightning_module_template.py?source=post_page

frompytorch-lightningimportTrainer
model=LightningModule(…)
trainer=Trainer()
trainer.fit(model)

1. DataLoader

这可能是最容易提速的地方。靠保存h5py或numpy文件来加速数据加载的日子已经一去不复返了。用 Pytorch dataloader 加载图像数据非常简单:https://pytorch.org/tutorials/beginner/data_loading_tutorial.html?source=post_page

关于NLP数据,请参照TorchText:https://torchtext.readthedocs.io/en/latest/datasets.html?source=post_page

dataset=MNIST(root=self.hparams.data_root,train=train,download=True)
loader=DataLoader(dataset,batch_size=32,shuffle=True)
forbatchinloader:
x,y=batch
model.training_step(x,y)
...

在Lightning中,你无需指定一个训练循环,只需定义dataLoaders,训练器便会在需要时调用它们。

2. DataLoaders中的进程数

加快速度的第二个秘诀在于允许批量并行加载。所以,你可以一次加载许多批量,而不是一次加载一个。

#slow
loader=DataLoader(dataset,batch_size=32,shuffle=True)
#fast(use10workers)
loader=DataLoader(dataset,batch_size=32,shuffle=True,num_workers=10)

3. 批量大小(Batch size)

在开始下一步优化步骤之前,将批量大小调高到CPU内存或GPU内存允许的最大值。

接下来的部分将着重于减少内存占用,这样就可以继续增加批尺寸。

记住,你很可能需要再次更新学习率。如果将批尺寸增加一倍,最好将学习速度也提高一倍。

4. 累积梯度

假如已经最大限度地使用了计算资源,而批尺寸仍然太低(假设为8),那我们则需为梯度下降模拟更大的批尺寸,以供精准估计。

假设想让批尺寸达到128。然后,在执行单个优化器步骤前,将执行16次前向和后向传播(批量大小为8)。

#clearlaststep
optimizer.zero_grad()

#16accumulatedgradientsteps
scaled_loss=0
foraccumulated_step_iinrange(16):
out=model.forward()
loss=some_loss(out,y)
loss.backward()

scaled_loss+=loss.item()

#updateweightsafter8steps.effectivebatch=8*16
optimizer.step()

#lossisnowscaledupbythenumberofaccumulatedbatches
actual_loss=scaled_loss/16properties

而在Lightning中,这些已经自动执行了。只需设置标记:

trainer=Trainer(accumulate_grad_batches=16)
trainer.fit(model)

5. 保留计算图

撑爆内存很简单,只要不释放指向计算图形的指针,比如……为记录日志保存loss。

losses=[]

...
losses.append(loss)

print(f'currentloss:)

上述的问题在于,loss仍然有一个图形副本。在这种情况中,可用.item()来释放它。

#bad
losses.append(loss)

#good
losses.append(loss.item())

Lightning会特别注意,让其无法保留图形副本。示例:https://github.com/williamFalcon/pytorch-lightning/blob/master/pytorch_lightning/models/trainer.py#L812

6. 单GPU训练

一旦完成了前面的步骤,就可以进入GPU训练了。GPU的训练将对许多GPU核心上的数学计算进行并行处理。能加速多少取决于使用的GPU类型。个人使用的话,推荐使用2080Ti,公司使用的话可用V100。

刚开始你可能会觉得压力很大,但其实只需做两件事:1)将你的模型移动到GPU上,2)在用其运行数据时,把数据导至GPU中。

#putmodelonGPU
model.cuda(0)

#putdataongpu(cudaonavariablereturnsacudacopy)
x=x.cuda(0)

#runsonGPUnow
model(x)

如果使用Lightning,则不需要对代码做任何操作。只需设置标记:

#asklightningtousegpu0fortraining
trainer=Trainer(gpus=[0])
trainer.fit(model)

在GPU进行训练时,要注意限制CPU和GPU之间的传输量。

#expensive
x=x.cuda(0)

#veryexpensive
x=x.cpu()
x=x.cuda(0)

例如,如果耗尽了内存,不要为了省内存,将数据移回CPU。尝试用其他方式优化代码,或者在用这种方法之前先跨GPUs分配代码。

此外还要注意进行强制GPUs同步的操作。例如清除内存缓存。

#reallybadidea.StopsalltheGPUsuntiltheyallcatchup
torch.cuda.empty_cache()

但是如果使用Lightning,那么只有在定义Lightning模块时可能会出现这种问题。Lightning特别注意避免此类错误。

7. 16位精度

16位精度可以有效地削减一半的内存占用。大多数模型都是用32位精度数进行训练的。然而最近的研究发现,使用16位精度,模型也可以很好地工作。混合精度指的是,用16位训练一些特定的模型,而权值类的用32位训练。

要想在Pytorch中用16位精度,先从NVIDIA中安装 apex 图书馆 并对你的模型进行这些更改。

#enable16-bitonthemodelandtheoptimizer
model,optimizers=amp.initialize(model,optimizers,opt_level='O2')

#whendoing.backward,letampdoitsoitcanscaletheloss
withamp.scale_loss(loss,optimizer)asscaled_loss:
scaled_loss.backward()

amp包会处理大部分事情。如果梯度爆炸或趋于零,它甚至会扩大loss。

在Lightning中, 使用16位很简单,不需对你的模型做任何修改,也不用完成上述操作。

trainer=Trainer(amp_level=’O2',use_amp=False)
trainer.fit(model)

8. 移至多GPU

现在,事情就变得有意思了。有3种(也许更多?)方式训练多GPU。

  • 分批量训练

919be072-3a75-11ec-82a9-dac502259ad0.jpg

A)在每个GPU上复制模型;B)给每个GPU分配一部分批量。

第一种方法叫做分批量训练。这一策略将模型复制到每个GPU上,而每个GPU会分到该批量的一部分。

#copymodeloneachGPUandgiveafourthofthebatchtoeach
model=DataParallel(model,devices=[0,1,2,3])

#outhas4outputs(oneforeachgpu)
out=model(x.cuda(0))

在Lightning中,可以直接指示训练器增加GPU数量,而无需完成上述任何操作。

#asklightningtouse4GPUsfortraining
trainer=Trainer(gpus=[0,1,2,3])
trainer.fit(model)
  • 分模型训练

91dcd8a2-3a75-11ec-82a9-dac502259ad0.jpg

将模型的不同部分分配给不同的GPU,按顺序分配批量

有时模型可能太大,内存不足以支撑。比如,带有编码器和解码器的Sequence to Sequence模型在生成输出时可能会占用20gb的内存。在这种情况下,我们希望把编码器和解码器放在单独的GPU上。

#eachmodelissooobigwecan'tfitbothinmemory
encoder_rnn.cuda(0)
decoder_rnn.cuda(1)

#runinputthroughencoderonGPU0
out=encoder_rnn(x.cuda(0))

#runoutputthroughdecoderonthenextGPU
out=decoder_rnn(x.cuda(1))

#normallywewanttobringalloutputsbacktoGPU0
out=out.cuda(0)

对于这种类型的训练,无需将Lightning训练器分到任何GPU上。与之相反,只要把自己的模块导入正确的GPU的Lightning模块中:

classMyModule(LightningModule):

def__init__():
self.encoder=RNN(...)
self.decoder=RNN(...)

defforward(x):
#modelswon'tbemovedafterthefirstforwardbecause
#theyarealreadyonthecorrectGPUs
self.encoder.cuda(0)
self.decoder.cuda(1)

out=self.encoder(x)
out=self.decoder(out.cuda(1))

#don'tpassGPUstotrainer
model=MyModule()
trainer=Trainer()
trainer.fit(model)
  • 混合两种训练方法

在上面的例子中,编码器和解码器仍然可以从并行化每个操作中获益。我们现在可以更具创造力了。

#changetheselines
self.encoder=RNN(...)
self.decoder=RNN(...)

#tothese
#noweachRNNisbasedonadifferentgpuset
self.encoder=DataParallel(self.encoder,devices=[0,1,2,3])
self.decoder=DataParallel(self.encoder,devices=[4,5,6,7])

#inforward...
out=self.encoder(x.cuda(0))

#noticeinputsonfirstgpuindevice
sout=self.decoder(out.cuda(4))#<--- the 4 here

使用多GPUs时需注意的事项

  • 如果该设备上已存在model.cuda(),那么它不会完成任何操作。

  • 始终输入到设备列表中的第一个设备上。

  • 跨设备传输数据非常昂贵,不到万不得已不要这样做。

  • 优化器和梯度将存储在GPU 0上。因此,GPU 0使用的内存很可能比其他处理器大得多。

9. 多节点GPU训练

9215bdd4-3a75-11ec-82a9-dac502259ad0.jpg

每台机器上的各GPU都可获取一份模型的副本。每台机器分得一部分数据,并仅针对该部分数据进行训练。各机器彼此同步梯度。

做到了这一步,就可以在几分钟内训练Imagenet数据集了! 这没有想象中那么难,但需要更多有关计算集群的知识。这些指令假定你正在集群上使用SLURM。

Pytorch在各个GPU上跨节点复制模型并同步梯度,从而实现多节点训练。因此,每个模型都是在各GPU上独立初始化的,本质上是在数据的一个分区上独立训练的,只是它们都接收来自所有模型的梯度更新。

高级阶段:

  1. 在各GPU上初始化一个模型的副本(确保设置好种子,使每个模型初始化到相同的权值,否则操作会失效。)

  2. 将数据集分成子集。每个GPU只在自己的子集上训练。

  3. On .backward() 所有副本都会接收各模型梯度的副本。只有此时,模型之间才会相互通信

Pytorch有一个很好的抽象概念,叫做分布式数据并行处理,它可以为你完成这一操作。要使用DDP(分布式数据并行处理),需要做4件事:

deftng_dataloader(,m):

d=MNIST()
#4:Adddistributedsampler
#samplersendsaportionoftngdatatoeachmachine
dist_sampler=DistributedSampler(dataset)
dataloader=DataLoader(d,shuffle=False,sampler=dist_sampler)

defmain_process_entrypoint(gpu_nb):
#2:setupconnectionsbetweenallgpusacrossallmachines
#allgpusconnecttoasingleGPU"root"
#thedefaultusesenv://
world=nb_gpus*nb_nodes
dist.init_process_group("nccl",rank=gpu_nb,world_size=world)

#3:wrapmodelinDPP
torch.cuda.set_device(gpu_nb)
model.cuda(gpu_nb)
model=DistributedDataParallel(model,device_ids=[gpu_nb])

#trainyourmodelnow...

if__name__=='__main__':
#1:spawnnumberofprocesses
#yourclusterwillcallmainforeachmachine
mp.spawn(main_process_entrypoint,nprocs=8)

Pytorch团队对此有一份详细的实用教程:https://github.com/pytorch/examples/blob/master/imagenet/main.py?source=post_page

然而,在Lightning中,这是一个自带功能。只需设定节点数标志,其余的交给Lightning处理就好。

#trainon1024gpusacross128nodes
trainer=Trainer(nb_gpu_nodes=128,gpus=[0,1,2,3,4,5,6,7])

Lightning还附带了一个SlurmCluster管理器,可助你简单地提交SLURM任务的正确细节。示例:https://github.com/williamFalcon/pytorch-lightning/blob/master/examples/new_project_templates/multi_node_cluster_template.py#L103-L134

10. 福利!更快的多GPU单节点训练

事实证明,分布式数据并行处理要比数据并行快得多,因为其唯一的通信是梯度同步。因此,最好用分布式数据并行处理替换数据并行,即使只是在做单机训练。

在Lightning中,通过将distributed_backend设置为ddp(分布式数据并行处理)并设置GPU的数量,这可以很容易实现。

#trainon4gpusonthesamemachineMUCHfasterthanDataParallel
trainer=Trainer(distributed_backend='ddp',gpus=[0,1,2,3])

有关模型加速的思考和技巧

如何通过寻找瓶颈来思考问题?可以把模型分成几个部分:

首先,确保数据加载中没有瓶颈。为此,可以使用上述的现有数据加载方案,但是如果没有适合你的方案,你可以把离线处理及超高速缓存作为高性能数据储存,就像h5py一样。

接下来看看在训练过程中该怎么做。确保快速转发,避免多余的计算,并将CPU和GPU之间的数据传输最小化。最后,避免降低GPU的速度(在本指南中有介绍)。

接下来,最大化批尺寸,通常来说,GPU的内存大小会限制批量大小。自此看来,这其实就是跨GPU分布,但要最小化延迟,有效使用大批次(例如在数据集中,可能会在多个GPUs上获得8000+的有效批量大小)。

但是需要小心处理大批次。根据具体问题查阅文献,学习一下别人是如何处理的!

原文链接:https://towardsdatascience.com/9-tips-for-training-lightning-fast-neural-networks-in-pytorch-8e63a502f565

编辑:jq
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • cpu
    cpu
    +关注

    关注

    68

    文章

    10732

    浏览量

    209690
  • 数据
    +关注

    关注

    8

    文章

    6725

    浏览量

    88369
  • gpu
    gpu
    +关注

    关注

    27

    文章

    4604

    浏览量

    128221
  • pytorch
    +关注

    关注

    2

    文章

    795

    浏览量

    13027

原文标题:用Pytorch训练快速神经网络的9个技巧

文章出处:【微信号:vision263com,微信公众号:新机器视觉】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Python自动训练人工神经网络

    人工神经网络(ANN)是机器学习中一种重要的模型,它模仿了人脑神经元的工作方式,通过多层节点(神经元)之间的连接和权重调整来学习和解决问题。Python由于其强大的库支持(如TensorFlow、
    的头像 发表于 07-19 11:54 171次阅读

    如何使用经过训练神经网络模型

    使用经过训练神经网络模型是一涉及多个步骤的过程,包括数据准备、模型加载、预测执行以及后续优化等。
    的头像 发表于 07-12 11:43 497次阅读

    脉冲神经网络怎么训练

    脉冲神经网络(SNN, Spiking Neural Network)的训练是一复杂但充满挑战的过程,它模拟了生物神经元通过脉冲(或称为尖峰)进行信息传递的方式。以下是对脉冲
    的头像 发表于 07-12 10:13 312次阅读

    PyTorch如何实现多层全连接神经网络

    PyTorch中实现多层全连接神经网络(也称为密集连接神经网络或DNN)是一相对直接的过程,涉及定义网络结构、初始化参数、前向传播、损失
    的头像 发表于 07-11 16:07 685次阅读

    20数据可以训练神经网络

    当然可以,20数据点对于训练神经网络来说可能非常有限,但这并不意味着它们不能用于训练。实际上,神经
    的头像 发表于 07-11 10:29 370次阅读

    怎么对神经网络重新训练

    重新训练神经网络是一复杂的过程,涉及到多个步骤和考虑因素。 引言 神经网络是一种强大的机器学习模型,广泛应用于图像识别、自然语言处理、语音识别等领域。然而,随着时间的推移,数据分布可
    的头像 发表于 07-11 10:25 325次阅读

    pytorch中有神经网络模型吗

    当然,PyTorch是一广泛使用的深度学习框架,它提供了许多预训练神经网络模型。 PyTorch中的
    的头像 发表于 07-11 09:59 547次阅读

    PyTorch神经网络模型构建过程

    PyTorch,作为一广泛使用的开源深度学习库,提供了丰富的工具和模块,帮助开发者构建、训练和部署神经网络模型。在神经网络模型中,输出层是
    的头像 发表于 07-10 14:57 317次阅读

    如何利用Matlab进行神经网络训练

    ,使得神经网络的创建、训练和仿真变得更加便捷。本文将详细介绍如何利用Matlab进行神经网络训练,包括网络创建、数据预处理、
    的头像 发表于 07-08 18:26 1149次阅读

    神经网络预测模型的构建方法

    神经网络模型作为一种强大的预测工具,广泛应用于各种领域,如金融、医疗、交通等。本文将详细介绍神经网络预测模型的构建方法,包括模型设计、数据集准备、模型训练、验证与评估等步骤,并
    的头像 发表于 07-05 17:41 432次阅读

    卷积神经网络训练的是什么

    训练过程以及应用场景。 1. 卷积神经网络的基本概念 1.1 卷积神经网络的定义 卷积神经网络是一种前馈深度学习模型,其核心思想是利用卷积操作提取输入数据的局部特征,并通过多层结构进
    的头像 发表于 07-03 09:15 226次阅读

    使用PyTorch构建神经网络

    PyTorch是一流行的深度学习框架,它以其简洁的API和强大的灵活性在学术界和工业界得到了广泛应用。在本文中,我们将深入探讨如何使用PyTorch构建神经网络,包括从基础概念到高级
    的头像 发表于 07-02 11:31 469次阅读

    如何使用Python进行神经网络编程

    。 为什么使用Python? Python是一种广泛使用的高级编程语言,以其易读性和易用性而闻名。Python拥有强大的库,如TensorFlow、Keras和PyTorch,这些库提供了构建和训练神经网络的工具。
    的头像 发表于 07-02 09:58 291次阅读

    如何训练和优化神经网络

    神经网络是人工智能领域的重要分支,广泛应用于图像识别、自然语言处理、语音识别等多个领域。然而,要使神经网络在实际应用中取得良好效果,必须进行有效的训练和优化。本文将从神经网络
    的头像 发表于 07-01 14:14 286次阅读

    Kaggle知识点:训练神经网络的7技巧

    科学神经网络模型使用随机梯度下降进行训练,模型权重使用反向传播算法进行更新。通过训练神经网络模型解决的优化问题非常具有挑战性,尽管这些算法在实践中表现出色,但不能保证它们会及时收敛到一
    的头像 发表于 12-30 08:27 559次阅读
    Kaggle知识点:<b class='flag-5'>训练</b><b class='flag-5'>神经网络</b>的7<b class='flag-5'>个</b>技巧