《有序混乱:针对边缘设备的不规则连接神经网络的内存感知调度》(三)

整合峰值内存占用约束
在动态编程的基础上,我们叠加特定问题的约束,以实现最优解。具体而言,我们在每个搜索步骤 i 中计算内存占用 u_i+1 及其对应的峰值 upeak_i+1,以选择用于记忆化的最优路径 s^*_i+1。在这里,我们澄清搜索步骤的过程,解释如何计算 upeak_i+1) 并保存 s_i+1。
在每个搜索步骤中,我们从唯一的零入度集合 z_i (签名)开始,该集合保存在记忆化表 M_i 的第 i 项中。对于每个 z_i ,我们附加到当前调度点 s_i 、内存中激活的总和 u_i 以及当前调度的峰值内存占用 upeak_i。因此,在每个搜索步骤 i 中,我们以 s_i 、u_i 和 upeak_i 开始。当我们迭代 z_i 来调度新节点 u_i 时,其输出激活被附加到 s_i 形成 s_i+1,并在内存中分配。节点 u_i 的大小为 ushape 的乘积 Q ,其中形状是激活张量的一个属性,包含通道、高度、宽度和精度(例如字节、浮点数),这个值被添加到 u_i ,因此 u_i+1 leftarrow u_i + Q(u_shape) )。

然后,我们使用 u_i+1 作为 upeak 来更新 upeak_i+1(用于 s_i+1 的峰值内存占用)。由于 u_i 的一些前驱在分配 u_i 后将不再使用,我们通过递减它们来更新节点的出度。更新出度后,我们将得到一个零出度集合,表示准备进行卸载的节点。我们卸载集合中的节点并相应更新 u_i+1。为了演示节点 u_i 的调度,图 6 模拟了在 i = 8 中调度节点 u_8 = H 。在图中,(1) H 被附加到 s_8 并分配到内存中,然后调度器记录此时的最大 upeak_8 和内存中所有激活的总和,作为 upeak_9。然后,它重新计算前驱节点的出度: D 和 E 的出度从 1 减少到 0。(2)然后,这些节点被卸载,此处的激活内存总和被记录为 u_9 。

在这里插入图片描述
查找具有最优峰值内存占用的调度. 调度 u_i 后,我们将新的签名保存到 M_i+1 中以备下一个搜索步骤 i+1 。由于本工作的目标是最小化整体的 upeak,我们通过仅保存具有最小 upeak_i+1 的 s_i+1 来识别每个 z_i+1的相应最优调度 s^i+1。我们整合上述调度 u_i 和更新 M_i+1 的步骤,完成所提议的基于动态编程的调度算法。算法 1 总结了该算法。作为第一步,算法开始初始化记忆化表 M_0 ,然后算法迭代不同的搜索步骤。在每个搜索步骤 i 中,算法对 z_i 中的所有 u_i 执行上述内存分配,并保存 s_i+1)、u_i+1 和 upeak_i+1。在遍历所有搜索步骤到 n-1 后, s^ 被保存在 M_n 中,并具有唯一条目,其中 n 是图 G 中的节点数量。我们在补充材料中提供了峰值内存占用最优性的证明。

算法复杂性. 所提议的基于动态编程的调度算法的复杂性为 O(|V |×2 |V | ) ,这比具有上限复杂度 O(|V|!) 的全面搜索 S_T 快得多。
在这里插入图片描述

图 7. 分治法的示意图,分割图为多个子图(划分),使用最优调度器调度每个子图(征服),然后将子调度连接以获得最终调度(合并)。

由于空间限制,我们将在补充材料中呈现算法复杂性的推导。

3.2 优化调度速度:加速基于动态编程的调度

虽然上述调度算法提高了搜索的复杂度,但由于巨大的不规则性,搜索空间仍可能是难以处理的。因此,我们设计了分治法和自适应软预算,以通过有效缩小和修剪搜索空间来加速搜索。

分治法

从图 1 中我们可以观察到,不规则连接的神经网络拓扑呈沙漏形状,因为许多 NAS 和随机网络生成器设计的单元具有单输入和单输出,然后将它们堆叠形成沙漏形状。文献 (Wilken et al., 2000) 表明,在通用代码调度期间,图可以被划分(划分)为多个子图,相应的解决方案(征服)可以连接(组合)以形成总体问题的最优解决方案。虽然调度算法的复杂性保持不变,但这种分治方法可以减少每个子问题中的节点数量,从而加快总体调度时间。例如,对于一个可以划分为 N 个相等子图的图,调度时间将从 |V |×2 ^ |V | 降低到|V |×2 ^ |V |/N ,根据图的大小和划分数量,我们可以加速调度多个数量级,相比于天真的方法。

