脸书AI首席开发布道师:如何贡献PyTorch代码

全文共9175字,预计学习时长18分钟

脸书AI首席开发布道师:如何贡献PyTorch代码
图片来源:redcharlie Unsplash

本文作者是Facebook的机器学习/人工智能首席开发布道师,为其麾下的PyTorch团队助力,曾经是一名软件工程师。

值得注意的是,在之前,作者从未使用过PyTorch。他将用自己的亲身经历告诉你:PyTorch并不难学。

脸书AI首席开发布道师:如何贡献PyTorch代码

PyTorch内容集锦

PyTorch及其工作原理:

脸书AI首席开发布道师:如何贡献PyTorch代码

• PyTorch是Facebook开发的深度学习框架,用于快速灵活实验。这是一个基于Python的计算软件包,含有 C++后端API。

• PyTorch的Python前端有三个不同部分:

Torch

这是一个包含多维张量与数学运算的数据结构包。

Torch.nn

用于创建并训练神经网络。区域块的导入数据以张量形式传递。

例如:为处理图像而训练卷积神经网络时,可使用nn.conv2D模块(这一想法来自笔者同事塞斯)。

Torch.optim

该优化算法可训练神经网络。

例如:适用于初学者的SGD或适合进阶者的Adam等算法,都可训练神经网络(这个好例子也源自塞斯)。

Tensors(张量)

PyTorch的Tensors 与Numpy数组类似。不同之处在于,Tensors数据可以是单个数字,或一维矩阵(向量),或囊括各种数据的多维结构。

算梯度即求导(没错,机器学习即微积分)。求出张量的梯度,便可最大程度地规避错误。

梯度下降这一算法能有效实现错误最小化。错误由数据决定,而数据的分类也有适当与不适当之别。

通过梯度降低不当分类项目数。

张量最重要的特点即自动跟踪梯度。每个张量中的数据代表神经网路的连接层。这其中,有三点值得一提:

• 阶 (rank): 确定张量的维数。例如,向量为一阶。

• 形状 (shape): 行数和列数,表现形式为tensor. Size ([x]). 

• 数据类型 (type): 给张量元素所指定的数据类型。

PyTorch的神经网络训练循环如下:确定目标函数、迭代输入其他数据、将数据运用于神经网络、执行梯度操作减少误差,将异常参数运用于神经网络。

在神经网络中重复迭代整个训练数据集即可。

C++ 后端

C++“后端”有五个不同部分。 

• Autograd: 自动求导,即张量上的记录操作,进而生成自动求导图,基本上依据梯度张量求导。

• ATen: 张量及数学运算库。

• TorchScript: 连接TorchScript的JIT编译器与解释器的界面(JIT为“即时”)

• C++前端: 训练与评价机器学习模型的高级构造。

• C++ 扩展: 通过自定义C++与CUDA的例程扩展,扩展Python的API.

CUDA (计算机统一设备架构) 是由Nvidia推出的并行计算架构及应用程序界面 (API) 模型。

上述内容皆援引自维基百科,总的来说,CUDA常用于GPU上的各项操作。

GPU即图像处理器。可将其视为具有强大运算力的电脑。

“说好的概览呢?这些知识点简直让人摸不着头脑。”虽然上述内容的确晦涩难懂,但它们至关重要。

