TensorFlow Fold:用动态计算图实现深度学习
论文链接:https://openreview.net/pdf?id=ryrGawqex
摘要
动态图的批处理过程在计算机视觉、自然语言处理等领域中十分普遍。然而,由于每个批次要处理的数据的类型和形态(shape)具有多样性,所以要想用现有的框架和库在这种数据集上使用静态图进行批处理工作几乎是不可能的。
在本研究(发表于ICLR 2017)中,来自谷歌的M. Looks等人开发了一个名为“动态批处理”的先进算法,同时他们也相应地开发了一个基于TensorFlow的库“TensorFlowFold”,它可以借助动态计算图来克服批处理带来的困难。
这项技术利用传统库生成的静态图,模仿任意形状的动态计算图。此外,除了可以对不同的输入图进行批处理操作外,它还可以在单个输入图中对大量不同的标记(note)进行处理。
背景
神经网络深度学习领域(尤其是化学信息学与自然语言理解领域)很流行用数据流图(data-flow graph)来进行计算。在大多数框架如TensorFlow中,图是静态的,这意味着批处理只能应用于一系列有着同样类型和形状的数据。然而,在最原始的数据集中,每个数据都有自己独有的类型或形状,这会使得神经网络无法用静态图对这些数据进行批处理。这个问题即是所谓的“动态图计算”(Dynamic Computation Graphs,DCG)问题。DCG会使得批处理低效,tooling很差。 近两年来,虽然进行情感分类与语义联系的研究者们在克服DCG问题上成功地取得了一些突破,然而,大量从业者仍然选择避免在动态图上直接进行批处理。因此,我们需要一种新的算法来对动态图进行批处理。
动态批处理
以下是进行动态批处理的几个法则:
1. 输入数据:
神经网络的输入可以是一系列不同形态的数据,这也意味着,对于每个不同的数据而言,其计算图也会不同。
2. “operations”与“ops”概念辨析:
虽然看上去类似,但二者实为两个不同的概念。
i)当我们说“ops”的时候,指的是单独的运算过程,比如加法或矩阵乘法等,这些单独的运算会以节点的形式呈现在图中。
ii)当我们说“operations”的时候,指的是函数运算,如前馈层或LSTM单元。在图中我们用子图(sub-graph)的方式来表示它。
“动态批处理”处理的是operations,而不是ops。
3. operation的输入与输出:
我们将operation的输入 (b, x1, x2, ..., xn)和输出(b, y1, y2, ..., yn) 称为张量数据类型,对此我们得事先进行规定,并在整个处理过程中不作改动,以便operation可以分别进行改变。
4. 处理的简明原则:
每个不同的数据都有自己的计算图,由循环图中不同深度(depth)的各种opeartion组成。通过对同一个operation的所有数据进行计算(同一深度),动态批处理将会替代(重写过程)先前的图。
5. 重写过程:
动态批处理将两个不同的operation “concat”(即concatenate,级联)和“gather”插入图中,以保证数据流可以很好地在已经批处理过的operation之间传递。
6. 在TensorFlow中实现:
d表示图中每个节点的深度,同时它也是后面while-loop的迭代器。
一个operation所有的输入都将在该operation执行之前由'tf.gather'收集,所有operation的输出都将由'tf.concat'连结起来。最后,所有这些ops都会在一个while-loop中执行。
7. While-Loop:
每个变量都有两个参数,t代表张量的数据类型,d代表深度。对于处理这些变量的operation来说,它们也需要分别由t和d两个参数来定义。
while-loop沿着输入图的深度进行迭代。loop会先维持 [state variables for tensor type t] 和 [the output of tf.concat for type t & iteration d],然后将其馈送至 [the tf.gather at tensor type t and iteration d+1] 。
图一表示深度为d的静态数据流图,它向我们展示了在单个迭代步骤中变量改变的情况。
实验结果
在实验中,我们开发了一个基于Tensorflow的库“TensorFlow Fold”。
为了测试该库的性能,我们进行了一项实验。因为本来的TensorFlow不能处理不同形状的图,只能执行那些由动态批处理(用'dynamic'标记)和手动批处理(用'manual'标记)在一批同样形状的随机图上进行操作从而生成的模型。测试模拟出了最好的情况,所有的operation都可以一起进行批处理。
此外,我们还进行了第三个测试组的实验(用'fully dynamic'标记),其中每个图都有自己独特的形状。因此这一组没有对照组。
从下表我们可以看到,对于同样的性能来说,使用TensorFlow Fold进行动态批处理的损耗(时间消耗)明显低于手动批处理。此外,批处理的速度与输入图的相似性之间完全没有任何联系,这意味着动态批处理的性能极佳且稳定。
COMBINATOR
简化例子:通过将一系列不同长度的词连接成一个句子这样的工作,他们引入了几个可以直接在单个块(或函数)上工作的连接器(combinator),combinator可以直接对元素(此处指输入单词)进行操作。
- Map(f) 产生一个向量[f(x1), f(x2), ..., f(xn)]:将一个块f应用到每一个输入词汇上,以便将词汇嵌入进向量。
- Fold(f, z) 产生 f(...g(g(z,x1), x2), ...xn):左链中按顺序应用f在一个序列上运行RNN。
- Reduce(g) 产生 g(Reduce([x1, x2, ...,xn]), Reduce( [x(n/2+1), ... xn] )):在平衡树(即图)上应用f,例如对词汇进行最大池化。
动态批处理算法的一个好处是,我们不需要填充单词或截断句子,使之达到相同长度,这给用户提供了极大的便利。
Combinator库旨在简化用户建模过程,同时它也展示了在更高度抽象化时使用动态批处理实现深度学习模型的好处。他们进行了一些实验,将N-ary Tree-LSTM应用在情感分析中,实验结果显示在下表:
表中,标有“fine-grained accuracy”的一列衡量所有的树,基于五种可能的标签进行计算。第二列“binary accuracy”只衡量非中性情感的树,并且基于消极vs积极分类。
从这些表我们可以总结出,相比之前的研究,他们在两种方法上的准确率都更高。同时,动态批处理使用的代码相比于其它方法也更为精简。
讨论
现有的深度学习库大部分只支持对静态数据流图进行批处理。因此,几乎不可能对动态计算图进行有效的批计算。Bowman引入了SPINN架构,这种架构能够对有不同拓扑结构的树进行计算,但是只限于二值树(binary tree)。
在这篇文章中,来自谷歌的M. Looks等人引入了一个新的算法“动态批处理”,同时他们开发了基于Tensorflow的库“TensorFlow Fold”,该库既在理论上也在实验中解决了DCG问题。
通过实验,他们证明了其模型的有效性,而且比之前的研究更加有效。下一步,他们需要用更多的项目来验证该算法的有效性。我们希望该方法也可以用于其他类似的DCG问题,目前,该算法的性能还有很大的提升空间。