一种残膜回收机防缠绕挑膜装置的制 一种秧草收获机用电力驱动行走机构

一种基于4bit到6bit的独立卷积3的制作方法

2022-12-20 20:30:57 来源:中国专利 TAG:

一种基于4bit到6bit的独立卷积3
×
3的设计方法
技术领域
1.本发明涉及图像处理技术领域,特别涉及一种基于4bit到6bit的独立卷积3
×
3的设计方法。


背景技术:

2.集成电路技术现在越来越成为技术的焦点,很多芯片厂商也都开发自己的芯片。而在芯片应用中,在各自的芯片设计中也会产生各自的问题。例如,北京君正集成电路股份有限公司生产的芯片,在北京君正的芯片上,直接使用c程序速度慢,不合理的使用有限的指令导致运行时间很慢。此外,例如北京君正的芯片t30和芯片t31的寄存器是128位寄存器,并且寄存器个数是有限的,这在优化设计中要考虑寄存器个数问题;simd指令集有限,有些运算需要使用几种指令才能实现其运算。而且,卷积核数据的有限数据是4bit、5bit或是6bit,在存储时是按照8bit存储。输出数据即特征图的深度是16的倍数。卷积计算中使用的步长是1、2或3,实际使用中没有超过卷积核长宽的步长或是失去使用的意义,卷积核中宽是3,长是3。因此在北京君正芯片上,直接使用c程序速度很慢,不合理的使用有限的指令也导致运行时间很慢。
3.另外,现有技术中的常用术语如下:
4.1、simd指令:单指令流多数据流,即一次运算指令可以执行多个数据流,这样可以提高程序的运算速度。更通俗理解,就是一种矢量(向量)的计算。不同芯片,具体指令集不同。
5.2、卷积核:卷积核是用来做图像处理时的矩阵,与原图像做运算的参数。卷积核通常是一个列矩阵数组成(例如3*3的矩阵),该区域上每个方格都有一个权重值。矩阵形状一般是1
×
1,3
×
3,5
×
5,7
×
7,1
×
3,3
×
1,2
×
2,1
×
5,5
×
1,
……

6.3、卷积:将卷积核的中心放置在要计算的像素上,一次计算核中每个元素和其覆盖的图像像素值的乘积并求和,得到的结构就是该位置的新像素值,这个过程称为卷积。
7.4、独立卷积:一个卷积核负责一个通道,一个通道只被一个卷积核卷积计算。
8.5、特征图:输入数据通过卷积计算后得到的结果称之为特征图(或输出数据),数据通过全连接后生成的结果也称为特征图(或输出数据)。特征图大小一般表示为长
×

×
深度,或1
×
深度。


技术实现要素:

9.为了解决上述现有技术中的问题,本技术的目的在于:实现速度的成倍提升,特别是相对于使用c程序提升速度。
10.本优化方法是基于芯片厂商特别是北京君正生产的t30,t31等t系列芯片中的simd指令集设计的一种优化方法。该方法适合矢量(向量)指令的运算。
11.具体地,本发明提供一种基于4bit到6bit的独立卷积3
×
3的设计方法,所述方法是将需要优化转化的数据顺序预先进行转化,即在卷积核数据的存储过程中,将相邻两个
深度的数据交叉存储,最后一个深度的数据与0交叉存储;并且在后面的卷积计算过程中,将原有的特征图数据调整顺序,再进行使用相乘再相邻相加的simd指令,从而使得8bit数据相乘相加后数据变为16bit;将卷积核数据顺序进行调整,存成使用时需要的顺序。是在使用前或成为计算前已经使用相关方法将卷积核数据进行交叉处理好。使用特定的simd指令,不能按照原有的特征数数据顺序进行加载运算,必须先将顺序调整到符合将要使用的指令需要的数据顺序,才能得到正确的结果。这里就是将加载的数据调整顺序,再进行simd指令的操作。还有其他一种指令,就是保留原来特征图中数据的顺序进行simd指令运算,后面需要很多处理转化,但这种指令效率很低,因而本技术并没有使用。
12.所述方法进一步包括以下步骤:
13.s1,输入数据并存储,其中,卷积核数据存储方式优化存储的处理:由于后面卷积计算是独立卷积,是9对数据相乘后,累加到一起,是生成的一个数据;而在指令集中只有一个指令能够满足相乘再相邻相加的结果的位数是16bit;两个4bit相乘,再相加,后面再累加9次(卷积核是3x3),不会超过16bit,但可能超过8比特。所以要求结果是16bit,就足够。同时可以提升运算效率。加载数据会增多。根据这个指令的使用,需要对数据进行交叉存储,并且需要增加一个0;将相邻两个深度的数据交叉存储,最后一个深度的数据与0交叉存储;
14.s2,利用simd指令进行simd指令优化算法的设计,实现卷积计算:将做卷积的特征图中的3
×
3个深度的数据,每两个深度一组进行交叉处理,可以组成4组,同时剩余一个深度数据,剩余的一个深度数据与0组合,此时是组成5组深度数据;
15.s3,将步骤s2中组成5组深度数据与步骤s1中已经处理好的卷积核数据进行对应的计算,所有数据对应相乘,再累加。
16.所述步骤s1中,输入数据是按照先深度再宽最后高的顺序存储数据;在计算时是考虑到数据的空间结构,在存储中,是一个向量的存储方式。
17.所述步骤s1中卷积核初始存储:设一个卷积核数据相关信息,输出深度out_dep是4,卷积核宽度为3,卷积核高度为3;数据的连续方式为在输出深度方向连续,然后由3组输出深度方向,其中每个方向是4个数据,12个数据组成宽度上的一组数据,最后有3组宽度上的数据组成高度上的数据。
18.所述方法在实际使用中使用的输出深度都是16的倍数。
19.所述步骤s1进一步包括:
20.设输入数据indata是一组输入深度in_depth为32,宽度in_width为256,高度in_height为256的数据;
21.卷积核数据filter_data为一组输出深度out_depth为32,卷积核宽ft_w为3,卷积核高ft_h为3的数据;
22.设输出数据即特征图outdata的结构:
23.深度为out_depth,此处与输入数据的输入深度一样,为32,宽度为out_width,高度out_height;
24.在卷积计算中,存在一个步长,设步长为stride:
25.输入数据的3
×
3个输入深度方向的数据为:
26.[ax1,ax2,ax3,ax4,ax5,ax6,ax7,ax8,ax9,ax10,ax11,ax12,ax13,ax14,ax15,
ax16,

ax32]
[0027]
[bx1,bx2,bx3,bx4,bx5,bx6,bx7,bx8,bx9,bx10,bx11,bx12,bx13,bx14,bx15,bx16,

bx32]
[0028]
[cx1,cx2,cx3,cx4,cx5,cx6,cx7,cx8,cx9,cx10,cx11,cx12,cx13,cx14,cx15,cx16,

cx32]
[0029]
dx1,dx2,dx3,dx4,dx5,dx6,dx7,dx8,dx9,dx10,dx11,dx12,dx13,dx14,dx15,dx16,

