CUDA矩阵乘法的优化

本文以 深入浅出谈cuda 中矩阵乘法优化的部分为主线,体会cuda的并行执行过程。

1 实验环境

个人笔记本电脑,显卡NIVIDA GTX950M,操作系统win10,IDE是VS2015,显卡的详细信息如图。

在这里插入图片描述

2 实验过程

2.1 初始版本

加载了4000个block,每个block 256个线程来做并行的矩阵乘法运算。
在这里插入图片描述

2.2 第一次改良——提高精度

由于GPU上只能用32位浮点数进行运算,大量累加时误差会累积。修改核函数中矩阵相乘计算的部分,利用 Kahan’s Summation Formula 来提高精确度。这样做提升了计算精度,但是没有改变运算时间。
在这里插入图片描述

2.3 第二次改良——使用共享内存

加载了1000个blcok,每个block 256个线程,共享内存大小32bit*1000,利用shared memory来实现同一block中各线程的数据共享。每个row的数据由一个block进行计算,最后同步,求和。

在这里插入图片描述

2.4 第三次改良——使用cudaMallocPitch()

考虑对齐问题,修改cudamalloc的部分。使用cudaMallocPitch() 申请逻辑二维数组,自动以最佳的倍数来配置内存,并把配置的宽度传回。

在这里插入图片描述

2.5 第四次改良——矩阵分块

将1000*1000的矩阵切分成8*8个16*16的矩阵,AB矩阵分块后两两相乘。加载64*64个block,每个block 16*16个线程(二维线程组织),从而将内存存取量降低到原来的1/8。
在这里插入图片描述

2.6 第五次改良——去掉if条件判断

在分块的基础上,利用矩阵乘法的特点,在申请完显存后将其置0,这样在核函数中做矩阵乘时就可以拿掉if条件判断语句,减少指令数。

在这里插入图片描述

3 遇到的问题和解决

1)每次核函数执行完,将矩阵c拷贝到内存时,经常不能正常获取到c。在cudaMemcpyDeviceToHost后调用cudaGetLastError,发现是从device拷贝到host时失败:CUDA error:unspecified launch failure,

这个错误在2.1和2.2中偶发,之后的改良中就没有再见过了,未解决。

2)在2.3及之后的改良中,发现每一次改进都达不到预期的加速效果。尤其是2.4使用pitch后,与之前几乎没有提升。

我想到使用cuda提供的方法,更细粒度地测量核函数运行时长,发现了关于kernel运行时间的讨论,其中提到了debug和release编译运行时间可能存在区别。

默认情况我们总是debug调试用,release分析性能用的。

于是我在release模式下重新配置了工程并编译运行,改进效果才有了第二节中明显的变化。

4 最后版本代码

#include <cuda_runtime.h>
#include <cublas_v2.h>
#include <device_launch_parameters.h>
#include <stdio.h>
#include <time.h>
#include <iostream>
#include <device_functions.h>
using namespace std;
#define NUM_THREADS 256 
#define BLOCK_SIZE 16

//初始化cuda
bool InitCUDA();
//生成a,b矩阵
void matgen(float *a, int Ida, int n);
//进行CUDA配置的函数,包括内存分配、传数、调用核函数计算等
clock_t matmultCUDA(const float* a, int lda, const float* b, int ldb, float* c, int ldc, int n);
//进行GPU计算的核函数
__global__ static void matMultCUDA(const float* a, size_t lda, const float* b, size_t ldb, float* c, size_t ldc, int n);
//以 CPU 进行矩阵乘法,用来进行验证答案正确与否
void matmult(const float* a, int Ida, const float* b, int Idb, float* c, int Idc, int n);
//计算两个矩阵的最大相对误差和平均相对误差,并把结果印出来
void compare_mat(const float*a, int Ida, const float* b, int Idb, int n);




int main() {
   
	
	int n = 1000;
	if (!InitCUDA()) return 0;

	//定义矩阵
	float *a, *b, *c, *d;
	a = (float*)malloc(sizeof(float) * n * n)
  • 1
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
CUDA乘法可以通过以下优化来提高性能: 1. 使用共享内存:将需要重复读取的全局内存数据缓存到共享内存中,可以减少全局内存访问次数,提高效率。 2. 使用纹理内存:对于具有空间局部性的数据,可以使用纹理内存来缓存数据,从而减少访问延迟和带宽占用。 3. 使用流处理器:将乘法运算分配到多个流处理器上并行计算,可以加速运算。 4. 使用向量化:使用向量化指令来一次性执行多个相同的操作,可以提高计算效率。 下面是一个使用CUDA优化乘法的示例C代码: ``` __global__ void matrix_multiply(float *A, float *B, float *C, int N) { __shared__ float As[BLOCK_SIZE][BLOCK_SIZE]; __shared__ float Bs[BLOCK_SIZE][BLOCK_SIZE]; int bx = blockIdx.x; int by = blockIdx.y; int tx = threadIdx.x; int ty = threadIdx.y; int row = by * BLOCK_SIZE + ty; int col = bx * BLOCK_SIZE + tx; float Cvalue = 0.0f; for (int m = 0; m < (N + BLOCK_SIZE - 1) / BLOCK_SIZE; ++m) { if (row < N && m * BLOCK_SIZE + tx < N) { As[ty][tx] = A[row * N + m * BLOCK_SIZE + tx]; } else { As[ty][tx] = 0.0f; } if (col < N && m * BLOCK_SIZE + ty < N) { Bs[ty][tx] = B[(m * BLOCK_SIZE + ty) * N + col]; } else { Bs[ty][tx] = 0.0f; } __syncthreads(); for (int k = 0; k < BLOCK_SIZE; ++k) { Cvalue += As[ty][k] * Bs[k][tx]; } __syncthreads(); } if (row < N && col < N) { C[row * N + col] = Cvalue; } } ``` 这个代码中使用了共享内存和流处理器技术,将矩阵乘法分解成了多个小的矩阵乘法,并行计算,从而提高了计算效率。同时,使用共享内存可以减少全局内存访问次数,使用流处理器可以将计算分配到多个处理器上并行计算,进一步提高了计算效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值