TensorFlow团队如何管理和支持开源项目
在开源社区帮助下改进软件需要耐心和良好的组织
编者注:更多关于TensorFlow近两年的进展及未来展望可以参考2018年4月10-13日人工智能北京大会

开源不仅仅是把代码共享到网络上,而是希望有人能使用它。从理论上讲我知道怎么做,但是作为Google TensorFlow团队的一员,我对围绕一个软件构建开源社区所需的各种不同的元素已大开眼界。

社区服务

当一个新项目在全球发布时,该项目独有的专家就是开发这个项目的人。他们是唯一可以撰写文档和回答问题的人,也是能最有效地改进软件的人。但与此同时,TensorFlow核心团队的我们却成为了这个项目扩展的瓶颈:我们无法同时完成所有事情。我们确实知道如何编写代码和文档,因为这些任务是我们在Google日常工作的一部分。而另一方面,尽管我们知道回答大型开发者社区的问题对项目的成功至关重要,但这并不是我们习惯处理的事情。

为了确保用户获得所需的答案,核心工程团队的成员都要轮流值班负责开源项目。团队成员可以选择解决Stack Overflow上标记为#tensorflow的问题,在GitHub上查看提交代码的请求,分类GitHub问题,处理外部和内部代码的同步问题,或者是追查测试失败的原因。

从事这些的工程师可以选择如何分工。通常每个工程师每次会对某个特定领域负责一个星期,所有可工作的工程师轮流循环负责。因此负责的工程师在那周的日常工作中的生产力要低得多,但每个人至少每隔几个月才会遇到一次这样的打扰。

代码提交请求

我们开源TensorFlow项目的部分原因是为了让社区贡献者来改善它。到目前为止,我们已经有超过400个外部贡献者添加了代码,从小的文档修复到大的诸如OS X GPU支持OpenCL实现InfiniBand RDMA等的代码添加。整个流程如下。首先,轮流负责开源项目的核心工程师必须对每项贡献进行审查以确定它是否有意义。如果贡献通过初始审查,则会启动一组Jenkins测试以确保其不会导致任何错误。一旦这些都通过了,值班工程师可能会将其转交给另外一个更熟悉该领域的核心工程师进行进一步审查。

GitHub新的详细代码审查工具在这个过程中起到了很大的帮助作用。在这之前,处理所有的个人意见对工程师来说是件痛苦的事情。通常越大的代码提交请求在这个过程中持续的时间会越长,虽然会有一个核心工程师和一个或多个外部贡献者在协同工作。一旦每个人都认同该请求,这个提交请求将会合并到Github上项目的树顶部,并在下次运行同步时合并到我们的内部代码库中。

代码许可协议

作为我们自动提交请求过程的一部分,我们可以通过将贡献者的GitHub帐户名称与我们在cla.developers.google.com上的记录相匹配来确保任何外部贡献都遵循代码许可协议(CLA)。 我们的目标是确认整个代码库的发布可以完全符合Apache 2.0许可证。如果电子邮件地址与提交请求中的登记信息不同,或者如果贡献者需要以公司身份登录时可能会很棘手。然而负责提交请求的工程师会来处理任何出现的问题。

GitHub上关于TensorFlow的问题

TensorFlow项目已经收到了5000多个的问题提交。这可能看起来令人沮丧,但这正是我最喜欢的指标,因为这说明人们真正地在使用我们的软件!为了确保我们对每个提交的问题都有回复,值班工程师在看到他们提交的消息时会尝试使用标签进行分类。如果这是一个我们不太可能短期内在内部实现的功能,我们会将其标记为“欢迎贡献”。而对于程序缺陷,我们会考虑其优先级。现在我们越来越多地看到问题无需我们的帮助就能得到解决。因为外部用户自己已经慢慢成为专家,特别是像在Windows这样我们并不是每天都在使用的平台上。

如果开源社区没有答案或解决方案,并且这是一个有足够高优先级的问题,值班工程师会将其分配给熟悉该领域的工程师。整个TensorFlow团队都有GitHub帐户,所以我们可以使用正常的GitHub问题跟踪系统来分配问题。我们确实考虑过在我们的内部系统中跟踪问题,但同步两个相同信息的成本太高了。因此我们要求我们的工程师打开GitHub上的问题电子邮件通知,以便他们除了关注我们的内部跟踪系统以外还可以看到他们在GitHub上被分配到的问题。

Stack Overflow

Derek Murray是Stack Overflow轮流值班的负责人,我深深佩服他回答问题的能力。根据他的个人资料页面,他的帖子已经影响和帮助了130多万人。他还设法建立了一个由RSS源驱动的自动化电子表格,以便我们可以使用#tensorflow标签来跟踪站点上的所有问题。刚开始的时候我们每周轮流一次,但后来发现问题数量变得太大以至于一个人处理不了了。而现在我们按照多人循环处理的方式自动分配提交上来的问题。

当我在值班时,每天早上我会查看我的邮件并会查看电子表格分配给我什么问题。不幸的是,我们自己无法回答所有的Stack Overflow上的问题,但是我们会查看所有的问题。如果某个问题比较简单,我们会尝试自己来回答。