dx32]
[0030]
ex1,ex2,ex3,ex4,ex5,ex6,ex7,ex8,ex9,ex10,ex11,ex12,ex13,ex14,ex15,ex16,

ex32]
[0031]
[fx1,fx2,fx3,fx4,fx5,fx6,fx7,fx8,fx9,fx10,fx11,fx12,fx13,fx14,fx15,fx16,

fx32]
[0032]
[gx1,gx2,gx3,gx4,gx5,gx6,gx7,gx8,gx9,gx10,gx11,gx12,gx13,gx14,gx15,gx16,

gx32]
[0033]
[hx1,hx2,hx3,hx4,hx5,hx6,hx7,hx8,hx9,hx10,hx11,hx12,hx13,hx14,hx15,hx16,

hx32]
[0034]
[jx1,jx2,jx3,jx4,jx5,jx6,jx7,jx8,jx9,jx10,jx11,jx12,jx13,jx14,jx15,jx16,

jx32]
‑‑‑‑‑
(7)
[0035]
卷积核原始数据为:
[0036]
[a1,a2,

,a32;b1,b2

,b32;c1,c2,

,c32;d1,d2,

,d32;e1,e2,

,e32;f1,f2,

,f32;g1,g2,

,g32;h1,h2,

,h32;j1,j2,

,j32];
‑‑‑‑‑
(8)
[0037]
卷积核优化数据为:
[0038]
[a1,b1,a2,b2,

,a16,b16;c1,d1,c2,d2,

,c16,d16;e1,f1,e2,f2,

,e16,f16;g1,h1,g2,h2,

,g16,h16;j1,0,j2,0,

,j16,0];
[0039]
[a17,b17,a18,b18,

,a32,b32;c17,d17,c18,d18,

,c32,d32;e17,f17,e18,f18,

,e32,f32;g17,h17,g18,h18,

,g32,h32;j17,0,j18,0,

,j32,0];
‑‑‑‑‑
(9)。
[0040]
所述步骤s2中,所述做卷积的特征图中的3
×
3个深度的数据,如数据(7);
[0041]
所述组成5组深度数据,如数据(10):数据结构为:
[0042]
[ax1,bx1,ax2,bx2,

,ax16,bx16,ax17,bx17,

,ax32,bx32]
[0043]
[cx1,dx1,cx2,dx2,

,cx16,dx16,cx17,dx17,

,cx32,dx32]
[0044]
[ex1,fx1,ex2,fx2,

,ex16,fx16,ex17,fx17,

,ex32,fx32]
[0045]
[gx1,hx1,gx2,hx2,

,gx16,hx16,gx17,hx17,

,gx32,hx32]
[0046]
[jx1,0,jx2,0,

,jx16,0,jx17,0,

,jx32,0]
‑‑‑‑‑
(10)。
[0047]
所述步骤s3,提前到卷积核存储中,将数据顺序调整好,存成使用需要的顺序的整个实现的伪代码如下:
[0048]
simd类型变量寄存器:
[0049]
sum_0,sum_1;
[0050]
in_value0,in_value1,in_value2,in_value3,in_value4,in_value5,in_value6,in_value7,in_value8,in_value9;
[0051]
in_0,in_1,in_2,in_3,in_4,in_5,in_6,in_7,in_8,in_9;
[0052]
in_value,cvft_0,cvft_1,cvft_2,cvft_3,cvft_4,cvft_5,cvft_6,cvft_7,cvft_8,cvft_9;
[0053]
stride为步长;
[0054]
in_data为输入的特征图数据;
[0055]
input_height为输入的特征图数据的高;
[0056]
input_width为输入的特征图数据的宽;
[0057]
input_depth为输入的特征图数据的深度;
[0058]
output_data为输出特征图数据;
[0059]
output_height为输出特征图数据的高;
[0060]
output_width为输出特征图数据的宽;
[0061]
output_depth为输出特征图数据的深度,output_depth=input_depth;
[0062]
ft_data为按照需要顺序存储的卷积核数据;
[0063]
output_depth为为输出特征图数据的深度;
[0064]
其他参数是指针或是常规数据;
[0065]
第一层循环:判断h《output_height是否成立,若否,则跳出循环,若成立,进行以下第一层循环内的计算,并进行out_h ,重新判断h《output_height是否成立,继续:
[0066]
int out_w=0;
[0067]
j=out_h*output_width;
[0068]
int in_h=out_h*stride;
[0069]
int8_t*in_ptr0=in_data in_h*input_width*input_depth;
[0070]
第二层循环:第二层循环包括在第一层循环内,判断out_w《output_width是否成立,若不成立,则跳出循环,若成立,进行以下第二层循环内的计算,并进行out_w ,j ,重新判断out_w《output_width是否成立,继续:
[0071]
int in_w=out_w*stride;
[0072]
int8_t*in_ptr1=in_ptr0 in_w*input_depth;
[0073]
int8_t*out_ptr=output_data j*output_depth;
[0074]
ft_ptr=ft_data;
[0075]
第三层循环:第三层循环包括在第二层循环内,dj=0,判断dj《=output_depth

