一种基于4bit普通卷积计算的优化方法与流程

文档序号:30309765发布日期:2022-06-05 10:27阅读:96来源:国知局
一种基于4bit普通卷积计算的优化方法与流程

1.本发明涉及图像识别技术领域,特别涉及一种基于4bit普通卷积计算的优化方法。


背景技术:

2.随着时代的发展,图像识别技术的应用变得越来越普遍。针对图像识别的优化方法也各种各样。特别是卷积计算的优化,当前优化方法包括例如基于北京君正t30,t31等t和x系列芯片的simd指令集设计的一种优化方法。该算法适合矢量(向量)指令的运算。t30和t31的寄存器是128位寄存器,并且寄存器个数是有限的,但这在优化设计中要考虑寄存器个数问题。并且在例如北京君正芯片上,直接使用c程序,速度会很慢。
3.现有技术中常用的技术术语包括:
4.1、simd指令[1]:单指令流多数据流,即一次运算指令可以执行多个数据流,这样可以提高程序的运算速度。更通俗理解,就是一种矢量(向量)的计算。不同芯片,具体指令集不同。
[0005]
2、卷积核:卷积核是用来做图像处理时的矩阵,与原图像做运算的参数。卷积核通常是一个列矩阵数组成(例如3*3的矩阵),该区域上每个方格都有一个权重值。矩阵形状一般是1
×
1,3
×
3,5
×
5,7
×
7,1
×
3,3
×
1,2
×
2,1
×
5,5
×
1,

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

×
深度,或1
×
深度。


技术实现要素:

[0008]
为了解决上述现有技术中存在的问题,本发明的目的在于:采用本发明的方法实现速度的成倍提升。
[0009]
具体地,本发明提供一种基于4bit普通卷积计算的优化方法,所述方法在完整的卷积计算的过程中,在算法最里层的一个循环中加入simd指令运算;在所述最里层的循环中通过加载数据simd指令加载数据,将数据加载后,数据一直在寄存器中不重复加载;在所述最里层的循环中,通过拷贝simd指令实现数据的重复使用;再通过乘法simd指令、选择simd指令和移位simd指令最终实现8个16bit数据存放到一个128位寄存器。
[0010]
所述方法使用的是一次加载16个数据,数据一次运算16个结果,所述方法每次加载的数据中的一个数据拷贝到simd指令的变量中,进行8bit的乘法simd指令计算,再进行转化16bit后,进行累加simd指令计算;这种乘法和累加是在算法的最内层循环中实现。
[0011]
所述最内层循环中,通过加载simd指令操作,将数据加载后,数据一直在寄存器中;通过拷贝simd指令操作,实现最内层循环中数据的重复使用;由于乘法simd指令得到的
结果是8bit数据,在寄存器中是16个8bit数据,需要将数据转化为16bit后才能进行后面的累加,此时需要将muls转存到两个128寄存器中,同时将16个数据转化为16bit。当芯片中没有8位到16位数据的转化指令时,用选择simd指令将muls数据前8个8bit数据存放到一个128位寄存器mul_0中,存放形式为:
[0012]
[a1,a1,b1,b1,c1,c1,d1,d1,e1,e1,f1,f1,g1,g1,h1,h1];
[0013]
再将该数据进行右移位simd指令操作,得到:
[0014]
[a1,b1,c1,d1,e1,f1,g1,h1]
[0015]
此时是8个16bit数据存放到一个128位寄存器mul_0;
[0016]
用选择simd指令将寄存器muls内数据的后8个8bit数据存放到一个128位寄存器mul_1中,存放形式为:
[0017]
[m1,m1,n1,n1,p1,p1,k1,k1,r1,r1,f1,f1,t1,t1,v1,v1];
[0018]
再将该数据进行右移位simd指令操作,得到:
[0019]
[m1,n1,p1,k1,r1,f1,t1,v1];
[0020]
此时是8个16bit数据存放到一个128位寄存器mul_1;这样处理的原因,寄存器里面存的都是有符号数据,为了保证数据的符号性,所以先将数据存放到高8位,再将寄存器数据执行右移位simd指令操作,使得数据8bit转化为16bit。
[0021]
所述方法包括以下步骤:
[0022]
s1,设输入数据indata是一组输入深度in_depth为32,宽度in_width为512,高度in_height为512的数据;卷积核数据filter_data为一组输出深度out_depth为128,输入深度in_depth为32,其与输入数据深度一致,卷积核宽ft_w为3,卷积核高ft_h为3的数据;
[0023]
设输出数据即特征图outdata的结构:深度为out_depth,宽度为out_width,高度out_height;在卷积计算中,存在一个步长,设步长为stride;
[0024]
设simd类型变量:sum_0,sum_1,in_value,in_0,ft_0,vrt1,vrt2,muls,mul_0,mul_1;其他参数是指针或是具体常规数据;
[0025]
s2,第一层循环:设h=0;
[0026]
s2.1,判断h《out_height是否成立,
[0027]
s2.2,若不成立,则停止第一层循环;若成立,
[0028]
执行:in_h=h*stride,
[0029]
执行:步骤s3;
[0030]
s2.3,进行h=h+1,返回步骤s2.1;
[0031]
s3,第二层循环:设w=0;
[0032]
s3.1,判断w《out_width是否成立,
[0033]
s3.2,若不成立,则停止第二层循环,进行步骤s2.3;若成立,
[0034]
执行:in_w=w*stride,
[0035]
执行:in_ptr=indata+in_w*in_depth,该参数为输入数据指针;
[0036]
执行:out_ptr=oudata+h*out_width*out_depth,该参数为输出数据即特征图指针;
[0037]
执行:步骤s4;
[0038]
s3.3,进行w=w+1,返回步骤s3.1;
[0039]
s4,第三层循环:设i=0;
[0040]
s4.1,判断i《=out_depth

16是否成立,
[0041]
s4.2,若不成立,则停止第三层循环,进行步骤s3.3;若成立,
[0042]
执行:b_ptr=ft_data+i;该参数为卷积核数据指针;
[0043]
执行:sum_0=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];初始化sum_0为0;
[0044]
执行:sum_1=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];初始化sum_1为0;
[0045]
执行:步骤s5;
[0046]
s4.3,进行i=i+16,返回步骤s4.1;
[0047]
s5,第四层循环:设p=0;
[0048]
s5.1,判断p《ft_h是否成立,
[0049]
s5.2,若不成立,在停止第四层循环,进行步骤s4.3;若成立,
[0050]
执行:ft_k=p*ft_h;
[0051]
执行:in_loc=in_ptr+(in_h+p)*in_width*in_height;
[0052]
执行:步骤s6;
[0053]
s5.3,进行++p,返回步骤s5.1;
[0054]
s6,第五层循环:设l=0;
[0055]
s6.1,判断l《=ft_w*in_depth

