1维卷积的公式如下.
用c++串行计算,程序如下:
void conv(vector<int> &uIn, vector<int>&vIn, vector<int>&convOut)
{
vector<int>::iterator itU = uIn.begin();
vector<int>::iterator itV = vIn.begin();
convOut.clear();
int uSize = uIn.size();
int vSize = vIn.size();
int numResult = uSize + vSize - 1;
convOut.resize(numResult);
for (int i = 0; i<numResult; i++)
{
convOut[i] = 0;
for (int j = 0; j <= i; j++)
{
int k = i - j;
int tempU = j<uSize ? uIn[j] : 0;
int tempV = k<vSize ? vIn[k] : 0;
convOut[i] += tempU*tempV;
}
}
}
现在需要在cuda上面进行并行计算,先进行并行化的算法设计:
一,总体思路,
- 将数据分割成块,每个块单独计算。
- 将数据进行合并。
二,具体算法,
- 分割成32x32的块(a中依次取32个数,b依次取32个数),每个块内进行计算。
- 每个32x32的块中,计算如下:
2.1,生成矩阵如下:
如果是4x4,那么类似的矩阵如下:
a0*b0 | 0 | 0 | 0 |
a0*b1 | a1*b0 | 0 | 0 |
a0*b2 | a1*b1 | a2*b0 | 0 |
a0*b3 | a1*b2 | a2*b1 | a3*b0 |
0 | a1*b3 | a2*b2 | a3*b1 |
0 | 0 | a2*b3 | a3*b2 |
0 | 0 | 0 | a3*b3 |
0 | 0 | 0 | 0 |
矩阵大小为8x4,其中第8行为全0,只是为了内存对齐。 a为1个数组,b为另1个数组。那么对于32x32的输入,那么生成的矩阵大小为64x32,最后一行也是全0。
2.2,将矩阵的每一行的数据相加,得到一个累加和,那么64行,就有64个结果。这64个结果就是这个32x32的卷积结果。
2.3, 将结果存入一片内存中,格式如下:
对于总长128x128(数组a的长度为128,数组b的长度为128)的数据,内存格式如下:
这个矩阵的宽和高等于length(a)/32. length(b)/32这个矩阵中,每个元素包含一个数组,长度为64,也就是2.2步的计算结果3
3. 合并的第一步是将2.3中的数据格式进行转换,转换结果如下:
这个矩阵中,每一个元素包含32个数据,这个32个数据是通过取2.3结果中的一个元素(下标为ia,ib)的前32个值,再取这个元素的上一行对应的元素(下标为ia-1,ib)的后32个值,然后对应相加。这部分的matlab程序如下:
blocksStep2 = cell(blockNumY*2,blockNumX);
for ix = 1:blockNumX
for iy = 1:(blockNumY + 1)
currArr32 = zeros(1,32);
if(iy<=blockNumY)
currArr32 = blocksStep1{iy,ix}(1:32);
end
lastArr32 = zeros(1,32);
if(iy>1)
lastArr32 = blocksStep1{iy-1,ix}(33:64);
end
blocksStep2{iy+ix-1,ix} = currArr32+lastArr32;
end
end
其中blockNumY为2.3结果矩阵的总行数,blockNumX为2.3结果矩阵的总列数。
4.将第3步的结果矩阵中的每一个元素中的32个数据 进行 列排列,1x32 à32x1。然后将矩阵的每一行的4个32x1数组拼接成一个32x4的矩阵。然后将这个32x4的矩阵的每一行的值进行相加,就得到32个数据。对应于第3步的矩阵中,每一行会有32个数据结果。然后将所有结果按顺序保存下来,得到最后的结果,数据个数为32x8最后一个数据无效,那么有效数据个数为32x8 – 1.
5.此文中,以128长度的数组为例进行解释,对于1024长度的数据,也是一样的道理,那么2.3的结果矩阵大小为32x32,第3步的结果矩阵大小为64x32.最后的总的结果数为64x32-1.
测试结果如下:
1,电脑配置:CPU, intel pentinum G860@ 3.00Ghz双核。
GPU,nvidia Geforce GTX 1060 3G (七彩虹)
2,数据长度,a的长度为1024,b的长度为1024
3,结果如下:
cuda conv cost 0.001453s
sum is 1074003968
cpu conv cost 0.294342s
sum is 1074003968
GPU还是很有优势的,如果把CPU换成高性能的,应该不用花费290ms这么多,但是也比不上GPU快
测试程序在https://gitee.com/yt2014/cuda-programs/tree/master/conv_1d