16是否成立,若否,则跳出循环,若成立,进行以下第三循环内的计算,并进行dj =16,重新判断dj《=output_depth

16是否成立,继续:
[0076]
sum_0=[0,0,

,0];初始化为0;
[0077]
sum_1=[0,0,

,0];初始化为0;
[0078]
in_locr=in_ptr;
[0079]
in_locr2=in_ptr 1*(input_width*input_depth);
[0080]
in_locr3=in_ptr 2*(input_width*input_depth);
[0081]
从in_locr中加载16个数据到寄存器in_value0中;
[0082]
从(in_locr input_depth)中加载16个数据到寄存器in_value1中;
[0083]
从(in_locr input_depth*2)中加载16个数据到寄存器in_value2中;
[0084]
从in_locr2中加载16个数据到寄存器in_value3中;
[0085]
从(in_locr2 input_depth)中加载16个数据到寄存器in_value4中;
[0086]
从(in_locr2 input_depth*2)中加载16个数据到寄存器in_value5中;
[0087]
从in_locr3中加载16个数据到寄存器in_value6中;
[0088]
从(in_locr3 input_depth)中加载16个数据到寄存器in_value7中;
[0089]
从(in_locr3 input_depth*2)中加载16个数据到寄存器in_value8中;
[0090]
从in_value1和in_value0中各选择出前8个8bit数据,交叉存放,放置到128寄存器in_0中;
[0091]
从in_value1和in_value0中各选择出后8个8bit数据,交叉存放,放置到128寄存器in_1中;
[0092]
从in_value3和in_value2中各选择出前8个8bit数据,交叉存放,放置到128寄存器in_2中;
[0093]
从in_value3和in_value2中各选择出后8个8bit数据,交叉存放,放置到128寄存器in_3中;
[0094]
从in_value5和in_value4中各选择出前8个8bit数据,交叉存放,放置到128寄存器in_4中;
[0095]
从in_value5和in_value4中各选择出后8个8bit数据,交叉存放,放置到128寄存器in_5中;
[0096]
从in_value7和in_value6中各选择出前8个8bit数据,交叉存放,放置到128寄存器in_6中;
[0097]
从in_value7和in_value6中各选择出后8个8bit数据,交叉存放,放置到128寄存器in_7中;
[0098]
从in_value8和zero中各选择出前8个8bit数据,交叉存放,放置到128寄存器in_8中,zero中存放的是16个8bit的0;
[0099]
从in_value8和zero中各选择出后8个8bit数据,交叉存放,放置到128寄存器in_9中,zero中存放的是16个8bit的0;
[0100]
接着,拷贝数据,每次拷贝16个8bit的数据,按照ft_ptr里面的顺序依次加载,具体如下:
[0101]
cvft_0内数据为:a1,b1,a2,b2,

,a8,b8;
[0102]
cvft_1内数据为:a9,b9,a10,b10,

,a16,b16;
[0103]
cvft_2内数据为:c1,d1,c2,d2,

,c8,d8;
[0104]
cvft_3内数据为:c9,d9,c10,d10,

,c16,d16;
[0105]
……
[0106]
cvft_8内数据为:j1,0,j2,0,

,j8,0
[0107]
cvft_9内数据为:j9,0,j10,0,

