我正在使用CUDA中的特殊矩阵 - 矩阵乘法(AxB
),其中A
是随机MxM
矩阵,B
是MxN
矩阵。在以下代码中,M
仅为2000
,但在实际情况下,它将替换为大号,以便为2GB
提供超过A
矩阵。实际上,A
的所有元素都是随机的,并且仅限于某个范围,因此将由随机函数生成。
我编写了下面的代码,其中A
的每个元素都是从数组中随机选取的,因此原始AxB
将被修改为长度为M
的向量乘以B
。这是我编写代码的方式,但似乎它不起作用
#include <iostream>
#include <cusp/complex.h>
using namespace std;
#define M 2000
#define N 300
typedef cusp::complex<double> Complex;
__global__ void MVult(Complex* ad, Complex* bd, Complex* cd, int m1, int n1, int n2)
{
int x = (blockIdx.x * blockDim.x) + threadIdx.x;
int y = (blockIdx.y * blockDim.y) + threadIdx.y;
if(x < n2 && y < m1)
{
Complex sum = Complex(0.0, 0.0);
int ridx = (rand()%(M-1)); // here I randomize the starting ridx
for(int i=0; i<n1; i++) sum += ad[ridx + i] * bd[i * n2 + x];
cd[y * n2 + x] = v;
}
}
int main(int argc, char *argv[])
{
std::vector< Complex > _A(2*M+1);
std::vector< Complex > _B(M*N);
Complex *A, *B, *C;
cudaMalloc((void**)&A, (2*M+1)*sizeof(Complex));
cudaMalloc((void**)&B, M*N*sizeof(Complex));
cudaMalloc((void**)&C, M*N*sizeof(Complex));
for (int i=0; i<2*M+1; i++) _A[i] = Complex((double)i, (double)i);
for (int i=0; i<M*N; i++) _B[i] = Complex(1.0, 0.0);
cudaMemcpy( A, &_A[0], (2*M+1)*sizeof(Complex), cudaMemcpyHostToDevice );
cudaMemcpy( B, &_B[0], (M*N)*sizeof(Complex), cudaMemcpyHostToDevice );
dim3 block(32, 32);
dim3 grid((N+31)/32, (M+31)/32);
MVult<<<grid, block>>>(A, B, C, M, M, N);
cudaMemcpy(&_B[0], &C[0], (M*N)*sizeof(Complex), cudaMemcpyDeviceToHost);
cudaFree(A);
cudaFree(B);
cudaFree(C);
return 0;
}
我尝试使用CPU循环将其循环M
次,每次运行向量和矩阵乘法(在CUDA中完成),但它太慢了。我正在寻找一种更快的方法来解决问题。
答案 0 :(得分:1)
由于两个主要原因,您的代码会很慢:
A
的方式中,您随机访问全局内存,因此阻止了合并访问; cuBLAS
慢。要加快代码速度,而不是使用__global__
函数MVult
,您可以/应该使用
cuRAND
用随机数填充矩阵A
; cuBLAS
执行A
和B
之间的矩阵乘法,特别是cublasCgemm()
,用于单精度复杂计算。 如果矩阵A
太大,那么您可以尝试将A*B
的计算划分为较小的切片,然后使用cuBLAS
的批处理功能(使用cublasSetStream()
)尝试使用CUDA流实现并发执行。
您可能还希望使用推力来查看以下示例:
Matrix multiplication on GPU using CUDA with CUBLAS, CURAND and Thrust
正如@talonmies所建议的那样,您可能也希望重新考虑您的方法。例如,如果A
是随机矩阵,那么A*B
也是随机的。是否有可能利用A
的统计数据以及B
可能的先验知识,通过随机方法直接构造矩阵A*B
,而无需使用矩阵乘法?