[Pytorch] torch.autograd.profiler细节

2024-01-11 09:32

本文主要是介绍[Pytorch] torch.autograd.profiler细节,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

官网使用说明;

Python部分:

核心类class profile:用户侧用with来创建和退出之;self.function_events成员是核心数据;缺点:DataLoader发起的多进程调用,其无法get到其他进程的操作的cuda时间;

    成员函数__enter__: with开始时调用,调用C++底层的torch.autograd._enable_profiler开始统计;

    成员函数__exit__: with结束时调用,调用C++底层的torch.autograd._disable_profiler结束统计;调用parse_cpu_trace将来自C++的“时间点”加工为“线段”,保存在self.function_events数据成员中;

    以下成员函数都是对self.function_events数据进行加工: _check_finish;table;export_chrome_trace;key_averages;total_average;self_cpu_time_total;其中好几个是先调用_check_finish(内部调用self.function_events.populate_cpu_children),建立FunctionEvent彼此之间的父子关系(之所以不在__exit__里调用,可能是lazy策略,这步就可以放在程序最末尾,减少对原程序的时间延迟打扰)

函数parse_cpu_trace:

    将来自C++的“时间点”(push或pop类型)加工为“线段”(FunctionEvent);

    自带cuda的线段要把cuda起始时间记录下来;(cudaEventRecord相对于本<node_id, device>的投一个cuda event的elapsed time,记作本时间点)(即这里得到的"线段"对应的cuda时间,等于其发射过的"头一个kernel开始执行至最后一个kernel结束"的总时长)(同一个kernel的执行时间,会被所有包含它的“线段”所"重复"统计,以为每个“线段”的开头和结尾都会调用cudaEventRecord)(这里,一个“线段”只能关联一个所谓的"kernel")

    记录该”线段“使用的总内存和总显存(只要遇到memory_alloc事件,则将所有包含其的”线段“,全部累加上这次的size,即每个”线段“记录的是total size而不是self size);

类EventList:继承自python的list类,profile类的self.function_events就是该类型,list成员是FunctionEvent(即"线段");

    成员函数populate_cpu_children:目的是在”线段“之间建立父子包含关系;把"线段"们先按<thread, node_id>分成不同的组,每组分别操作:

        先按线段的<起始时间,-终止时间>做key来排序,目的是确保“母线段”一定在其“子线段”之前;

        维护一个栈,里面所有线段具有”包含关系“,新来的线段违背”包含关系“时,就pop栈知道满足”包含关系“;对所有满足包含关系的相邻线段,建立父子关系;

    成员函数table:调用build_table来格式化成好看的字符串类型表格;

    成员函数export_chrome_trace:导出到json格式的文件,可以被chrome://tracing打开看trace-view;包括:CPU线段,GPU线段,CPU线段和GPU线段之间的联系线;(args字段里可以放很多附加内容)

    成员函数key_averages:统计,以<event.key, event.node_id>做key把线段们aggregation起来;也可把input_shape加到key里;

    成员函数self_cpu_time_total:统计,所有线段的CPU self time全部加起来;

    成员函数total_average:统计,把所有线段的数值全加和起来;

类FunctionEvent:”线段“;CPU侧的线段,里面self.kernels成员可以包含多个"kernel"线段;关键成员字段:

    node_id, name, thread, cpu_interval(包含起始时间点), kernels, cpu_children, input_shapes, 

    cpu_memory_usage, cuda_memory_usage, is_async, is_remote,  sequence_nr

    成员函数self_cpu_memory_usage

    成员函数self_cuda_memory_usage

    成员函数self_cpu_time_total

    (注意:唯独没有self_cuda_time_total)

    成员函数cuda_time_total

    成员函数cpu_time_total

类FunctionEventAvg:”线段“们的平均;

