zoukankan      html  css  js  c++  java
  • [CUDA]CUDA编程实战四——矩阵乘法

    矩阵乘法是最常见的操作,现代神经网络的基础便是矩阵乘法。

    一个N*M的矩阵,乘以一个M*P的矩阵,得到N*P的矩阵,矩阵乘法即为将每一行与被乘矩阵对应列进行乘加,最后将所有结果进行汇总。

    CPU版本

    根据以上矩阵乘法的描述,便可以很快地实现矩阵乘法,三层循环,最内层循环做向量的乘加,最外的两层则做输出矩阵的元素遍历。

    #include <iostream>
    #include <stdlib.h>
    #include <sys/time.h>
    
    
    const int ROWS = 1024;
    const int COLS = 1024;
    
    using namespace std;
    
    void matrix_mul_cpu(float* M, float* N, float* P, int width)
    {
        for(int i=0;i<width;i++)
            for(int j=0;j<width;j++)
            {
                float sum = 0.0;
                for(int k=0;k<width;k++)
                {
                    float a = M[i*width+k];
                    float b = N[k*width+j];
                    sum += a*b;
                }
                P[i*width+j] = sum;
            }
    }
    
    int main()
    {
        struct timeval start, end;
        gettimeofday( &start, NULL );
        float *A, *B, *C;
        int total_size = ROWS*COLS*sizeof(float);
        A = (float*)malloc(total_size);
        B = (float*)malloc(total_size);
        C = (float*)malloc(total_size);
    
        //CPU一维数组初始化
        for(int i=0;i<ROWS*COLS;i++)
        {
            A[i] = 80.0;
            B[i] = 20.0;
        }
    
        matrix_mul_cpu(A, B, C, COLS);
    
        gettimeofday( &end, NULL );
        int timeuse = 1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec - start.tv_usec;
        cout << "total time is " << timeuse/1000 << "ms" <<endl;
    
        return 0;
    }
    

    这里我们使用了行优先的存储方式,即所有的数据都存储在一维数据中,通过行优先的方式遍历得到。
    而我们的矩阵也有些特殊,这里使用的是N*N大小的矩阵,输出也为N*N大小。

    运行结果

    这里运行结果为6344ms,是个不小的运行时间。

    CUDA版本

    #include "cuda_runtime.h"
    #include "device_launch_parameters.h"
    #include <sys/time.h> 
    #include <stdio.h>
    #include <math.h>
    
    const int Row=1024;
    const int Col=1024;
     
    __global__ 
    void matrix_mul_gpu(int *M, int* N, int* P, int width)
    {
        int i = threadIdx.x + blockDim.x * blockIdx.x;
        int j = threadIdx.y + blockDim.y * blockIdx.y;
                    
        int sum = 0;
        for(int k=0;k<width;k++)
        {
            int a = M[j*width+k];
            int b = N[k*width+i];
            sum += a*b;
        }
        P[j*width+i] = sum;
    }
     
    int main()
    {
        struct timeval start, end;
        gettimeofday( &start, NULL );
    
        int *A = (int *)malloc(sizeof(int) * Row * Col);
        int *B = (int *)malloc(sizeof(int) * Row * Col);
        int *C = (int *)malloc(sizeof(int) * Row * Col);
        //malloc device memory
        int *d_dataA, *d_dataB, *d_dataC;
        cudaMalloc((void**)&d_dataA, sizeof(int) *Row*Col);
        cudaMalloc((void**)&d_dataB, sizeof(int) *Row*Col);
        cudaMalloc((void**)&d_dataC, sizeof(int) *Row*Col);
        //set value
        for (int i = 0; i < Row*Col; i++) {
            A[i] = 90;
            B[i] = 10;
        }
                                                                    
        cudaMemcpy(d_dataA, A, sizeof(int) * Row * Col, cudaMemcpyHostToDevice);
        cudaMemcpy(d_dataB, B, sizeof(int) * Row * Col, cudaMemcpyHostToDevice);
        dim3 threadPerBlock(16, 16);
        dim3 blockNumber((Col+threadPerBlock.x-1)/ threadPerBlock.x, (Row+threadPerBlock.y-1)/ threadPerBlock.y );
        printf("Block(%d,%d)   Grid(%d,%d).
    ", threadPerBlock.x, threadPerBlock.y, blockNumber.x, blockNumber.y);
        matrix_mul_gpu << <blockNumber, threadPerBlock >> > (d_dataA, d_dataB, d_dataC, Col);
        //拷贝计算数据-一级数据指针
        cudaMemcpy(C, d_dataC, sizeof(int) * Row * Col, cudaMemcpyDeviceToHost);
                                                                                                 
        //释放内存
        free(A);
        free(B);
        free(C);
        cudaFree(d_dataA);
        cudaFree(d_dataB);
        cudaFree(d_dataC);
    
        gettimeofday( &end, NULL );
        int timeuse = 1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec - start.tv_usec;
        printf("total time is %d ms
    ", timeuse/1000);
    
        return 0;
    }
    

    在CUDA版本中,我们使用了1024个线程,每个线程执行一行的向量乘加,且每块中含有16*16个线程,其他地方和CPU版本基本类似。

    运行结果

    运行结果为1462ms,可见GPU确实加快了运行的速度,大概有5倍的提升。

  • 相关阅读:
    面向复杂应用,Node.js中的IoC容器 -- Rockerjs/core
    一步步学会用docker部署应用(nodejs版)
    nodeEE双写与分布式事务要点一二
    提升node.js中使用redis的性能
    puppeteer实现线上服务器任意区域截图
    Nodejs“实现”Dubbo Provider
    TypeScript入门教程
    node.js与比特币(typescript实现)
    关于首屏时间采集自动化的解决方案
    回顾2017,未来仍需要不停充电
  • 原文地址:https://www.cnblogs.com/wildkid1024/p/14878125.html
Copyright © 2011-2022 走看看