xnor,vhdl中信号都能进行哪些运算?
VHDL提供了6种预定义的运算操作符,分别是:赋值运算符,逻辑运算符,算术运算符,关系运算符,移位运算符,并置运算 符。VHDLl赋值运算符:在VHDL中,赋值运算符用来给信号xnor、变量和常数赋值。赋值运算符包括以下3种:<=用于对SIGNAL赋值。:= 用于对VARIABLE,CONSTANT和GENERIC赋值,也可用于赋初始值。=>给矢量中的某些位赋值,或对某些位之外的其他位(常用OTHERS表示)赋值。VHDL逻辑运算符 在VHDL中,逻辑运算符用来执行逻辑运算操作。操作数必须是BIT,STD_LOGIC或STD_ULOGIC类型的数据(或者是这些数据类型的扩展,即BIT_VECTOR,STD_LOGIC_VECTOR或STD_ULOGIC_VECTOR)。VHDL的逻辑运算符有以下几种:-NOT–取反-AND–与-OR–或-NAND–与非-NOR–或非-XOR–异或XNOR是”同或”运算符,它在VHDL87中没有定义,在VHDL93中被引入。注意,从上至下,这些运算符的优先级是递减的。VHDL算术运算符: 在VHDL中,算术运算符用来执行算术运算操作。操作数可以是INTEGER,SIGNED,UNSIGNED或REAL数据类型,其中 REAL类型是不可综合的。如果声明了ieee库中的包集std_logic_signed和std_logic_unsigned,即可对STD_LOGIC_VECTOR类型的数据进行加法和减法运算。VHDL语言有以下8种算术运算符:+ 加- 减* 乘/ 除** 指数运算MOD 取模REM 取余ABS 取绝对值上述运算符中,加法、减法和乘法运算符是可以综合成逻辑电路的,对于除法运算,只有在除数为2的n次幕时才有可能进行综合,此时除法操作对应的是将被除数向右进行n次移位。对于指数运算,只有当底数和指数都是静态数值(常量或GENERIC参数)时才是可综合的。在算术运算符的使用中,要注意MOD和REM的区别:y MOD x运算的结果是y除以x所得的余数,运算结果通过信号x返回;y REM x运算的结果是y除以x所得的余数,结果通过信号y返回。ABS运算返回操作数的绝对值。上述后3个运算符(MOD,REM和ABS)通常是不可综合的。VHDL关系运算符:在VHDL中,关系运算符用来对两个操作数进行比较运算。VHDL有以下6种关系运算符:= 等于/= 不等于< 小于> 大于<= 小于等于>= 大于等于这里需要注意的是:关系运算符左右两边操作数的数据类型必须相同,这些关系运算符适用于前面所讲的所有数据类型。VHDL移位运算符:在VHDL中,移位操作符用来对数据进行移位操作,它们是在VHDL93中引入的。其语法结构为:<左操作数><移位操作符><右操作数>其中,左操作数必须是BIT_VECTOR类型的,右操作数必须是INTEGER类型(前面可以加正负号)的。VHDL中的移位操作符有以下几种:sll 逻辑左移——数据左移,右端空出来的位置填充’0’srl 逻辑右移——数据右移,左端空出来的位置填充’0’sla 算术左移——-数据左移,同时复制最右端的位,在数据左移操作后填充在右端空出的位置上sra 算术右移——-数据右移,同时复制最左端的位,在数据右移操作后填充在左端空出的位置上rol 循环逻辑左移—–数据左移,同时从左端移出的位依次填充到右端空出的位置上ror 循环逻辑右移——数据右移,同时从右端移出的位依次填充到左端空出的位置上VHDL 并置运算符:在VHDL中,提供了一种并置操作符 , 它的符号如下所示 :& 或者(,,,,)-用来进行位和位矢量的连接运算这里 , 所谓位和位矢量的连接运算是指将并置操作符右边的内容接在左边的内容之后以形成一个新的位矢量.通常采用并置操作符进行连接的方式很多 : 既可以将两个位连接起来形成一个位矢量 , 也可以将两个位矢量连接起来以
过二值化,使模型的参数占用更小的存储空间;同时利用位移操作来代替网络中的乘法运算,大大降低了运算时间。
Stochastic方法:对x计算一个概率p,当p大于一个阙值(计算机随机产生)时为+1,否则为-1。
由于Stochastic方法需要由硬件生成随机数,这比较难实施。所以论文中的实验用的是Deterministic方法。
2、权值更新算法
在理解权值更新之前,先看看前向传播算法。下图为论文中给出的第一个算法,该算法是二值网络的训练算法,其中包括了前向传播和权值更新。
训练时的前向传播:二值网络训练时的权值参数W,必须包含实数型的参数,然后将实数型权值参数二值化得到二值型权值参数,即。然后利用二值化后的参数计算得到实数型的中间向量,该向量再通过Batch Normalization操作,得到实数型的隐藏层激活向量。如果不是输出层的话,就将该向量二值化。
求梯度:根据链式法则,在求解第k层和第k+1层的权值参数的梯度之前,必须先求解第k+1层的误差值即。由于二值网络中,除了输出层,其他隐藏层都经过二值化。所以在求Batch Normalization的参数时,必须先求二值操作层(我们把二值化也当做一层来看待)的梯度,即。其中,可以用
表示。另外一个不同点是,二值网络在对权值求梯度的时候,是对二值化后的权值求梯度,而不是对二值化前的实数型权值求梯度。这是因为二值化前的权值并没有真正的参与网络的前向传播过程。
权值更新:在求权值(W)梯度的时候是对二值化后的权值求梯度,但是在权值更新的时候,是利用上面求得的权值梯度对实数型的权值进行更新。
注:关于Batch Normalization的相关求导可参考我的博文:/linmingan/article/details/50780761
3、乘法优化
Shift-based Batch Normalization:二值网络对Batch Normalization操作的优化主要是通过AP2(x)操作和<<>>操作来代替普通的乘法。AP2(x)的作用是求与x最接近的2的幂次方,如AP2(3.14)=4,AP2(2.5)=2;而<<>>操作就是位移操作。AP2(x)的操作,在作者给出的源码中能够找到;但是<<>>的操作,从源码中只能看到Torch的点乘函数cmul()。(注:Shift-based AdaMax中的乘法操作也是用上述两个操作代替 )
前向传播:二值网络中最重要的乘法优化是前向传播中隐藏层的输出乘以权值W的乘法优化。这个优化是利用两个累积连乘命令完成,即popcount和xnor。下图是论文中BNN的测试时前向传播算法。需要注意的是,只有输入数据是8位二进制,而激活向量和权值矩阵中的元素全都是1位二进制表示的。因此,输入层与第一层隐藏层之间的乘法是用操作实现的。(注:从作者给出的代码来看,似乎并没有采用这个操作,而是直接用普通的乘法。作者在论文中也说明了这一层的乘法的耗费很小。)
对于除了输入层与第一层隐藏层之间的乘法之外,作者的GPU加速算法就是利用操作实现,其中popcount的意思是计算一串二进制串中有多少个1,xnor(代码里面是xor,xnor应该是作者搞错了)就是对两个二进制串按位取亦或。
看个例子,大家就明白怎么计算了。
假设某一层隐藏层的激活向量二值化后a=[1,-1, 1, 1, -1],同时又有二值化后的权值W=[-1,1,1,-1,-1]。在程序中是以a=[1,0,1,1,0],W=[0,1,1,0,0]表示的。
那么按照正常的乘法应该是:
a1*w1+a2*w2+a3*w3+a4*w4+a5*w5=1*-1+-1*1+1*1+1*-1+-1*-1=-1
按照作者给出的操作应该是:
a^W=[1^0,0^1,1^1,1^0,0^0]=11010
Popcount(a^w)=3
这明显不等于-1呀。这是因为作者没在论文中写清楚,我通过作者给的GPU优化代码发现,在进行Popcount(a^w)操作后,还有一个计算,即-(2*Popcount(a^w)-5) = -1;其中5表示的是二进制串的长度,不同的长度的二进制串这个数值是不一样的,因为我这个例子的长度是5,所以才减去5。
4、总结
由于二值网络权值W中的元素只占一位二进制,因此在保存训练好后的模型时所需的内存非常小;同时又去除了普通的乘法操作。在减少模型参数所占的内存和运算量的同时还能保持神经网络的性能,这给深度学习在移动端的应用带来了非常大的前景。