如前所述,数据缓存是创建高效DNN加速器的关键组件之一。因此,除了选择适当的数据流(控制数据缓存的位置和时间)外,DNN加速器还需要一个缓存方案,该方案应寻求实现以下目标:
l 以高效并及时的方式准确地传送数据的consumer需要的数据;
l 将未来所需数据的接收与当前正在使用的数据的使用重叠;
l 在不再需要数据时删除数据;
l 通过同步来完成上述所有操作。
一般来说,可以实现这些目标的称为实现良好的数据编排。[170]中对当前数据编排方法的分类如图5.29所示。在图中,buffer的用法沿着两个轴进行划分。在较高的层次上,沿一个轴的implicit/explicit区分是指利用工作负载来控制数据缓冲决策的程度,而在另一个轴上的coupled/decoupled是指内存响应和请求是往返(请求-响应)还是向前流(自动将数据推送给consumer)。
图5.29: 数据编排方法的分类。假设通信(带箭头的线)在硬件通道(通常是 NoC 链路)上传输。 (图来自[170])
5.8.1 隐式与显式编排
在通用计算中,cache是主要的缓冲机制,并且基于加载/存储操作。缓存有几个理想的属性,例如以不可见的方式组合成层次结构。内存级并行性(多个未完成的填充以及填充和访问当前内容之间的并发性)可以使用经过充分研究的附加硬件(通常称为无锁缓存结构)来实现。
Cache可以被描述为执行implicit式数据编排,因为加载请求发起者不直接控制缓存层次结构关于响应数据是否保留在存储层次结构的任何给定级别上的决策,也不直接控制何时删除响应数据。启发式替换策略在通用场景中是有利的,因为它们与工作负载无关。另一方面,对于DNN加速器来说,标签匹配和关联集等特征的面积和能量开销很高。
Cache的另一种替代方法是使用scratchpad,它为加载和存储了特定暂存缓冲区的地址范围,从而支持对数据编排的显式和精确控制 (在图5.29中,这是由管理本地和全局请求/响应的数据路径表示的)。GPU的共享scratchpad [171]是这种显式数据编排习惯用法的一个例子。scratchpad的大小和地址范围在体系结构上是公开的,数据进出scratchpad的传输是通过明确的指令进行管理的。虽然scratchpad避免了缓存的硬件开销,但提取内存并行性(跨填充和重叠填充和访问)既繁琐又容易出错,因此很难将它们组合成层次结构。
5.8.2 耦合和解耦编排
缓存和暂存区都使用加载/存储模式,其中请求的发起方也接收响应。这被称为数据的耦合分段,反映在图5.29的左列中。有了这种设置,数据需求和数据可用性之间的同步既高效又直观——当相应的响应返回时(load-use)会通知请求者。缺点是,由于单个requester/consumer必须在请求和使用响应之间交替,它使数据块的填充和访问重叠(例如,通过双缓冲)变得复杂。此外,传入数据tile的“landing zone”必须在整个往返加载延迟期间保留(因此是空闲的),这增加了内存资源的压力,否则内存资源可能会用于更大的瓦tile size。
另一种选择是将负载请求启动器与响应接收器解耦(在图5.29中,这由指向不同模块的请求/响应箭头表示)。在这种设置中,一个单独的硬件模块(例如DMA引擎或地址生成器(AGEN))负责将数据推入一个或多个功能单元的缓冲器。为了容忍延迟,这些缓冲器通常是双缓冲的,有时被称为ping-pong buffers [172, 173]。这种方法的主要优点是,请求者可以以自己的速率运行,并且可以将数据多播到多个同时使用的用户。此外,pipeline的前馈特性意味着只需要按层次结构相邻级别之间的延迟比例保留tile landing zone,而不是整个层次结构遍历往返,从而增加对同等大小内存的利用率。最后,这种方法通常可以传输大数据块(即批量传输,这比小请求更有效),这些数据块必须动态地重新合并对同一内存行的访问。
这种分离的producer/consumer方法类似于Smith[174]的通用计算架构的decoupled access execute (DAE)风格。在DAE组织中,两个处理器通过硬件队列连接。访问处理器负责执行所有地址计算和生成负载——类似于DMA引擎。负载响应被传递给执行处理器——类似于加速器的功能单元及其本地staging缓冲区。DAE提高了并行性,减少了指令的关键路径,同时允许两个处理器以其自然速率进行计算。然而经典的DAE并没有显式地控制数据编排缓冲区——关于暂存在数据的决策仍然由缓存层次管理,因此图5.29将DAE归类为隐式解耦。
5.8.3 显式解耦数据编排(EDDO)
DNN加速器中最常见的缓冲方法是显式解耦数据编排(EDDO)。硬件FIFO[175,176]是一种传统的可重用EDDO分段缓冲结构。其优点是FIFO通过头指针和尾指针清晰地封装了同步,并且易于分层组合。然而在实践中FIFO不够灵活,无法满足DNN加速器的需求,因为DNN加速器经常在一个窗口内重复访问(例如,在执行卷积时)。此外,对于部分和之类的数据类型,分级数据必须在清除之前进行多次修改。这在没有昂贵的再循环的单写端口FIFO中是不可能的。
一些深度神经网络加速器[142, 152, 159, 177, 178]已经将显式解耦数据编排(EDDO)方案作为定制缓冲机制纳入其中,并提出了其他特定的EDDO缓冲方案,如DESC[179]。然而,为了说明典型的EDDO方案将描述buffets[170],它是Eyeriss[101]中数据编排方案的概括。
从本质上讲,buffet的操作就像FIFO一样,值从输入NoC链路(即硬件通信通道)填充到由头和尾指针控制的圆形缓冲区中。只有当填充发生时,值才会从填充NoC链接中删除。对缓冲区中的数据的访问是由读取命令提供的,但是与只能在其头部读取的FIFO不同,buffet读取增加了一个地址,这被解释为头部的偏移量。在buffet中保留一组值并多次读取它们可以重用数据块。与填充类似,read命令只在读取值可以在读取值NoC链路上发送时才会执行(即,NoC链路没有阻塞)。
Buffets还支持在其缓冲区中更新值。只允许更新之前读过的值,并使用read+update命令读取位置的值。这使得buffet支持存储和更新partial sum。
最后,buffet提供了一个shrink操作,从缓冲区的头部删除指定数量的项。shrink可以让人轻松地释放tile占用的空间。为了避免在切换tile时发生延迟,可以定义一个比buffet尺寸小的tile。因此,在处理前一个tile片时,可以开始填充下一个tile。然而,额外的空间只需要足够大,就避免在下一个tile上开始工作之前的启动瞬态。这通常比双缓冲所需的空间要小得多。
shrink不需要移除整个tile。只移除tile的一部分(例如,只移除一个值),然后从零偏移开始按顺序再次读取,这样buffets就可以支持滑动窗口。
图5.30给出了buffet的框图。当操作(命令或填充)所需的所有输入NoC链接上都有值,并且输出NoC链接中有空间(仅用于读取)时,就会发生操作。图中所示的活动如下。
图5.30: buffet框图: 主要的输入是一个fill value; a read address and read value; an update address, and update value; 以及一个command,可以指定是执行读取、读取+更新还是shrink。唯一的输出是一个read value。head、tail和date单元在内部提供了同步,通过暂停操作来保持正确的顺序。
l 正在调用read命令(r),该read命令将读取地址(1)作为从head的偏移量来产生read value(d)
l Update address (3)处的更新正在将update value(f’)写入buffet。请注意,这是允许的,因为较早的命令必须是偏移量3处的read+update
l Fill value(k)即将写入buffet的尾部tail
上述所有活动都是在buffet内部通过head、tail和最新状态进行协调的,这保证了正确的ordering。例如,一个read操作必须等待数据filled and updated (如果之前有一个read+update)。fill必须等到缓冲区有空间。
这里没有说明shrink命令,它只是在等待未完成的更新后调整头部指针,从buffet头部删除给定数量的值。
图5.31展示了一个简单的示例,演示了buffet是如何自然组合的,并可以用来处理滑动窗口和更新。L1输入buffet与L0输入buffet的自然组合允许外部无同步填充,因为填充由每个buffet的内部排序控件控制。在L0 Input Buffet中的1个shrink会创建一个输入滑动窗口,因此输入的相对序列将是0, 1, 2, 1, 2, 3, 2, 3, 4......内部同步还控制partial sum的更新。
图5.31: buffet示例——一个类似于Eyeriss的全局缓冲区和使用buffet构建的PE的示例。对L1输入buffet的读取填充L0 buffet,L0 buffet执行读取,将输入滑动窗口传递给乘法器。L0输出缓冲区执行一系列read+update命令来生成partial sum。Weight buffet没有显示。
总之,在DNN加速器设计中需要有效的数据编排,并且通常由管理数据移动的机制(如buffet)提供。这通常在设计中表现为明确的控制,其中数据在存储层次结构中被确定地推送,避免了昂贵的往返通信,并最大限度地减少了“landing space”存储需求。通过解耦的活动还可以提高效率,其中硬件提供所需值的本地确定和本地同步控制。显然,并非每个存储缓冲区都需要buffet的完整语义,因此可以采用这些语义子集的优化实现或其他提供类似好处的自定义设计。
-
加速器
+关注
关注
2文章
796浏览量
37840 -
缓冲器
+关注
关注
6文章
1921浏览量
45473 -
FIFO存储
+关注
关注
0文章
103浏览量
5968 -
AI芯片
+关注
关注
17文章
1879浏览量
34992
发布评论请先 登录
相关推荐
评论