16是否成立,
[0056]
s6.2,若不成立,则停止第五层循环,进行步骤s5.3;若成立,
[0057]
执行:ft_l=ft_k+l;
[0058]
执行:加载数据,从指针a_loc+l位置开始读取128位数据,即读取16个8位数据,将数据存放到128位寄存器in_value中,即表示为in_value=ingenic_load(a_loc+l);
[0059]
执行:步骤s7;
[0060]
s6.3,进行l=l+16,返回步骤s6.1;
[0061]
s7,最内层循环:设fn=0;
[0062]
s7.1,判断fn《16是否成立,
[0063]
s7.2,若不成立,则停止最内层循环,进行步骤s6.3;若成立,
[0064]
执行:拷贝simd指令,拷贝一个数据,将变量中指定位置拷贝到输出变量中,指定位置用fn表示,每次拷贝的是8bit数据,即表示为in_0=ingenic_copy1(in_value,fn);
[0065]
执行:乘法simd指令,即表示为muls=ingenic_mul_b(in_0,vrt);
[0066]
执行:选择simd指令,从muls中选择出前8个8bit数据,放置到128寄存器mul_0内部每个16位的高8位中,即表示为mul_0=ingenic_choise_h(muls,muls,vrt1);
[0067]
执行:移位simd指令,对数据进行右移位simd指令操作,将前8个8bit数据恢复到实际数据值,即表示为mul_0=ingenic_shift_right(mul_0,1);
[0068]
执行:从muls中选择出后8个8bit数据,放置到128寄存器mul_1内部每个16位的高8位中,即表示为mul_1=ingenic_choise_h(muls,muls,vrt2);
[0069]
执行:对数据进行右移位simd指令操作,将前8个8bit数据恢复到实际数据值,即表示为mul_1=ingenic_shift_right(mul_1,1);
[0070]
执行:执行simd指令将两个寄存器的相加,结果存到128位寄存器sum_0中,即表示为sum_0=ingenic_add_h(sum_0,mul_0);
[0071]
执行:执行simd指令将两个寄存器的相加,结果存到128位寄存器sum_1中,即表示为sum_1=ingenic_add_h(sum_1,mul_1);
[0072]
s7.3,进行fn=fn+1,返回步骤s7.1。
[0073]
所述步骤s1中,输入数据的一个输入深度方向的数据为:
[0074]
[x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,

x32];
[0075]
卷积核数据两个输出深度方向的数据为:
[0076]
[a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,

a128],
[0077]
[b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,

b128]。
[0078]
所述方法还可以使用相乘再相邻相加的simd指令进一步优化,所述最内层循环中,循环8次,加载两次卷积核数据,即
[0079]
ft_0=ingenic_load(b_ptr+filter_count*(ft_l+2*fn));
[0080]
ft_1=ingenic_load(b_ptr+filter_count*(ft_l+2*fn+1));
[0081]
由于执行的for循环是8次,而在循环里面加载卷积核是两次,所以对于卷积核加载是同样的,但可以重复使用in_0,减少一个simd指令,降低相应的计算时间;
[0082]
假设ft_0,ft_1的具体数据如下:
[0083]
ft_0=[f0,f1,f2,f3,f4,f5,f6,f7,g0,g1,g2,g3,g4,g5,g6,g7];
[0084]
ft_1=[j0,j1,j2,j3,j4,j5,j6,j7,k0,k1,k2,k3,k4,k5,k6,k7];
[0085]
在choise_0=ingenic_choise_h(ft_0,ft_1,vrt0)中通过vrt0指定具体位置后,得到如下的choise_0:
[0086]
choise_0=[f0,j0,f1,j1,f2,j2,f3,j3,f4,j4,f5,j6,f6,j6,f7,j7];
[0087]
在choise_1=ingenic_choise_h(ft_0,ft_1,vrt1)中通过vrt1指定具体位置后,得到如下的choise_1:
[0088]
choise_1=[g0,k0,g1,k1,g2,k2,g3,k3,g4,k4,g5,k5,g6,k6,g7,k7];
[0089]
后面再执行相乘相加的simd指令:
[0090]
sum_0=ingenic_muladd_h(sum_0,in_0,choise_0);
[0091]
sum_1=ingenic_muladd_h(sum_1,in_0,choise_1);
[0092]
这相当于在最内层连续执行了两次,即执行了fn和(fn+1),使用ingenic_muladd_h指令,一次将加法和乘法,还有8bit转化为16bit的换算全都执行了,但实现过程需要卷积核数据内相邻深度数据的交叉存储到一个寄存器,同时需要两个寄存器存储。所述相乘相加:两个向量对应数相乘,相乘后,得到一个向量a,再把这个a向量两个数据相加,例如a0+a1,a2+a3,

