README
前言
真正的发现之旅,不在于寻找新的风景,
而在于拥有新的眼光。
——马塞尔·普鲁斯特(法国作家,1871—1922)
如今,深度学习正在推动各个领域的创新。自动驾驶技术、疾病自动诊断技术、高精度机器翻译技术、先进的机器人控制技术……这些仿佛在虚拟世界中才会出现的技术近年来正在成为现实,而且在实际生活中得到了应用。令人惊讶的是,这些技术大多因为深度学习才得以实现(或者正在实现)。可以说我们生活在一个由深度学习改变世界的时代。
这股深度学习的热潮催生出众多深度学习框架,包括PyTorch、Chainer①、TensorFlow和Caffe等。深度学习领域有很多不同的框架,这些框架每天都在相互竞争中发展。得益于此,全世界的研究人员和工程师可以高效地解决很多问题。可以说深度学习框架是支持和推进深度学习技术发展的不可或缺的动力。
阅读本书的读者也许用过深度学习框架。如今深度学习的学习资料非常丰富,运行环境也已完善,因此,编写深度学习代码也变得非常容易。得益于这些框架,我们只用几十行(甚至几行)代码就可以实现复杂的技术。
那么,这些被许多人用在许多地方的框架实际上是如何工作的呢?它们采用了什么样的技术,又有什么样的思想作为支撑呢?让我们带着这些问题,开启一段新的旅程吧!
只有创建,才能看见
深度学习的框架中包含着很多惊人的技术和有趣的机制。本书旨在解读它们,帮助读者正确地理解这些技术,让读者感受到这些技术的有趣之处。为了实现这一目标,本书采取“从零开始创建”的做法,也就是从零开始边开发边思考,让大家在运行程序的过程中加深理解。通过这样的体验,读者将了解到深度学习框架的本质。
在创建框架的过程中,读者会学到很多东西,会体验到“我明白了,原来可以用这个技术!”“原来这个想法可以这样实现!”之类的瞬间,这些体验是仅仅使用现有工具所无法获得的。有些东西,只有创建,才能理解;有些东西,只有创建,才能被看见。
比如,有人可能认为深度学习框架只不过是一个拼凑了层和函数等组件的库,其实深度学习框架包含的东西远不止于此。可以说框架是一种编程语言,具体来说,它是一种具有求导功能的编程语言(最近也有人称它为“可微分编程语言”)。阅读本书,体验从零开始创建的过程,你就能体会到这一点。
本书的原创框架
深度学习框架在黎明期彼此差异很大,而现代深度学习框架已经进入成熟期,PyTorch、Chainer和TensorFlow等被广泛使用的框架实际上都在朝着同一个方向发展(当然,它们有各自的特点,有不同的用户接口,但它们的设计思想正趋于一致)。本书基于这些共性,设计了一个重视教学的极简框架。因为是从零开始创建的,所以笔者将这个框架命名为DeZero,并为它制作了图1所示的标识。
DeZero
图1 DeZero的标识
DeZero是本书原创的框架。它的实现以Chainer为基础,同时引入了PyTorch的设计。下面笔者来详细介绍一下它的特点。
1. 极简主义
DeZero是以简单易懂为第一设计原则的框架。在设计方面尽量减少了外部库的使用,内部代码也压缩到了最简。因此,读者不用花费很多时间就能理解DeZero的全部代码。
2. 纯Python
许多深度学习框架使用多种编程语言(如Python和C++等)来实现,而DeZero只用Python来实现。因此,只要懂Python,就可以毫无障碍地阅读DeZero的代码。由于该框架只使用Python来实现,所以我们可以轻松地在智能手机上,或者使用Google Colaboratory等服务在云端运行它。
3.具备现代深度学习框架的功能
PyTorch、Chainer和TensorFlow等现代深度学习框架有许多相同的功能,其中一个重要的功能是Define-by-Run。Define-by-Run是在进行深度学习计算时在计算之间建立“连接”的机制(正文中将详细介绍这个特性)。本书创建的DeZero框架就是一个Define-by-Run风格的框架,它采用了许多与现代深度学习框架相同的设计。

本系列的前作《深度学习入门:基于Python的理论与实现》《深度学习进阶:自然语言处理》带领大家从零开始实现深度学习,并介绍了它的工作原理。不过,这两本书在实现时以简单为先,计算之间的“连接”都是手动设置的。而真正的框架会自动实现连接,这就需要用到Define-by-Run。本书通过从零开始构建DeZero来让读者了解它的工作原理。在阅读本书之前,读者不需要事先阅读本系列的前两部作品。
增量开发
DeZero 虽然是一个小框架,但它的内容足够复杂。为了化繁为简,本书将创建 DeZero 的工程划分为多个小步骤。具体来说,就是依次完成 60 个步骤,一点点地创建 DeZero,本书的目录也是按步骤划分的。
比如步骤1是创建DeZero的变量,完成这个步骤只需3行代码。步骤2是给函数编写代码。各步骤的内容都是独立完成的,代码可以实际运行。在本书中,我们会通过这种增量开发的方式来逐步创建DeZero,一边运行代码一边加深理解。
此外,通过本书得到的经验也可以运用在软件开发中。体验从头开始创建一个复杂系统的过程是学习软件开发的好方法。考虑到这一点,本书也使用了一些篇幅来介绍软件开发方法的相关内容。
本书的路线图
如前所述,本书由60个步骤构成,这60个步骤又可分为如图2所示的5个阶段。下面笔者简单介绍一下每个阶段的内容。

