简介

2021年夏天,在博士毕业之后,我加入了工业界做智能系统相关的工作。原因有很多,其中之一就是我对AlphaGo、GPT-3等等大型智能系统充满好奇。罗马不是一天建成的,绝不可能有一个人从一开始就设计好了所有的架构与细节,大家按照这样的设计写完代码,在大数据集上训练,一次性成功。

如何组织多人,甚至数十上百人,在一年左右的尺度下,成功开发出大型智能系统?

There must be something there.

在工作近一年之后,我渐渐有一些模糊的理解,在这里加以整理记录。对工业界的朋友而言,这些可能是融入血液的常识,但对久处象牙塔的我而言,却是极大的启发。我认为这些是极为重要的“元经验”,是工程开发的“第一性原理”,也是学术界,尤其是应用数学界,应该从工业界学习的东西。


效率的提升

在工作中,始终应该保持"提高工作效率,增加单位时间产出”的意识。这既包括个人工作,也包括团队合作。除了“善用工具、劳逸结合”等等一般意义上的提高效率,软件开发有独特的一面。

有人可能会问,我一个做应用数学的,不是应该更注重灵感吗?解释如下:

  • 应用数学离不开数值实验,灵感也是从信息中来的。快速实验,快速获得反馈。有些实验甚至必须建立在极高的效率之上。
  • 节省时间与脑力,多花在阅读文献,思考,讨论之上。
  • 提高效率不仅仅限于软件开发,比如说教程库与文献库的建设。我个人认为数学和软件工程有非常多的相似性,数学定理的封装与应用,也可以理解成“复用”。

自动化

无聊的工作也会消耗脑力。

尽可能把所有无聊工作自动化,比如一键提交、提醒、处理、下载。会不会浪费时间在工具的搭建呢?不会的,只要我们尽可能复用工具。如下。

复用与基建

复用的动机以及指导原则是:

  • 节省个人和团队的时间。
  • 更重要的,可以逐渐变得更好,最后形成分享的“基建”。

我需要特别解释一下“更好”。这里的更好包括:

  • incrementally更好,比如让某一些代码更加general。
  • 通过封装、嵌套、组合,最后达到指数级的复合增长——这是软件工程的魔法。

不用着急一步到位,一点一点建设,积累下来就是很多工作了。

代码复用

  • 定义好接口
  • 文档(尤其是注释)与范例
  • 尽可能成系统,定期整理

文档复用

比如说,我要给一个人讲一套东西,那我可以写成教程,这样如果有另一个人需要我再讲一遍,我就可以把这个教程给他,而节省了再讲一遍的时间。而如果未来的我,或者另一个人,对这个教程有补充,那就可以变得更好!最后我们可能就有了教程库,甚至一本书。本文就是一个案例。

再比如说,团队一起建设文献库。每一个人记录对新的文献的理解和评价,可以节约文献阅读和搜索的时间。额外的好处是,也加强了沟通。

注意精简而不失信息,以提高信息传递的精度以及阅读效率。关键的地方值得迭代。

项目复用

也就是我下一个项目尽可能是建立在上一个项目的基础之上,我每一个项目也尽可能为后续的项目做好准备。不仅仅是代码复用,文档复用,也有知识与经验的复用。

分布式并行开发

建议所有人学习git。


迭代

这是最有意思的部分。

迭代的动机和指导原则:

  • 在一开始并不知道要做成什么样子,需要依靠对比、反馈来决定后续工作
  • 便于并行开发
  • 提供短期回馈,保持心理健康

测试代码

测试代码可以帮助控制代码质量,同时也是文档和范例(接口是啥,功能是啥,怎么使用)。

标准问题(Benchmark)

我之前低估了benchmark的重要性,毕竟在数学里,好坏是可以推导出来的。但是用标准问题比较好坏,确实要简单快捷很多。更重要的是,便于分布式开发。各个lab一起试图解决某个问题,这不就是分布式开发嘛。

神经网络的迭代

传统的软件开发,可以分模块测试、迭代。神经网络讲究end-to-end,并不容易分模块,那要怎么办呢?

定义小问题

  • small dataset
  • small batch size
  • small training steps

在小问题上通过快速迭代找到好的神经网络结构和loss function,几轮小迭代之后,就可以在更大的问题上测试,用稍低的频率迭代。最后上超级大问题。

注意记录结果。按照同事的说法,不一定需要grid正交测试,线性测试是可以的。效果不显著的不要留,但如果复合逻辑,可以keep in mind,之后再试试。

调参对个人而言是一个经验活,但是对组织而言,只要有足够快速的迭代(这又回到了效率的问题),总是可以找到好东西的。


这个文档只是我暂时的记录,以后会继续更新。