得到的数据个数是原来的一半。再将相加后的向量与sum_0相加,得到的结果再赋给sum_0。
[0093]
优化的所述步骤s7为,最内层循环,设fn=0:
[0094]
s7.1,判断fn《8是否成立,
[0095]
s7.2,若不成立,则停止最内层循环;若成立,则
[0096]
执行:复制连续两个数据到寄存器in_0中,即in_0=ingenic_copy2(in_value,fn);
[0097]
in_value里面是16个8bit数据组成的向量,但在寄存器里这个向量是128bit。复制连续两个数据,就是把操作看成从寄存器中复制出16bit数据,也就是是2*8bit的数据。
这个指令fn是指定拷贝第几个16bit数据。在in_0里面,是把这个拷贝的数据[a0,a1](例如fn=0,a0,a1是8bit数据)重复性放置,也就是[a0,a1,a0,a1,a0,a1,a0,a1,a0,a1,a0,a1,a0,a1,a0,a1,a0,a1,a0,a1];执行:ft_0=ingenic_load(b_ptr+filter_count*(ft_l+2*fn));执行:ft_1=ingenic_load(b_ptr+filter_count*(ft_l+2*fn+1));
[0098]
执行:从ft_0和ft_1中选择出指定的16个8bit数据,放置到128寄存器choise_0内,即choise_0=ingenic_choise_h(ft_0,ft_1,vrt0);
[0099]
执行:从ft_0和ft_1中选择出指定的16个8bit数据,放置到128寄存器choise_1内,即choise_1=ingenic_choise_h(ft_0,ft_1,vrt1);
[0100]
执行:simd指令将两个寄存器的相加,结果存到128位寄存器sum_0中,即sum_0=ingenic_muladd_h(sum_0,in_0,choise_0);
[0101]
执行:simd指令将两个寄存器的相加,结果存到128位寄存器sum_1中,即
[0102]
sum_1=ingenic_muladd_h(sum_1,in_0,choise_1);
[0103]
s7.3,进行fn=fn+1,返回步骤s7.1。
[0104]
进一步优化所述方法的操作为降低数据的重复加载,采用有限的窗口或步长的计算模式。因此,所述方法还可以为以下步骤:
[0105]
s1,设输入数据indata是一组输入深度in_depth为32,宽度in_width为512,高度in_height为512的数据;卷积核数据filter_data为一组输出深度out_depth为128,输入深度in_depth为32,其与输入数据深度一致,卷积核宽ft_w为3,卷积核高ft_h为3的数据;
[0106]
设输出数据即特征图outdata的结构:深度为out_depth,宽度为out_width,高度out_height;在卷积计算中,存在一个步长,设步长为stride;
[0107]
设simd类型变量:sum_0,sum_1,sum_20,sum_21,in_value,in_value1,in_0,in_1,ft_0,vrt1,vrt2,mul_0,其他参数是指针或是具体常规数据;
[0108]
s2,第一层循环:设h=0;
[0109]
s2.1,判断h《out_height是否成立,
[0110]
s2.2,若不成立,则停止第一层循环;若成立,
[0111]
执行:in_h=h*stride,
[0112]
执行:步骤s3;
[0113]
s2.3,进行h=h+1,返回步骤s2.1;
[0114]
s3,第二层循环:设w=0;
[0115]
s3.1,判断w《out_width是否成立,
[0116]
s3.2,若不成立,则停止第二层循环,进行步骤s2.3;若成立,在输入数据即特征图的宽度方向执行步长为2的重复性计算:
[0117]
执行:in_w=w*stride,
[0118]
执行:in_ptr=indata+in_w*in_depth,该参数为输入数据指针;
[0119]
执行:out_ptr=oudata+h*out_width*out_depth,该参数为输出数据即特征图指针;
[0120]
执行:步骤s4;
[0121]
s3.3,进行w=w+2,返回步骤s3.1;
[0122]
s4,第三层循环:设i=0;
[0123]
s4.1,判断i《=out_depth

16是否成立,
[0124]
s4.2,若不成立,则停止第三层循环,进行步骤s3.3;若成立,
[0125]
执行:b_ptr=ft_data+i;该参数为卷积核数据指针;
[0126]
执行:sum_0=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];初始化sum_0为0;
[0127]
执行:sum_1=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];初始化sum_1为0;
[0128]
执行:sum_20=sum_0;
[0129]
执行:sum_21=sum_0;
[0130]
这里是由输出数据宽度每次加2,产生出两个结果;
[0131]
执行:步骤s5;
[0132]
s4.3,进行i=i+16,返回步骤s4.1;
[0133]
s5,第四层循环:设p=0;
[0134]
s5.1,判断p《ft_h是否成立,
[0135]
s5.2,若不成立,在停止第四层循环,进行步骤s4.3;若成立,
[0136]
执行:ft_k=p*ft_h;
[0137]
执行:in_loc=in_ptr+(in_h+p)*in_width*in_height;
[0138]
执行:步骤s6;
[0139]
s5.3,进行++p,返回步骤s5.1;
[0140]
s6,第五层循环:设l=0;
[0141]
s6.1,判断l《=ft_w*in_depth

