网易首页 > 网易号 > 正文 申请入驻

使用PyTorch Profiler进行模型性能分析,改善并加速PyTorch训练

0
分享至


如果所有机器学习工程师都想要一样东西,那就是更快的模型训练——也许在良好的测试指标之后

加速机器学习模型训练是所有机器学习工程师想要的一件事。更快的训练等于更快的实验,更快的产品迭代,还有最重要的一点需要更少的资源,也就是更省钱。

熟悉PyTorch Profiler

在进行任何优化之前,你必须了解代码的某些部分运行了多长时间。Pytorch profiler是一个用于分析训练的一体化工具。它可以记录:

CPU操作时间、CUDA内核计时、内存消耗历史

要记录事件,只需要将训练嵌入到分析器上下文中,如下所示:

import torch.autograd.profiler as profiler
with profiler.profile(
activities=[ProfilerActivity.CPU, ProfilerActivity.CUDA],
on_trace_ready=torch.profiler.tensorboard_trace_handler('./logs'),
) as prof:
train(args)

然后就可以启动tensorboard查看分析轨迹。如果这一步有问题,请查看是否安装了torch-tb-profiler。



Profiler有很多不同的选项,但最重要的是activities和profile_memory,一般情况下我们只需要这两个选项,因为启用的选项越少,开销就越小。

如果只想要分析CUDA内核执行时间,那么关闭CPU分析和所有其他功能也是可以的。因为在这种模式下,我们可以理解为显卡能力的真实评测。

为了方便分析,我们可以为每一步操作指定名称,例如

with profiler.record_function("forward_pass"):
result = model(**batch)
with profiler.record_function("train_step"):
step(**result)

或者增加更精细的自定义的标签,这里的名称将在跟踪中可见,我们就可以更简单的追踪想要的东西了。

with profiler.record_function("transformer_layer:self_attention"):
data = self.self_attention(**data)
...
with profiler.record_function("transformer_layer:encoder_attention"):
data = self.encoder_attention(**data, **encoder_data)

查看PyTorch Traces

收集完信息后,tensorboard显示是这样的



训练的过程一般包括:数据加载、前向传播、反向传播

反向传播由PyTorch在一个单独的线程中处理(上图中的线程16893),因此很容易识别,这部分门也控制不了,因为都是Pytorch根据我们的计算来自动进行的。(当然也可以自定义反向传播,但是这过于复杂,一般不建议自己实现)

首先看看数据加载:对于数据加载我们希望时间接近于零。

这是因为在数据加载过程中,GPU什么也不做,这会使可用资源利用率不足。并且在Pytorch的训练时数据处理可以与GPU计算重叠,因为它们是独立的部分,也就是说我们加载一个批次的时间只要与一个前向和一个反向传播的时间相近就可以了,这样就可以最大化的利用GPU的资源。

这里可以很容易地识别GPU空闲的区域-查看性能分析器跟踪中的GPU Est. SM效率和GPU利用率数字。没有活动的区域是我们的关注点,因为GPU什么都不做。

如果使用PyTorch DataLoader,则可以通过指定num_workers来多线程处理数据。如果您使用IterableDataset,则会更复杂,因为数据将被复制。这个问题可以通过使用get_worker_info()来解决,需要以某种方式调整迭代,以便每个worker接收不同的、不相交的行,所以这个比较麻烦,一般尽量避免IterableDataset。

内存分配器 memory allocator

当你在CUDA设备上使用PyTorch分配张量时,PyTorch将使用缓存分配器。这里是CUDA的执行机制:cudaMalloc和cudaFree的操作比较昂贵,我们要尽量避免。所以PyTorch会尝试重用以前通过cudaMalloc块分配的,如果PyTorch的分配器有一个合适的块可用,它会直接给出它,而不调用cudaMalloc。这样cudaMalloc只在开始时被调用。

但是如果你处理的是可变长度的数据(比如文本数据),不同的正向传播将需要不同大小的中间张量。因此,PyTorch的分配器可能没有适当的可用数据块。在这种情况下,分配器会调用cudaFree释放以前分配的块,为新的分配释放空间。

