Introduction

整理一些PyTorch,CUDA,OpenGL相关的性能调优trick。

绝不是什么专家,但或许我的workflow可以帮你解决纠结了很久的bug。

之所以整理这个blog,是因为其中记录的几乎所有内容都无法直接在网上、在GPT口中简单搜索得到。即使能有相关信息,也是鱼龙混杂,让人看了眼花缭乱,正儿八经的guide都很少。

我是做计算机视觉的体积视频方向的,工作中会涉及到实时渲染相关内容,但同时又得用python和pytorch(也并不会c++),因此喜欢搞点写起来容易,但性能也不输c++的操作。

本文所需的一些前置信息

一些本blog中会提到的资源和工具:

PyTorch官方的performance tuning guide: https://pytorch.org/tutorials/recipes/recipes/tuning_guide.html

PyTorch和CUDA的相爱相杀关系: https://pytorch.org/docs/master/notes/cuda.html

Python上的CUDA Runtime和NVIDIA Driver接口: https://developer.nvidia.com/cuda-python

Python上的OpenGL接口: https://github.com/mcfletch/pyopengl

PyTorch官方的提供的profiler(有时候比cuda的profiler都好用): https://pytorch.org/blog/introducing-pytorch-profiler-the-new-and-improved-performance-tool/ https://pytorch.org/tutorials/recipes/recipes/profiler_recipe.html

NVIDIA的Nsight Systems和Nsight Graphics(目测只有Windows版本): https://docs.nvidia.com/nsight-systems/UserGuide/index.html https://developer.nvidia.com/nsight-graphics https://developer.nvidia.com/nsight-systems

RenderDoc,无需多言,检查frame和graphics api调用的(Window,WSL2,Ubuntu都能用,MacOS好像也可以用): https://renderdoc.org/

Chrome,浏览器,但是Chrome那帮人也是优化高手,因此他们做了工具来可视化tracing: PyTorch Profiler生成的tracing文件可以用 chrome://tracing 印象里FireFox和Edge也有类似的工具,FireFox的似乎能更好看,但兼容性不太好 https://www.chromium.org/developers/how-tos/trace-event-profiling-tool/ https://profiler.firefox.com/

在读blog之前,我们需要先同步一些事情。

PyTorch中Synchronization的基本概念

Python代码速度不快,这一点在很多PyTorch应用和codebase中也存在。如果所有指令都线性执行,我们的deep learning work load可能会慢到无法想象。所幸,CPU和GPU的物理分离性导致这两者上可以同时跑代码,PyTorch的大部分CUDA Kenel都是异步运行的,这意味着提交好GPU任务后,CPU上仍然可以运行程序。一个例子是,我们希望计算一张图片中所有像素值的mean,我们执行了 img.mean() 这条指令,那么PyTorch的后端就会启动一个对应的cuda kernel来进行上面的计算。此时如果我想做一些CPU操作,例如打印一句话print('Hello, world.') 这段CPU代码会立刻被执行,即使 img.mean() 还没有被执行完。

当你在测试这一点时,需要注意很多Python的解释器会将你敲击回车前最后一条指令的返回值打印到屏幕上,此时 img.mean() 就不再是异步执行的了,因为你的CPU需要拿到这条指令的结果才会知道要将什么屏幕打印到屏幕上。

要验证PyTorch的异步CUDA Kernel调用相对于使用它要麻烦的多,你需要首先理解Stream的概念。

对于此,最好的文档就是PyTorch官方的documentation: