CUDA学习之二:shared_memory使用,矩阵相乘

CUDA中使用shared_memory可以加速运算,在矩阵乘法中是一个体现。

矩阵C = A * B,正常运算时我们运用 C[i,j] = A[i,:] * B[:,j] 可以计算出结果。但是在CPU上完成这个运算我们需要大量的时间,设A[m,n],B[n,k],那么C矩阵为m*k,总体,我们需要做m*n*k次乘法运算,m*(b-1)*k次加法运算,并且是串行执行,总体的复杂度为O(m*n*k) 。

矩阵类:

1 class Matrix
2 {
3 public:
4     int cols;   // x
5     int rows;   // y
6     float *data;  //数据,一位数组
7 }

CPU上的程序,一个三层循环

for(int i =0;i< C.rows;i++)
    {
        for(int j =0;j< C.cols;j++)
        {
            float *a = A.data;
            float *b = B.data;
            for(int k=0;k<A.cols;k++)
                C.data[i*C.cols+j]+=a[i*A.cols+k] * b[k*B.cols+j];
        }
    }
}

我们想到用GPU加速,在CUDA上实现,我们这么写kernel:

__global__ void matrixMulKernel(const Matrix A, const Matrix B, Matrix C)
{
    // Each thread computes one element of C
    // by accumulating results into Cvalue
    float Cvalue = 0;
    int row = blockIdx.y * blockDim.y + threadIdx.y;
    int col = blockIdx.x * blockDim.x + threadIdx.x;
    for (int e = 0; e < A.cols; ++e)
    Cvalue += A.data[row * A.cols + e]* B.data[e * B.cols + col];
    C.data[row * C.cols + col] = Cvalue;
}  

此时,计算过程是并行的,但是访问A,B矩阵时,不能同时访问,因此主要的时间花在内存读取,每个线程读取A的一行,B的一列,计算C的对应值;所以这样需要从global memory中读n次A,m次B。时间复杂度是O(m+n)次内存访问,以及k次乘法运算。

实际上还有一种办法,可以用shared memory,这里我们把A,B矩阵按照blocksize划分为子矩阵subA[blocksize][blocksize]、subB[blocksize][blocksize]。并将子矩阵设置为__shared__。 thread block内所有threads共用(可读可写)shared memory。如此一来,A只从global memory读了n/block_size次,B只读了m/block_size次;时间复杂度是O(m/block_size+n/block_size)次内存访问,以及k次乘法运算。进一步减少的时间复杂度。代码如下:

__global__ void matrixMulKernel(const float *A, const float *B, float *C,int Aw ,int Bw)
{
    const int bs = CUDA_LG::block_size;
    int tx = threadIdx.x;
    int ty = threadIdx.y;
    int bx = blockIdx.x;
    int by = blockIdx.y;

    int aBlockFisrt = by * bs * Aw ;
    int aBlockStep  = bs ;
    int aBlockLast  = by * bs * Aw  + Aw - 1 ;
    int bBlockFisrt = bx * bs ;
    int bBlockStep  = bs * Bw ;

    float subC=0;

    for(int a = aBlockFisrt,int b = bBlockFisrt; a <= aBlockLast ;a+=aBlockStep,b+=bBlockStep )
    {
        //定义两个shared memory的子矩阵
        __shared__ float  subA[bs][bs];
        __shared__ float  subB[bs][bs];

        subA[ty][tx] = A[a + ty * Aw + tx];
        subB[ty][tx] = B[b + ty * Bw + tx];

        __syncthreads(); 

        for(int i = 0;i<bs;i++)
        {
            subC += subA[ty][i] * subB[i][tx];
        }    

        __syncthreads();
    }
    C[ by*bs*Bw + bx*bs + ty * Bw +tx] = subC;

}

参考sample_6.5\0_Simple\matrixMul程序。里面注释详细

参考Rachel zhang的博客CUDA学习系列之二:http://blog.csdn.net/abcjennifer/article/details/42528569

时间: 2024-11-06 21:53:32

CUDA学习之二:shared_memory使用,矩阵相乘的相关文章

CUDA学习笔记二

