⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 convolutionseparable.cu

📁 可分离据卷积,在GPU上实现并行运算
💻 CU
字号:

/*
 这个例子利用高斯内核执行一个二维信号的可分离卷积滤波
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <cutil.h>

////////////////////////////////////////////////////////////////////////////////
// 共同的主机和设备函数
////////////////////////////////////////////////////////////////////////////////
//Round a / b to nearest higher integer value     ??a/b是一个高度接近整型的值??????
int iDivUp(int a, int b){
    return (a % b != 0) ? (a / b + 1) : (a / b);
}

//Round a / b to nearest lower integer value
int iDivDown(int a, int b){
    return a / b;
}

//Align a to nearest higher multiple of b
int iAlignUp(int a, int b){
    return (a % b != 0) ?  (a - a % b + b) : a;
}

//Align a to nearest lower multiple of b
int iAlignDown(int a, int b){
    return a - a % b;
}
/////////////////////////////////////////////
//读图片
//////////////////////////////////////////////
extern "C" void LoadBMPFile(uchar4 **, int *, int *, const char *);


//////////////////////////////////////////////
// 涉及到的cpu卷积
/////////////////////////////////////////////
extern "C" void convolutionRowCPU(			
    float *h_Result,
    float *h_Data,
    float *h_Kernel,
    int dataW,
    int dataH,
    int kernelR
);

extern "C" void convolutionColumnCPU(
    float *h_Result,
    float *h_Data,
    float *h_Kernel,
    int dataW,
    int dataH,
    int kernelR
);

//////////////////////////////////////////////
//GPU卷积
//////////////////////////////////////////////
//全局宏,打开卷积内部控制循环
#define UNROLL_INNER		//打开内部
#include <convolutionSeparable_kernel.cu>
#define M 12
//在主函数循环计算开始时传出一个虚拟计算目的是唤醒硬件驱动
#define WARMUP
/////////////////////////////////////////////
// 主函数
/////////////////////////////////////////////
int main(int argc, char **argv){
    float
        *h_Kernel,
        *h_DataA,
        *h_DataB,
        *h_ResultGPU;

    float
        *d_DataA,
        *d_DataB,
        *d_Temp;

    double gpuTime;	
    int i;   
    uchar4 *h_Src;
    cudaArray *a_Src;
	int imageW, imageH;
	float Gtime[M];
	float Ctime[M];
	int x[M];
	int y[M];
	char picname[M][10]={{"1.bmp"},{"2.bmp"},{"3.bmp"},{"4.bmp"},{"5.bmp"},{"6.bmp"},
						{"7.bmp"},{"8.bmp"},{"9.bmp"},{"10.bmp"},{"11.bmp"},{"12.bmp"}};
	for(int t=0;t<M;t++)
	{
		printf("导入图片%-8s  ",picname[t]);

		unsigned int hTimer;
		CUT_DEVICE_INIT();
		CUT_SAFE_CALL(cutCreateTimer(&hTimer));

		const char *image_path = cutFindFilePath(picname[t], argv[0]);//设置读取文件
		LoadBMPFile(&h_Src, &imageW, &imageH, image_path);
		printf("  分别在GPU和CPU上作卷积运算,并存储数据\n");
		int DATA_W=imageW;
		int DATA_H=imageH;
		x[t]=imageW;
		y[t]=imageH;
		const int   DATA_SIZE = DATA_W * DATA_H * sizeof(float);
		const int KERNEL_SIZE = KERNEL_W * sizeof(float);	
		//printf("图片格式为:%i x %i\n", x[t], y[t]);    
		//printf("初始化数据\n");
		h_Kernel    = (float *)malloc(KERNEL_SIZE);
		h_DataA     = (float *)malloc(DATA_SIZE);
		h_DataB     = (float *)malloc(DATA_SIZE);
		h_ResultGPU = (float *)malloc(DATA_SIZE);
		CUDA_SAFE_CALL( cudaMalloc( (void **)&d_DataA, DATA_SIZE) );
		CUDA_SAFE_CALL( cudaMalloc( (void **)&d_DataB, DATA_SIZE) );
		CUDA_SAFE_CALL( cudaMalloc( (void **)&d_Temp , DATA_SIZE) );

			//具体是什么算法??高斯????
		float kernelSum = 0;
		for(i = 0; i < KERNEL_W; i++)
		{
			float dist = (float)(i - KERNEL_RADIUS) / (float)KERNEL_RADIUS;
			h_Kernel[i] = expf(- dist * dist / 2);
			kernelSum += h_Kernel[i];
		}
		for(i = 0; i < KERNEL_W; i++)
			h_Kernel[i] /= kernelSum;       	
		CUDA_SAFE_CALL( cudaMemcpyToSymbol(d_Kernel, h_Kernel, KERNEL_SIZE) );
		CUDA_SAFE_CALL( cudaMemcpy(d_DataA, h_Src, DATA_SIZE, cudaMemcpyHostToDevice) );//导入图片数据


		dim3 blockGridRows(iDivUp(DATA_W, ROW_TILE_W), DATA_H);
		dim3 blockGridColumns(iDivUp(DATA_W, COLUMN_TILE_W), iDivUp(DATA_H, COLUMN_TILE_H));
		dim3 threadBlockRows(KERNEL_RADIUS_ALIGNED + ROW_TILE_W + KERNEL_RADIUS);
		dim3 threadBlockColumns(COLUMN_TILE_W, 8);


	#ifdef WARMUP
		convolutionRowGPU<<<blockGridRows, threadBlockRows>>>(
			d_Temp,
			d_DataA,
			DATA_W,
			DATA_H
		);
		CUT_CHECK_ERROR("GPU行卷积失败!\n");
		convolutionColumnGPU<<<blockGridColumns, threadBlockColumns>>>(
			d_Temp,
			d_DataA,
			DATA_W,
			DATA_H,
			COLUMN_TILE_W * threadBlockColumns.y,
			DATA_W * threadBlockColumns.y
		);
		CUT_CHECK_ERROR("GPU列卷积失败!\n");
		CUDA_SAFE_CALL( cudaThreadSynchronize() );
	#endif
		//printf("\n在GPU上执行可分离卷积运算:\n");
		CUDA_SAFE_CALL( cudaThreadSynchronize() );
		CUT_SAFE_CALL( cutResetTimer(hTimer) );
		CUT_SAFE_CALL( cutStartTimer(hTimer) );
		convolutionRowGPU<<<blockGridRows, threadBlockRows>>>(
			d_DataB,
			d_DataA,
			DATA_W,
			DATA_H
		);
		CUT_CHECK_ERROR("GPU行卷积失败!\n");

		convolutionColumnGPU<<<blockGridColumns, threadBlockColumns>>>(
			d_DataA,
			d_DataB,
			DATA_W,
			DATA_H,
			COLUMN_TILE_W * threadBlockColumns.y,
			DATA_W * threadBlockColumns.y
		);
		CUT_CHECK_ERROR("GPU列卷积失败!\n");
		CUDA_SAFE_CALL( cudaThreadSynchronize() );
		CUT_SAFE_CALL(cutStopTimer(hTimer));
		gpuTime = cutGetTimerValue(hTimer);
		//printf("GPU卷积时间: %f 毫秒	||	%f像素/每秒\n", gpuTime, 1e-6 * DATA_W * DATA_H / (gpuTime * 0.001));
		//float q=gpuTime;
		Gtime[t]=gpuTime;
		//printf("读回GPU结果\n");
		CUDA_SAFE_CALL( cudaMemcpy(h_ResultGPU, d_DataA, DATA_SIZE, cudaMemcpyDeviceToHost) );


		//printf("\n在CPU上执行普通卷积运算:\n");
	    

		CUT_SAFE_CALL( cutResetTimer(hTimer) );
		CUT_SAFE_CALL( cutStartTimer(hTimer) );
		convolutionRowCPU(
			h_DataB,
			h_DataA,
			h_Kernel,
			DATA_W,
			DATA_H,
			KERNEL_RADIUS
		);
		convolutionColumnCPU(
			h_DataA,
			h_DataB,
			h_Kernel,
			DATA_W,
			DATA_H,
			KERNEL_RADIUS
		);


		CUT_SAFE_CALL(cutStopTimer(hTimer));
		gpuTime = cutGetTimerValue(hTimer);
		//printf("CPU卷积时间: %f 毫秒	||	%f像素/每秒\n", gpuTime, 1e-6 * DATA_W * DATA_H / (gpuTime * 0.001));
		//float w=gpuTime;
		Ctime[t]=gpuTime;
		//printf("\n比较结果:\n");
		//printf("q=%f\nw=%f",q,w);
		//printf("在GPU上执行可分离卷积运算速度是在CPU上执行卷积速度的%f倍!",w/q);
	   	
		//printf("\n\n结束\n");
		CUDA_SAFE_CALL( cudaFree(d_Temp ) );
		CUDA_SAFE_CALL( cudaFree(d_DataB) );
		CUDA_SAFE_CALL( cudaFree(d_DataA) );
		free(h_ResultGPU);
		free(h_DataB);
		free(h_DataA);
		free(h_Kernel);

		CUT_SAFE_CALL(cutDeleteTimer(hTimer));

	   // CUT_EXIT(argc, argv);
    }
    printf("\n图片名称    大小     GPU上卷积速率    CPU上卷积速率  GPU时间是CPU上时间的多少倍\n\n");
    	FILE *fp;
    fp=fopen("date.txt","a+");
     fprintf(fp,"\n图片名称    大小     GPU上卷积时间   GPU上卷积速率    CPU上卷积时间   CPU上卷积速率  GPU时间是CPU上时间的多少倍\n\n");
     fprintf(fp,"\KERNEL_RADIUS=%d\n", KERNEL_RADIUS); 
    for(int t=0;t<M;t++)
    {
		//printf("图片 %s 大小为 %d × %d 作卷积运算数据如下:\n",picname[t],x[t],y[t]);
		//printf("GPU卷积时间: %f 毫秒 || %f像素/每秒\n", Gtime[t], 1e-6 * x[t] * y[t] / (Gtime[t] * 0.001));
		//printf("CPU卷积时间: %f 毫秒 || %f像素/每秒\n", Ctime[t], 1e-6 * x[t] * y[t] / (Ctime[t] * 0.001));
		//printf("在GPU上执行可分离卷积运算速度是在CPU上执行卷积速度的%f倍!\n\n", Ctime[t]/Gtime[t]);
		
		//printf("%-8s %-4d× %-4d %-10f毫秒   %-10f毫秒\t  %-10f\n",picname[t],x[t],y[t],Gtime[t],Ctime[t],Ctime[t]/Gtime[t]);
		printf("%-8s %-4d× %-4d %-10f像素/每秒   %-10f像素/每秒\t  %-10f\n",picname[t],x[t],y[t],1e-6 * x[t] * y[t] / (Gtime[t] * 0.001), 1e-6 * x[t] * y[t] / (Ctime[t] * 0.001),Ctime[t]/Gtime[t]);
		 fprintf(fp,"%-8s %-4d× %-4d %-10f毫秒   %-10f像素/每秒   %f 毫秒   %-10f像素/每秒\t  %-10f\n",picname[t],x[t],y[t],Gtime[t],1e-6 * x[t] * y[t] / (Gtime[t] * 0.001), Ctime[t],1e-6 * x[t] * y[t] / (Ctime[t] * 0.001),Ctime[t]/Gtime[t]);
		if(t%4==3)
			printf("\n");
    }
    
    CUT_EXIT(argc, argv);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -