The deep learning competitive landscape
2017年1月PyTorch 0.1问世,这一事件可能标志着诸如像深度学习库、封装器和数据转换格式等从寒武纪爆炸式的扩增时代过渡到平稳统一的时代(这里面用到的比喻可能不太恰当,大家意会下)。
请注意:
近几年深度学习领域发展得非常迅猛,以至于在读者阅读本书时,某些方面的介绍可能已经过时了。即使读者对下面提到的某些库不太熟悉,也不必在意(作者又开始暗示了,没听过的都是过时的,吼吼)。
在PyTorch第一个beta版本发布的时候:
Theano和TensorFlow是主要的更偏向于底层的采用延迟执行方式的库。
Lasagne和Keras是Theano的高级封装库,而Keras同时也对TensorFlow和CNTK进行了高级封装。
Caffe、Chainer、Dynet、Torch(基于Lua的PyTorch的前身)、mxnet、CNTK和DL4J等库填补了深度学习生态系统中的各个领域。
随后大约两年,该领域便发生了巨大的变化。PyTorch或TensorFlow背后的社区已经基本巩固完善,与之伴随的是其他库的使用量逐渐减少,或者只能退居某一特定领域:
Theano是最早的深度学习框架之一,现已停止发展。
TensorFlow
使用Keras作为核心API
提供即时执行模型——eager mode
宣布eager mode为TF2.0的默认执行模型
PyTorch
使用Caffe2作为后端
替换了基于Lua的Torch项目中重复使用的大多数低级代码
增加了对ONNX的支持,定义了一种与深度学习库无关的模型描述和转换格式
增加了称为TorchScript的延迟执行图模式运行引擎
发布了1.0版本
TensorFlow配有强大的工业部署渠道,并且在行业内拥有广泛的社区支持和分量占比。另一方面,由于PyTorch的易用性,它已经在研究和教学领域中取得了巨大进展,并且随着研究人员和院校培养的毕业生不断进入行业而不断发展壮大。有趣的是,随着TorchScript和eager mode的出现,这两个框架的功能开始趋向于一致。
PyTorch has the batteries included
在之前的表述中我们已经透露出PyTorch的一些组件。现在,我们将花费一些时间来正式介绍PyTorch的主要组件之间的高级映射关系。
首先,PyTorch有Python中的Py,但其中又有很多非Python代码。由于性能原因,大多数PyTorch都是用C++和CUDA语言编写的,CUDA是NVIDIA开创的具有C++风格的语言,可以在NVIDIA GPU上进行编译来实现大规模并行运算。PyTorch可以基于C语言运行。这种做法的主要目的是为模型的工业部署提供一个可靠的方案。然而大多数情况下,读者将基于Python来运行PyTorch,构建和训练模型,并使用训练后的模型来解决问题。如果以给定的示例对性能和规模的需求为参考,纯Python代码的方案足以将模型投入生产。例如,使用Flask web服务器来封装一个基于Python实现的PyTorch模型是完全切实可行的。
实际上,就可用性和与广泛的Python生态系统的集成性而言,Python API就是PyTorch的亮点。接下来,我们来探究下PyTorch的内置模块。
PyTorch的核心是提供多维数组的库,在PyTorch术语中这些多维数组称为张量,而torch模块则提供了可对其进行扩展操作的库。
张量和相关操作都可以在CPU或GPU上运行。与CPU相比,在GPU上运行可以显著提高速度(如果愿意为高端GPU付费的话(精彩精彩,不就是币吗,我给还不行吗)),而使用PyTorch来将代码部署到GPU上运行最多需要一到两个额外的函数。
PyTorch提供的第二个核心功能是允许张量跟踪对其所执行的操作,并通过反向传播来计算输出相对于其任何输入的导数。此功能由张量自身提供,并通过torch.autograd进一步扩展完善。
我们可以说,基于张量和可使用autograd的张量标准库,PyTorch不仅可以用于神经网络,(我们是正确的):PyTorch还可用于物理、渲染、优化、仿真和建模等。我们很可能会看到PyTorch将以创造性的方式在各种科学应用中得到使用。
首先,PyTorch是一个深度学习库。因此,它提供了构建和训练神经网络所需的所有模块。下图展示了一个标准流程:加载数据,训练模型,然后将该模型部署到生产环境中。
PyTorch中用于构建神经网络的核心模块位于torch.nn中,该模块提供了常见的神经网络层和其他架构组件。该模块包含了全连接层、卷积层、激活函数和损失函数。这些组件可用于构建和初始化下图中心部分所展示的待训练模型。
为了训练该模型,读者需要以下几样:(循环可直接采用标准的Python for循环):储存训练数据的资源,使模型能够适应训练数据的优化器,以及将模型和数据导入硬件中的方法,该硬件将执行训练模型所需的计算。
torch.util.data模块能够用于数据加载和处理。需要用到的两个主要的类是Dataset和DataLoader。Dataset承担了开发者自定义的数据(该数据可能是任何一种格式)与标准PyTorch张量之间的转换任务。DataLoader可以在后台生成子进程来从Dataset中加载数据,使数据提前准备就绪,随时等待进入训练循环中。
在最简单的情况下,模型将在本地CPU或单个GPU上运行所需的计算。因此,当训练循环获取到数据时就能够立即开始运算。然而更常见的情形是使用专用的硬件(例如多个GPU)或利用多台计算机的资源来训练模型。在这些情况下,可以通过torch.nn.DataParallel和torch.distributed来使用其他的可用硬件。
当模型根据训练数据得到输出结果后,torch.optim提供了更新模型的标准方法,从而使输出更接近于训练数据中的标签。
如前所述,PyTorch的默认运行方式为即时执行(eager mode)。每当Python解释器执行到包含PyTorch的指令时,相应的操作就会立即通过底层的C++或CUDA来执行。
为了避开Python解释器所带来的成本,以及使模型能够独立于Python而运行,PyTorch还提供了一个名为TorchScript的延迟执行模块。借助TorchScript,PyTorch可以序列化一组独立于Python而被调用的指令。读者可以将这个模型看作是虚拟的机器,它具有针对张量操作的有限指令集。除了不产生调用Python的开销外,这种执行模式还使得PyTorch能够实时(JIT)将已知操作序列转换为更有效的混合操作。这些功能是PyTorch生产部署能力的基础。