简单的向量加 /** * Vector addition: C = A + B. * * This sample is a very basic sample that implements element by element * vector addition. It is the same as the sample illustrating Chapter 2 * of the programming guide with some additions like error checki

CUDA学习之一:二维矩阵加法

今天忙活了3个小时,竟然被一个苦恼的CUDA小例程给困住了,本来是参照Rachal zhang大神的CUDA学习笔记来一个模仿,结果却自己给自己糊里糊涂,最后还是弄明白了一些. RZ大神对CUDA关于kernel,memory的介绍还是蛮清楚,看完决定写一个二维数组的加法.如果是C++里的加法,那就简单了,用C[i][j] = A[i][j] +B[i][j]就可以. 1 void CppMatAdd(int A[M][N],int B[M][N],int C[M][N]){ 2 for(int

【CUDA并行编程之四】矩阵相乘

前面介绍了基本的Cuda编程的相关知识,那么这一篇在此基础之上来看看GPU在处理数据计算上的高效能,我们拿矩阵相乘来作为例子. 1.CPU上执行矩阵相乘以及性能. 在CPU上进行矩阵相乘运算的代码: mat_mul.cc: <span style="font-family:Microsoft YaHei;font-size:18px;">//a[i]*b[i] + c[i] = d[i] #include<iostream> #include<vector

CUDA范例精解通用GPU架构-(2)其实写个矩阵相乘并不是那么难

程序代码及图解析: #include <iostream> #include "book.h" __global__ void add( int a, int b, int *c ) { *c = a + b; } int main( void ) { int c; int *dev_c; HANDLE_ERROR( cudaMalloc( (void**)&dev_c, sizeof(int) ) ); add<<<1,1>>>

CUDA学习笔记(二)【转】

来源:http://luofl1992.is-programmer.com/posts/38847.html 编程语言的特点是要实践,实践多了才有经验.很多东西书本上讲得不慎清楚,不妨自己用代码实现一下. 作为例子,我参考了书本上的矩阵相乘的例子,这样开始写代码,然后很自然地出现了各种问题. 以下的内容供大家学习参考,有问题可以留言与我反馈. 开始学着使用 CUDA,实现一个矩阵乘法运算. 首先我们要定义一个矩阵的结构体,话说CUDA是否支持结构体作为设备端的函数的参数呢? 不妨都一股脑试验一下

CUDA 矩阵相乘完整代码

#include "cuda_runtime.h"#include "device_launch_parameters.h" #include <stdio.h>#include <stdlib.h>#include <time.h>#include "cublas_v2.h" #define BLOCK_SIZE 16 cudaError_t multiCuda(float *c, float *a, flo

CUDA 矩阵相乘

#include "cuda_runtime.h"#include "device_launch_parameters.h" #include <stdio.h>#include <stdlib.h>#include "cublas_v2.h" #define BLOCK_SIZE 16 /***************/ 用cuBlas的内置函数API,cublasSgemm cudaError_t multiWithc

R语言学习中的小bug:R中矩阵相乘错误于A %*% B: 需要数值/复数矩阵/矢量参数

遇到了小bug: R中矩阵相乘错误于A %*% B: 需要数值/复数矩阵/矢量参数 看到网上别人的做法,发现了用class(A)和class(B)之后才发现,是因为读入的时候数据的类型不对,A.B的类型并不是matrix,才导致了这个问题. 用as.matrix来变型一下,就OK了. R语言学习中的小bug:R中矩阵相乘错误于A %*% B: 需要数值/复数矩阵/矢量参数,布布扣,bubuko.com

学习心得:《十个利用矩阵乘法解决的经典题目》from Matrix67

本文来自:http://www.matrix67.com/blog/archives/tag/poj大牛的博文学习学习 节选如下部分:矩阵乘法的两个重要性质:一,矩阵乘法不满足交换律:二,矩阵乘法满足结合律经典题目1 给定n个点,m个操作,构造O(m+n)的算法输出m个操作后各点的位置.操作有平移.缩放.翻转和旋转    这 里的操作是对所有点同时进行的.其中翻转是以坐标轴为对称轴进行翻转(两种情况),旋转则以原点为中心.如果对每个点分别进行模拟,那么m个操作总共耗时 O(mn).利用矩阵乘法可