图2 本书结构
在第1阶段,我们会为创建DeZero打好基础。在这个阶段,我们只处理简单的问题,用最短的时间实现自动微分的功能(在阅读本书的过程中,读者会逐渐理解自动微分的意思)。
在第2阶段,我们将扩展DeZero,使其能以更自然的代码来表达。在第2阶段结束时,我们应该就能使用平常用到的Python语法,比如if语句和for语句等来编写代码。
在第3阶段,我们将继续扩展DeZero,使它可以计算二阶导数。要做到这一点,需要使DeZero实现“反向传播的反向传播”。通过了解其工作原理,我们会发现DeZero和现代深度学习框架中蕴含的新的可能性。
在第4阶段,我们会让DeZero实现神经网络的功能。这样一来,我们就能用DeZero轻松地构建神经网络。
最后在第5阶段,我们将增加对GPU的支持、模型的保存和恢复等深度学习必备的功能,还会研究CNN和RNN等更先进的模型。在深度学习的应用方面,这些都是很重要的问题,但这些问题都不好解决。不过,在这个阶段我们会了解到,(具备Define-by-Run能力的) DeZero可以用简单的代码来解决这些问题。

本书最后完成的DeZero已经被发布到了PyPI(Python Package Index)中。PyPI是Python的软件包仓库。大家可以在命令行使用pip installdezero命令安装DeZero。当然,也可以在本书创建的DeZero的基础上开发自己的框架,并在网上公开。
踏上创建DeZero之旅
以上就是本书的大致内容。总结一下,本书介绍了从零开始创建原创框架DeZero的过程。DeZero是一个小而强大的框架,我们将通过60个步骤来完成它。在这一过程中,读者会加深对PyTorch、Chainer和TensorFlow等现代深度学习框架的理解。
最后再次强调,本书的目的不仅仅是创建原创框架DeZero,更重要的是通过创建DeZero的旅程,让大家拥有观察现代深度学习框架的“新的视角”。拥有了新的视角,我们就能更广泛、更深入地探索深度学习领域。发现这个新的视角的过程,才是本书真正的价值所在。
好了,准备工作完成了,下面就让我们开启创建DeZero之旅吧!
必要的软件
本书使用的Python版本及外部库如下所示。
Python 3
NumPyMatplotlib
CuPy(可选)
Pillow(可选)
DeZero还提供了能在NVIDIA的GPU上运行的功能作为可选项。要实现这个功能,我们需要用到名为CuPy的外部库。同样,我们还需要选配
Pillow这个图像处理库。除Python之外,本书还使用了以下软件。
Graphviz
笔者将在步骤25介绍如何安装Graphviz。
文件构成
本书使用的代码可以从以下网址获取。
ituring.cn/book/2863
各文件夹的内容如表1所示
表 1 文件夹的内容
steps文件夹中的step01.py、step02.py等文件与本书各步骤中创建的文件一一对应。我们可以通过以下Python命令运行这些文件(可以在任何目录下运行Python命令)。
$ python steps/step01.py
$ python steps/step02.py
$ cd steps
$ python step31.py第1阶段
自动微分
导数广泛应用在现代科学技术的各个领域,尤其在包括深度学习在内的机器学习的各个领域,导数起着核心作用。从某种意义上来说,深度学习框架就是计算导数的工具。因此,本书的主题自然包括导数。换言之,如何利用计算机求导是本书的一个重要知识点。
马上要进入的第1阶段共包括10个步骤。在这个阶段,我们将创建自动微分的机制。这里所说的自动微分指的是由计算机(而不是人)来计算导数。具体来说,就是指在对某个计算(函数)编码后,由计算机自动求出该计算的导数的机制。
在这个阶段,我们将创建代表变量和函数的两个类(Variable类和Function类)。让人惊讶的是,有了这两个类,我们就为自动微分打好了基础。在第1阶段结束时,对于简单的计算(函数),DeZero应该可以自动求出它的导数了。下面就进入创建DeZero的首个阶段吧!

步骤1
作为“箱子”的变量
本书的第1个步骤是创建DeZero的组成元素——变量。变量是DeZero最重要的组成部分。在这个步骤中,我们将思考变量是如何工作的,并实现变量的功能。