16是否成立,
[0142]
s6.2,若不成立,则停止第五层循环,进行步骤s5.3;若成立,
[0143]
执行:ft_l=ft_k+l;
[0144]
执行:加载数据,从指针a_loc+l位置开始读取128位数据,即读取16个8位数据,将数据存放到128位寄存器in_value中,即表示为in_value=ingenic_load(a_loc+l);
[0145]
执行:in_value1=ingenic_load(a_loc+l+in_depth*stride);
[0146]
执行:步骤s7;
[0147]
s6.3,进行l=l+16,返回步骤s6.1;
[0148]
s7,最内层循环:设fn=0;
[0149]
s7.1,判断fn《8是否成立,
[0150]
s7.2,若不成立,则停止最内层循环,进行步骤s6.3;若成立,执行:拷贝数据:
[0151]
in_0=ingenic_copy2(in_value,fn);
[0152]
加载数据需要多加载一组,也就是in_1,即in_1=ingenic_copy2(in_value1,fn);
[0153]
执行:加载simd指令:
[0154]
ft_0=ingenic_load(b_ptr+filter_count*(ft_l+2*fn));
[0155]
ft_1=ingenic_load(b_ptr+filter_count*(ft_l+2*fn+1));
[0156]
执行:选择simd指令:
[0157]
choise_0=ingenic_choise_h(ft_0,ft_1,vrt0);
[0158]
choise_1=ingenic_choise_h(ft_0,ft_1,vrt1);
[0159]
执行:累加simd指令:
[0160]
sum_0=ingenic_muladd_h(sum_0,in_0,choise_0);
[0161]
sum_1=ingenic_muladd_h(sum_1,in_0,choise_1);
[0162]
sum_20=ingenic_muladd_h(sum_0,in_1,choise_0);
[0163]
sum_21=ingenic_muladd_h(sum_1,in_1,choise_1);
[0164]
s7.3,进行fn=fn+1,返回步骤s7.1。
[0165]
所述方法在输出数据即特征图宽度上连续生成两组数据,sum_0和sum_1是第一组,sum_20和sum_21是第一组,也就是:
[0166]
sum_0=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
[0167]
sum_1=sum_0;
[0168]
sum_20=sum_0;
[0169]
sum_21=sum_0;
[0170]
由于生成的结果同时生成两组,所以在输入数据中需要同时加载两组数据:
[0171]
in_value=ingenic_load(a_loc+l);
[0172]
in_value1=ingenic_load(a_loc+l+in_depth*stride);
[0173]
最内层循环,同时实现两组输出数据的计算,将ft_0和ft_1使用了两次;这里是步长为2。
[0174]
综上,应用本技术方法能够实现的优势在于:本方法步骤简单,比纯使用c算法的方法速度提升10-20倍左右,实现对现有技术的优化。
附图说明
[0175]
此处所说明的附图用来提供对本发明的进一步理解,构成本技术的一部分,并不构成对本发明的限定。
[0176]
图1是特征图平面图存储结构的示意图。
[0177]
图2是图1中输入深度、输入数据宽度和输入数据高度三维空间的示意图。
[0178]
图3是数据存储结构的示意图。
[0179]
图4是图3中将其输出深度压缩为一个质点,四维空间变成三维空间的示意图。
[0180]
图5是输出深度out_d是5,一个输出深度方向的数据为[a1,a2,a3,a4,a5],形象理解用虚线表示的示意图。
[0181]
图6即是图4中的第一个矩形表示,矩形中有两个虚线的示意图。
[0182]
图7是卷积核宽度w是3,一个卷积核宽度方向的数据包括三组输入深度方向的数据的形象理解的示意图。
[0183]
图8是本方法的第一实施例方法的流程示意图。
[0184]
图9是图8中步骤s7具体内容的示意图。
[0185]
图10是本方法的第一实施例中步骤s7进一步优化的示意图。
[0186]
图11是本方法的第二实施例方法的流程示意图。
[0187]
图12是图11中步骤s7具体内容的示意图。
具体实施方式
[0188]
为了能够更清楚地理解本发明的技术内容及优点,现结合附图对本发明进行进一
步的详细说明。
[0189]
1、输入数据的存储和输入卷积核数据的存储方式的介绍
[0190]
输入数据是按照先深度再宽最后高的顺序存储数据。在计算是考虑到数据的空间结构,在存储中,是一个向量的存储方式。特征图平面图存储结构理解图(如图1所示)。图中输入深度是指具体的数据深度个数,输入数据宽度是指有多少个输入深度,输入数据高度是指有多少个输入数据宽度。三维空间如图2所示。
[0191]
卷积核数据的存储方式:先存储输出深度,再存储输入深度,然后是卷积核宽度,最后是卷积核高度。数据存储结构理解图(如图3所示)。图中输出深度是指具体的数据深度个数,输入深度是指有多少个输入深度,卷积核宽度是指有多少个输入深度,卷积核高度是指有多少个卷积核宽度。其空间结构是四维结构,无法在三维空间表示。将其输出深度压缩为一个质点,四维空间变成三维空间,表示如图4所示。
[0192]
不妨设一个卷积核数据相关信息,输出深度out_d是5,输入深度in_dep是2,卷积核宽度w是3,卷积核高度h是3。具体如下:
[0193]
输出深度out_d是5,一个输出深度方向的数据为[a1,a2,a3,a4,a5],形象理解用图5中的虚线表示;
[0194]
输入深度in_dep是2,一个输入深度方向的数据包括两组输出深度数据,可以表示为:
[0195]
[a1,a2,a3,a4,a5;
[0196]
b1,b2,b3,b4,b5];
[0197]
形象理解用图6所示,图6即是图4中的第一个矩形表示,矩形中有两个虚线。
[0198]
卷积核宽度w是3,一个卷积核宽度方向的数据包括三组输入深度方向的数据,可以表示为:
[0199]
{[a1,a2,a3,a4,a5;
[0200]
b1,b2,b3,b4,b5];
[0201]
[c1,c2,c3,c4,c5;
[0202]
d1,d2,d3,d4,d5];
[0203]
[e1,e2,e3,e4,e5;
[0204]
f1,f2,f3,f4,f5]}
[0205]
形象理解用如图7所示。
[0206]
卷积核高度h是3。形象理解用如图4所示。整个数据表示为:
[0207]
{[a1,a2,a3,a4,a5;
[0208]
b1,b2,b3,b4,b5];
[0209]
[c1,c2,c3,c4,c5;
[0210]
d1,d2,d3,d4,d5];
[0211]
[e1,e2,e3,e4,e5;
[0212]
f1,f2,f3,f4,f5]},
[0213]
{[g1,g2,g3,g4,g5;
[0214]
h1,h2,h3,h4,h5];
[0215]
[i1,i2,i3,i4,i5;
[0216]
j1,j2,j3,j4,j5];
[0217]
[k1,k2,k3,k4,k5;
[0218]
m1,m2,m3,m4,m5]},
[0219]
{[p1,p2,p3,p4,p5;
[0220]
q1,q2,q3,q4,q5];
[0221]
[r1,r2,r3,r4,r5;
[0222]
s1,s2,s3,s4,s5];
[0223]
[t1,t2,t3,t4,t5;
[0224]
u1,u2,u3,u4,u5]}
[0225]
2、simd指令算法。
[0226]
1)simd指令介绍
[0227]
涉及到的simd指令如下。
[0228]
a)相乘再相邻相加的simd指令:
[0229]
vrd=ingenic_muladd_h(vrd,vrs,vrt);
[0230]
输入变量vrd,vrs,vrt,输出变量是vrd。vrd,vrs,vrt是simd类型变量,这些变量是128位寄存器。vrd存储的是8个int16_t的数据,vrs和vrt存储的是16个int8_t数据。由于运算中存在相乘和相加,4bit数据运算后需要16bit存储,我们将4bit输入数据存储成8bit。
[0231]
vrd=[vrd0,vrd1,vrd2,vrd3,vrd4,vrd5,vrd6,vrd7];
[0232]
vrs=[vrs0,vrs1,vrs2,vrs3,vrs4,vrs5,vrs6,vrs7,vrs8,vrs9,vrs10,vrs11,vrs12,vrs13,vrs14,vrs15];
[0233]
vrt=[vrt0,vrt1,vrt2,vrt3,vrt4,vrt5,vrt6,vrt7,vrt8,vrt9,vrt10,vrt11,vrt12,vrt13,vrt14,vrt15];
[0234]
等价的运算:
[0235]
vrd0:=vrd0+vrs0*vrt0+vrs1*vrt1;
[0236]
vrd1:=vrd1+vrs2*vrt2+vrs3*vrt3;
[0237]
...
[0238]
vrd7:=vrd7+vrs14*vrt14+vrs15*vrt15;
[0239]
b)乘法simd指令:
[0240]
vrd=ingenic_mul_b(vrs,vrt);
[0241]
输入变量vrs,vrt,输出变量是vrd。vrd存储的是16个int8_t的数据,vrs和vrt存储的是16个int8_t数据。
[0242]
等价的运算:
[0243]
vrd0:=vrs0*vrt0;
[0244]
vrd1:=vrs1*vrt1;
[0245]
……
[0246]
vrd7:=vrs7*vrt7;
[0247]
……
[0248]
vrd15:=vrs15*vrt15;
[0249]
c)加法simd指令:
[0250]
vrd=ingenic_add_h(vrs,vrt);
[0251]
输入变量vrs,vrt,输出变量是vrd。vrd存储的是8个int16_t的数据,vrs和vrt存储的是8个int16_t数据。
[0252]
等价的运算:
[0253]
vrd0:=vrs0+vrt0;
[0254]
vrd1:=vrs1+vrt1;
[0255]
……
[0256]
vrd7:=vrs7+vrt7;
[0257]
d)移位simd指令:将变量里的每个元素进行移位,移动i个8位。
[0258]
左移移位simd指令
[0259]
vrd=ingenic_shift_left(vrs,i)
[0260]
右移移位simd指令
[0261]
vrd=ingenic_shift_right(vrs,i)
[0262]
e)指定选择simd指令:从变量vrs和vrt中根据vri设置的编号选择出4个或8个或16个数据,在使用该指令时,需要占有一个永久寄存器vri,用于指令选择具体位置的数据。
[0263]
vrd=ingenic_choise_h(vrs,vrt,vri)
[0264]
f)加载数据simd指令:输入的待载入的数据,当前是数据的指针,从该数据在内存里指向的位置开始加载128bit的数据,如果是8bit的数据是加载16个,如果是16bit数据加载8个。数据加载到变量vrd中。
[0265]
vrd=ingenic_load(indata)
[0266]
g)复制或拷贝指定元素simd指令:将变量中指定位置拷贝到输出变量中。指定位置用i表示,每次拷贝的是8bit数据。
[0267]
vrs=[vrs0,vrs1,vrs2,vrs3,vrs4,vrs5,vrs6,vrs7,vrs8,vrs9,vrs10,vrs11,vrs12,vrs13,vrs14,vrs15];
[0268]
拷贝一个数据
[0269]
vrd=ingenic_copy1(vrs,i)
[0270]
例如:
[0271]
i=0;
[0272]
vrd=ingenic_copy1(vrs,i)
[0273]
vrd=[vrs0,vrs0,vrs0,vrs0,vrs0,vrs0,vrs0,vrs0,vrs0,vrs0,vrs0,vrs0,vrs0,vrs0];
[0274]
i=3;
[0275]
vrd=[vrs3,vrs3,vrs3,vrs3,vrs3,vrs3,vrs3,vrs3,vrs3,vrs3,vrs3,vrs3,vrs3,vrs3,vrs3,vrs3];
[0276]
拷贝连续两个数据
[0277]
vrd=ingenic_copy2(vrs,i)
[0278]
例如:
[0279]
i=0;
[0280]
vrd=[vrs0,vrs1,vrs0,vrs1,vrs0,vrs1,vrs0,vrs1,vrs0,vrs1,vrs0,vrs1,vrs0,vrs1,vrs0,vrs1];
[0281]
i=3;
[0282]
vrd=[vrs6,vrs7,vrs6,vrs7,vrs6,vrs7,vrs6,vrs7,vrs6,vrs7,vrs6,vrs7,vrs6,vrs7,vrs6,vrs7];
[0283]
2)simd指令实现卷积计算
[0284]
实现卷积相乘累加的方式和选择simd指令,有很多种,不同的方式和选择的不同的simd指令,会使数据加载次数不同和计算量不同,从而运行速度差异很大。一个合理的使用和设计优化算法可以成倍提高运行速度。
[0285]
不妨设输入数据indata是一组输入深度in_depth为32,宽度in_width为512,高度in_height为512的数据;卷积核数据filter_data为一组输出深度out_depth为128,输入深度in_depth为32(与输入数据深度一致),卷积核宽ft_w为3,卷积核高ft_h为3的数据。设输出数据(特征图)outdata的结构:深度为out_depth,宽度为out_width,高度out_height。在卷积计算中,存在一个步长,设步长为stride。输入数据的一个输入深度方向的数据为:
[0286]
[x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,

x32]
[0287]
卷积核数据两个输出深度方向的数据为:
[0288]
[a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,

a128]
[0289]
[b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,

b128]
[0290]
……
[0291]
a)一种的实现方法。
[0292]
每次加载的数据中的一个数据拷贝到simd指令的变量中,进行8bit的乘法simd指令计算,再进行转化16bit后,进行累加simd指令计算。这种乘法和累加是在最内层循环中实现。其伪代码如下:
[0293]
[0294][0295]
这个伪代码,实现的是一个完整的卷积计算过程,可以扩展到任意尺寸的卷积核和任意尺寸的卷积计算。该算法中设涉及到simd指令运算主要在最里层一个循环。其他的可以视为与c程序算法设计一样。在最里层循环中,使用的是一次加载16个数据,数据一次运算16个结果,从而极大的提升的运算时间。
[0296]
in_value=ingenic_load(a_loc+l)的simd指令操作,将数据加载后,数据一直在寄存器中,没有了重复加载,节省很多时间。在最里层的循环中,实现数据的重复使用。这个重复使用体现在in_0=ingenic_copy1(in_value,fn)。由于乘法simd指令得到的结果是8bit数据,在寄存器中是16个8bit数据,需要将数据转化为16bit后才能进行后面的累加,此时需要将muls转存到两个128寄存器中,同时将16个数据转化为16bit。我们的芯片中没有8位到16位数据的转化指令,这里用选择simd指令将muls数据前8个8bit数据存放到一个128位寄存器mul_0中,存放形式为:
[0297]
[a1,a1,b1,b1,c1,c1,d1,d1,e1,e1,f1,f1,g1,g1,h1,h1];
[0298]
再将该数据进行右移位simd指令操作,得到:
[0299]
[a1,b1,c1,d1,e1,f1,g1,h1]
[0300]
此时是8个16bit数据存放到一个128位寄存器mul_0。
[0301]
用选择simd指令将寄存器muls内数据的后8个8bit数据存放到一个128位寄存器mul_1中,存放形式为:
[0302]
[m1,m1,n1,n1,p1,p1,k1,k1,r1,r1,f1,f1,t1,t1,v1,v1];
[0303]
再将该数据进行右移位simd指令操作,得到:
[0304]
[m1,n1,p1,k1,r1,f1,t1,v1];
[0305]
此时是8个16bit数据存放到一个128位寄存器mul_0。这样处理的原因,我们寄存器里面存的都是有符号数据,为了保证数据的符号性,所以先将数据存放到高8位,再将寄存器数据执行右移位simd指令操作,使得数据8bit转化为16bit。
[0306]
上面的混合c和simd指令算法,比纯c算法,提升速度在10倍以上。
[0307]
b)对上面的算法进行改进,使用相乘再相邻相加的simd指令,进一步优化算法。
[0308]
在a)的伪代码中,最里层一个循环可以改为如下伪代码:
[0309]
for(int fn=0;fn《8;fn++){
[0310]
in_0=ingenic_copy2(in_value,fn);复制连续两个数据到寄存器in_0中
[0311]
ft_0=ingenic_load(b_ptr+filter_count*(ft_l+2*fn));
[0312]
ft_1=ingenic_load(b_ptr+filter_count*(ft_l+2*fn+1));
[0313]
choise_0=ingenic_choise_h(ft_0,ft_1,vrt0);
[0314]
该操作从ft_0和ft_1中选择出指定的16个8bit数据,放置到128寄存器choise_0内。
[0315]
choise_1=ingenic_choise_h(ft_0,ft_1,vrt1);
[0316]
该操作从ft_0和ft_1中选择出指定的16个8bit数据,放置到128寄存器choise_1内。
[0317]
sum_0=ingenic_muladd_h(sum_0,in_0,choise_0);
[0318]
执行simd指令将两个寄存器的相加,结果存到128位寄存器sum_0中
[0319]
sum_1=ingenic_muladd_h(sum_1,in_0,choise_1);
[0320]
执行simd指令将两个寄存器的相加,结果存到128位寄存器sum_0中
[0321]
}
[0322]
这段伪代码中,加载两次卷积核数据:
[0323]
ft_0=ingenic_load(b_ptr+filter_count*(ft_l+2*fn));
[0324]
ft_1=ingenic_load(b_ptr+filter_count*(ft_l+2*fn+1));
[0325]
由于执行的for循环是8次,而在循环里面加载卷积核是两次,所以对于卷积核加载是同样的,但可以重复使用in_0,减少一个simd指令,降低相应的计算时间。
[0326]
假设ft_0,ft_1的具体数据如下:
[0327]
ft_0=[f0,f1,f2,f3,f4,f5,f6,f7,g0,g1,g2,g3,g4,g5,g6,g7];
[0328]
ft_1=[j0,j1,j2,j3,j4,j5,j6,j7,k0,k1,k2,k3,k4,k5,k6,k7];
[0329]
在choise_0=ingenic_choise_h(ft_0,ft_1,vrt0)中通过vrt0指定具体位置后,
得到如下的choise_0:
[0330]
choise_0=[f0,j0,f1,j1,f2,j2,f3,j3,f4,j4,f5,j6,f6,j6,f7,j7];
[0331]
在choise_1=ingenic_choise_h(ft_0,ft_1,vrt1)中通过vrt1指定具体位置后,得到如下的choise_1:
[0332]
choise_1=[g0,k0,g1,k1,g2,k2,g3,k3,g4,k4,g5,k5,g6,k6,g7,k7];
[0333]
后面再执行相乘相加的simd指令:
[0334]
sum_0=ingenic_muladd_h(sum_0,in_0,choise_0);
[0335]
sum_1=ingenic_muladd_h(sum_1,in_0,choise_1);
[0336]
这相当于在a)伪代码的最内层连续执行了两次,即执行了fn和(fn+1),使用ingenic_muladd_h指令,一次将加法和乘法,还有8bit转化为16bit的换算全都执行了,节省的时间更多。但实现过程需要卷积核数据内相邻深度数据的交叉存储到一个寄存器,同时需要两个寄存器存储。具体实现如上。所述相乘相加:两个向量对应数相乘,相乘后,得到一个向量a,再把这个a向量两个数据相加,例如a0+a1,a2+a3,