,j16,0
[0108]
sum_0、sum_1的过程:
[0109]
对应in_0至in_9,cvft_0至cvft_9,依次执行simd指令,两个寄存器的相乘相加的结果存到128位寄存器sum_0,sum_1中,sum_0和sum_1中各存的是8个16bit数据,最后得到的sum_0,sun_1就是独立卷积计算生成的结果。可以把simd指令运算看做一个函数,里面输入的是数组,输出也是数据。这个数组有些特殊,数组成员总的比特数是定值128比特,数组
成员可以可以是8比特,可以是16比特,或是32比特。具体的计算过程详见后文。
[0110]
所述伪代码中,主要指令相乘后相邻相加,计算过程如下:
[0111]
第一次迭代
[0112]
sum_0=[0,0,

,0];初始化为0;
[0113]
sum_1=[0,0,

,0];初始化为0;
[0114]
in_0=[ax1,bx1,ax2,bx2,

,ax8,bx8];
[0115]
in_1=[ax9,bx9,ax10,bx10,

,ax16,bx16];
[0116]
cvft_0=[a1,b1,a2,b2,

,a8,b8];
[0117]
cvft_1=[a9,b9,a10,b10,

,a16,b16];
[0118]
使用相乘后相邻相加指令后的结果:
[0119]
sum_0=[a1*ax1 b1*bx1,a2*ax2 b2*bx2,

,a8*ax8 b8*bx8]
[0120]
sun_1=[a9*ax9 b9*bx9,a10*ax10 b10*bx10,

,a16*ax16 b16*bx16];
[0121]
in_2=[cx1,dx1,cx2,dx2,

,cx8,dx8];
[0122]
in_3=[cx9,dx9,cx10,dx10,

,cx16,dx16];
[0123]
cvft_2=[c1,d1,c2,d2,

,c8,d8];
[0124]
cvft_3=[c9,d9,c10,d10,

,c16,d16];
[0125]
使用相乘后相邻相加指令后的结果:
[0126]
sum_0=[a1*ax1 b1*bx1 c1*cx1 d1*dx1,a2*ax2 b2*bx2 c2*cx2 d2*dx2,

,a8*ax8 b8*bx8 c8*cx8 d8*dx8]
[0127]
sun_1=[a9*ax9 b9*bx9 c9*cx9 d9*dx9,a10*ax10 b10*bx10 c10*cx10 d10*dx10,

,a16*ax16 b16*bx16 c16*cx16 d16*dx16];
[0128]
最终迭代结果:
[0129]
sum_0=[(a1*ax1 b1*bx1 c1*cx1 d1*dx1

j1*jx1),(a2*ax2 b2*bx2 c2*cx2 d2*dx2 j2*jx2),

,a8*ax8 b8*bx8 c8*cx8 d8*dx8 j8*jx8]
[0130]
sun_1=[(a9*ax9 b9*bx9 c9*cx9 d9*dx9 j9*jx9),(a10*ax10 b10*bx10 c10*cx10 d10*dx10 j10*jx10),

,(a16*ax16 b16*bx16 c16*cx16 d16*dx16 j16*jx16)],
[0131]
所得到的结果就是普通计算的卷积结果。
[0132]
所述方法是一种可以采用任意步长的方法,如果步长固定,也可以采用固定窗口的方法进行优化。
[0133]
由此,本技术的优势在于:提供了一种新的卷积核数据存储方式,基于4bit到6bit的独立卷积3
×
3的设计方法,该优化方法适合矢量(向量)指令的运算,由于simd一次计算16个数据,数据重复使用性很高,降低了加载数据的时间,从而极大的降低了时间。实现速度的成倍提升,相对c程序可以提升40倍左右。
附图说明
[0134]
此处所说明的附图用来提供对本发明的进一步理解,构成本技术的一部分,并不构成对本发明的限定。
[0135]
图1是本发明的方法流程图。
[0136]
图2是输入数据特征图平面图存储结构示意图。
[0137]
图3是输入数据的数据空间三维结构示意图。
具体实施方式
[0138]
为了能够更清楚地理解本发明的技术内容及优点,现结合附图对本发明进行进一步的详细说明。
[0139]
如图1所示,本发明涉及一种基于4bit到6bit的独立卷积3
×
3的设计方法,所述方法包括以下步骤:
[0140]
s1,输入数据并存储,其中,卷积核数据存储方式优化存储的处理:由于后面卷积计算是独立卷积,是9对数据相乘后,累加到一起,是生成的一个数据;而在指令集中只有一个指令能够满足相乘再相邻相加的结果的位数是16bit;
[0141]
根据这个指令的使用,需要对数据进行交叉存储,并且需要增加一个0;将相邻两个深度的数据交叉存储,最后一个深度的数据与0交叉存储;
[0142]
s2,利用simd指令进行simd指令优化算法的设计,实现卷积计算:将做卷积的特征图中的3
×
3个深度的数据,每两个深度一组进行交叉处理,可以组成4组,同时剩余一个深度数据,剩余的一个深度数据与0组合,此时是组成5组深度数据;
[0143]
s3,将步骤s2中组成5组深度数据与步骤s1中已经处理好的卷积核数据进行对应的计算,所有数据对应相乘,再累加。
[0144]
所述步骤s1中,输入数据的存储和卷积核数据一种存储顺序:
[0145]
输入数据是按照先深度再宽最后高的顺序存储数据。在计算时是考虑到数据的空间结构,在存储中,是一个向量的存储方式。特征图平面图存储结构理解图(如图2)。图中输入深度是指具体的数据深度个数,输入数据宽度是指有多少个输入深度,输入数据高度是指有多少个输入数据宽度。三维空间如图3所示。
[0146]
2)输入卷积核数据的存储方式。
[0147]
a)卷积核初始存储方式:
[0148]
不妨设一个卷积核数据相关信息,输出深度out_dep是4,卷积核宽度为3,卷积核高度为3。数据的连续方式为在输出深度方向连续,然后由3组输出深度方向(每个方向是4个数据)12个数据组成宽度上的一组数据,最后有3组宽度上的数据组成高度上的数据。具体如下:
[0149]
输出深度out_dep是4,可以表示为:
[0150]
[a1,a2,a3,a4];
‑‑‑‑‑
(1)
[0151]
卷积核宽度3上的数据,表示为:
[0152]
[a1,a2,a3,a4;b1,b2,b3,b4;c1,c2,c3,c4];
‑‑‑‑‑
(2)
[0153]
卷积核高度3上的数据,表示为:
[0154]
[a1,a2,a3,a4;b1,b2,b3,b4;c1,c2,c3,c4;d1,d2,d3,d4;e1,e2,e3,e4;f1,f2,f3,f4;g1,g2,g3,g4;h1,h2,h3,h4;j1,j2,j3,j4];
‑‑‑‑‑
(3)
[0155]
在计算机里存储为:
[0156]
[a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4,d1,d2,d3,d4,e1,e2,e3,e4,f1,f2,f3,f4,g1,g2,g3,g4,h1,h2,h3,h4,j1,j2,j3,j4];
‑‑‑‑‑
(3)
[0157]
b)卷积核数据存储方式优化存储:
[0158]
如果使用常规的数据存储,卷积核数据需要根据优化方式转化,每次使用都要转化数据顺序,极大的消耗时间,降低优化效率,增加计算量。而将需要优化转化的顺序预先转化好,使用中直接使用,既可以达到优化目的,也可以不增加计算量。
[0159]
由于后面卷积计算是独立卷积,是9对数据相乘后,累加到一起,是生成的一个数据。而在指令集中只有一个指令能够满足相乘再相邻相加的结果的位数是16bit。
[0160]
根据这个指令的使用,我们需要对数据进行交叉存储,后面算法实现会具体实现,并且需要增加一个0。将相邻两个深度的数据交叉存储,最后一个深度的数据与0交叉存储,具体存储如下。
[0161]
[a1,b1,a2,b2,a3,b3,a4,b4;c1,d1,c2,d2,c3,d3,c4,d4;e1,f1,e2,f2,e3,f3,e4,f4;g1,h1,g2,h2,g3,h3,g4,h4;j1,0,j2,0,j3,0,j4,0];
‑‑‑‑‑
(4)
[0162]
在计算机里存储为:
[0163]
[a1,b1,a2,b2,a3,b3,a4,b4,c1,d1,c2,d2,c3,d3,c4,d4,e1,f1,e2,f2,e3,f3,e4,f4,g1,h1,g2,h2,g3,h3,g4,h4,j1,0,j2,0,j3,0,j4,0];
‑‑‑‑‑
(5)
[0164]
实际使用中使用的输出深度都是16的倍数。上面假设输出深度out_dep是4,是为了举例说明理解。
[0165]
由于在simd优化算法设计中,使用的深度上每次连续计算16个输出结果,在使用卷积核中,每次使用的个数是16
×
(3
×
3 1),所以,我们在数据存储中也是按照这个使用卷积核的顺序存储。当输出深度超过16(out_dep为16的倍数)时,存储方式为:
[0166]
[a1,b1,a2,b2,

,a16,b16;c1,d1,c2,d2,

,c16,d16;e1,f1,e2,f2,

,e16,f16;g1,h1,g2,h2,

,g16,h16;j1,0,j2,0,

,j16,0];
[0167]
[a17,b17,a18,b18,

,a32,b32;c17,d17,c18,d18,

,c32,d32;e17,f17,e18,f18,

,e32,f32;g17,h17,g18,h18,

,g32,h32;j17,0,j18,0,

,j32,0];
[0168]
……
[0169]
[a(out_dep-15),b(out_dep-15),a(out_dep-14),b(out_dep-14),

,a(out_dep),b(out_dep);
[0170]
c(out_dep-15),d(out_dep-15),c(out_dep-14),d(out_dep-14),

,c(out_dep),d(out_dep);
[0171]
e(out_dep-15),f(out_dep-15),e(out_dep-14),f(out_dep-14),

,e(out_dep),f(out_dep);
[0172]
g(out_dep-15),h(out_dep-15),g(out_dep-14),h(out_dep-14),

,g(out_dep),h(out_dep);j(out_dep-15),0,j(out_dep-14),0,

,j(out_dep),0];
‑‑‑‑‑
(6)
[0173]
2、simd指令算法。
[0174]
1)simd指令介绍
[0175]
涉及到的simd指令如下。
[0176]
a)相乘再相邻相加的simd指令:
[0177]
vrd=ingenic_muladd_h(vrd,vrs,vrt);
[0178]
输入变量vrd,vrs,vrt,输出变量是vrd。vrd,vrs,vrt是simd类型变量,这些变量是128位寄存器。vrd存储的是8个int16_t的数据,vrs和vrt存储的是16个int8_t数据。由于运算中存在相乘和相加,4bit数据运算后需要16bit存储,我们将4bit输入数据存储成
8bit。
[0179]
vrd=[vrd0,vrd1,vrd2,vrd3,vrd4,vrd5,vrd6,vrd7];
[0180]
vrs=[vrs0,vrs1,vrs2,vrs3,vrs4,vrs5,vrs6,vrs7,vrs8,vrs9,vrs10,vrs11,vrs12,vrs13,vrs14,vrs15];
[0181]
vrt=[vrt0,vrt1,vrt2,vrt3,vrt4,vrt5,
[0182]
vrt6,vrt7,vrt8,vrt9,vrt10,vrt11,vrt12,vrt13,vrt14,vrt15];
[0183]
等价的运算:
[0184]
vrd0:=vrd0 vrs0*vrt0 vrs1*vrt1;
[0185]
vrd1:=vrd1 vrs2*vrt2 vrs3*vrt3;
[0186]
......
[0187]
vrd7:=vrd7 vrs14*vrt14 vrs15*vrt15;
[0188]
b)加载数据simd指令:输入的待载入的数据,当前是数据的指针,从该数据在内存里指向的位置开始加载128bit的数据,如果是8bit的数据是加载16个,如果是16bit数据加载8个。数据加载到变量vrd中。
[0189]
vrd=ingenic_load(indata)
[0190]
c)指定选择simd指令:从变量vrs和vrt中根据vri设置的编号选择出4个或8个或16个数据,在使用该指令时,需要占有一个永久寄存器vri,用于指令选择具体位置的数据。
[0191]
vrd=ingenic_choise_h(vrs,vrt,vri);
[0192]
3)simd指令实现卷积计算.
[0193]
卷积的计算,实现的方法很多。在使用simd指令中,可以先将数据转化到16bit后,使用乘法,加法,进行计算。也可以将数据直接进行乘法,再将乘后的结果转化为16bit,再进行累加计算,实现卷积计算。但不同的算法,执行后的效率不一样,所消耗的时间也不同。下面的算法设计,将最大程度的降低冗余计算,提高效率。
[0194]
设输入数据indata是一组输入深度in_depth为32,宽度in_width为256,高度in_height为256的数据;卷积核数据filter_data为一组输出深度out_depth为32,卷积核宽ft_w为3,卷积核高ft_h为3的数据。设输出数据(特征图)outdata的结构:深度为out_depth(与输入数据的输入深度一样,为32),宽度为out_width,高度out_height。在卷积计算中,存在一个步长,设步长为stride。输入数据的3
×
3个输入深度方向的数据为:
[0195]
[ax1,ax2,ax3,ax4,ax5,ax6,ax7,ax8,ax9,ax10,ax11,ax12,ax13,ax14,ax15,ax16,

ax32]
[0196]
[bx1,bx2,bx3,bx4,bx5,bx6,bx7,bx8,bx9,bx10,bx11,bx12,bx13,bx14,bx15,bx16,

bx32]
[0197]
[cx1,cx2,cx3,cx4,cx5,cx6,cx7,cx8,cx9,cx10,cx11,cx12,cx13,cx14,cx15,cx16,

cx32]
[0198]
dx1,dx2,dx3,dx4,dx5,dx6,dx7,dx8,dx9,dx10,dx11,dx12,dx13,dx14,dx15,dx16,

