2012-12-27 211 views
0

我想在cuda中做矩阵乘法。我的实现与cuda示例不同。cuda矩阵乘以列

cuda示例(来自cuda样本)通过将第一个矩阵的行中的每个值乘以第二个矩阵的列中的每个值来执行矩阵乘法,然后对乘积求和并将其存储在输出向量中来自第一个矩阵的行的索引。

我的实现将第一个矩阵的列中的每个值乘以第二个矩阵的行的单个值,其中行索引=列索引。然后在全局内存中有一个输出向量,每个索引都更新。

cuda示例实现可以让一个线程更新输出向量中的每个索引,而我的实现可以有多个线程更新每个索引。

我得到的结果只显示了一些值。例如,如果我做了4次迭代更新,它只会做2或1.

我认为线程可能互相干扰,因为他们都试图写入相同的索引全球存储器中的矢量。也许,当一个线程写入索引时,另一个线程可能无法插入其值并更新索引?

只是想知道这个评估是否有意义。

例如。乘以以下两个矩阵:

[3 0 0 2   [1  [a 
3 0 0 2 x  2 = b 
3 0 0 0   3  c 
0 1 1 0]   4]  d] 

在CUDA样品确实矩阵乘法中使用4个线程以下方式其中a,b,C,d被存储在全局存储器:

Thread 0: 3*1 + 0*2 + 0*3 + 2*4 = a 
Thread 1: 3*1 + 0*2 + 0*3 + 2*4 = b 
Thread 2: 3*1 + 0*2 + 0*3 + 0*4 = c 
Thread 3: 0*1 + 1*2 + 1*3 + 0*4 = d 

我的实现看起来像这样:

a = b = c = d = 0 

Thread 0: 
3*1 += a 
3*1 += b 
3*1 += c 
0*1 += d 

Thread 1: 
0*2 += a 
0*2 += b 
0*2 += c 
1*2 += d 

Thread 2: 
0*3 += a 
0*3 += b 
0*3 += c 
1*3 += d 

Thread 3: 
2*4 += a 
2*4 += b 
0*4 += c 
0*4 += d 

所以有一次所有四个线程可能试图更新其中一个索引。

+0

您的内核的某些代码可能会有所帮助。我不能说我完全理解你的描述。但是,如果你有多个线程更新给定的输出点,那么你可能想考虑使用[atomics](http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#atomic-函数)以避免线程之间的干扰。 –

+0

所以你基本上是通过另一个矩阵的对角线条目缩放一个矩阵的列?现在并不明显,为什么你需要有多个线程更新单个输出项。每个输出条目都不会独立于除自己的值和第二个矩阵的常量对角线条目之外的任何东西吗? – talonmies

+0

抱歉,您的模糊描述。我更新了问题以帮助描述问题。我担心的是线程在尝试更新输出向量时会相互干扰。我会看看原子,看看那是关于什么的。感谢您的回应! – napl

回答

1

为了解决这个问题,我用atomicAdd来做+ =的操作。当一个线程执行操作3 * 1 + = a(例如)时,它执行三件事。

  1. 它得到的一个
  2. 于前值它做3 * 1 +前值更新值
  3. 然后将新值到一个

通过使用atomicAdd它保证这些操作可以由线程发生而不会中断其他线程。如果不使用atomicAdd,thread0能拿一个于前值和同时thread0正在更新值,线程1可以得到的一个以前的值,并执行自己的更新。通过这种方式,+ =操作不会发生,因为线程无法完成其操作。

如果一个+ = 3 * 1是用来代替atomicAdd(&一个,3 * 1),则有可能对线程1干涉并改变thread0的值thread0完成它在做什么之前。它创造了一个竞赛条件。

atomicAdd+ =操作。您可以使用以下代码执行操作:

__global__ void kernel(){  
int a = 0; 
atomicAdd(&a, 3*1); //is the same as a += 3*1 
}