引子 | 造轮子还是不造轮子,这是一个问题

理查德·费曼教授去世后,人们在他的黑板上发现了 What I cannot create, I do not understand 这句话。其实,费曼教授的本意是:除非你能由基本原理推导出某个结论,否则就没有真正理解它。记结论或背公式是没有用的,只有从一张白纸开始一步步地将结论构建出来,你才是真正理解了一个理论或一个事物。

程序员爱说一句话:不要重复造轮子。在工作和生产中的确不应该重复造轮子,但在学习和理解的过程中却需要重复。

费曼教授的黑板上还有一句话:Know how to solve every problem that has been solved(应该知道每一个已被解决的问题的解决方法)。许多教师都会强调习题的重要性,这是对的。在座的诸位“做题家”对此自然也体会深刻。但费曼教授更高一筹,他所传达的思想是做题不是目的,目的是教人学会自己动手构造。光看明白是不够的,只有会造轮子才能改进轮子;只有会解有答案的问题,才能去解决还没有答案的问题。

1.重新构建整棵树才能真正认识一棵知识树

如果将一个领域的知识比作一棵大树,那么我们对它的认识过程不应该是从外向里、从顶向下的,不应该只满足于认识并记住它那繁多的树叶。以神经网络与深度学习为例,初学者往往会陷入茴字四种写法的误区,并且以知道各种模型、各个网络为荣,从而陷入概念和术语的迷宫却看不到它们之间存在的更深刻的联系。

也就是说,要想认识一棵树,从树冠开始一片一片认识每个树叶无疑是效率低下的。更重要的是,通过这种方式根本无法达到真正理解。我们应该从树根出发,沿着树干向上,并尝试重新构建整棵树。在此期间,可以在某个树枝的根部就停下来,因为那时会发现,剩下的细枝末节(字面意思)已经不再重要了,只要在需要的时候再查看那个分支就行了。

总之,要想真正地理解(understand)一个领域,就必须能从基本原理出发重新建造(create)它们,最终你会具备统一的、非碎片化的眼光。

2. 从零开始打造一款深度学习框架

enter image description here

1984 年,《现代操作系统》(俗称马戏团书)的作者塔嫩鲍姆教授(Andrew S. Tanenbaum)开发了一个教学用的操作系统 Minix。受其启发(多大程度未知),Linus Torvalds 创造了 Linux 系统。

这里我们决定效仿前辈,带领读者用 Python 语言从零开始实现一个基于计算图的机器学习/深度学习框架,我们称其 MatrixSlow。取这个谦卑的名字是为了表明它只是一个用于教学的框架。若在座诸君中有哪位能受其启发并创造一个专业的深度学习框架,我们将深感欣慰。

3. 为何实现基于计算图的深度学习框架

计算图是一个强大的工具,用它可以搭建并训练从简单的线性回归、逻辑回归到复杂的深度神经网络等一大类机器学习模型。计算图通过自动求导和梯度下降法,以统一的方式给这一类机器学习模型提供了训练算法。因此,实现了计算图也就等于实现了大部分机器学习算法。

在一步步带领读者实现计算图框架的同时,我们还介绍了机器学习、模型、训练等相关概念和原理(我们假设所有读者都没有前导知识,完全从空白讲起)。

此外,本书以相当大的篇幅介绍了线性模型、逻辑回归、多层全连接神经网络、非全连接深度神经网络、循环神经网络和卷积神经网络等模型的原理和结构,并且尤其注重它们之间的联系。读者会看到,动机和思路是如何被反复应用并逐渐发展的。我们还以一些实际问题为例展示了这些模型的应用。

最后,我们讨论了一些工程方面的问题,例如模型的保存与服务、分布式训练以及要想实现专业级深度学习框架还需应对的若干问题。

4. 是否有必要亲手实现模型

虽然本书的主旨为理解与建造,但是通过建造达成理解才是关键。时常会有朋友问:“是否有必要亲手实现模型?”必要与否很难界定,这取决于想要实现模型的人的目的和工作层次(这里的层次并无高低褒贬之意)。所以,我们不谈目的与必要性,只谈亲手实现模型的好处。以我的浅见以及亲身经历来看,亲手实现模型极其有助于夯实理解。

