当我们说起TensorFlow,不可避免会提到图结构,为什么TensorFlow要用图结构呢?有什么好处呢?为了搞清楚这些问题,我们先从深度学习的计算过程说起。
深度学习计算过程
作为图像计算的一种,深度学习计算与其他图计算并没有什么本质的区别,输入图像,根据定义好的规则对图像进行计算,并输出计算结果,然后按照规则对计算结果,然后得到最终场景需要的结果。
其中,这个规则就是由深度学习模型来定义,决定我们如何对图像进行一层层计算,并得到结果。我们稍微细化一下,从结果倒推,为了得到计算结果,我们至少需要什么?
首先我们需要计算设备,最差的情况下,我们只需要一台仅仅包含CPU的主机;
然后是对计算过程进行表示,最简单的情况下,我们选择使用C++来描述整个计算过程,从normalization到conv到relu,无一例外可以表示成纯C++的函数,根据模型定义的规则,逐个调用这些计算函数,我们就可以完成计算过程。注意我们这里说的是最极端的情况。
除此之外,我们还需要加载模型,包括这些函数的顺序,以及函数里面的参数值,这些都得通过模型加载进来。最简单的情况,我们分成两步,一个文件用来描述计算的过程,一个用来保存计算中用到的参数,如何保存呢?最笨的方法,我们可以用txt或者JSON或者XML或者其他任意一种结构化的语言来描述计算过程。参数值怎么办呢?简单!用一个二进制文件来保存,因为我们是知道每一个函数需要多少个参数的,所以不会出错。
OK了!一个最简易的深度学习计算过程就有了,我们通过某种格式来加载了模型的计算顺序和具体的参数值,然后通过C++函数调用,在一个CPU设备上完成了所有的计算过程并输出结果。
恭喜! 我们得到了一个最简易的前向推理框架!
马上有人发现不对劲了,说好的反向传播、损失函数、优化算法呢?我们的建议前向推理框架急需扩充,否则搞不定训练的需求了。但是实际上反向传播、损失函数和优化算法五一例外也都可以表示成一个个函数,也就是说,最笨的方法,我们手动把这些函数的调用过程排好,然后训练的时候是一套过程,前向的时候就用我们上面说的模型描述文件来定义过程。之于模型的保存,可能要稍微费点劲,不过没什么事情是手动操作不了的。再往前一步,我们将这些计算过程封装一下,不要是一个个底层计算函数,包装成一个个layer,然后模型的定义是通过一个个layer的组合来实现,岂不是少了很多的人工操作。
恭喜!我们得到了一个最简易的训练框架!
工程最重要的三件事:效率,效率,效率!
效率问题
上面的框架有哪些效率问题?从哪些角度来评判呢?
一般来说,图像计算框架的效率分为两个方面,一是计算过程本身,二是计算的编排。
如果从计算本身的代码实现上来说,针对上面的框架,我们可以通过优化CPU代码来提高效率,比如向量化和汇编等,从而提高计算性能。但是实际上上述框架在计算过程中更大的问题是计算的编排太粗糙。我们在定义模型的时候,有一些操作或layer,与我们实际的计算结果可能并无关联,这就使得,我们需要手动调整计算过程,避免不需要的计算,这是一点;其次,如果我们有多个CPU,想要发挥多CPU的性能,将计算过程并行化,这个时候我们又是要手动编排来达到这个目的,更进一步,如果还有GPU等异构设备参与计算,那我们不仅需要处理计算过程编排,还得处理设备间的通信以及数据同步等一系列问题。。。
图表示为什么能提升效率
上面的计算是真正的“人工智能”,因为几乎所有的效率相关的工作都只能通过人的经验来解决,如果使用者不那么专业或者偷了一点懒,那结果可能失之千里。有没有什么办法可以很好的表示这个过程而且效率较高呢?
有!用图来表示!
相较于直接操作数据和过程得到结果的命令式编程,符号式编程就是将表示过程和实际运算过程分开。本质上来说也是解耦合,通过将这两个过程解耦,我们可以很方便的表示计算过程以及执行计算过程,缺点是理解难度加大,不太好上手。
使用图来表示深度学习的计算,简单来说有以下几个好处:
1.常数折叠,可以将几个常数符号折叠到一起,缩短计算过程
2.清理不相关节点,将与计算结果不相关的计算过程清理掉,减少计算过程
3.子图拆分,将大图根据依赖关系拆分成几个不相关的子图,可以并发执行,提升效率
4.去除公共子图,某些公共操作,不需要重复进行,只计算几次,减少计算过程
真实原因
上面我们是从深度学习的结果出发,逆向推理得到为什么要用图来表示,当然图结构表示计算过程绝不仅仅只有我们提到的这些优点。
当然google也不是因为这些优点才使用图来表示,真实原因是TensorFlow本身就不是完全从“深度学习计算”这个角度出发从下到上完成框架设计的,而是一开始就确定了图这种表示和编程模型!
TensorFlow的前身DistBelief,是Google Brain的第一代分布式机器学习框架,就已经采用了有向无环图来表示计算过程,并将一些特定的机器学习操作融合成层,将层组合成图,就是DistBeleief的编程模型。作为DistBelief的继任者,TensorFlow继续保持图的结构也就完全在意料之中了。