将各种各样的数据抽象成张量表示,然后再输入神经网络模型进行后续处理是一种非常必要且高效的策略,这样做能够统一不同类型的数据,将它们用标准的方式表现出来。此外,当数据处理完成后,还可以将张量转换为其他想要的格式。 2. 运算 接下来是对张量对象的数学运算和处理。
我们可以将神经网络视为对输入张量进行一系列运算从而实现某个目的的过程。这些运算包括简单的矩阵乘法,也可以是卷积、池化和LSTM等稍复杂的运算。而且各框架支持的张量操作通常也不尽相同,详细情况可以查看其官方文档(如下为NumPy、Theano和TensorFlow的说明文档)。 NumPy: Theano: TensorFlow: https://www.tensorflow.org/api_docs/python/math_ops/ 需要指出的是,大部分的张量操作都是基于类实现的(而且是抽象类),而并不是函数(这一点可能要归功于大部分的深度学习框架都是用面向对象的编程语言实现的)。这种实现思路一方面允许开发者将各种类似的操作汇总在一起,方便组织管理。另一方面也保证了整个代码的复用性、扩展性和对外接口的统一。总体上让整个框架更灵活和易于扩展,为将来的发展预留了空间。 3. 计算图和优化 有了张量和基于张量的各种操作之后,下一步就是将各种操作整合起来,输出需要的结果。 但很可惜,随着操作种类和数量的增多,有可能引发各种意想不到的问题,包括多个操作之间应该并行还是顺次执行,如何协同各种不同的底层设备,以及如何避免各种类型的冗余操作等等。这些问题有可能拉低整个深度学习网络的运行效率或者引入不必要的Bug,而计算图正是为解决这一问题产生的。 它包含到各种Ops实例的链接,以及操作需要输出哪个操作以及附加信息的关系。不同的框架有不同的方式实现。 将计算图作为前后端之间的中间表可以带来良好的交互性,开发者可以将Tensor对象作为数据结构,函数/方法作为操作类型,将特定的操作类型应用于特定的数据结构,从而定义出类似MATLAB的强大建模语言。 需要注意的是,通常情况下开发者不会将用于中间表示得到的计算图直接用于模型构造,因为这样的计算图通常包含了大量的冗余求解目标,也没有提取共享变量,因而通常都会经过依赖性剪枝、符号融合、内存共享等方法对计算图进行优化。 目前,atv,各个框架对于计算图的实现机制和侧重点各不相同。例如Theano和MXNet都是以隐式处理的方式在编译中由表达式向计算图过渡。而Caffe则比较直接,可以创建一个Graph对象,然后以类似Graph.Operator(xxx)的方式显示调用。 因为计算图的引入,开发者得以从宏观上俯瞰整个神经网络的内部结构,就好像编译器可以从整个代码的角度决定如何分配寄存器那样,计算图也可以从宏观上决定代码运行时的GPU内存分配,以及分布式环境中不同底层设备间的相互协作方式。除此之外,现在也有许多深度学习框架将计算图应用于模型调试,可以实时输出当前某一操作类型的文本描述。 4. 自动微分工具 拥有计算图(computational graph)的另一个好处是,学习阶段的计算梯度变得模块化,简单明了,便于计算。这要归功于chain rule,它们能让你以系统的方式计算函数组成的导数(derivatives)。正如我们所见,神经网络能够被认为是简单的非线性组合,进而产生更加综合性的函数。区分这些函数只是简单地将图形从输出返回到输入。符号微分或自动微分是一种可以在计算图中计算梯度的程序化方法。 符号微分指的是分析性地计算导数。例如,你能得到关于梯度是什么的表示。为了使用符号微分,你只需要把Value 嵌入到导数中,然后直接使用。不幸的是,一些非线性,比如ReLU (Rectified Linear Units)在一些点是不能微分的。因此,我们以迭代方式计算梯度。由于第二种方法可以普遍使用,大多数计算图包,如计算图工具包() 来实现自动微分。 (责任编辑:本港台直播) |