本文以内部pytorch核心开发者视角,非常详细透彻的分析了pytorch的内部结构,为开发者提供一张地图,告诉您“支持自动区分的张量库”的基本概念结构,并提供一些工具和技巧,以便找到适合代码库。对学习pytorch、尤其是致力于参与pytorch贡献有非常大的意义。
pytorch是一个开源的python机器学习库,基于torch,已成为最受欢迎的机器学习框架之一。
相比tensorflow,pytorch的社区由更多专业机器学习开发人员、软件架构师和公司内部程序员组成。
pytorch也更多地用于数据分析和业务环境中的特殊模型中。
在pytorch社区中,有更多的python开发人员从事web应用程序。此外,这种python向框架的多功能性,使得研究人员能够以几乎无痛的方式测试想法,使得它成为最先进的尖端解决方案的首选框架。
对于准备、正在学习pytorch的读者来说,了解其内部机制能够极大的提升学习效率、增进对pytorch设计原理和目的的了解,从而能够更好的在工作学习中使用该工具。如果你立志参与到pytorch后续的改进中,那么更应该深入的了解其内部机制。
好消息是,facebook research engineer、斯坦福博士生、pytorch核心开发人员edward z. yang为大家带来一份pytorch内部机制的详解slides,新智元在此强力推荐给广大读者。正文约3500字,阅读可能需要10分钟。
由于微信的限制无法展示高清图像,我们特意为大家在文末找来了可下载的高清完整版,预祝大家学习愉快!
这份内部机制详解是为谁准备的?
主要针对使用过pytorch的人,尤其是希望成为pytorch贡献者、但却被pytorch的庞大复杂的c++代码库吓到的人。
最终目的是能够为大家提供一个通关宝典,让大家了解“支持自动区分的tensor库”的基本概念结构,并提供一些工具和技巧,用来更容易的找到适合代码库。
读者只需要对pytorch有一个初步的了解,并且有过一定的动手经验即可。门槛还是非常低的。
全部内容分为两部分。首先介绍tensor库的概念。作者将从tensor数据类型开始,更详细地讨论这种数据类型提供的内容,以便让读者更好地了解它是如何实际实现的。布局、设备和dtype的三位一体,探讨如何考虑对tensor类的扩展。
第二部分将讨论pytorch实战。例如使用autograd来降低工作量,哪些代码关键、为什么?以及各种用来编写内核的超酷的工具。
理解tensor库的概念
tensor
tensor是pytorch中的中心数据结构。我们可以将tensor视为由一些数据组成,然后是一些描述tensor大小的元数据,包含元素的类型(dtype),tensor所依赖的设备(cpu内存?cuda内存?)。以及strides(步幅)。strides实际上是pytorch的一个显著特征。
tensor是一个数学概念。在计算机上最常见的表示是将tensor中的每个元素连续地存储在内存中,将每一行写入内存,如上所示。
在上面的例子中,指定tensor包含32位整数,每个整数位于物理地址中,相互偏移四个字节。要记住tensor的实际尺寸,还必须记录哪些尺寸是多余的元数据。
假设我想在逻辑表示中访问位置tensor[0,1]处的元素。通过stride我们应该这样做:
找出tensor的任何元素存在的位置,将每个索引乘以该维度的相应stride,并将它们加在一起。
上图中将第一维蓝色和第二维红色进行了颜色编码,以便在stride计算中跟踪索引和步幅。
以上是stride的一个例子。stride表示实际上可以让你代表tensor的各种有趣的方法; 如果你想玩弄各种可能性,请查看stride visualizer。
可能存在共享相同存储的多个tensor,但请记住一点:有tensor的地方,就有存储。
存储定义tensor的dtype和物理大小,而每个tensor记录大小,步幅和偏移,定义物理内存的逻辑解释。
tensor扩展
有很多有趣的扩展,如xla张量,量化张量,或mkl-dnn张量,作为张量库,我们必须考虑是如何适应这些扩展。
当前的扩展模型在张量上提供了四个扩展点。首先,用三个参数用来确定张量是什么:
设备
张量的物理存储器实际存储在何处,例如在cpu上,nvidia gpu(cuda)上,或者可能在amd gpu(hip)或tpu(xla)上的描述。设备的显着特征是它有自己的分配器,不能与任何其他设备一起使用。
布局
布局用来描述我们如何逻辑地解释这个物理内存。最常见的布局是跨步张量,但稀疏张量具有不同的布局,涉及2个张量:一个用于索引、一个用于数据。
mkl-dnn张量可能具有更奇特的布局,例如阻挡布局,这不能仅使用步幅来表示。
dtype
描述了它实际存储在张量的每个元素中的含义。这可以是浮点数或整数,或者它可以是例如量化的整数。
顺便说一下,如果你想为pytorch张量添加一个扩展名,请联系pytorch官方。
实战技巧
了解你手里的武器
pytorch有很多文件夹,contributing文档有非常详细的描述。但实际上,你真正需要了解的只有四个:
torch/:包含导入和使用的实际python模块。python代码,很容易上手调试。
torch/csrc/:它实现了在python和c++之间进行转换的绑定代码,以及一些非常重要的pytorch功能,如autograd引擎和jit编译器。它还包含c++前台代码。
aten/:“a tensor library”的缩写(由zachary devito创造),是一个实现tensors操作的c++库。存放一些内核代码存在的地方,尽量不要在那里花太多时间。
c10/:这是一个双关语。c代表caffe,10既是二级制的2,也是十进制的10(英文ten,同时也是tensor的前半部分)。包含pytorch的核心抽象,包括tensor和storage数据结构的实际实现。
让我们看看这种代码分离在实践中是如何分解的:
调用一个函数的时候,会经历以下步骤:
将python翻译成c
处理变量调度
处理设备类型/布局调度
我们有实际的内核,它既可以是现代本机函数,也可以是传统的th函数
值得一提的是,所有代码都是自动生成的,所以不会出现在github的repo里,必须自己构建pytorch后才能看到。不过你也不必非常深刻地理解这段代码在做什么,自动生成的嘛。
从武器库中挑选写内核的趁手兵刃
pytorch为内核编写者提供了许多有用的工具。在本节中,我们将介绍其中比较趁手的工具。
要利用pytorch带来的所有代码生成,需要为运算符编写schema。详细介绍参见github的readme。
错误检查可以通过低阶api(torch_check)和高阶api实现。高阶api可以基于tensorarg元数据提供用户友好的错误消息。
要执行dtype调度,应该使用at_dispatch_all_types宏,用来获取张量的dtype,并用于可从宏调度的每个dtype的lambda。通常,这个lambda只调用一个模板化的辅助函数。
如何提高工作效率
别编辑header!
编辑header会导致很长的重构时间,尽量去编辑.cpp文件。
别直接用ci去测试
ci是一个直接可用的测试代码的变动是否有效的非常棒的工具,但如果你真的一点不都改设置恐怕要浪费很长时间在测试过程中。
强烈建议设置ccache
它有可能让你避免在编辑header时进行大量重新编译。而当我们在不需要重新编译文件时进行了重新编译,它还有助于掩盖构建系统中的错误。
用一台高性能的工作站
如果你建立一个带有cpu和ram的强大服务器,你将获得更愉快的体验。特别是,不建议在笔记本电脑上进行cuda构建。
韩国第三大运营商重申:不会封杀华为5G设备
iphone历史版本你拥有过哪些?最值得期待的是iPhone 8?
如何正确合理的使用水浸传感器来监测机房漏水情况
基于频偏功能的混频器/变频器一致性测量解析
Oppo推出了Find X2和Find X2 Pro 5G智能手机
PyTorch核心华人开发者透彻解读PyTorch内部机制
发现一个Spring事务的巨坑bug 你必须要小心了
uCloudlink 推出创新移动数据服务 “GlocalMe® Inside”
低价竞争致业绩大幅缩水 华为/OPPO供应商同兴达能否脱困?
浪涌防雷器的工作原理是什么
Molex定制 Soligie柔性印刷型传感器解决方案
王晓鹏用6年追求的顶尖国产虹膜识别技术怎么样了
为什么说云计算对中国未来的IC设计产业至关重要?
生产物流液晶电子看板走势
如何让自已调频接收出靓声
协作机器人在3C电子行业的典型应用场景展示
银行高清可视化火灾预警方案的结构组成和特点分析
板带表面缺陷检测系统助力实现高效精确智能化
Wrap 函数:绝对坐标中旋转分度的简化位置控制
地球为什么要流浪?(芯片角度分析)