然后分配器再次开始构建它的缓存,进行大量的cudaMalloc,这是一个昂贵的操作,但是可以通过tensorboard分析器查看器的内存分析器部分来发现这个问题。



可以看到与分配器的保留内存相对应的红线不断变化。这意味着PyTorch分配器不能有效地处理分配请求。而当分配程序在没有频繁调用的情况下处理分配时,红线是完全笔直的,如下图所示:



我们如何解决呢?

第一件值得尝试的事情是设置PyTorch相对较新的分配器模式:

PYTORCH_CUDA_ALLOC_CONF="expandable_segments:True"

这告诉PyTorch分配器分配可以在将来扩展的块。但是,如果大小变化太大,它仍然可能无法解决问题。

所以我们智能手动来进行优化,那就是是使数据形状一致。这样分配器就更容易找到合适的数据块进行重用。

比如最简单的将数据填充到相同的大小。或者可以通过运行具有最大输入大小的模型来预热分配器。

内存历史记录

我们想要最大化的使用所有可用的GPU内存——这让我们能够运行大量数据,并更快地处理数据。但是在某些时候,当增加批处理太大时,将遇到CUDA内存不足错误。是什么导致了这个错误?

为了调试它,我们可以查看分配器的内存历史记录。它可以通过PyTorch记录,然后在https://pytorch.org/memory_viz上可视化

  • Start:torch.cuda.memory._record_memory_history(max_entries=100000)
  • Save:torch.cuda.memory._dump_snapshot(file_name)
  • Stop:torch.cuda.memory._record_memory_history(enabled=None)

可视化会画出这样的东西:



x轴表示时间,y轴表示已使用的总内存,彩色块表示张量。它显示了张量何时被分配,何时被释放。

你可能会注意到狭窄的尖峰,这些是持续时间很短的张量,并且占据了很多空间。通过点击一个张量,可以得到这个张量被分配到哪里的信息。我们希望的就是最小化这些峰值,因为它们限制了有效的内存使用。检查导致这个峰值的原因,并考虑优化或者使用其他计算方法替代。

除了峰值之外,很容易检测到内存泄漏:



第一次运行之后的一些数据没有被清除,所以导致内存占用过高。通过点击块,可以知道这些张量是从哪里来的。在图像中,梯度在训练步骤之后没有被清除,因此它们在向前传递过程中处于无用状态,占用了宝贵的内存。

提高模型速度,减少内存使用

我们知道了原因,并且可以通过Profiler来找到瓶颈,那么我们可以通过什么方法来加速训练呢?

1、FlashAttention

首先可以使用FlashAttention来计算点积注意力来提高效率。如果你没有听说过它,它是一种计算精确的点积注意力的方法,并且不需要明确地构建注意力矩阵。这优化了GPU的io操作,提高了速度,也极大地减少了内存消耗。

但是FlashAttention仅适用于兼容硬件上的fp16和bf16精度。那就是NVIDIA Ampere, Hooper以上的GPU

当然也有其他的库可以替换,例如XFormers,和NV自己的Transformer Engine

新版本的PyTorch也内置了FlashAttention的支持,在文档中:

torch.backends.cuda.enable_flash_sdp(): Globally enables or disables FlashAttention.

2、 FSDP 优化多gpu数据冗余

如果使用多个gpu来运行训练,基本的解决方案是使用DistributedDataParallel。生成了几个相同的进程,并且在反向传播期间聚合梯度。

当我们生成相同的进程时,在每个GPU上都有相同的模型和优化器状态,这是冗余的。可以通过跨数据分片来优化内存使用



当在多个gpu上进行训练时,每个进程在使用DDP进行训练时都有相同数据的精确副本。可以通过实现以下几个增强功能来优化它:

ZeRO 1 :分片优化器状态

当使用DDP进行训练时,每个进程都拥有优化器状态的完整副本。对于zer01,可以让每个rank只保留优化器状态的一部分。在反向传播期间,每个rank只需要收集与其参数相关的优化器状态来进行优化步骤。这种冗余的减少有助于节省内存。