得到的数据个数是原来的一半。再将相加后的向量与sum_0相加,得到的结果再赋给sum_0。
[0337]
c)降低数据的重复加载,采用有限的窗口或步长的计算模式。
[0338]
采用有限窗口的原因有两个:1)卷积计算是多个输入数据和卷积核中多个数据相乘累加后得到一个输出特征图数据的一个值,有限个寄存器个数无法容纳卷积核中所有的的数据或是输入数据,这就导致了无法避免的重复性加载。2)由于寄存器个数有限,寄存器超过使用个数,会导致寄存器内的数据存储到内存,再次使用该数据时,从内存中加载数据,导致出现寄存器数据反复存取数据,从而降低速度。所以采用有限的几个窗口数,可以增大速度,超过一定数目,反而降低速度。
[0339]
目前我们有如下有限窗口或步长的实现方法。伪代码如下:
[0340]
[0341][0342]
这段伪代码中,在输出数据(特征图)宽度上连续生成两组数据,sum_0和sum_1是第一组,sum_20和sum_21是第一组,也就是:
[0343]
sum_0=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
[0344]
sum_1=sum_0
[0345]
sum_20=sum_0;
[0346]
sum_21=sum_0;
[0347]
由于生成的结果同时生成两组,所以在输入数据中需要同时加载两组数据:
[0348]
in_value=ingenic_load(a_loc+l);
[0349]
in_value1=ingenic_load(a_loc+l+in_depth*stride);
[0350]
其中a_loc+l+in_depth*stride指针指向的位置与a)伪代码中生成第二组数据时需要的输入数据指针指向的位置相同,所以在这里可以同时加载。
[0351]
最里层一个for循环,同时实现两组输出数据的计算,将ft_0和ft_1使用了两次,数据使用量增加,加载次数减少一倍。指令个数减少。所以整体计算时间减少。
[0352]
这里是步长为2的一个设计,是从寄存器总数和后面量化处理需要一些寄存器考虑,没有再增大步长或是使用大的窗口,如果后面算法处理节省出更多寄存器或是芯片寄存器个数更多一些,可以增大步长或窗口窗口。
[0353]
此时该simd指令算法比纯c算法提升20倍左右。
[0354]
具体地,如图8所示,本发明的第一实施例方法,所述方法包括以下步骤:
[0355]
s1,设输入数据indata是一组输入深度in_depth为32,宽度in_width为512,高度
in_height为512的数据;卷积核数据filter_data为一组输出深度out_depth为128,输入深度in_depth为32,其与输入数据深度一致,卷积核宽ft_w为3,卷积核高ft_h为3的数据;
[0356]
设输出数据即特征图outdata的结构:深度为out_depth,宽度为out_width,高度out_height;在卷积计算中,存在一个步长,设步长为stride;
[0357]
设simd类型变量:sum_0,sum_1,in_value,in_0,ft_0,vrt1,vrt2,muls,mul_0,mul_1;其他参数是指针或是具体常规数据;
[0358]
s2,第一层循环:设h=0;
[0359]
s2.1,判断h《out_height是否成立,
[0360]
s2.2,若不成立,则停止第一层循环;若成立,
[0361]
执行:in_h=h*stride,
[0362]
执行:步骤s3;
[0363]
s2.3,进行h=h+1,返回步骤s2.1;
[0364]
s3,第二层循环:设w=0;
[0365]
s3.1,判断w《out_width是否成立,
[0366]
s3.2,若不成立,则停止第二层循环,进行步骤s2.3;若成立,
[0367]
执行:in_w=w*stride,
[0368]
执行:in_ptr=indata+in_w*in_depth,该参数为输入数据指针;执行:out_ptr=oudata+h*out_width*out_depth,该参数为输出数据即特征图指针;
[0369]
执行:步骤s4;
[0370]
s3.3,进行w=w+1,返回步骤s3.1;
[0371]
s4,第三层循环:设i=0;
[0372]
s4.1,判断i《=out_depth