dx32]
[0199]
ex1,ex2,ex3,ex4,ex5,ex6,ex7,ex8,ex9,ex10,ex11,ex12,ex13,ex14,ex15,ex16,

ex32]
[0200]
[fx1,fx2,fx3,fx4,fx5,fx6,fx7,fx8,fx9,fx10,fx11,fx12,fx13,fx14,fx15,
fx16,

fx32]
[0201]
[gx1,gx2,gx3,gx4,gx5,gx6,gx7,gx8,gx9,gx10,gx11,gx12,gx13,gx14,gx15,gx16,

gx32]
[0202]
[hx1,hx2,hx3,hx4,hx5,hx6,hx7,hx8,hx9,hx10,hx11,hx12,hx13,hx14,hx15,hx16,

hx32]
[0203]
[jx1,jx2,jx3,jx4,jx5,jx6,jx7,jx8,jx9,jx10,jx11,jx12,jx13,jx14,jx15,jx16,

jx32]
‑‑‑‑‑
(7)
[0204]
卷积核原始数据为:
[0205]
[a1,a2,

,a32;b1,b2

,b32;c1,c2,

,c32;d1,d2,

,d32;e1,e2,

,e32;f1,f2,

,f32;g1,g2,

,g32;h1,h2,

,h32;j1,j2,

,j32];
‑‑‑‑‑
(8)
[0206]
卷积核优化数据为:
[0207]
[a1,b1,a2,b2,

,a16,b16;c1,d1,c2,d2,

,c16,d16;e1,f1,e2,f2,

,e16,f16;g1,h1,g2,h2,

,g16,h16;j1,0,j2,0,

,j16,0];
[0208]
[a17,b17,a18,b18,

,a32,b32;c17,d17,c18,d18,

,c32,d32;e17,f17,e18,f18,

,e32,f32;g17,h17,g18,h18,

,g32,h32;j17,0,j18,0,

,j32,0];
‑‑‑‑‑
(9)
[0209]
a)常规计算方法
[0210]
将公式(7)与公式(8)对应相乘,再累加到一起,就是计算求得输出结果中深度方向上的一个数据。
[0211]
b)simd指令优化算法设计
[0212]
常规算法,使用的指令多,计算重复性也多。在这里,使用的是将做卷积的特征图中的3
×
3个深度的数据,如数据(7),每两个深度一组进行交叉处理,可以组成4组,同时剩余一个深度数据,剩余的一个深度数据与0组合,此时是组成5组深度数据,如数据(10)。数据结构为:
[0213]
[ax1,bx1,ax2,bx2,

,ax16,bx16,ax17,bx17,

,ax32,bx32]
[0214]
[cx1,dx1,cx2,dx2,

,cx16,dx16,cx17,dx17,

,cx32,dx32]
[0215]
[ex1,fx1,ex2,fx2,

,ex16,fx16,ex17,fx17,

,ex32,fx32]
[0216]
[gx1,hx1,gx2,hx2,

,gx16,hx16,gx17,hx17,

,gx32,hx32]
[0217]
[jx1,0,jx2,0,

,jx16,0,jx17,0,

,jx32,0]
‑‑‑‑‑
(10)
[0218]
将数据(10)与已经处理好的卷积核数据(9)进行对应的计算,所有数据对应相乘,再累加,其结果与数据(7)与数据(8)相乘再累加后的结果完全一样。
[0219]
simd是一种向量计算,每次计算的个数越多,使用的指令越少,运算越节省时间。这里主要使用a)相乘再相邻相加的simd指令,这个指令可以使的8bit数据相乘相加后数据变为16bit。使用该指令,需要将原有的特征图数据进行处理,也就是需要将数据(7)处理成数据(8)的顺序,再进行使用。这样才能满足指令相乘再相邻相加的要求。同样,卷积核数据也要进行交叉顺序处理,由于在计算中进行处理,耗费时间,将这种处理提前到卷积核存储中,将数据顺序调整好,存成使用需要的顺序。整个实现的伪代码如下:
[0220]
simd类型变量寄存器:
[0221]
sum_0,sum_1;
[0222]
in_value0,in_value1,in_value2,in_value3,in_value4,in_value5,in_
value6,in_value7,in_value8,in_value9;
[0223]
in_0,in_1,in_2,in_3,in_4,in_5,in_6,in_7,in_8,in_9;
[0224]
in_value,cvft_0,cvft_1,cvft_2,cvft_3,cvft_4,cvft_5,cvft_6,cvft_7,cvft_8,cvft_9;
[0225]
stride为步长;
[0226]
in_data为输入的特征图数据;
[0227]
input_height为输入的特征图数据的高;
[0228]
input_width为输入的特征图数据的宽;
[0229]
input_depth为输入的特征图数据的深度;
[0230]
output_data为输出特征图数据;
[0231]
output_height为输出特征图数据的高;
[0232]
output_width为输出特征图数据的宽;
[0233]
output_depth为输出特征图数据的深度(output_depth=input_depth);
[0234]
ft_data为按照需要顺序存储的卷积核数据;
[0235]
output_depth为为输出特征图数据的深度;
[0236]
其他参数是指针或是常规数据;
[0237]
第一层循环:判断h《output_height是否成立,若否,则跳出循环,若成立,进行以下第一层循环内的计算,并进行out_h ,重新判断h《output_height是否成立,继续:
[0238]
for(;out_h《output_height;out_h ){
[0239]
int out_w=0;
[0240]
j=out_h*output_width;
[0241]
int in_h=out_h*stride;
[0242]
int8_t*in_ptr0=in_data in_h*input_width*input_depth;
[0243]
第二层循环:第二层循环包括在第一层循环内,判断out_w《output_width是否成立,若不成立,则跳出循环,若成立,进行以下第二层循环内的计算,并进行out_w ,j ,重新判断out_w《output_width是否成立,继续:
[0244]
for(;out_w《output_width;out_w ,j ){
[0245]
int in_w=out_w*stride;
[0246]
int8_t*in_ptr1=in_ptr0 in_w*input_depth;
[0247]
int8_t*out_ptr=output_data j*output_depth;
[0248]
ft_ptr=ft_data;
[0249]
第三层循环:第三层循环包括在第二层循环内,dj=0,判断dj《=
[0250]
output_depth

16是否成立,若否,则跳出循环,若成立,进行以下第三循环内的计算,并进行dj =16,重新判断dj《=output_depth

16是否成立,继续:
[0251]
for(dj=0;dj《=output_depth-16;dj =16){
[0252]
初始化sum_0为0:sum_0=[0,0,

,0];
[0253]
初始化sum_1为0:sum_1=[0,0,

,0];
[0254]
赋值:
[0255]
in_locr=in_ptr;
[0256]
in_locr2=in_ptr 1*(input_width*input_depth);
[0257]
in_locr3=in_ptr 2*(input_width*input_depth);
[0258]
从in_locr中加载16个数据到寄存器in_value0中:in_value0=ingenic_load(in_locr,0);
[0259]
从(in_locr input_depth)中加载16个数据到寄存器in_value1中:in_value1=ingenic_load(in_locr input_depth,0);
[0260]
从(in_locr input_depth*2)中加载16个数据到寄存器in_value2中:in_value2=ingenic_load(in_locr input_depth*2,0);
[0261]
从in_locr2中加载16个数据到寄存器in_value3中:in_value3=ingenic_load(in_locr2,0);
[0262]
从(in_locr2 input_depth)中加载16个数据到寄存器in_value4中:in_value4=ingenic_load(in_locr2 input_depth,0);
[0263]
从in_locr2中加载16个数据到寄存器in_value3中:in_value5=ingenic_load(in_locr2 input_depth*2,0);
[0264]
从in_locr3中加载16个数据到寄存器in_value6中:in_value6=ingenic_load(in_locr3,0);
[0265]
从(in_locr3 input_depth)中加载16个数据到寄存器in_value7中:in_value7=ingenic_load(in_locr3 input_depth,0);
[0266]
从(in_locr3 input_depth*2)中加载16个数据到寄存器in_value8中:in_value8=ingenic_load(in_locr3 input_depth*2,0);
[0267]
从in_value1和in_value0中各选择出前8个8bit数据,交叉存放,放置到128寄存器in_0中:in_0=ingenic_choise_h(in_value1,in_value0,cvt_ft_0);
[0268]
从in_value1和in_value0中各选择出后8个8bit数据,交叉存放,放置到128寄存器in_1中:in_1=ingenic_choise_h(in_value1,in_value0,cvt_ft_1);
[0269]
从in_value3和in_value2中各选择出前8个8bit数据,交叉存放,放置到128寄存器in_2中:in_2=ingenic_choise_h(in_value3,in_value2,cvt_ft_0);
[0270]
从in_value3和in_value2中各选择出后8个8bit数据,交叉存放,放置到128寄存器in_3中:in_3=ingenic_choise_h(in_value3,in_value2,cvt_ft_1);
[0271]
从in_value5和in_value4中各选择出前8个8bit数据,交叉存放,放置到128寄存器in_4中:in_4=ingenic_choise_h(in_value5,in_value4,cvt_ft_0);
[0272]
从in_value5和in_value4中各选择出后8个8bit数据,交叉存放,放置到128寄存器in_5中:in_5=ingenic_choise_h(in_value5,in_value4,cvt_ft_1);
[0273]
从in_value7和in_value6中各选择出前8个8bit数据,交叉存放,放置到128寄存器in_6中:in_6=ingenic_choise_h(in_value7,in_value6,cvt_ft_0);
[0274]
从in_value7和in_value6中各选择出后8个8bit数据,交叉存放,放置到128寄存器in_7中:in_7=ingenic_choise_h(in_value7,in_value6,cvt_ft_1);
[0275]
从in_value8和zero中各选择出前8个8bit数据,交叉存放,放置到128寄存器in_8中,zero中存放的是16个8bit的0:in_8=ingenic_choise_h(in_value8,zero,cvt_ft_0);
[0276]
从in_value8和zero中各选择出后8个8bit数据,交叉存放,放置到128寄存器in_9
中,zero中存放的是16个8bit的0:in_9=ingenic_choise_h(in_value8,zero,cvt_ft_1);
[0277]
接着拷贝数据,每次拷贝16个8bit的数据,按照ft_ptr里面的顺序依次加载。如下:
[0278]
cvft_0内数据为:a1,b1,a2,b2,

,a8,b8;
[0279]
cvft_1内数据为:a9,b9,a10,b10,

,a16,b16;
[0280]
cvft_2内数据为:c1,d1,c2,d2,

,c8,d8;
[0281]
cvft_3内数据为:c9,d9,c10,d10,

,c16,d16;
[0282]
……
[0283]
cvft_8内数据为:j1,0,j2,0,

,j8,0
[0284]
cvft_9内数据为:j9,0,j10,0,

,j16,0
[0285]
可表示为以下:
[0286]
cvft_0=ingenic_load(ft_ptr,0);
[0287]
cvft_1=ingenic_load(ft_ptr,16);
[0288]
cvft_2=ingenic_load(ft_ptr,32);
[0289]
cvft_3=ingenic_load(ft_ptr,48);
[0290]
cvft_4=ingenic_load(ft_ptr,64);
[0291]
cvft_5=ingenic_load(ft_ptr,80);
[0292]
cvft_6=ingenic_load(ft_ptr,96);
[0293]
cvft_7=ingenic_load(ft_ptr,112);
[0294]
cvft_8=ingenic_load(ft_ptr,128);
[0295]
cvft_9=ingenic_load(ft_ptr,144);
[0296]
ft_ptr =160;
[0297]
sum_0、sum_1的计算过程:
[0298]
对应in_0至in_9,cvft_0至cvft_9,依次执行simd指令,两个寄存器的相乘相加的结果存到128位寄存器sum_0,sum_1中,sum_0和sum_1中各存的是8个16bit数据,最后得到的sum_0,sun_1就是独立卷积计算生成的结果:
[0299]
可以表示如下:
[0300][0301]
在上面的伪代码中,所述sum_0、sum_1的计算过程,主要指令相乘后相邻相加。计算过程如下:
[0302]
第一次迭代
[0303]
sum_0=[0,0,

,0];初始化为0;
[0304]
sum_1=[0,0,

,0];初始化为0;
[0305]
in_0=[ax1,bx1,ax2,bx2,

,ax8,bx8];
[0306]
in_1=[ax9,bx9,ax10,bx10,

,ax16,bx16];
[0307]
cvft_0=[a1,b1,a2,b2,

,a8,b8];
[0308]
cvft_1=[a9,b9,a10,b10,

,a16,b16];
[0309]
使用相乘后相邻相加指令后的结果:
[0310]
sum_0=[a1*ax1 b1*bx1,a2*ax2 b2*bx2,

,a8*ax8 b8*bx8]
[0311]
sun_1=[a9*ax9 b9*bx9,a10*ax10 b10*bx10,

,a16*ax16 b16*bx16];
[0312]
in_2=[cx1,dx1,cx2,dx2,

,cx8,dx8];
[0313]
in_3=[cx9,dx9,cx10,dx10,

,cx16,dx16];
[0314]
cvft_2=[c1,d1,c2,d2,

,c8,d8];
[0315]
cvft_3=[c9,d9,c10,d10,

,c16,d16];
[0316]
使用相乘后相邻相加指令后的结果:
[0317]
sum_0=[a1*ax1 b1*bx1 c1*cx1 d1*dx1,a2*ax2 b2*bx2 c2*cx2 d2*dx2,

,
a8*ax8 b8*bx8 c8*cx8 d8*dx8]
[0318]
sun_1=[a9*ax9 b9*bx9 c9*cx9 d9*dx9,a10*ax10 b10*bx10 c10*cx10 d10*dx10,

,a16*ax16 b16*bx16 c16*cx16 d16*dx16];
[0319]
最终迭代结果:
[0320]
sum_0=[(a1*ax1 b1*bx1 c1*cx1 d1*dx1

j1*jx1),(a2*ax2 b2*bx2 c2*cx2 d2*dx2 j2*jx2),

,a8*ax8 b8*bx8 c8*cx8 d8*dx8 j8*jx8]
[0321]
sun_1=[(a9*ax9 b9*bx9 c9*cx9 d9*dx9 j9*jx9),(a10*ax10 b10*bx10 c10*cx10 d10*dx10 j10*jx10),

,(a16*ax16 b16*bx16 c16*cx16 d16*dx16 j16*jx16)];
[0322]
显然,这就是普通计算的卷积结果。由于simd一次计算16个数据,数据重复使用性很高,降低了加载数据的时间,从而极大的降低了时间。
[0323]
通过上面的simd指令算法,可以将速度提升近40倍。上面的算法是一种任意步长的算法,如果步长固定,例如是1,可以采用固定窗口等方法进一步进行优化,还可以进一步降低运行时间。
[0324]
以上所述仅为本发明的优选实施例而已,并不用于限制本发明,对于本领域的技术人员来说,本发明实施例可以有各种更改和变化。凡在本发明的精神和原则之内,所作的任何修改、等同替换、改进等,均应包含在本发明的保护范围之内。
再多了解一些

本文用于创业者技术爱好者查询,仅供学习研究,如用于商业用途,请联系技术所有人。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

相关文献