在Adam的情况下,它保存的参数大约是模型大小的两倍,将优化器状态分片为8个rank意味着每个rank只存储总状态大小的四分之一(2/8)。

ZeRO 2:梯度分片

除对优化器状态进行分片外,还可以修改优化器步骤来切分梯度。我么可以

将所有与该rank持有的状态相关的梯度集合起来,计算优化步骤,然后将部分参数的优化步骤发送给所有其他rank

现在每个rank不需要保存一个完整的梯度副本,这样可以进一步降低峰值内存消耗。

ZeRO 3 :模型参数分片

我么不需要在每个rank上存储模型的完整副本,我们将在向前和向后期间及时获取所需的参数。在大型模型的情况下,这些优化可以显著降低内存消耗

如何使用FSDP?

其实很简单。我们所需要的就是用FSDP包裹模型:

import torch
import torch.nn as nn
import torch.optim as optim
from torch.distributed.fsdp import FullyShardedDataParallel as FSDP
model = FSDP(model)
# it's critical to get parameters from the wrapped model
# as only a portion of them returned (sharded part)
optimizer = optim.Adam(model.parameters())
# consuct training as usual
train(model, optimizer)

可以指定FSDP的分片策略。例如可以选择SHARD_GRAD_OP策略来实现与ZeRO2类似的行为。

3、torch.compile

这是最简单也是最直接的优化方式了,只要启用torch compile,它就可以将代码的速度提高几个百分点。

在Torch2.0中增加了compile方法,他会跟踪执行图,并尝试将其编译成一种有效的格式,以便几乎无需Python调用即可执行模型。

import torch
model = torch.compile(model)

也就是说,2.0以后只要你的模型能用compile那么就用compile吧。

总结

本文中介绍了使用PyTorch Profiler来查找运行瓶颈,并且介绍了一些简单的提速方法,虽然这篇文章没有完整的解释,但是里面提供的方法都是值得马上尝试方法,希望对大家有所帮助。

https://avoid.overfit.cn/post/95f7fa956805466db713e797d9d62e67

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
37岁俞灏明和王晓晨好事将近,用演技惊艳半个娱乐圈的男人

37岁俞灏明和王晓晨好事将近,用演技惊艳半个娱乐圈的男人

柴叔带你看电影
2024-12-01 00:35:45
跌没4450亿!百度,危险的“信号”曝光

跌没4450亿!百度,危险的“信号”曝光

侃见财经
2024-12-01 08:33:11
电视剧全网热度榜,《我是刑警》跌至第二,第一热度高达76.92

电视剧全网热度榜,《我是刑警》跌至第二,第一热度高达76.92

观察鉴娱
2024-12-01 13:56:38
阴花不能进阳宅!这4种花“打死”也不养,家里若有?快挪走!

阴花不能进阳宅!这4种花“打死”也不养,家里若有?快挪走!

风谈笔录
2024-11-16 07:40:11
去了浙江才发现,电线早已不埋墙里了!瞧人家这么设计,真是先进

去了浙江才发现,电线早已不埋墙里了!瞧人家这么设计,真是先进

风谈笔录
2024-11-14 07:30:27
6260万,重签勇士!给金州吃下了定心丸,但你不该承受如此大压力

6260万,重签勇士!给金州吃下了定心丸,但你不该承受如此大压力

呆哥聊球
2024-12-01 18:53:05
老了才知道,不管多心疼儿女,帮忙带娃时,都要留3个心眼

老了才知道,不管多心疼儿女,帮忙带娃时,都要留3个心眼

通文知史
2024-11-30 12:50:02
读秒绝平!莫塔不敢相信:3分变1分,尤文爆冷,落后榜首6分

读秒绝平!莫塔不敢相信:3分变1分,尤文爆冷,落后榜首6分

足球狗说
2024-12-02 05:49:06
油价大跌超7毛/升,12月4日油价迎今年第24次调整,油价或变跌