类emit_nvtx:把通过C++函数和cudaEventRecord打点,换成nvtx的push、pop来打点;还是调用C++层的torch.autograd._enable_profiler来开始统计,只是传过去的参数变成了NVTX;使用nvprof启动进程,代码里有with torch.autograd.profiler.emit_nvtx()则生效;(类开头的一大段注释解释sequence_nr的用法,有一些不太懂)

parse_nvprof_trace:读取nvtx的.sqlite文件,把里面的"点“转为"线段"(FunctionEvent), 有kernel的要在成员变量里挂上kernel(一个”线段“可以挂在多个kernel,kernel的所有”祖先“线段都会挂载它);

NVTX的parse这里做的很粗糙,暂时没有考虑node_id和thread;

类record_function:用户自定义“范围”,用with把一段代码包起来统计之;成员函数_call_end_callbacks_on_future的用法暂时未知;

build_table:把"线段"们格式化成好看的字符串类型表格

 

其他:

is_async:FunctionEvent如果开头和结尾不是同一个thread,就叫做async的;

<node_id, device>: 每个cuda event都有这些属性,可以拿到不同机器的不同卡的cuda event?

<event.key, event.node_id>: 在key_averages里面使用了这个做aggregation的key,即考虑了不同机器分开统计;

sequence_nr: 用于将forward和backward操作关联起来的序号;C++层埋的信息;

 

C++部分:

profiler.h文件:

Event类:打的“点”;字段如下:

  int64_t cpu_ns_ = 0;at::StringView name_;EventKind kind_;uint16_t thread_id_;at::RecordFunctionHandle handle_ {0};std::vector<std::vector<int64_t>> shapes_;int64_t cpu_memory_usage_ = 0;int64_t cuda_memory_usage_ = 0;int device_ = -1;CUDAEventStub cuda_event = nullptr;int node_id_ = 0;bool is_remote_ = false;int64_t cuda_us_ = -1;int64_t sequence_nr_ = -1;

node_id_: torch\distributed\rpc\__init__.py里面,_set_profiler_node_id(rank),即设置rpc的process rank作为node_id_;

device_: 在reportMemoryUsageToProfiler时赋值的,注意就是个整数;

profiler.cpp文件:

mark、pushRange、popRange、reportMemoryUsage,分别是打点4种EventKind;

成员函数enableProfiler:为每个deivce打初始点__cuda_start_event,同时为host打点__start_profile,后续cuda的点就可以和自己device上的初始点计算elapsed time,同理host后续的点也和host初始点计算elapsed time,因为所有device和host都几乎同时打的初始点,所以所有这些elapsed time可以当作“wall-clock time"使用!(cuda上打初始点似乎有overhead,所以人家先warm-up了一把,即__cuda_startup)

profiler.py文件里的parse_cpu_trace,会调用adjusted_time:

return cuda_time_0.cuda_elapsed_us(cuda_record) + start_record.cpu_elapsed_us(cuda_time_0)

其中前半部分计算cuda_record的Event减去cuda_time_0的Event的时间差;后半部分计算cuda_time_0的cpu_ns_减去start_record的cpu_ns_的时间差;假设:cuda_time_0的Event和其cpu_ns_是几乎同时时刻!目的:总体等价于cuda_record的Event在GPU上执行到的时刻相对于start_record的cpu_ns_的时间差;为什么需要后半部分:因为在C++里是一个循环为每个Device挨个打__cuda_start_event,最后再打__start_profile,所以两者之间可能是有微笑时间差的,即__cuda_start_event的时刻不完全等于__start_profile,为了更精确,所以加了后半部分。

这篇关于[Pytorch] torch.autograd.profiler细节的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

vscode中使用go环境配置细节

1、在docker容器中下载了go的sdk 2、在/etc/profile.d/go.sh里填入如下内容: #!/bin/bashexport GOROOT=/home/ud_dev/goexport PATH=$GOROOT/bin:$PATH  3、设置go env go env -w GOPROXY=https://goproxy.cn,directgo env -w GO

使用WebP解决网站加载速度问题,这些细节你需要了解