因此,图 7 显示了这一见解可以扩展到我们的设置问题,在这里我们可以先对每个单元进行调度,然后将这些解决方案合并以形成最终解决方案。第一阶段是将原始图 G 划分为多个子图 g (划分)。然后,利用子图之间的独立性,可以分别调度每个子图 g 的相应最优调度 s_g (征服)。考虑到子图 g 中的节点数量远小于整个图 G ,调度时间将显著减少。最后,子图的调度被连接,以给出整个图的最优调度 s^* (合并)。

自适应软预算

虽然分治法可以减少节点数量,但由于算法的指数复杂性,调度算法仍可能不够快。因此,我们探索在调度的早期阶段避免次优解,而不影响原始算法的最优性。由于我们的目标是在给定内存预算 τ∗ =µ∗ 内找到一个可运行的单一解决方案,而可以丢弃所有其他解决方案,设置一个大于或等于 µ∗ 的预算 τ,并修剪那些其 µpeak 超过 τ 的次优调度,可以将搜索集中到一个更小的搜索空间 S’T ⊂ST,同时仍然实现最优调度 s* 。在此基础上,我们开发了一个关于τ 的元搜索。这个思路来自于工程师在程序因堆栈溢出失败时(即因过于激进的修剪导致“无解”)购买更大内存(增加τ),以及在当前预算过高时(即因缺乏修剪导致“超时”)卖出多余内存(减少 τ)。SERENITY 利用这一见解,开发了一种自适应软预算方案,在调度时减少整体探索的调度数量。图 8 通过先展示如何在图 8(a) 中根据给定预算τ修剪一些调度,然后在图 8(b) 中展示不同τ 对调度时间的影响,概述了整体思路。
在这里插入图片描述
(a) 虽然路径 s_1 和 s_2 的调度都导致相同的 z_0 ,但它们的 u 和 µpeak 变化,因此我们可以修剪那些导致高于给定预算 τ 的调度。框或圆旁的数字为 u ,边旁的数字为µpeak。

在这里插入图片描述
(b) 自适应软预算以设置硬预算 τmax 作为软预算 τ 的最大值开始。接着,进行 τ 的二分查找,高于 τ * ,以找到解决方案,但不过于高,以便调度快速完成。

图 8(a) 描述了在调度 G 时的某一点,其中节点 G、 H 、 F 和 J 可以被调度。特别地,该图比较了两个可能的解决方案 s_1 和 s_2 ,分别调度 H → F 和 F → H ,给定 τ = 36 。虽然 s_1 和 s_2 的起始状态都是 z 且 u = 32 ,调度 H 导致 µpeak = 32+3 (H) = 35 ,而调度 F 或 J 导致 µpeak = 32+6 (F or J) = 38。因此,由于我们假设 τ = 36 , s_2 和 s_3 将失败,因为 µpeak = 38对于 s_2 和 s_3 超过了 36。因此,只要我们将预算 τ 设定高于 µ* ,调度器仍能找到单一的最优解决方案,同时避免许多次优路径。另一方面,如果 τ < µ* 太小,将导致无解,因为最优路径将被修剪掉。

在这里插入图片描述

在确立修剪的可能性后,我们的问题归结为发现一个大于或等于 u^* 的 τ,我们称之为最优预算 u^,但要足够接近以有效缩小搜索空间。图 8(b) 和算法 2 总结了所提出的自适应软预算。由于我们一开始对τ的近似范围没有信息,我们采用一种常用的拓扑排序算法,称为卡恩算法(Kahn, 1962)(复杂度为 O(|V| + |E|) )来自适应地获取 τ 的范围。我们使用该序列中的峰值内存占用作为我们的硬预算 τmax,与此相对,我们称自适应变化的 τ 为软预算。由于 τmax ≥ µ,我们知道任何 τ ≥τmax 都不需要被探索。拥有这个搜索的上界后,自适应软预算实现了二分查找,首先使用 τ 和 T 作为输入运行调度算法,其中 T 是限制每个搜索步骤调度时间的超参数。如果找到“无解”,则二分查找增加 τ (τnew ← (τnew + τold)/2) ,如果搜索步骤返回“超时”(搜索步骤持续时间超过 T ),则减少 τ (τnew ←τnew/2) 。一旦找到调度(“解决方案”),二分查找停止,使用二分查找的方法保证因为随着τ 的增加,探索的调度数量单调递增。

在这里插入图片描述
图 9. 图重写模式的示意图:通道划分和内核划分分别可以减少卷积和深度卷积的内存成本。

猜你喜欢

转载自blog.csdn.net/weixin_38498942/article/details/143027544