16是否成立,
[0373]
s4.2,若不成立,则停止第三层循环,进行步骤s3.3;若成立,
[0374]
执行:b_ptr=ft_data+i;该参数为卷积核数据指针;
[0375]
执行:sum_0=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];初始化sum_0为0;
[0376]
执行:sum_1=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];初始化sum_1为0;
[0377]
执行:步骤s5;
[0378]
s4.3,进行i=i+16,返回步骤s4.1;
[0379]
s5,第四层循环:设p=0;
[0380]
s5.1,判断p《ft_h是否成立,
[0381]
s5.2,若不成立,在停止第四层循环,进行步骤s4.3;若成立,
[0382]
执行:ft_k=p*ft_h;
[0383]
执行:in_loc=in_ptr+(in_h+p)*in_width*in_height;
[0384]
执行:步骤s6;
[0385]
s5.3,进行++p,返回步骤s5.1;
[0386]
s6,第五层循环:设l=0;
[0387]
s6.1,判断l《=ft_w*in_depth

16是否成立,
[0388]
s6.2,若不成立,则停止第五层循环,进行步骤s5.3;若成立,
[0389]
执行:ft_l=ft_k+l;
[0390]
执行:加载数据,从指针a_loc+l位置开始读取128位数据,即读取16个8位数据,将数据存放到128位寄存器in_value中,即表示为in_value=ingenic_load(a_loc+l);
[0391]
执行:步骤s7;
[0392]
s6.3,进行l=l+16,返回步骤s6.1;
[0393]
如图9所示,s7,最内层循环:设fn=0;
[0394]
s7.1,判断fn《16是否成立,
[0395]
s7.2,若不成立,则停止最内层循环,进行步骤s6.3;若成立,
[0396]
执行:拷贝simd指令,拷贝一个数据,将变量中指定位置拷贝到输出变量中,指定位置用fn表示,每次拷贝的是8bit数据,即表示为in_0=ingenic_copy1(in_value,fn);
[0397]
执行:乘法simd指令,即表示为muls=ingenic_mul_b(in_0,vrt);
[0398]
执行:选择simd指令,从muls中选择出前8个8bit数据,放置到128寄存器mul_0内部每个16位的高8位中,即表示为mul_0=ingenic_choise_h(muls,muls,vrt1);
[0399]
执行:移位simd指令,对数据进行右移位simd指令操作,将前8个8bit数据恢复到实际数据值,即表示为mul_0=ingenic_shift_right(mul_0,1);
[0400]
执行:从muls中选择出后8个8bit数据,放置到128寄存器mul_1内部每个16位的高8位中,即表示为mul_1=ingenic_choise_h(muls,muls,vrt2);
[0401]
执行:对数据进行右移位simd指令操作,将前8个8bit数据恢复到实际数据值,即表示为mul_1=ingenic_shift_right(mul_1,1);
[0402]
执行:执行simd指令将两个寄存器的相加,结果存到128位寄存器sum_0中,即表示为sum_0=ingenic_add_h(sum_0,mul_0);
[0403]
执行:执行simd指令将两个寄存器的相加,结果存到128位寄存器sum_1,即表示为sum_1=ingenic_add_h(sum_1,mul_1);
[0404]
s7.3,进行fn=fn+1,返回步骤s7.1。
[0405]
如图10所示,优化的所述步骤s7为,
[0406]
s7,最内层循环,设fn=0:
[0407]
s7.1,判断fn《8是否成立,
[0408]
s7.2,若不成立,则停止最内层循环;若成立,则
[0409]
执行:复制连续两个数据到寄存器in_0中,即in_0=ingenic_copy2(in_value,fn);
[0410]
in_value里面是16个8bit数据组成的向量,但在寄存器里这个向量是128bit。我们复制连续两个数据,就是把操作看成从寄存器中复制出16bit数据,也就是是2*8bit的数据。这个指令fn是指定拷贝第几个16bit数据。在in_0里面,是把这个拷贝的数据[a0,a1](例如fn=0,a0,a1是8bit数据)重复性放置,也就是[a0,a1,a0,a1,a0,a1,a0,a1,a0,a1,a0,a1,a0,a1,a0,a1,a0,a1,a0,a1];
[0411]
执行:ft_0=ingenic_load(b_ptr+filter_count*(ft_l+2*fn));
[0412]
执行:ft_1=ingenic_load(b_ptr+filter_count*(ft_l+2*fn+1));
[0413]
执行:从ft_0和ft_1中选择出指定的16个8bit数据,放置到128寄存器choise_0内,即choise_0=ingenic_choise_h(ft_0,ft_1,vrt0);
[0414]
执行:从ft_0和ft_1中选择出指定的16个8bit数据,放置到128寄存器choise_1
内,即choise_1=ingenic_choise_h(ft_0,ft_1,vrt1);
[0415]
执行:simd指令将两个寄存器的相加,结果存到128位寄存器sum_0中,即sum_0=ingenic_muladd_h(sum_0,in_0,choise_0);
[0416]
执行:simd指令将两个寄存器的相加,结果存到128位寄存器sum_1中,即
[0417]
sum_1=ingenic_muladd_h(sum_1,in_0,choise_1);
[0418]
s7.3,进行fn=fn+1,返回步骤s7.1。
[0419]
如图11所示,本发明的第二实施例方法,所述方法还可以为以下步骤:
[0420]
s1,设输入数据indata是一组输入深度in_depth为32,宽度in_width为512,高度in_height为512的数据;卷积核数据filter_data为一组输出深度out_depth为128,输入深度in_depth为32,其与输入数据深度一致,卷积核宽ft_w为3,卷积核高ft_h为3的数据;
[0421]
设输出数据即特征图outdata的结构:深度为out_depth,宽度为out_width,高度out_height;在卷积计算中,存在一个步长,设步长为stride;
[0422]
设simd类型变量:sum_0,sum_1,sum_20,sum_21,in_value,in_value1,in_0,in_1,ft_0,vrt1,vrt2,mul_0,其他参数是指针或是具体常规数据;
[0423]
s2,第一层循环:设h=0;
[0424]
s2.1,判断h《out_height是否成立,
[0425]
s2.2,若不成立,则停止第一层循环;若成立,
[0426]
执行:in_h=h*stride,
[0427]
执行:步骤s3;
[0428]
s2.3,进行h=h+1,返回步骤s2.1;
[0429]
s3,第二层循环:设w=0;
[0430]
s3.1,判断w《out_width是否成立,
[0431]
s3.2,若不成立,则停止第二层循环,进行步骤s2.3;若成立,在输入数据即特征图的宽度方向执行步长为2的重复性计算:
[0432]
执行:in_w=w*stride,
[0433]
执行:in_ptr=indata+in_w*in_depth,该参数为输入数据指针;
[0434]
执行:out_ptr=oudata+h*out_width*out_depth,该参数为输出数据即特征图指针;
[0435]
执行:步骤s4;
[0436]
s3.3,进行w=w+2,返回步骤s3.1;
[0437]
s4,第三层循环:设i=0;
[0438]
s4.1,判断i《=out_depth