说到网页的图片格式,大家最常想到的可能是JPEG、PNG,毕竟这些老牌格式陪伴我们这么多年。然而,近几年,有一个格式悄悄崭露头角,那就是WebP。很多人可能听说过,但到底它好在哪?你的网站或者项目是不是也应该用WebP呢?别着急,今天咱们就来好好聊聊WebP这个图片格式的前世今生,以及它值不值得你花时间去用。 为什么会有WebP? 你有没有遇到过这样的情况?网页加载特别慢,尤其是那

Nn criterions don’t compute the gradient w.r.t. targets error「pytorch」 (debug笔记)

Nn criterions don’t compute the gradient w.r.t. targets error「pytorch」 ##一、 缘由及解决方法 把这个pytorch-ddpg|github搬到jupyter notebook上运行时,出现错误Nn criterions don’t compute the gradient w.r.t. targets error。注:我用

分享MSSQL、MySql、Oracle的大数据批量导入方法及编程手法细节

1:MSSQL SQL语法篇: BULK INSERT      [ database_name . [ schema_name ] . | schema_name . ] [ table_name | view_name ]         FROM 'data_file'        [ WITH       (      [ [ , ] BATCHSIZE = batch_siz

【LVI-SAM】激光雷达点云处理特征提取LIO-SAM 之FeatureExtraction实现细节

激光雷达点云处理特征提取LIO-SAM 之FeatureExtraction实现细节 1. 特征提取实现过程总结1.0 特征提取过程小结1.1 类 `FeatureExtraction` 的整体结构与作用1.2 详细特征提取的过程1. 平滑度计算(`calculateSmoothness()`)2. 标记遮挡点(`markOccludedPoints()`)3. 特征提取(`extractF

【超级干货】2天速成PyTorch深度学习入门教程,缓解研究生焦虑

3、cnn基础 卷积神经网络 输入层 —输入图片矩阵 输入层一般是 RGB 图像或单通道的灰度图像,图片像素值在[0,255],可以用矩阵表示图片 卷积层 —特征提取 人通过特征进行图像识别,根据左图直的笔画判断X,右图曲的笔画判断圆 卷积操作 激活层 —加强特征 池化层 —压缩数据 全连接层 —进行分类 输出层 —输出分类概率 4、基于LeNet

pytorch torch.nn.functional.one_hot函数介绍

torch.nn.functional.one_hot 是 PyTorch 中用于生成独热编码(one-hot encoding)张量的函数。独热编码是一种常用的编码方式,特别适用于分类任务或对离散的类别标签进行处理。该函数将整数张量的每个元素转换为一个独热向量。 函数签名 torch.nn.functional.one_hot(tensor, num_classes=-1) 参数 t

torch.nn 与 torch.nn.functional的区别?

区别 PyTorch中torch.nn与torch.nn.functional的区别是:1.继承方式不同;2.可训练参数不同;3.实现方式不同;4.调用方式不同。 1.继承方式不同 torch.nn 中的模块大多数是通过继承torch.nn.Module 类来实现的,这些模块都是Python 类,需要进行实例化才能使用。而torch.nn.functional 中的函数是直接调用的,无需

pytorch计算网络参数量和Flops

from torchsummary import summarysummary(net, input_size=(3, 256, 256), batch_size=-1) 输出的参数是除以一百万(/1000000)M, from fvcore.nn import FlopCountAnalysisinputs = torch.randn(1, 3, 256, 256).cuda()fl

Post-Training有多重要?一文带你了解全部细节

1. 简介 随着LLM学界和工业界日新月异的发展,不仅预训练所用的算力和数据正在疯狂内卷,后训练(post-training)的对齐和微调方法也在不断更新。InstructGPT、WebGPT等较早发布的模型使用标准RLHF方法,其中的数据管理风格和规模似乎已经过时。近来,Meta、谷歌和英伟达等AI巨头纷纷发布开源模型,附带发布详尽的论文或报告,包括Llama 3.1、Nemotron 340