一个用GPU写的矩阵乘法

这个过程相当繁琐,个人认为有优化的可能:

先说一下思路,矩阵相乘A矩阵乘B矩阵相当于A矩阵和B矩阵的转置做内积.所以我就先把B矩阵做了转置,再做内积.其中有两个核函数是在主函数中执行的,先执行转置,再执行乘法.再乘法函数中又嵌套了一个内积函数.这样充分的利用了并行化.

如图所示:

以3*3矩阵为例.我先开3*3个线程做内积运算,然后在每个线程中又开了1*3个线程做内积运算.其中求和部分我没有用并行方式求和而是使用串行方式求和的,个人认为这是一个可以优化的点.还有一个优化点就是,个人认为不必要算矩阵的转置就可以实现内积,只不过在乘法中算法变一下就行了.以后有机会讨论优化问题.这样我就开了3*3*3等于27个线程.这样求出的矩阵乘法.

一会看看其他人的算法思路是否有借鉴之处,这是本人的GPU求矩阵的乘法的思路.思想很简单,但是不是很成熟,有更简单的算法一起讨论学习.

代码使用:

输入一个数为矩阵的维度,代码会自动生成两个n*n的随机矩阵.然后相乘得到另外的矩阵.

实验结果:

请输入矩阵的维度:
3

CPU内存数据h_a:
h_a[0][0] = 2	h_a[0][1] = 4	h_a[0][2] = 10	
h_a[1][0] = 9	h_a[1][1] = 7	h_a[1][2] = 3	
h_a[2][0] = 8	h_a[2][1] = 10	h_a[2][2] = 9	
CPU内存数据h_b:
h_b[0][0] = 2	h_b[0][1] = 0	h_b[0][2] = 8	
h_b[1][0] = 7	h_b[1][1] = 4	h_b[1][2] = 8	
h_b[2][0] = 6	h_b[2][1] = 1	h_b[2][2] = 6	
CPU内存数据h_bt:
h_bt[0][0] = 2	h_bt[0][1] = 7	h_bt[0][2] = 6	
h_bt[1][0] = 0	h_bt[1][1] = 4	h_bt[1][2] = 1	
h_bt[2][0] = 8	h_bt[2][1] = 8	h_bt[2][2] = 6	
GPU内存数据:
h_c[0][0] = 92	h_c[0][1] = 26	h_c[0][2] = 108	
h_c[1][0] = 85	h_c[1][1] = 31	h_c[1][2] = 146	
h_c[2][0] = 140	h_c[2][1] = 49	h_c[2][2] = 198	
运行结束

 代码:

#include <cuda_runtime.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>

__global__ void zhuanshi(int *d_b,int *d_bt,int n)
{
	int ITdx = threadIdx.x;
	int IBdx = blockIdx.x;

	d_bt[ITdx * n + IBdx] = d_b[IBdx * n + ITdx];
}
__global__ void neiji(int *d_a,int *d_bt,int *d_c,int *d_data,int ICTdx,int ICBdx,int n)
{
	int INTdx = threadIdx.x;
	int temp = 0;

	d_data[(ICTdx * n + ICBdx) * n + INTdx] = d_a[ICTdx * n + INTdx] * d_bt[ ICBdx * n + INTdx];

	__syncthreads();
	for(int i = 0; i < n; ++i)
	{
		temp += d_data[(ICTdx * n + ICBdx) * n + i];
	}
	d_c[ICTdx * n + ICBdx] = temp;

}
__global__ void chengfa(int *d_a,int *d_bt,int *d_c,int *d_data,int n)
{

	int ICTdx = threadIdx.x;
	int ICBdx = blockIdx.x;
	neiji<<<1,n>>>(d_a,d_bt,d_c,d_data,ICTdx,ICBdx,n);
	__syncthreads();

}

int main()
{
	int blag = 1;//标志位
	int n = 0;
	/******判断输入数据是否合法************/
	do{
		std::cout << "请输入矩阵的维度:" << std::endl;
		std::cin >> n;
		if(n <= 0)
		{
			std::cout << "你输入的矩阵维度有误,请重新输入!" << std::endl;
		}else{
			blag = 0;
		}
	}while(blag);

	/*******申请主机内存*********/
	int *h_a = (int*)malloc(sizeof(int) * n * n);
	int *h_b = (int*)malloc(sizeof(int) * n * n);
	int *h_c = (int*)malloc(sizeof(int) * n * n);
	int *h_bt = (int*)malloc(sizeof(int) * n * n);
	/*******初始化主机内存数据********/
	srand(time(NULL));//设置随机数值
	for(int i = 0; i < n * n; ++i)
	{
		h_a[i] = rand() % 11;
		h_b[i] = rand() % 11;
		h_c[i] = 0;
		h_bt[i] = 0;
	}

	/*******申请设备内存*******/
	int *d_a,*d_b,*d_c,*d_bt,*d_data;
	cudaMalloc((void**)&d_a,sizeof(int) * n * n);
	cudaMalloc((void**)&d_b,sizeof(int) * n * n);
	cudaMalloc((void**)&d_c,sizeof(int) * n * n);
	cudaMalloc((void**)&d_bt,sizeof(int) * n * n);
	cudaMalloc((void**)&d_data,sizeof(int) * n * n * n);

	/******主机内存数据复制到设备内存中************/
	cudaMemcpy(d_a,h_a,sizeof(int) * n * n,cudaMemcpyHostToDevice);
	cudaMemcpy(d_b,h_b,sizeof(int) * n * n,cudaMemcpyHostToDevice);

	/*******执行核函数******/
	zhuanshi<<<n,n>>>(d_b,d_bt,n);
	chengfa<<<n,n>>>(d_a,d_bt,d_c,d_data,n);

	/*****设备内存数据复制到主机内存中*****/
	cudaMemcpy(h_bt,d_bt,sizeof(int) * n * n,cudaMemcpyDeviceToHost);
	cudaMemcpy(h_c,d_c,sizeof(int) * n * n,cudaMemcpyDeviceToHost);

	std::cout << "CPU内存数据h_a:" << std::endl;
	for(int i = 0; i < n; ++i)
	{
		for(int j = 0; j < n; ++j)
		{
			printf("h_a[%d][%d] = %d\t",i,j,h_a[n * i + j]);
		}
		printf("\n");
	}
	std::cout << "CPU内存数据h_b:" << std::endl;
	for(int i = 0; i < n; ++i)
	{
		for(int j = 0; j < n; ++j)
		{
			printf("h_b[%d][%d] = %d\t",i,j,h_b[n * i + j]);
		}
		printf("\n");
	}
	std::cout << "CPU内存数据h_bt:" << std::endl;
	for(int i = 0; i < n; ++i)
	{
		for(int j = 0; j < n; ++j)
		{
			printf("h_bt[%d][%d] = %d\t",i,j,h_bt[n * i + j]);
		}
		printf("\n");
	}
	std::cout << "GPU内存数据:" << std::endl;
	for(int i = 0; i < n; ++i)
	{
		for(int j = 0; j < n; ++j)
		{
			printf("h_c[%d][%d] = %d\t",i,j,h_c[n * i + j]);
		}
		printf("\n");
	}

	/*******释放内存*********/
	free(h_a);
	free(h_b);
	free(h_c);
	free(h_bt);
	cudaFree(d_a);
	cudaFree(d_b);
	cudaFree(d_c);
	cudaFree(d_bt);
	cudaFree(d_data);

	std::cout << "运行结束" << std::endl;
	return 0;
}

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

波雅_汉库克

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值