在动手实现模型的过程中,你不得不把对理论的理解厘清到最细微处,这里容不得半点含糊。更重要的是,当自己实现的模型运转起来,应用于实际问题以测试其正确性时,现实会逼迫你反复测试,这个过程可以极大地帮助你加深对于模型行为的理解。作为程序员,测试本来是一件在概念上简单明确的事情。在设计程序的时候,预测有如此这般的输出,它就应该有如此这般的输出。对于一个断言(assert)来说,它过就是过,不过就是不过。但是在机器学习领域,这个范式就会有一定程度上的失效。

我们知道,模型(起码本书讨论的这类模型)的训练是一个近似迭代优化的过程,其中到处存在随机性:参数的随机初始化,样本的随机洗牌(shuffle)以及一些例如 Drop Out 之类引入随机性的正则化方法等,都会带来不确定性。训练的结果,比如模型参数、损失和评价指标等,都只具有统计意义。

更重要的是,模型在样本集上的损失取决于问题本身,我们不可能知道这个高维函数的真实“地形”。基于梯度的优化算法也不能保证可以找到全局最优点。全局最优点可能根本就不存在或者存在但不唯一。所以,模型训练根本没有严格的正确与否一说。

但是,模型的实现总有对错。错的实现在各个测试问题上都不会有好的表现。简单来说,好的表现就是随着训练的进行,损失值降低而指标上升。但是,受制于问题本身、模型结构以及超参数,对的实现有时也未见得会有好表现,或者好表现的现象需要很久才能显现。

这迫使实现者必须反复在各类问题上验证自己的实现,尝试各种模型结构和超参数的组合,这是一个永无终点的过程。实现者对自己的实现的信心会随着无数次尝试而逐渐坚定。更为宝贵的是,所有的这些操作和观察都能帮助实现者建立起对模型行为的认知和直觉。

我们知道,结构和超参数控制着模型的自由度,自由度又决定了模型的偏差方差权衡,进而影响了模型的过拟合/欠拟合。

在物理学中,一套完整的约束可将动力系统的自由度降低一个整数值。由此,之后就可以用数量更少的广义坐标表示该系统。类比到模型训练,正则化方法施加的约束并不是完整的,模型的自由度也不是整数。

狭义的正则化之外的超参数,乃至模型结构,都在以复杂的方式影响着模型的自由度。我们常说调参,就是以一种经验的、半猜半试的方式控制模型自由度,以改进模型的表现。当然,我们还有网格搜索和随机搜索,以及一些非参数优化算法,如遗传、贝叶斯等,但是它们都需要较大的计算量,使得我们在大部分时候难以承受。

了解每一个超参数的原理和含义,以及它们对自由度的大致影响,是建模工程师的必备能力。

各种超参数在具体问题、具体模型上究竟会以什么形式产生什么影响,只有经过观察和经验的积累才能形成认识。实现并验证模型的过程,就是一个密集经历这种观察和经验积累的过程。

在复杂的科学和技术领域,亲身经历与体验是必不可少的,这是一个经历生命的过程。魔鬼梅菲斯特曾对拜访浮士德博士的青年学生说:“理论是灰色的,而生命之树长青。”

5. 读代码的终极大招在机器学习中失效了

既然说到了理论,这又是一个机器学习领域与程序员熟悉的其他领域不同的地方。实现和应用机器学习必须要理解其原理,而阅读其他领域的源代码时,只要把代码读透也就彻底理解了。你也许会这样想,在完全知道内存、总线和CPU 中发生的每一件事后,我难道还不能理解这个程序在干什么吗?对于机器学习来说,这还真不够。比如,你在某处看到了一个计算,但是这里为什么要计算?计算的目的是什么?为什么有效?这些可不是代码能告诉你的。“读代码”原本是程序员了解一个东西的终极大招,但是在机器学习这里又失效了。

有种常见的说法是把公式推导一遍。理解机器学习的数学原理可不能只是简单地“推导公式”,而应该要理解公式究竟说了什么。当然,在初学时能够把公式推导的每一步都弄明白就已经不易了。但是如果把注意力都集中到推导,又容易使人难以看清这些公式究竟表达了什么。这就好比虽然踩着脚印亦步亦趋,最后确实也走到了目的地,但始终没有抬头看清这是什么路,目的地是哪里,为什么走这条路,而这些才是最重要的。

