system: [SYSTEM]

user: 5. 基于计算图顶点消除的伴随计算优化技术 业务变分资料同化系统一般应用梯度类算法进行求解，因此如何快速、准确、高效地计算梯度信息，对于变分资料同化求解具有重要意义。计算梯度需要求解目标函数相对于每一个控制变量的导数。计算导数方法主要有：有限差分法、直接计算法以及伴随方法，等等。若计算目标函数相对于一个控制变量的导数，有限差分法必须至少计算两次目标函数，因此其计算量与设计变量数量成正比。此外，由于计算机有效数字位数的限制，差分步长的选择将严重影响导数的计算精度。复变量差分法可以获得目标函数相对于设计变量的精确导数，而且受差分步长影响较小，其计算目标函数相对于一个设计变量的导数需要进行一次带复变量扰动的目标函数计算，因此其计算量也与设计变量个数成正比 [ 5 ]。在典型变分资料同化求解问题中，作为控制变量的初始场维数超过千万。在这种问题中，若采用限差分法或复变量差分法，计算一次梯度将需要反复调用数值预报模式求解目标函数，产生极大的计算代价。伴随方法通过求解原始数值预报模式的伴随方程，只需要经过一次方程求解过程，即可获得目标函数相对于所有设计变量的导数。伴随方程求解梯度过程中，其计算量与控制变量个数之间基本可实现解耦合，并且精度较高，在大规模最优化问题中具有显著优势。离散伴随方法可以计算得到机器精度的目标函数导数信息，且计算代价合理，与其它方法相比具有明显优势。该方法的基本思想是在数值预报模式计算中，无论计算过程或函数如何复杂，在本质上都是执行一系列的初等计算、初等函数及逻辑运算的有限次组合。对这些初等运算迭代运用链式求导法则，然后将初等函数微分进行连续逆向累积得到复杂函数的微分信息，最终可以精确地得到目标函数的导数信息。为了说明各种方法的优劣，以计算下面函数的梯度作为示例。虽然用作实例说明的函数形式上简单，但具有典型代表性。 y = f ( x 1 ， x 2 ， x 3 ) = cos [ ( x 1 + x 2 + x 3 ) ⋅ x 3 1 / 2 ] (19) 首先定义独立变量 x i ( i = 1 ， 2 ， 3 )和引入中间变量 v i ( i = 1 ， 2 ， 3 ， 4 )，将函数计算过程分解成一系列的基本运算序列，如表1中左栏所示。 直接计算方法是按照从自变量(Independent Variable)到因变量(Dependent Variable)的方向将求导法则应用到表1左栏所示的函数计算序列中。从自变量到最终函数传递中间变量关于自变量的梯度向量，同时得到函数值以及具有机器精度的梯度值，具体如表1中栏所示。离散伴随方法与直接计算方法完全相反，是按照从因变量到自变量反方向逐次计算梯度信息，如表1右栏所示，变量 v i 的伴随 v ¯ i 被定义为因变量y关于 v i 的导数。在伴随方法中首先正向执行最左栏的函数计算序列，并记录中间变量，然后通过传递因变量与自变量之间的导数关系，反向累积得到导数信息。 Table 1 Computation sequence of the function (19) and its gradient calculation by the direct and adjoint method respectivel 函数计算序列 直接计算方法 离散伴随方法 x 1 ∇ x 1 = [ 1 0 0 ] x ¯ i = 0 ， i = 1 ， 2 ， 3 x 2 ∇ x 2 = [ 0 1 0 ] v ¯ i = 0 ， i = 1 ， 2 ， 3 ， 4 x 3 ∇ x 3 = [ 0 0 1 ] y ¯ = 1 v 1 = x 1 + x 2 ∇ v 1 = ∇ x 1 + ∇ x 2 v ¯ 4 = v ¯ 4 − y ¯ ⋅ sin v 4 v 2 = v 1 + x 3 ∇ v 2 = ∇ v 1 + ∇ x 3 v ¯ 2 = v ¯ 2 + v 3 ⋅ v ¯ 4 ， v ¯ 3 = v ¯ 3 + v 2 ⋅ v ¯ 4 v 3 = x 3 ∇ v 3 = ∇ x 3 / ( 2 x 3 ) x ¯ 3 = x ¯ 3 + v ¯ 3 / ( 2 x 3 ) v 4 = v 2 ⋅ v 3 ∇ v 4 = ∇ v 2 ⋅ v 3 + v 2 ⋅ ∇ v 3 v ¯ 1 = v ¯ 1 + v ¯ 2 ， x ¯ 3 = x ¯ 3 + v ¯ 2 y = cos v 4 ∇ y = − ∇ v 4 ⋅ sin v 4 x ¯ 1 = x ¯ 1 + v ¯ 1 ， x ¯ 2 = x ¯ 2 + v ¯ 1 表1. 函数(19)式的计算序列、基于直接方法和伴随方法计算梯度的序列 图模型是在研究变量之间因果关系时被广泛应用的工具，对表1中的三种类型计算都可以通过计算图表示。首先定义图 G = ( V ， E ) ，其中 V = { v i | i = 1 ， 2 ， ⋯ ， | V | } 是图 G 中顶点所代表的变量集合，表示数值计算过程应用中所有计算子任务的集合； E = { e k | k = 1 ， 2 ， ⋯ ， | E | } 是图 G 的边集合，表示不同顶点代表的变量之间的依赖关系。图模型中的边表示为 e k = ( v i ， v j ) ，其中 v i 和 v j 分别表示边 e k 的起点和终点，只有在 v i 执行完毕之后才可以执行 v j 。如果 ( v i ， v j ) 和 ( v j ， v i ) 都属于 E ，则在图 G 中顶点 v i 和 v j 之间的边为无向边，即只是一条简单的连线。如果只有 ( v i ， v j ) ∈ E ，则在 G 中表现为 ，即为有向边。如果 中只存在有向边或无向边，则分别称为有向图和无向图。表1左栏计算过程可以通过计算图表示，具体如图2所示。图中的顶点包含了函数(19)式中间变量的所有计算过程，在计算中每一个顶点只有当它的所有前驱顶点成功执行之后才被执行。在计算图顶点集合中存在两类特殊顶点：无任何前驱的顶点为输入顶点，无任何后继的顶点为输出顶点。因为在图中不存在任何回路，所以这种图一般被称为有向无环图(Directed Acyclic Graph，简称DAG)。如果计算出每一个顶点所定义的基本函数关于前驱顶点变量的局地偏导数，并作为计算子任务放置在DAG图形边上，那么就产生了如图3所示的线性化DAG (Linearizd DAG，简称LDAG)。从图3可知，放置在图形边上的导数表达式与表1中间栏中的偏导数是相同的，因此线性化DAG表示的是基于直接方法计算梯度的过程。因为直接方法的计算复杂性与独立变量数量成正比，所以需要三次遍历图3才能计算出所有导数向量。 图2. 函数 的有向无环图 图3. f的线性化有向无环图 如果将图3线性化DAG中每一条有向边的方向设置为相反方向，并根据伴随关系(表1右栏所示)重新设置顶点变量和每条边上的计算子任务，则得到如图4所示的伴随DAG (Adjoint DAG，简称ADAG)。ADAG和LDAG的计算顺序完全相反，在ADAG中伴随量将从依赖输出量(y)逆向传播到独立输入量(即自变量 、 和 )，直到梯度被完全累积计算，即通过对ADAG的一次逆向遍历计算就能获得梯度向量。从上到下依次计算这些操作产生了输入变量的伴随值 ，即梯度量。伴随状态用零初始化。一个变量的伴随可以通过计算LDAG中其所有后继变量伴随量的加权和得到，而权重就是局地导数。伴随(信息)量的传播能够通过图4所示的伴随DAG图形显示出来。伴随方法一个明显的缺点是需要存储整个计算图来完成导数计算，在解决大规模问题时需要相当大的内存。利用稀疏分布特征，可以实现Jacobian矩阵的压缩存储，从而减小计算机内存需求。下面通过采用基于计算图顶点消除方法，进一步减小伴随计算内存需求和计算代价。 对比图4和图5可知，在伴随DAG中消除顶点 和 后，计算梯度所需要的计算初等函数次数将由8次减小到6次，即减小的计算次数为消除的图顶点总数。说明通过消除伴随计算图中的顶点能够减小计算代价，函数(19)式表示的只是某个子计算过程或伴随程序代码的运算情形，如果对变分资料同化中每个伴随程序采用类似的方法进行改写，特别是针对某些反复调用的热点伴随程序进行优化改进，将大大减小计算量。在变分资料同化中主要计算过程是迭代最优化过程中的切线性模式正向积分步程序和伴随模式逆向积分步程序，在采用特定的时空离散格式后两者的结构是固定不变的，因此可以通过消除计算图顶点的优化技术对程序进行改进后永久使用，而不需要每次调用之前都对伴随程序进行优化。 图4. f的伴随有向无环图 图5. f经过改进后的伴随DAG