2011-02-16 31 views
7

Estoy enzarzado con la multiplicación de matrices en CUDA. La matriz resultante del producto es siempre cero. He leído algunos códigos de muestra como matrix multiplication in cuda para resolver mi problema, pero todo fue en vano.Multiplicación de matrices usando CUDA

Aparte del resultado errático de 0, el tamaño máximo de "Ancho" (código a continuación) no es ni siquiera 512. No pude depurar dónde reside el problema. Puede ser que podamos discutirlo en StackOverflow.

me refiero "Programación de procesadores masivamente paralelos"

#include<cuda.h> 
#include<stdio.h> 

int main(void) { 
    void MatrixMultiplication(float *, float *, float *, int); 
    const int Width = 5; 
    float M[Width*Width], N[Width*Width], P[Width*Width]; 
    for(int i = 0; i < (Width*Width) ; i++) { 
     M[i] = 5; 
     N[i] = 5; 
     P[i] = 0; 
    } 
    MatrixMultiplication(M, N, P, Width); 
    for(int i = 0; i < (Width*Width) ; i++) { 
     printf("%d \n", P[i]); 
    } 
    int quit; 
    scanf("%d",&quit); 
    return 0; 
} 

//Matrix multiplication kernel - thread specification 
__global__ void MatrixMulKernel(float *Md, float *Nd, float *Pd, int Width) { 
    //2D Thread ID 
    int tx = threadIdx.x; 
    int ty = threadIdx.y; 

    //Pvalue stores the Pd element that is computed by the thread 
    float Pvalue = 0; 

    for(int k = 0; k < Width ; ++k) { 
     float Mdelement = Md[ty*Width + k]; 
     float Ndelement = Nd[k*Width + tx]; 
     Pvalue += (Mdelement*Ndelement); 
    } 

    Pd[ty*Width + tx] = Pvalue; 
} 

void MatrixMultiplication(float *M, float *N, float *P, int Width) { 
    int size = Width*Width*sizeof(float); 
    float *Md, *Nd, *Pd; 

    //Transfer M and N to device memory 
    cudaMalloc((void**)&Md, size); 
    cudaMemcpy(Md,M,size,cudaMemcpyHostToDevice); 
    cudaMalloc((void**)&Nd, size); 
    cudaMemcpy(Nd,N,size,cudaMemcpyHostToDevice); 

    //Allocate P on the device 
    cudaMalloc((void**)&Pd,size); 

    //Setup the execution configuration 
    dim3 dimBlock(Width,Width); 
    dim3 dimGrid(1,1); 

    //Launch the device computation threads! 
    MatrixMulKernel<<<dimGrid,dimBlock>>>(Md,Nd,Pd,Width); 

    //Transfer P from device to host 
    cudaMemcpy(P,Pd,size,cudaMemcpyDeviceToHost); 

    //Free device matrices 
    cudaFree(Md); 
    cudaFree(Nd); 
    cudaFree(Pd); 
} 
+2

Para obtener el formato de código correcto, debe sangrar todo el código con 4 espacios. Puede hacerlo fácilmente resaltando su código y presionando 'Ctrl + K'. –

+0

¡Gracias, Jeff! Simplemente iba a hacer eso –

+0

Si no necesita seguir su propio código, la Guía de programación de CUDA C tiene una maravillosa implementación matrix-mul que puede manejar matrices con otras dimensiones que potencias de dos y que se optimiza utilizando la memoria compartida. Lo recomiendo mucho para el uso en el mundo real y para el aprendizaje. –

Respuesta

1

me di cuenta de lo que era incorrecto. Analicemos que:

Punto 1: El intento de eliminar la siempre monótona "valor cero"

Como se ha señalado, debe reemplazar printf("%d \n", P[i]); como printf("%f \n", P[i]);

Punto 2: ¿Por qué el programa falla con un valor de Ancho 512?

En realidad fallará incluso para un valor pequeño como 23. ¿Por qué? Porque 23 * 23 es> 512 (¡El número máximo de hilos que una GPU puede tener por bloque a partir de hoy!)

0

En sus MatrixMulKernel funcionan su ciclo for es como

for(int k = 0; k < Width ; ++k) 
{ 
    //rest of code  
} 

En lugar de Width, debe utilizar Width*Width que incluía la matriz es de tamaño Width*Width.

+1

El objetivo de utilizar el paralelismo CUDA es eliminar la sobrecarga computacional. En este caso, cada hilo es responsable de solo 1 resultado de la matriz del producto. Un resultado (elemento) de la matriz del producto se puede encontrar utilizando iteraciones de "Ancho". Por lo tanto, Ancho * Ancho no va a funcionar en ningún caso. –

+0

como @Gaurav dijo, Ancho * Ancho solo volará la memoria .. – ardiyu07

4

que estaba haciendo bien hasta este punto:

for(int i = 0; i < (Width*Width) ; i++) { 
    printf("%d \n", P[i]); 
} 

lo cambié a% f (porque es un flotador) y todos ellos de impresión muy bien :)

$ ./test.exe 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
125.000000 
+0

¡De hecho! Aunque lo descubrí sin leer tu respuesta y solo iba a publicarlo. –

Cuestiones relacionadas