16是否成立,
[0439]
s4.2,若不成立,则停止第三层循环,进行步骤s3.3;若成立,
[0440]
执行:b_ptr=ft_data+i;该参数为卷积核数据指针;
[0441]
执行:sum_0=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];初始化sum_0为0;
[0442]
执行:sum_1=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];初始化sum_1为0;
[0443]
执行:sum_20=sum_0;
[0444]
执行:sum_21=sum_0;
[0445]
这里是由输出数据宽度每次加2,产生出两个结果;
[0446]
执行:步骤s5;
[0447]
s4.3,进行i=i+16,返回步骤s4.1;
[0448]
s5,第四层循环:设p=0;
[0449]
s5.1,判断p《ft_h是否成立,
[0450]
s5.2,若不成立,在停止第四层循环,进行步骤s4.3;若成立,
[0451]
执行:ft_k=p*ft_h;
[0452]
执行:in_loc=in_ptr+(in_h+p)*in_width*in_height;
[0453]
执行:步骤s6;
[0454]
s5.3,进行++p,返回步骤s5.1;
[0455]
s6,第五层循环:设l=0;
[0456]
s6.1,判断l《=ft_w*in_depth

16是否成立,
[0457]
s6.2,若不成立,则停止第五层循环,进行步骤s5.3;若成立,
[0458]
执行:ft_l=ft_k+l;
[0459]
执行:加载数据,从指针a_loc+l位置开始读取128位数据,即读取16个8位数据,将数据存放到128位寄存器in_value中,即表示为in_value=ingenic_load(a_loc+l);
[0460]
执行:in_value1=ingenic_load(a_loc+l+in_depth*stride);
[0461]
执行:步骤s7;
[0462]
s6.3,进行l=l+16,返回步骤s6.1;
[0463]
如图12所示,s7,最内层循环:设fn=0;
[0464]
s7.1,判断fn《8是否成立,
[0465]
s7.2,若不成立,则停止最内层循环,进行步骤s6.3;若成立,
[0466]
执行:拷贝数据:
[0467]
in_0=ingenic_copy2(in_value,fn);
[0468]
加载数据需要多加载一组,也就是in_1,即in_1=ingenic_copy2(in_value1,fn);
[0469]
执行:加载simd指令:
[0470]
ft_0=ingenic_load(b_ptr+filter_count*(ft_l+2*fn));
[0471]
ft_1=ingenic_load(b_ptr+filter_count*(ft_l+2*fn+1));
[0472]
执行:选择simd指令:
[0473]
choise_0=ingenic_choise_h(ft_0,ft_1,vrt0);
[0474]
choise_1=ingenic_choise_h(ft_0,ft_1,vrt1);
[0475]
执行:累加simd指令:
[0476]
sum_0=ingenic_muladd_h(sum_0,in_0,choise_0);
[0477]
sum_1=ingenic_muladd_h(sum_1,in_0,choise_1);
[0478]
sum_20=ingenic_muladd_h(sum_0,in_1,choise_0);
[0479]
sum_21=ingenic_muladd_h(sum_1,in_1,choise_1);
[0480]
s7.3,进行fn=fn+1,返回步骤s7.1。
[0481]
以上所述仅为本发明的优选实施例而已,并不用于限制本发明,对于本领域的技术人员来说,本发明实施例可以有各种更改和变化。凡在本发明的精神和原则之内,所作的
任何修改、等同替换、改进等,均应包含在本发明的保护范围之内。
当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1