若想对相关知识有深入全面的了解,请参阅优达课程(https://classroom.udacity.com/courses/ud188)并阅读PyTorch docs(https://pytorch.org/docs/stable/index.html)这份资料,必能让你获益匪浅。

那份资料并不着眼于PyTorch的方方面面,而是帮助读者开始给GitPyTorch开源数据库贡献代码(https://github.com/pytorch/pytorch)。

在这份repo中,你可根据上述信息,自行推断大量所含文件夹的内容。

脸书AI首席开发布道师:如何贡献PyTorch代码

搭建开发环境

贡献任何代码之前,务必阅读CONTRIBUTING.md这份文档(https://github.com/pytorch/pytorch/blob/master/CONTRIBUTING.md),切勿有所遗漏。这是笔者从血泪中总结出的教训。

若条件允许,无论是处理Python还是C++问题,最好都借助GPU。

还可采用其他途径(如AWS DLAMI或Nvidia Docker),这会显著提升运行速度。

作为初学者,笔者犯下的第一个错误就是在本地电脑上开工。由于本地电脑性能不够强大,各种令人困惑头疼的段错误也就层出不穷。

最终,笔者用SSH、MOSH、TMUX等登陆GPU服务器,效果极佳。如果想就此做好准备,可参阅以下博文:

• HPC上的GPU运算简介:安装GPU与SSH

https://sydney-informatics-hub.github.io/training.artemis.gpu/setup.html

• PyTorch必备——GPU

https://discuss.pytorch.org/t/solved-make-sure-that-pytorch-using-gpu-to-compute/4870

• GPU内存须知 

https://discuss.pytorch.org/t/reserving-gpu-memory/25297

• 安装PyTorch与Tensorflow—— 采用支持CUDA的GPU

https://medium.com/datadriveninvestor/installing-pytorch-and-tensorflow-with-cuda-enabled-gpu-f747e6924779

接下来,搭建PyTorch开发环境。想用SSH登陆GPU,须做好以下内务处理操作:

• 连接GitHub账号,确保在GPU创建SSH**,并将其添加至GitHub账号。

• 你的设备很可能会用到Python。须确保用的是Python 3。你很可能已经安装了 pip。如若不然,务必全部安装。

• 安装Miniconda. 这和pip极为类似。官方网站并没有很好的终端安装指南,在此列出笔者的操作方式:

$ with-proxy wget “https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh"$ chmod +x Miniconda-latest-Linux-x86_64.sh$ bash Miniconda3-latest-MacOSX-x86_64.sh

• 重启终端,输入conda,确保操作无误。

• 运行conda config — set auto_activate_base false, 以防止Conda自动**,不然会干扰机器的运作。

• 运行 conda activate,**Conda。每次开发前,务必保证conda处于**态,注意终端的(base)语句即可。

• 安装 ccache。如果无效,在启用conda的情况下执行 conda install ccachewhen conda。若依然无效,请尝试wget。"https://www.samba.org/ftp/ccache/ccache-3.3.3.tar.gz".

• 输入ccache 确保一切奏效,输入conda list确保其出现在安装列表。

• 安装一个faster linker。除非万不得已,不然请勿输入 ln -s /path/to/downloaded/ld.lld /usr/local/bin/ld 指令。笔者曾遇到这种情况,由于它们作用不大,最终还得将相关文档全部删除。

• 运行 pip install ghstack 或 conda install ghstack.

• 运行 pip install ninja 或 conda install ninja.

• 通过pip install flake8 flake8-mypy flake8-bugbear flake8-comprehensions flake8-executable flake8-pyi mccabe pycodestyle pyflakes安装 Flake8,它会为你纠错。若想给文档纠错 (lint),输入 flake8 <FILENAME> 即可。

• 安装一个IDE,通过SSH登陆GPU。笔者在Atom. 上查找remote-ssh ,即可得到相关操作说明。

• 最后,安装PyTorch:

$ git clone https://github.com/pytorch/pytorch$ cd pytorch$ git pull --rebase$ git submodule sync — recursive$ git submodule update — init — recursive$ python setup.py develop

python setup.py develop 就是用来编写PyTorch代码的工具。一开始会花些工夫,但一旦写过一次,以后就能使用不少加速方法。

编辑C++时需要构建PyTorch,但编辑Python时则不然。

想把这一系列步骤办好,就得斗志昂扬,心怀热忱。不过一旦完成这不易的任务,你就可以长舒一口气,好好犒赏下自己。

如果碰壁,不要恐慌,笔者也有过类似的经历。参照后文的《常见错误》,或在评论区留言,笔者必竭力相助。搭建好开发环境会花一番工夫,祝各位马到成功。

脸书AI首席开发布道师:如何贡献PyTorch代码

代码时间到!

开发环境搭建完毕,可以开始写代码了!

如果你之前从未贡献过开源代码,务必略读《行为准则》(https://github.com/pytorch/pytorch/blob/5bc7c1f83dd3ea740ba1d2af286c464862b90743/docs/source/community/governance.rst)。很多代码库都有这样的文档,简言之,做好人,行好事。

关注GitHub的问题 (issues) 选项卡。其中囊括很多社区成员提出的问题。点击训练营 (bootcamp) 标签,查看初学者级别的问题,选择自己能力范围内的任务,加以攻坚。

笔者建议,开始动手前,先阅读相关资料,洞悉个中玄机。还可更新过滤器 (filter) 查看训练营的历史纪录,研究已解决的问题。

如果你胸怀大志,大可点击 pull requests 标签。不是所有的PR都有相关的问题可供参考,有时研究问题本身更容易了解情况。

刚研究这些问题时,“冒牌货综合征”如乌云般笼罩在自己心头。“我又不是科班出身,怎么做得了这个?”打住!相信自己,你能行! 

解决问题无须全知全能,找到方向,难题便迎刃而解。

如果你找到一个愿意动手解决的问题,要敢于留言并发问,哪怕是这样的一句话,“我想接下这个任务,请问你能就如何着手给我一些建议吗?”都大有裨益。

这些问题板块下的评论者都很乐于助人,因为如果有人对这些问题感兴趣,他们自己也会很高兴。对此笔者有切身体会,在他们的引导下,笔者解决了一系列问题,自己的PyTorch技术也日臻完善。

接下来是案例分析,阐述笔者如何在一头雾水的情况下解决问题。

脸书AI首席开发布道师:如何贡献PyTorch代码

第17893号问题:确保Grad_outputs的输出值形状与torch.autograd.grad()一致

幸运的是,据笔者切身经验来说,PyTorch库的作者往往细致缜密,言之有物。

就此例:https://github.com/pytorch/pytorch/issues/17893而言,结合前文的知识,不难发现,由于该问题涉及“接受输入”,所以这必定与Python前端有关。

乍一看这个问题角度很刁钻,虽然本质上与Python相关,但题目中的autograd,却有将人引向C++之嫌。

笔者创建一个新分支并将其导至最高级的torch文件夹(本例中,所涉及的函数正是torch)。

有趣的是,在最早创立的文件夹中,正好有一个名为autograd ,真可谓无巧不成书。

打开 autograd 文件夹,在 grad( 语句中调用git grep ,以确定函数定义。可以确定,其中一个就在 __init__.py 文件中。

更巧的是,在 grad 函数,中 正好有以 *gasp*为名的变量,也就是说只需要做一个简单的condition,一切便迎刃而解。

如题所示, outputs 与 grad_outputs 须形状一致。通过NumPy,有一个简单的法子可以做到这点。

import numpy as np...if np.shape(outputs) != np.shape(grad_outputs):

    raise RuntimeError("grad_outputs and outputs do not have the same shape")

作为一名优秀的软件工程师,笔者很清楚只有先测试代码,才能保证自己的PR滴水不漏。不过首先,得确认程序的兼容性没有问题。

据CONTRIBUTING.md 文件所示, 先得运行 python test/run_test.py。

运行结果并不尽如人意,那么究竟是哪里出了纰漏?原来PyTorch在调用NumPy并不直接照搬,而是会做出相应调整。只能这样说,PyTorch可以无损调用NumPy中的函数。在这篇文章(https://github.com/wkentaro/pytorch-for-numpy-users)中,笔者获悉如何实现两种程序的代码转化。

此外,这篇文章中还提到,只能在一个(而非多个)张量中读取形状需求,因此笔者调用shape() 语句时也出了差错。因此,__init__.py 中 grad() 函数代码也须修改,详情如下:

for out, grad in zip(outputs, grad_outputs):
   if not out.shape == grad.shape:
     raise RuntimeError("grad_outputs and outputs do not have the same shape")

再次测试程序,这次终于成功,接下来是报错测试。

打开test 文件夹,里面是带有test_grad 函数的 test_autograd.py 文件,一切都是那么的简洁明了!

在敲定测试方案前,笔者先加入一些打印语句。谨记,打印语句是Python编程师的鼎力助手。

打印随机变量有助于深入了解张量,并从程序上将其与梯度张量相比较。

此外,读取其他测试,了解项目中相关对象的创建与测试,也能令人获益匪浅。最终,测试如下:

grad_out = torch.ones(2)try:

   torch.autograd.grad(

      outputs=[grad_sum], grad_outputs=[grad_out],

      inputs=[x], create_graph=True)

   self.assertFail()

except RuntimeError as error:

   self.assertEqual(str(error), "grad_outputs and outputs do not have the same shape")

运行上述测试,万无一失。接下来,用Flake8纠错,在GitHub上提交修改结果,创建PR,添加问题标签,确认与原问题标签一致,提交,搞定收工!

很快,笔者就收到了评论,这些意见逻辑清晰、颇有洞见,因此也极易落实。

第一桩PR圆满完成!幸好只用Python就可解决,毕竟,又有谁敢去编辑臭名昭著的C++呢?不过明知山有虎,偏向虎山行,有请下一个问题!

脸书AI首席开发布道师:如何贡献PyTorch代码

第22963号问题: 通过Torch.flatten(),输入零维张量,得出零维张量(非一维) 

起初,笔者并未意识到该问题涉及C++API, 但仔细一看(再次给出题者点个赞),一切不言而喻。

切勿一见讨论而萌生退意,围绕这些问题的讨论往往蕴含很多信息。在接手问题之前,要确保自己有解决的方法。

该问题涉及两方面,一是“返回值”,二是“输入值”。输入值与“前端”相关,即Python;而“输出值”与“后端”相关,即C++。

创建新分支,大胆一试。大部分编程都是这么一回事——怀揣希望,放手一试。

首先,探寻 flatten() 函数的奥秘。而这便是打印语句的用武之地。

导航回 test 文件夹, 在flatten( 上调用git grep 。经过一番查询,笔者恰好在test_torch.py文件找到test_flatten 函数。

打开文件,研究其断言,明白自己所找何物后,输入如下打印语句:

# Test that flatten returns 1-dim tensor when given a 0-dim tensor

zero_dim_tensor = torch.tensor(123)

one_dim_tensor = torch.tensor([123])

cool_dim_tensor = torch.tensor([1,2,3])

flat0 = zero_dim_tensor.flatten()

flat1 = one_dim_tensor.flatten()

flat2 = cool_dim_tensor.flatten()print("--zero dim tensor--")

print(zero_dim_tensor)

print(zero_dim_tensor.shape)

print(flat0)

print(flat0.shape)

print("--one dim tensor--")

print(one_dim_tensor)

print(one_dim_tensor.shape)

print(flat1)

print(flat1.shape)

print("--cool dim tensor--")

print(cool_dim_tensor)

print(cool_dim_tensor.shape)

print(flat2)

print(flat2.shape)

输出值如下:

--zero dim tensor--

tensor(123)

torch.Size([])

tensor(123)

torch.Size([])

--one dim tensor--

tensor([123])

torch.Size([1])

tensor([123])

torch.Size([1])

—cool dim tensor--

tensor([1, 2, 3]) 

torch.Size([3])

tensor([1, 2, 3])

torch.Size([3])

结果与问题相吻合。展开后,零维张量与一维张量是等值的。

根据这些打印语句可得,这个等值性是由其形状(shape)为torch.Size([1])决定的。一经展开,零维向量等于一维向量。

接下来在代码中验证这一观点。笔者在GitHub库中搜索“flatten”的实例。在Python中,的确有Flatten模块这一说法。

由此,笔者第一次意识到自己得处理C++编程,一般来说人们不愿从事模块编辑,而这其中另有玄机。

有这么一种模块框架,名为 caffe2。你大可谷歌百度,简言之,它是PyTorch的一部分,并且人们往往不赞成使用这一框架。对笔者来说,编辑Caffe2不是个好主意。

无奈地盯着tensor_flatten.cpp文件,笔者似乎只能止步于此。这可是让人头疼的C++,就算费上九牛二虎之力,恐怕到头来自己仍一筹莫展。

鼓起勇气求助之前,笔者对着屏幕足足懊丧了一个小时,“冒牌者综合征”如阴云般在脑海中挥之不去。

干坐着泄气可不是理想的应对之策。如果不是坐在办公室,笔者恐怕早就发帖询问该从哪里下手了。所幸的是,办公桌几步之外,便是好心的工程师同伴。谢天谢地,在他们的点拨下,阴云散去,柳暗花明。

解决这一难题的关键在于aten. 因为 ATen 即张量运算库,而flatten 与运算息息相关。

明白这个道理需要花一番工夫。如果你因无处解惑而一筹莫展,可参阅PyTorch技术文档(https://pytorch.org/docs/stable/torch.html?highlight=flatten#torch.flatten)。

这表明,想解决这个问题,须找到带有各种参数(如input, start_dum, end_dim)的flatten  函数,返回一个Tensor 。根据这个说法,很明显之前笔者的尝试有如南辕北辙。

笔者决定在顶层调用 git grep,实现Tensor flatten( 。于是顺理成章地得到atn, TensorShape.cpp。这代码看上去没问题,准没错。

为了彻底理解该代码,笔者审阅了数遍,并确保单步执行的函数符合逻辑。

这代码看起来如何?简洁易懂!这样每当输入一维张量时,它就会模仿flatten 函数,而非返回输入值:

if (self.dim() == 0) {

    shape.reserve(1);

    shape.push_back(1);

    return self.reshape(shape);

}

更新测试,代入合适的结果,然后一切水到渠成。接下来就是纠错,做PR,获取建议反馈,贡献PyTorch代码大功告成!

脸书AI首席开发布道师:如何贡献PyTorch代码

点滴感悟

笔者贡献开源代码已有些时日,以下几点经验教训值得牢记:

1. 勇于探索  不要对代码心生畏惧。这些代码都是聪明人写出来的(对于大项目来说更是如此),其中蕴含许多玄机可供探索。勇于揭开那些代码的神秘面纱,哪怕不准备为其添砖加瓦,仅仅是了解其工作原理,也能使自己获益匪浅。

2. 勤于发问 不必害羞瑟缩,GitHub开源社区倡导共享精神,主张领导力培养。别人会因为你的发问与参与心潮澎湃,进而伸出援助之手。

3. 乐于学习  你并不是团队中的冒牌者,只要自己乐于学习敢于拼搏,哪怕不是科班出身,不能做到凡事心领神会,你依然可以为团队发展添砖加瓦。

4. 善于钻研  多读资料。查阅README,技术文档,参与论坛,这些都能让人受益颇多。

5. 敢于尝试  哪怕自己不是稳操胜券,想不出万全之策,也不要踌躇不前,要敢于尝试。

望诸位的编程之路一帆风顺! 

脸书AI首席开发布道师:如何贡献PyTorch代码

常见错误一览

Import not found, or import not connecting

1. 确认是否键入输入值。

2. 确认conda 是否**。

3. 重启PyTorch。

NumPy functions don’t work

1. 先确认能否在不影响效果的情况下,用 PyTorch 替换Numpy。

2. 如若不然,在GitHub上创建问题,征求PyTorch可兼容的函数来达到预期效果。亦可自己写出函数。

Not all the tests on my PR are passing

1. 别气馁,深呼吸,相信自己。

2. 有时,这不是你的错。检查日志文件,留意是否有来自本机的新消息,若收到新消息,重新访问代码。

3. 你并未合并自己的PR,但团队其他成员合并了各自的PR。不过你有个好团队,伙伴们会告知你并为你分忧。

脸书AI首席开发布道师:如何贡献PyTorch代码

推荐阅读专题

脸书AI首席开发布道师:如何贡献PyTorch代码

留言 点赞 发个朋友圈

我们一起分享AI学习与发展的干货

编译组:董宇阳、张婷华  

相关链接:

https://medium.com/better-programming/committing-to-pytorch-by-someone-who-doesnt-know-a-ton-about-pytorch-fa222253cf2d

如需转载,请后台留言,遵守转载规范

推荐文章阅读

长按识别二维码可添加关注

读芯君爱你

脸书AI首席开发布道师:如何贡献PyTorch代码

相关文章:

  • 2021-10-05
  • 2022-12-23
  • 2022-12-23
  • 2021-07-27
  • 2022-02-08
  • 2022-02-08
  • 2021-11-11
  • 2021-10-01
猜你喜欢
  • 2021-12-29
  • 2021-10-09
  • 2021-10-09
  • 2021-07-20
  • 2021-08-28
  • 2021-11-13
  • 2022-12-23
相关资源
相似解决方案