油价大跌超7毛/升,12月4日油价迎今年第24次调整,油价或变跌

油价早知道
2024-11-29 09:20:40
专家告诉你:色情片其实没你想象中那么好看,它的危害难以置信

专家告诉你:色情片其实没你想象中那么好看,它的危害难以置信

芊芊之言
2024-11-06 19:03:07
停火后黎真主党领导人首次讲话:已重建指挥系统,对巴勒斯坦的支持不会停止

停火后黎真主党领导人首次讲话:已重建指挥系统,对巴勒斯坦的支持不会停止

极目新闻
2024-11-30 10:23:31
重伤!大概率赛季报销!再见了,中国男篮得分王

重伤!大概率赛季报销!再见了,中国男篮得分王

象牙三
2024-12-01 11:57:04
2025蛇年春晚官宣啦!有赵本山吗?总导演是谁?

2025蛇年春晚官宣啦!有赵本山吗?总导演是谁?

圈里的甜橙子
2024-12-01 20:59:29
博主让糖尿病母亲停西药,改中药后腿部结痂流脓,称:二甲双胍的毒逼出来了

博主让糖尿病母亲停西药,改中药后腿部结痂流脓,称:二甲双胍的毒逼出来了

小萝卜丝
2024-11-22 20:32:00
澳门特区第六届政府候任主要官员和检察长首次集体亮相 岑浩辉:将推动特区稳定发展,持续提升市民福祉

澳门特区第六届政府候任主要官员和检察长首次集体亮相 岑浩辉:将推动特区稳定发展,持续提升市民福祉

每日经济新闻
2024-12-01 22:51:07
持续低迷,瓜迪奥拉执教生涯首次遭遇连续7场不胜

持续低迷,瓜迪奥拉执教生涯首次遭遇连续7场不胜

懂球帝
2024-12-02 03:04:28
3-1!日本拒绝放水,国足逼上绝境,伊万有后手,印尼空欢喜一场

3-1!日本拒绝放水,国足逼上绝境,伊万有后手,印尼空欢喜一场

体育就你秀
2024-12-01 08:12:15
父母最大的悲哀,就是轻易向别人透露子女这3件隐私,真 的很傻!

父母最大的悲哀,就是轻易向别人透露子女这3件隐私,真 的很傻!

华人星光
2024-12-01 12:39:21
三舰岛设计,实在是让人迷茫,美媒:令人费解的中国航母开始海试

三舰岛设计,实在是让人迷茫,美媒:令人费解的中国航母开始海试

现代小青青慕慕
2024-12-02 04:10:38
赵本山儿子赵大牛12万巴黎世家棉袄穿出30块地摊货感,网友:绝了

赵本山儿子赵大牛12万巴黎世家棉袄穿出30块地摊货感,网友:绝了

娱不咸
2024-10-31 20:20:02
2024-12-02 06:32:49
deephub
deephub
CV NLP和数据挖掘知识
1507文章数 1417关注度
往期回顾 全部

科技要闻

我国首个商业航天发射场首发成功

头条要闻

湖南省委原常委落马后 其妻追讨5000万巨额债务引关注

头条要闻

湖南省委原常委落马后 其妻追讨5000万巨额债务引关注

体育要闻

勇士四连败,到底是谁的错?

娱乐要闻

黄晓明姥姥去世,祖孙俩手牵手好温馨

财经要闻

女首富,死刑!交出800亿,免死!

汽车要闻

科技是中国豪车梦的支点 腾势Z9走心试驾体验

态度原创

房产
游戏
亲子
教育
军事航空

房产要闻

一燃再燃!又卖2亿!白鹅潭顶流,引爆全城!

梦幻西游超级联赛S2非诚勿扰2比0提前夺冠,德云皓子卫冕冠军

亲子要闻

加大加厚折叠儿童泡澡桶,家里有娃的放心入

教育要闻

2024第40届数学竞赛决赛国集获奖名单公布!江苏 2人入选

军事要闻

泽连斯基开出停火条件 俄方回应

无障碍浏览 进入关怀版