值班工程师战斗在处理提交上来的问题的前线,但有时候回答问题需要更多的时间或专业知识。如果问题看上去是可以回答的,但开源社区中没有人主动回答,我们会在代码中做一些查询工作(通常使用“git blame”)来确定团队中谁可能会有一些想法。然后值班工程师会发送一封电子邮件给我们识别出的该内部专家来询问是否可以提供帮助。

邮件列表

我们有设置一个邮件列表,但是起初我们不太清楚它应该用来做什么。很快我们就发现它并不是一种跟踪问题或回答普通问题的好方法。

尽管如此,我们仍然将邮件列表用在不适合其他任何方式的讨论中。然而在实践中我们发现即使对于架构问题的讨论,GitHub可能更合适。现在我们使用邮件列表来发送信息并分享公告,这还是值得订阅的。

代码同步

很多人都惊讶地发现我们在Google内部使用的代码库与Github上共享的几乎完全相同。不过还是有一些区别的:例如对 Google独有的基础架构的支持是不同的并且包含路径是不同的,但是同步过程是完全一致的。我们每周至少进行一次内部变更推送,而从Github上拉取代码则更频繁。

棘手的部分是我们需要做双向同步。在GitHub公共项目上和我们的内部版本中都有很多同时进行的更改,我们需要将它们全部合并在一起。我们没有现成的基础架构可以使用,所以我们创建了一组Python脚本来处理这个问题。脚本将GitHub的更改导入到我们的内部资源仓库中,转换所有标题路径和其他小的更改,并将其与最新的内部代码合并创建一个内部副本。然后我们从另一个方向,将所有内部代码转换为外部格式,并使用该脚本将转换结果与GitHub上最新的代码进行合并。

对于内部更改,我们也尽力确保每个提交都显示为单个git提交,并包括作者的GitHub帐户和更改注释。我们在GitHub上有一个特殊的“tensorflow-gardener”帐户用于管理此过程。您可以在这里看到一个内部提交在迁移到GitHub之后的样子

确保转换过程在代码发生变化时仍能正常工作是一项具有挑战性的任务。为了验证其功能,我们要确保每个内部更改都可以通过运行该脚本转换到外部版本,同时能再反方向转换回内部版本,并且与原始内部版本没有任何差别。该测试运行在涉及TensorFlow代码库的每个内部变化上,并阻止任何未通过测试的提交。对于那些发送来的提交请求,我们有时会要求作者进行一些奇怪的更改,这通常是因为我们必须确保他们的代码能适用于这一同步基础架构。

Jenkins测试

由于TensorFlow需要支持很多平台,因此我们希望拥有涉及面广泛的测试基础框架。TensorFlow需要能够运行在Linux、Windows和OS X的桌面操作系统以及在iOS、Android、Android Things和Raspberry Pi的移动和嵌入式系统上。我们针对GPU还有不同的代码路径,包括对CUDA和OpenCL的支持,以及Bazel、cmake和简单的makefile的构建过程。

我们不可能让每个开发人员在进行代码更改时手动测试所有的这些组合,因此我们运行了一套支持大多数平台的自动化测试程序,所有这些都由Jenkins自动化系统控制。维护这一系统的运作需要大量的时间和精力,因为总是存在操作系统更新、硬件问题以及与TensorFlow无关的可能导致测试失败的其他问题。我们有一个工程师团队致力于维护整个测试过程。这个团队使我们的工作免遭潜在问题的破坏,所以对这个团队的投资是值得的。

开发人员关系

我们在Google从事开源工作并不孤单,我们也从其他诸如Kubernetes和Open Source Program Office项目(他们也有一套很好的文档)中学到了很多。我们有一个非常努力的开发人员关系专家团队来协助我们,他们处理了大量繁重的文档、代码示例以及开发人员体验的其他重要部分。我们的长期目标是将关键专业知识转移到核心开发人员之外,以便更多的Google员工和Google外部人员可以帮助到社区。

让核心工程师兼职参与客户服务的一大好处就是让我们直接了解用户所遇到的问题。参与客户服务也促使我们可以改进常见的程序缺陷并添加文档,所以我们可以直观地看到这些工作所带来的客户支持工作量的减少。

在不久的将来,我们希望随着更多的人熟悉Tensorflow框架的内部细节、文档质量的不断提高以及我们为处理常见任务(如程序缺陷分类)创建更多的“指南”,我们的工作量能更多地被分配出去。至此我很幸运有机会能与这么多的外部开发人员进行互动,希望对其中的一些人产生积极的影响,帮助其创造激动人心的基于机器学习的新应用程序。

Pete Warden

Pete Warden是TensorFlow Mobile团队的技术主管。他之前是Jetpac的首席技术官。Jetpac于2014年被Google收购,以优化Google在移动和嵌入式设备上的深入学习技术。他以前曾在苹果从事用于图像处理的GPU的优化工作,并为O'Reilly撰写了几本关于数据处理的书籍。

Cultivation. (source: Pexels).