CUDA矩阵乘法的优化

本文详述了在CUDA环境下优化矩阵乘法的过程,包括提高精度、使用共享内存、使用cudaMallocPitch()、矩阵分块以及去掉if条件判断等策略。在实验中,通过不断改进,实现了对矩阵乘法计算效率的提升。
摘要由CSDN通过智能技术生成

本文以 深入浅出谈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
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值