两个一维向量点积的约简算法

Posted

技术标签:

【中文标题】两个一维向量点积的约简算法【英文标题】:Reduction Algorithm for Dot Product of Two 1D Vectors 【发布时间】:2015-11-12 07:14:48 【问题描述】:

我一直在尝试制定一种算法,通过约简获得 CUDA 程序中两个向量的点积,但似乎卡住了:/

本质上,我正在尝试在 CUDA 中编写这段代码:

for (int i = 0; i < n; i++)
    h_h += h_a[i] * h_b[i];

其中h_ah_b 是浮点数组,h_h 对点积求和。

我正在尝试在这里使用归约 - 到目前为止,我已经掌握了这个...

__global__ void dot_product(int n, float * d_a, float * d_b)

     int i = threadIdx.x;

     for (int stride = 1; i + stride < n; stride <<= 1) 
         if (i % (2 * stride) == 0)
             d_a[i] += d_a[i + stride] * d_b[i + stride];
         
         __syncthreads();
     

如果我将主线更改为d_a[i] += d_a[i + stride];,它可以很好地总结数组。从我收集的信息来看,我似乎在这里遇到了一个平行的问题。有人能指出我的问题吗?

我的内核调用是:

dot_product&lt;&lt;&lt;1, n&gt;&gt;&gt;(n, d_a, d_b);,其中n 是每个数组的大小。

【问题讨论】:

【参考方案1】:

这里有两个问题:

    正如 cmets 中所指出的,您永远不会计算第一个元素的乘积(这是一个小问题) 您的点积计算不正确。并行减少应该执行相应元素的单个乘积的总和。您的代码在并行归约的每个阶段执行产品,因此产品在相加时再次相乘。这是不正确的。

你想做这样的事情:

__global__ void dot_product(int n, float * d_a, float * d_b)

     int i = threadIdx.x;

     d_a[i] = d_a[i] * d_b[i]; // d_a now contains products
     __syncthreads();

     for (int stride = 1; i + stride < n; stride <<= 1) 
         if (i % (2 * stride) == 0)
             d_a[i] += d_a[i + stride]; // which are summed by reduction
         
         __syncthreads();
     

[免责声明:在浏览器中编写,从未编译或测试,使用风险自负]

【讨论】:

以上是关于两个一维向量点积的约简算法的主要内容,如果未能解决你的问题,请参考以下文章

关于向量点积和叉积的回顾和总结

NumPy 点积:取向量积的积(而不是求和)

函数式编程的约简操作

向量点积几何意义是啥 向量点积几何意义介绍

向量数组,计算点积

向量积的几何意义 向量积的几何意义是啥