【新智元导读】在 ThingsExpo 会议上,谷歌软件工程师 Natalia Ponomareva 作了有关如何在大规模机器学习中取得成功的讲座。Natalia 回顾了可用于对大量数据进行机器学习模型训练的框架,解释了特征工程和算法选择,并提供了有关如何避免错误的 tips。这是一份非常实用的机器学习指导手册。本文后半部分谈了如何选择深度学习框架的问题,以及Theano 贡献者、苏黎世联邦理工学院的深度学习研究者 Gokula Krishnan Santhanam 对常用深度学习框架基本构成的分析。
谷歌机器学习:实际应用技巧
什么是机器学习(ML)?
从概念上讲:给定(训练)数据,发现一些潜在的模式并将这个模式应用于新数据。
ML 的类型:监督学习;无监督学习;半监督学习;……
监督学习:用于训练的输入数据有标记。
无监督学习:输入数据没有标记,尝试在数据中查找“隐藏的”结构。
示例:对聚类流服务用户进行分组,对这些组以及某个视频在这些组中的受欢迎程度进行分析。
ML如何帮助企业业务
特征工程(feature engineering)是什么?
在概念上,特征工程是将原始数据(日志,产品购买的历史记录或上网行为等)转换成可以由学习算法在训练和预测中使用的矢量(vector)的过程。
特征工程:如何做?
高级步骤:
准备最终的训练数据
特征标准化(Feature normalization )
你的特征很有可能比例不同:
有些机器学习模型可能无法很好地处理这样的范围各异的特征。
解决方案: 标准化特征,使特征的范围大致相同
怎样评估模型?
你最关心的是什么?是“没有假正(false positives)”吗?还是整体的预测准确度?
模型选择:
分类:逻辑回归,感知器算法,AdaBoost,SVM(线性内核为大量数据,RBF为小数据),随机森林
回归:线性回归,随机森林
考虑深度学习
超参数调优(Hyperparameter tuning)
ML模型具有超参数:这些是在训练开始之前就已经固定并且影响训练过程和复杂性的参数。
例如:学习率,正则化常数等
过程:设置值,训练模型, 评估,(基于评估)细化值
方法:Grid;算法辅助超参数调优(贝叶斯等)
有监督 ML pipelines
需要为以下内容设置 pipeline:
选择工具/框架前需要考虑的事
初步的分析是有必要的,那么下一步该做什么?
- 在有新数据时更新模型,还是根据情况进行再训练?
- 训练数据是否都适合内存?
- 是否有资源在云中设置一个完整的ML云 pipeline(DIY方法)?
- 还是利用“ML即服务” (ML as a service)?
ML生产工具:实践方法
数据处理框架:
ML 工具:ML 即服务
ML即服务(ML as a service):预构建全栈解决方案(使用堆栈轻松训练和部署模型)
Google 云服务:
TensorFlow
谷歌云机器学习(alpha)
预训练的模型
如何选择深度学习框架
上面说完了谷歌机器学习的实用技巧,也正好说到了 TensorFlow——代表谷歌深度学习的开源框架。现在,开源深度学习框架越来越多,除了 TensorFlow,目前可选的就有 Theano + Lasagne / Keras,Torch,PyTorch,Mxnet / minpy,Chainer,Neon,CNTK,Caffe 和 dynet。
每个框架都有各自的优势,使得选择哪个框架变得越来越难以权衡。此前 Soumith 的 convnet-benchmarks (https://github.com/soumith/convnet-benchmarks)是很不错的框架间的比较基准,但也已经很久没有更新了。
为此,前不久 Reddit 用户 m_ke 在 Reddit 机器学习板块发起了讨论:2017 年常用深度学习开源框架的状况会是怎样?
m_ke 对这个讨论还做了补充说明:
1.你现在使用哪个框架?
2.你使用该框架做什么任务(CV / NLP / RL)?
3.你喜欢该框架的哪些地方?
4.你是否考虑换个框架?
5.你现在遇到的最大的瓶颈是什么:内存,计算,还是数据?
这些问题引起了一些有意思的讨论,以下是摘选:
用户 sbt_:
这个问题就像在 emacs 和 vim 之间进行选择。当前的框架在性能方面都没有什么太大的不同,没有哪个能好到你能说它比其他的都好。
如果你想知道这些库/框架之间有何区别,可以在典型的使用案例(硬件和模型架构)上自己做基准比较。我偏好的可能仍然是 Theano,但我发现 TensorFlow 对我的任务也表现得同样好——选择 Theano 只是因为我对它更熟悉。此外,我两三天前看了下 PyTorch,看起来也非常好。
用户 feedtheaimbot:
我个人使用 Lasagne 和 Theano 做研究。它的功能完整,设计良好。我的研究领域包括 RL,CV,贝叶斯推理,Memnets 等,它对所有这些工作都表现良好,哪怕我试图实现一些非常不标准化的想法。
我唯一的不满是 Theano 的编译时间长的令人生厌。这点能够部分得到解决,至少对合理性检查方面,通过添加一些标志例如 device = cpu。
我也对 Pytorch 和 minPy 挺感兴趣,特别是我觉得 numpy 很好,有助于加快我的迭代速度。
用户 miketout:
对我来说,在 Ubuntu 上安装和使用最简单的是 Neon。我是做模型的,编程和数学都是初学者。不久我写了自己的可组合容器和更高级的模型。我在示例中遇到一些bug,修复了其中一些,并且可能会在某些点提交一些 pull 请求。Neon 有一些非常好的示例,涵盖了最新的一些研究的实现。在尝试 Neon 之前,我安装过 Theano,Tensoflow 和 Keras / Tensorflow,但几乎没有使用过。我认为不考虑设置的话,在易用性上 Keras 和 Neon 差不多。
当我开始考虑为大规模分布式训练写一点东西,我在打造自己的解决方案之前再次查看,并开始设置 mxnet。Mxnet 支持分布式训练和基于 ZMQ 的分布式KV存储,这正是我想要的。乍看之下它也像 Neon 一样可以直接使用。但在 Windows 和 Ubuntu 16.04 上设置 mxnet 简直就是噩梦,我只能放弃了对本地机器的 CUDA 支持。Amazon 上有一些预安装的示例。
我的经验是,Neon 最容易设置,在设置模型的难度上可能类似于 Keras,并且完全适应各种任务,包括图像处理、DL 以及其他不需要分布式训练的任务。就目前来说,好像也是 Neon 的性能最好。
用户 congerous:
与 Torch 和 Neon 相比,Tensorflow 是最慢的。虽然 Neon 也不是很有吸引力,很像 Chainer 和 Lasagne。Caffe 和 Neon 在图像任务上都很快,但他们不是真正意义上通用目的的框架。只说持久力的话,Theano,Torch / PyTorch,MxNet,TensorFlow / Keras 和 CNTK 应该都会继续增长。
深度学习框架的基本构成:五大基本要素
很多人都会遇到该如何选择框架的问题,了解这些框架的基础构造有助于你更好地做出选择。
常用的框架包括 Theano、TensorFlow、Torch 和 Keras。它们各有千秋,苏黎世联邦理工学院计算机科学系硕士研究生,同时也是 Theano 贡献者(contributor)的 Gokula Krishnan Santhanam 日前撰文详细剖析了这些框架共通的基础构成。
首先,一个深度学习框架含有以下五个核心组件:
为了向开发者提供尽量简单的接口,大部分深度学习框架通常都会将普通的概念抽象化,这可能是造成许多用户感知不到上述五点核心组件的重要原因。
下面,我们就来一一看一下这五大组成。
1. 张量(Tensor Object)
用张量表示的对象是一个深度学习框架中的核心组件,因为后续的所有运算和优化算法都是基于张量进行的。几何代数中定义的张量是基于向量和矩阵的推广,通俗一点理解的话,我们可以将标量视为零阶张量,矢量视为一阶张量,那么矩阵就是二阶张量。
举例来说,可以将任意一张RGB彩色图片表示成一个三阶张量,三个维度分别是图片的高度、宽度和色彩数据。下图如果按照RGB三原色表示,就可以拆分为三张红色、绿色和蓝色的灰度图片(见下图中间的三张不同突破),再将这张图用张量表示出来,就是最下方的那张表格。
图中只显示了前5行、320列的数据,每个方格代表一个像素点,其中的数据[1.0, 1.0, 1.0]即为颜色。假设用[1.0, 0, 0]表示红色,[0, 1.0, 0]表示绿色,[0, 0, 1.0]表示蓝色,那么如图所示,前面5行的数据则全是白色。
将这一定义进行扩展,我们也可以用四阶张量表示一个包含多张图片的数据集,其中的四个维度分别是:图片在数据集中的编号,图片高度、宽度,以及色彩数据。
将各种各样的数据抽象成张量表示,然后再输入神经网络模型进行后续处理是一种非常必要且高效的策略,这样做能够统一不同类型的数据,将它们用标准的方式表现出来。此外,当数据处理完成后,还可以将张量转换为其他想要的格式。
2. 运算
接下来是对张量对象的数学运算和处理。
我们可以将神经网络视为对输入张量进行一系列运算从而实现某个目的的过程。这些运算包括简单的矩阵乘法,也可以是卷积、池化和LSTM等稍复杂的运算。而且各框架支持的张量操作通常也不尽相同,详细情况可以查看其官方文档(如下为NumPy、Theano和TensorFlow的说明文档)。
需要指出的是,大部分的张量操作都是基于类实现的(而且是抽象类),而并不是函数(这一点可能要归功于大部分的深度学习框架都是用面向对象的编程语言实现的)。这种实现思路一方面允许开发者将各种类似的操作汇总在一起,方便组织管理。另一方面也保证了整个代码的复用性、扩展性和对外接口的统一。总体上让整个框架更灵活和易于扩展,为将来的发展预留了空间。
3. 计算图和优化
有了张量和基于张量的各种操作之后,下一步就是将各种操作整合起来,输出需要的结果。
但很可惜,随着操作种类和数量的增多,有可能引发各种意想不到的问题,包括多个操作之间应该并行还是顺次执行,如何协同各种不同的底层设备,以及如何避免各种类型的冗余操作等等。这些问题有可能拉低整个深度学习网络的运行效率或者引入不必要的Bug,而计算图正是为解决这一问题产生的。
它包含到各种Ops实例的链接,以及操作需要输出哪个操作以及附加信息的关系。不同的框架有不同的方式实现。
将计算图作为前后端之间的中间表可以带来良好的交互性,开发者可以将Tensor对象作为数据结构,函数/方法作为操作类型,将特定的操作类型应用于特定的数据结构,从而定义出类似MATLAB的强大建模语言。
需要注意的是,通常情况下开发者不会将用于中间表示得到的计算图直接用于模型构造,因为这样的计算图通常包含了大量的冗余求解目标,也没有提取共享变量,因而通常都会经过依赖性剪枝、符号融合、内存共享等方法对计算图进行优化。
目前,各个框架对于计算图的实现机制和侧重点各不相同。例如Theano和MXNet都是以隐式处理的方式在编译中由表达式向计算图过渡。而Caffe则比较直接,可以创建一个Graph对象,然后以类似Graph.Operator(xxx)的方式显示调用。
因为计算图的引入,开发者得以从宏观上俯瞰整个神经网络的内部结构,就好像编译器可以从整个代码的角度决定如何分配寄存器那样,计算图也可以从宏观上决定代码运行时的GPU内存分配,以及分布式环境中不同底层设备间的相互协作方式。除此之外,现在也有许多深度学习框架将计算图应用于模型调试,可以实时输出当前某一操作类型的文本描述。
4. 自动微分工具
拥有计算图(computational graph)的另一个好处是,学习阶段的计算梯度变得模块化,简单明了,便于计算。这要归功于chain rule,它们能让你以系统的方式计算函数组成的导数(derivatives)。正如我们所见,神经网络能够被认为是简单的非线性组合,进而产生更加综合性的函数。区分这些函数只是简单地将图形从输出返回到输入。符号微分或自动微分是一种可以在计算图中计算梯度的程序化方法。
符号微分指的是分析性地计算导数。例如,你能得到关于梯度是什么的表示。为了使用符号微分,你只需要把Value 嵌入到导数中,然后直接使用。不幸的是,一些非线性,比如ReLU (Rectified Linear Units)在一些点是不能微分的。因此,我们以迭代方式计算梯度。由于第二种方法可以普遍使用,大多数计算图包,如计算图工具包(http://rll.berkeley.edu/cgt/) 来实现自动微分。
推出自己的梯度计算模块通常不是一个好主意,因为由工具包来提供显然更容易,更快速地。所以,要么有自己的计算图工具包和自动分化模块或使用外部包。
由于每个节点处的导数必须仅相对于其相邻节点计算,所以可以将计算梯度的方法添加到类中并且可以由微分模块调用。
5. BLAS / cuBLAS和cuDNN扩展
使用所有上述组件,你可以拥有一个功能齐全的深度学习框架。它将能够将数据作为输入并转换为张量,以有效的方式对它们执行操作、计算梯度以学习并返回测试数据集的结果。然而,问题在于,因为你最有可能在高级语言(Java / Python / Lua)中实现它,所以你可以得到的加速 是有上限的。这是因为即使在高级语言中最简单的操作也比在低级语言中完成时花费更多的时间(CPU周期)。
在这些情况下,我们可以采取两种不同的方法。
第一个是来自编译器的另一个类推。编译过程的最后一步是 Assembly中生成的特定的硬件代码。类似地,不是运行以高级语言编写的图,而是在C中生成用于网络的相应代码,并且其被编译和执行。它的代码存储在每个Ops中,并且可以在编译阶段合并在一起。通过包装器 (wrappers)(如pyCUDA和Cython)实现从低级到高级代码数据传输。
第二种方法是使用像C ++这样的低级语言实现后端,这意味着低级语言 - 高级语言交互内部框架是与前面的方法不同的,并且可以更快,因为我们不需要每次都编译整个图。相反,我们可以使用适当的参数调用编译的方法。
非最优行为的另一个来源来自低级语言的缓慢实现。编写高效的代码十分困难,我们更好优化了这些方法实现的库。 BLAS或基本线性代数子程序是优化矩阵运算的集合,最初用Fortran 编写。这些可以用于做非常快的矩阵(张量)操作,并且可以提供显著的加速。还有许多其他软件包,如英特尔MKL,ATLAS也执行类似的功能。你可以根据自己的偏好进行选择。
BLAS包通常是已经优化的,其前提假设是指令将在CPU上运行。在深度学习中,情况并非如此,BLAS可能无法充分利用GPU提供的并行性。为了解决这个问题,NVIDIA发布了针对GPU优化的cuBLAS,现在包括在CUDA工具包中。最后,cuDNN是一个基于cuBLAS的功能集的库,并提供优化的神经网络特定操作,如Winograd卷积和RNN。
因此,通过使用这些软件包就可以框架中获得显著的加速。加速在DL中十分要,这是你训练神经网络只花费四个小时而不是四天的原因。在快速变化的AI创业公司中,速度就是你能成为领跑的还是追赶别人的关键。
总结
现在,你已经了解了不同框架之间的相似的特性,可以更好地认识和使用一个深度学习框架。对于不仅对学会使用深度学习框架感兴趣,了解各个常用框架的内部组成和共性特征,还有助于你自己动手搭建深度框架。
优秀的工程师/研究员不仅要知道自己该使用哪种工具,还应该知道为什么这个工具才是最好的选择。
深度学习框架基本要素编译自:https://medium.com/@gokul_uf/the-anatomy-of-deep-learning-frameworks-46e2a7af5e47#.x8ilbhdqv