人们总是希望(妄想)生活中不要有数学。实际上,所谓数学和非数学,无非都是在说事说理而已。要想把事情说得精确深刻,就必须把相关的量以及量之间的关系说清楚,而数学就是简洁地表达这些关系的一种手段。

由于本书面向的是初学者,因此在数学上没有搞得太深入、太复杂。我们会尽力阐述,以帮助读者掌握机器学习的数学所说的“事”是什么,也就是“推导公式”时容易看不清的那些东西。

本书不避讳使用公式,因为这是必不可少的,但量确实不大。我们把一些较为高级的主题放在了选读框中。读者可以根据实际需要选择是否略过这些高级主题,而不至于干扰阅读。记住,数学永远都是必要的。鉴于此,读者可以参考本书的姊妹篇《深入理解神经网络:从逻辑回归到CNN》。

6. 内容简单介绍

本书分为三个部分。第一部分是原理篇,包含第 1 章至第 3 章。其中,第 1 章介绍机器学习的基本概念,引入了一个简单的线性模型 ADALINE,这一章介绍的概念贯穿本书。第 2 章介绍计算图,其核心内容是计算图的原理、梯度下降法以及计算图上的自动求导。第 3 章介绍梯度下降法的各种变体。在前三章中,我们带领读者实现 MatrixSlow 框架的核心基础设施,并在此过程中渗透讲解基础原理和概念。

第二部分是模型篇。有了基础设施,我们就可以搭建各种模型了。本部分包括第 4 章至第 8 章。其中,第 4 章介绍逻辑回归,第5 章介绍多层全连接神经网络,第 6 章介绍几种非全连接神经网络,第 7 章介绍循环神经网络,第 8 章介绍卷积神经网络。这些模型/网络的选择和顺序不是任意的。我们的想法是由简到繁、由浅至深地介绍其动机和思路的发展演变,使读者看到这些典型的、常用的模型/网络之间的联系。虽然原则上读者可以按照兴趣选读这些章节,但是我们还是建议大家能按顺序阅读,特别是第 4 章和第 5 章。模型虽然简单,但它们是后续一切复杂延伸的基础和出发点。

第三部分是工程篇。在这一部分中,我们将讨论一些与深度学习框架相关的工程问题。本部分包括第 9 章至第 12 章。其中,第 9 章对训练逻辑做进一步封装,并讨论模型评估;第 10 章介绍模型的保存、加载、预测和服务部署;第 11 章介绍分布式训练,在大数据和深度学习时代,样本量和网络规模都是巨大的,这些使得分布式训练必不可少;第 12 章简单讨论要实现一个专业级的深度学习框架还需面对和处理的一些问题。

7. 大佬推荐

这是一本引人入胜的书,它通过由浅入深地讲解让你了解深度学习的原理、模型和实现方法,内容清晰易懂,表达生动形象。
——邱锡鹏,复旦大学计算机学院教授

我们团队做了好几年深度学习框架研发,一直苦于没有好的入门教材。现在终于有一本书把深度学习框架的工作原理通俗易懂地讲了出来。
——袁进辉,一流科技创始人兼 CEO

对于复杂难懂的概念,除非亲手实现,否则很难真正理解掌握。我非常赞同这个理念,很高兴作者把这个建造与理解的过程分享出来,为众多对这个领域感兴趣的朋友提供参考。
——赵勇,格灵深瞳创始人兼 CEO

本书提供了框架本身和构建各类模型的代码,既深入核心原理,又浅显易懂。所谓“不能创造,无法理解”,相信通过自己打造一个深度学习框架,读者可以更深入地理解其中的原理。
——邓亚峰,奇虎 360 集团副总裁、人工智能研究院院长

8. 作者简介

张觉非

本科毕业于复旦大学计算机系,于中国科学院古脊椎动物与古人类研究所取得古生物学硕士学位,目前在互联网行业从事机器学习算法相关工作。

陈震

硕士毕业于北京大学。现任奇虎 360 智能工程部总监、负责人,带领团队建设集团的机器学习计算调度平台、机器学习建模平台、机器学习推理引擎以及推荐平台等AI基础设施。

9. 跟着这本书造个大轮子