今天聊的这本书,《机器学习从入门到入行》,是微软在 Github 上的开源项目 AI for Beginners 的中文译本,由清华大学出版社出版,冯磊、周慧梅老师翻译。
说来惭愧,我的职业生涯迄今为止,自己从未经历过一个真正以机器学习为核心技术需求的项目——我职业生涯的主要工作领域是操作系统、运维和独立游戏,我的脑袋里大部分时间塞的是内存、性能、图形界面、玩法设计。虽然凭着自学我也手搓过朴素贝叶斯模型,但如今这个领域发展一日千里,特别是深度学习之后,新技术新框架层出不穷,我最多也就算一个初学者。然而,本着计算机这个行业「谁知道啥时候就能用得上」的原则,从原理层面掌握一些技术,丰富自己的技术栈,是绝对必要的。
作为初学者,我可能无法评价算法本身或者代码质量:这超出了我的能力。但我绝对敢说:这本书,我读起来特别舒服。
机器学习,还是深度学习?
直击重点,是这本书带给我的第一个印象。虽然本书自表为机器学习入门,但在前两章简单介绍机器学习领域的发端之后,第三章开始就直接跳入了神经网络,至于机器学习历史中曾经和现在广为使用的许多方法则没有任何消耗任何笔墨,如贝叶斯、Logistic 回归、决策树、支撑向量机等算法,在本书中完・全・没・有・出・现。换言之,这本书更应该被称为深度学习入门。
对我来说,这是件大好事。上述的非深度算法相当一部分我相对比较熟悉,至少使用过;市面上也不缺介绍它们的入门书籍。我希望补全的,恰恰是深度学习以后的技术路线。本书将绝大多数篇幅用来专门讨论时下应用面最广的分支领域:神经网络技术、计算机视觉、自然语言处理,避免初学者分散精力。
如此安排行文,多少也需要做一些取舍。熟悉机器学习的朋友们都知道,深度学习需要的许多基础数学知识,都来自非深度学习的引用领域,比如 Logistic 回归用到的 Sigmoid 函数,又比如支撑向量机使用的超平面,原书对这些知识采用的是「拿来就用」的原则,直接列出个公式就用在下一段代码里。因为本书完全不讨论那些非深度学习算法,所以读者未必清楚这些数学工具是如何被引入的。然而本书的风格讲究直接上手写代码,先让读者用起来,等真的读完并且入门再细细研究,也是来得及的。
读书笔记,还是动手实验?
前面提到本书的风格是直接上手写代码。事实上,本书的大部分内容都围绕在原作者开发的一组开发课程,一共 24 节,12 周。每一周的课程内容都被组织为一个 Python Notebook。借助 notebook,作者将描述、代码和可视化的部分组织为一个整体,所有的代码都可以直接从 notebook 执行并从图表中看到效果。
书中并不拘泥于使用最流行的框架。从第一节课 到第四节为止,作者给出的代码使用的是相对底层的 numpy、sklearn 等函数库,只用于生成数据集和快速处理向量等操作。从第五章开始,才开始使用 Tensorflow,Keras 和 PyTorch 等框架。我相信作者是有意为之:第四节课对对多层感知机的实现覆盖了大量通用概念:激活函数、梯度下降优化、反向传播、概率转换等。这些概念在现存的框架中大部分都以实用函数的形式给出,可以直接调用。事实上,第五节课以后的代码就开始使用 PyTorch 或者 Tensorflow 的函数。然而,对于那些对深度学习没有多少概念的初学者,直接开始调用框架提供的函数,就难免对原理层面缺少实感。所以,尽管第三节和第四节课被称为 Toy Problem(玩具问题),但我强烈建议读者和我一样,尝试着手写实现其中的代码并自己执行看看效果,而不是只读 Notebook。要读懂这两节课需要消耗大量的时间,但对我来说,绝对物有所值。
我并不是说第五章以后就可以看着 Notebook 的内容一日千里。虽然第五章以后开始使用框架,但那是是为了让读者们可以把精力放在理解场景和算法设计,而非计算细节。譬如第八课,就需要讨论梯度爆炸或无效的处理方法,这仍然需要读者们把代码跑起来,最好是用自己的数据做实验,才能有切身体会。
总而言之,如果仅仅是泡杯咖啡抱着书,坐在图书馆里看一个下午,吸收率基本为 0。正确的打开方式是拿着书打开电脑,一行行输入进去。
按部就班,还是各取所需?
第六课开始,本书开始着重讨论两个最流行的深度学习应用场景:计算机视觉(第六课到第十二课),以及自然语言处理(第十三课到第二十课)。相信读到这部分的朋友们,应该也开始着手处理一些真正的工程问题。这两部分的讲解相对独立——事实上也确实如此,虽然基础知识都来自神经网络算法,但视觉和语言这两个场景使用的具体数学工具是不同的。本书对两个场景最知名的技术留足了篇幅,即第十课的生成对抗网络和第十八课的 Transformer,也按照 Tensorflow (包括 Keras)和 PyTorch 的框架进行独立实现。读者们可以根据自己的喜好和实际任务跳过无需深入的章节,等回头有了实际需要再读也不迟。
基于类似的原因,本书最后一篇(第二十一课到第二十四课),作者也覆盖了一些不那么流行的场景:强化学习、和遗传算法。老实说这一节内容和我的专业领域其实更接近,因为游戏开发中用人工智能理解并执行动作其实更多地使用这些领域里的知识。这部分篇幅相对较短,谈的也不多,对我而言多少有些遗憾,但反过来说,这也意味着我得多花一些时间来自己探索,如果前面的知识学得扎实,自己探索并不是大问题,也更有乐趣。
关于本书附带的代码
中文版贴心地将教程所用的 notebook 教程从 Github 复制到了国内的 http:// gitee.com ,免去了国内读者访问网络时的不便。需要提醒的是,两个网站上的教程目录结构有一些差异。原版项目中用于设置开发环境的 environment.yml 和 requirements.txt 文件有两份,一份位于项目根目录下,一份位于 .devcontainer/,这是兼顾了使用本机 Python 环境和使用 Docker 构建开发环境的两种使用场景,而 Gitee 版则大幅度简化,只保留了 .devcontainer/ 目录。除此之外,因为有本书的搭配,Gitee 版本也删去了原版目录结构中网页版本的英文教程。
不必担心,这些差异并不影响使用:本文最核心部分的教程——也就是 lessons/ 目录下的全套 notebook——没有任何缩减。事实上,Gitee 版本甚至做了许多修订。首先,Gitee 版本将英文注释全部翻译成中文,且添加了不少额外的注释和书中正文的部分引用,以配合阅读体验,比如 Perceptron.zh.ipynb 中对 Toy Problem 的描述,能访问 Github 的读者可以对比原版的 Perception.ipynb ,一看便知。其次,Gitee 版本去除了原版 notebook 中一些如今已不再推荐使用的老旧库,比如多个 notebook 代码中对 pylab 的引用,帮助初学者们养成好的开发习惯(至于不再推荐使用 pylab 的理由,请参考 matplotlib 的文档 )。
感谢两位译者老师的辛勤工作。
那么,这到底是一本什么样的书?
如前所述,我更乐于把这本书看作一本「实验手册」。它最大的价值在于作者仔细搭配的二十四节 Notebook。手动完成这些课程并不容易,但能让我从浅入深,一步步把代码写出来,跑起来,了解数学概念的同时也熟悉了常用的框架。我不敢说读完这本书就能成为高手——别的不说,我多少也了解一些游戏相关的技术,其中的分支众多,哪怕是我知道的一些领域,也没有被这本书完全覆盖。这本书最大的价值,在于构造一个循序渐进的实验体系,正如标题所言:从入门到入行。恰如其分。