ShiDianNao: Shifting Vision Processing Closer to the Sensor
二、Abstract why?尽管近年来神经网络在很多领域都表现出色,但是神经网络的能效和性能都受限于访存,这在计算机视觉领域主要是指CNN(卷积神经网络),因此,如果要进行CNN在边缘应用中的推广,这是一个必须解决的问题。
how?本文中,作者利用卷积神经网络权重共享的特性,提出了一个叫做ShiDianNao的加速器,它充分进行了数据复用,消除了对DRAM的访问,并且将它直接和传感器相连。
result?作者用65nm工艺实现了一个面积仅为 4.86 m m 2 4.86mm^2 4.86mm2,功耗仅为320mW的加速器,但是它比先前加速器的能效提升了60倍,比高端GPU快了30倍左右。
三、Methods System Integration 上图展示了ShiDianNao的总体架构,整个过程由嵌入式微处理器控制,输入数据直接送入缓冲区,并且为了避免缓存整幅图像,输入输出都是通过串行流式通道的。
起初,人们尝试了CNN纯粹空间上的实现,它为每一个神经元分配一个累加器,为每一个权重分配一个乘法器,虽然晶体管密度在逐年增大,但是人们也发现这种纯粹的空间上的实现对于那种大型CNN是不切实际的,因此人们便开始考虑将整个CNN分块,然后按照时间顺序分别映射这些块到加速器上。 图3展示了几种典型的CNN的实现方式,(d)是本文ShiDianNao的实现方法,它具有以下特征 1.每个处理单元PE负责一个输出神经元,PE按照二维网状排列。 2.每个PE接收被广播的权重
w
i
,
j
w_{i,j}
wi,j。 3.每个PE接收来自右边或者下边PE亦或者是缓存中的的输入特征。 4.每个PE会将和累加,最终得到输出神经元的值。
图4是ShiDianNao的体系结构示意图,主要有以下结构:1个输入特征缓存NBin,一个输出特征缓存NBout,一个权重缓存SB,一个用于计算卷积的神经功能单元NFU,一个用于计算激活函数的ALU,一个缓存指令的IB和一个用于译码的Decoder。 这里,ALU和NFU均是采用16bit定点数计算,原因主要有以下两点: 1)采用16bit定点数对模型准确率几乎没有影响; 2)16bit定点数运算单元所耗费的硬件资源比32bit浮点数运算单元少很多。
本文ShiDianNao中的NFU是一个 P x ∗ P y P_x * P_y Px∗Py的二维PE阵列,因此它比DianNao更加适合处理二维的特征图。 事实上,一种更加直观的方式是实现一个 K x ∗ K y K_x*K_y Kx∗Ky的PE阵列,这 K x ∗ K y K_x*K_y Kx∗Ky个PE负责计算一个输出,但这种方法存在着很多缺点:首先,它会导致复杂的硬件逻辑,其次,为了适应各种尺寸的卷积核,就要求 K x , K y K_x,K_y Kx,Ky可变,这进一步增加了硬件的复杂性。基于此,作者提出了ShiDianNao的NFU结构: 将每个输出神经元映射到单个PE,通过改变输入特征和相应的权重来分时复用PE单元。
图5是NFU的结构示意图,NFU同时读取权重和输入特征,然后将它们分发到各个PE,此外,每个PE单元还有内部的存储结构,以支持PE之间数据的传输。当这些PE计算完成之后,NFU便收集这些结果,然后将其发送给NBin/NBout或者是ALU。
如图6所示,每一个周期,每一个PE都会进行一次乘累加运算(卷积、全连接或者归一化层),或者是一次加法运算(平均池化),亦或者是一次比较运算(最大池化)。每个
P
E
i
,
j
PE_{i,j}
PEi,j都接收三个数据,一是控制信号,还有就是权重和输入神经元,这个输入神经元可能来自
P
E
i
+
1
,
j
PE_{i+1,j}
PEi+1,j,也可能来自
P
E
i
,
j
+
1
或
者
来
自
N
B
i
n
PE_{i,j+1}或者来自NBin
PEi,j+1或者来自NBin。每个PE有两个输出,一个是写到NBin或者NBout的计算结果,另一个则是用于PE间传输数据的。
由于卷积运算的相邻滑动窗口之间有着大量的重复使用的数据,因此,PE之间传输数据能大大缓解存储带宽的需求。每个PE,都可以接受来自右边或者底部PE传递的数据。我们通过设置两个FIFO来实现上述PE间数据传递的功能,分别是FIFO-H和FIFO-V。
(ii)Arithmetic Logic Unit (ALU)在ALU中,作者实现了许多16bit定点运算,包括除法(平均池化和归一化层)和非线性激活函数(tanh、sigmoid),本文中,作者通过分段线性插值来近似激活函数,既加快了速度,又没有很大的精度损失。
Accelerator Architecture: Storage在ShiDianNao中,作者仅使用片上SRAM来存储指令和权重,尽管这似乎令人难以置信,但是最近的研究表明,4.55 KB–136.11 KB的存储空间就能存下大多数实际CNN的权重参数。在本文中SRAM的大小被设为 288 KB,这个大小足以支持以下10个典型的CNN。
上面所说的SRAM,又被分为三部分,分别是存储输入特征的NBin,存储输出特征的NBout和存储权重的SB,而且当所有输出被计算完毕时,NBout转变为下一层的NBin。
如图8所示,NBin被分为
2
∗
P
y
2*P_y
2∗Py行,每行为
P
x
∗
2
P_x*2
Px∗2字节(即
P
x
个
16
位
定
点
数
P_x个16位定点数
Px个16位定点数),NBout和NBin必须足够大,以能够存储整个层的神经元,SB则需要存储整个网络的权重,并且它有Py个Bank。
如图9,NB controller是NBin和NBout的读写控制器,用于支持不同形式的读写模式。
图10展示了NB controller的6种读数据模式: (a)Read multiple banks (#0 to #Py-1). (b) Read multiple banks (#Py to #2Py-1). (c)Read one bank. (d) Read a single neuron. (e)Read neurons with a given step size. (f)Read a single neuron per bank (#0 to #Py-1 or #Py to #2Py-1). 下面举几个例子 卷积运算:在图8(1)中,用到了(a)或(b)这两种数据读取模式,而在图8(3)中,则用到了(c)这种数据读取模式,图8(b)用到了(f)这种读取模式。 池化运算: 用到的读取模式同卷积运算类似,为(a), (b), (c), (e), (f)。 全连接层:使用(d)读取模式,即读取单个输入
a
j
a_j
aj,和多个
W
i
,
j
,
(
i
=
0
,
1
,
2
,
.
.
.
,
P
x
∗
P
y
−
1
)
W_{i,j},(i=0,1,2,...,P_x*P_y-1)
Wi,j,(i=0,1,2,...,Px∗Py−1)相乘得到部分和。 图11展示了NB controller的写模式。
当
P
x
∗
P
y
P_x*P_y
Px∗Py个输出神经元计算结束后,若这个
P
x
∗
P
y
P_x*P_y
Px∗Py个神经元位于输出特征图的2kPx,…,((2k + 1)Px-1)列,则它们被一起写回Bank #0至Bank #Py-1,否则,它们被写回到Bank #Py至Bank #2Py-1。 这种排布方式也说明了为什么卷积计算中的(f)是
P
y
至
2
P
y
−
1
P_y至2P_y-1
Py至2Py−1里的列被读入NFU。
作者发现,如果按照每个周期一条指令来配置ShiDianNao,那么存储指令所需的存储空间将非常大,因此作者采用了一种two-level Hierarchical Finite State Machine (HFSM)的方式来描述加速器的执行过程。 如图12所示,第一个层次描述的是比较抽象的任务,例如卷积、池化、全连接等等,而第二个层次是对第一个层次中的任务的细分,图12右半部份就显示了Conv的第二层执行过程。 这样,就可以用一个61bit的指令去描述这些状态以及相关的参数,得益于HFSM,现在一个执行需要50K个周期的CNN只需要1KB的指令缓存就能满足,并且译码器的开销也非常小。
如上图所示,
P
x
=
P
y
=
2
,
K
x
=
K
y
=
3
,
S
x
=
S
y
=
1
P_x=P_y=2,K_x=K_y=3,S_x=S_y=1
Px=Py=2,Kx=Ky=3,Sx=Sy=1,则
P
E
0
,
0
负
责
计
算
浅
蓝
色
窗
口
,
P
E
1
,
0
负
责
计
算
红
色
窗
口
P
E
0
,
1
负
责
计
算
紫
色
窗
口
,
P
E
1
,
1
则
负
责
计
算
绿
色
窗
口
。
整
个
过
程
可
以
概
括
如
下
PE_{0,0}负责计算浅蓝色窗口,PE_{1,0}负责计算红色窗口\\PE_{0,1}负责计算紫色窗口,PE_{1,1}则负责计算绿色窗口。\\整个过程可以概括如下
PE0,0负责计算浅蓝色窗口,PE1,0负责计算红色窗口PE0,1负责计算紫色窗口,PE1,1则负责计算绿色窗口。整个过程可以概括如下 第0个周期将每个PE负责计算的窗口的第一个输入神经元发送到每个PE,并广播第一个权重,作乘累加运算,之后的K-1个周期,最右边的那一列PE接收来自NBin的下一列的神经元,而前边的
P
x
−
1
P_x-1
Px−1列则接收右边毗邻PE传递过来的神经元(数据复用)。第K个周期时,由于卷积窗口的一行已经计算完毕,因此需要读入下一行,即PE阵列的底部一行从NBin读入下一行,而非底部的那些行则接收来自下面那行传递上来的神经元,然后继续水平方向移动K-1个周期,再垂直方向移动一个周期…直至完成整个窗口的计算(K*K个周期)。
如图14,是池化运算的示意图,这里 P x = P y = K x = K y = S x = S y = 2 P_x=P_y=K_x=K_y=S_x=S_y=2 Px=Py=Kx=Ky=Sx=Sy=2,由于K=S,因此没有可以复用的数据,但是也存在S
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?