【转载】OpenCL实现矩阵相乘
矩阵相乘其实就是前一个矩阵的每一行乘以后一个矩阵的每一列,然后将乘后的每一个数字相加,得到结果矩阵的指定位置的数值。具体算法回顾一下线性代数即可。但是这种行列相乘其实都是独立的,如果是CPU计算必须串行算法,一行一列的乘,但是放到GPU里面则可以并行相乘,如果维数很大那就会大大节约时间。
具体代码如下:
__kernel
void simpleMultiply(__global float* outPutC,
int widthA,
int heightA,
int widthB ,
int heightB ,
__global float* inputA ,
__global float* inputB
)
{
int row = get_global_id();
int col = get_global_id();
float sum = 0.0f ;
for(int i=;i<widthA; i++)
{
sum += inputA[row*widthA+i] * inputB[i*widthB+col];
}
outPutC[row*widthB+col] = sum;
} ;
// FirstOpenCL.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include<time.h>
#include <string>
#include<math.h>
#include <vector>
#include <CL/cl.h>
#include <fstream> using namespace std; #pragma comment (lib,"OpenCL.lib")
std::string convertToString(const char *filename)
{
size_t size;
char* str;
std::string s;
std::fstream f(filename, (std::fstream::in | std::fstream::binary));
if(f.is_open())
{
size_t fileSize;
f.seekg(, std::fstream::end);
size = fileSize = (size_t)f.tellg();
f.seekg(, std::fstream::beg);
str = new char[size+];
if(!str)
{
f.close();
std::cout << "Memory allocation failed";
return NULL;
} f.read(str, fileSize);
f.close();
str[size] = '\0';
s = str;
delete[] str;
return s;
}
else
{
std::cout << "\nFile containg the kernel code(\".cl\") not found. Please copy the required file in the folder containg the executable.\n";
exit();
}
return NULL;
} int main()
{
//查询平台
cl_int ciErrNum;
cl_platform_id platform;
ciErrNum = clGetPlatformIDs(, &platform, NULL); //获取设备信息
cl_device_id device;
cl_int status;
cl_uint maxDims;
cl_event events[];
size_t globalThreads[];
size_t localThreads[];
size_t maxWorkGroupSize;
size_t maxWorkItemSizes[]; ciErrNum = clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, , &device, NULL);
status = clGetDeviceInfo( device, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(size_t),(void*)&maxWorkGroupSize,NULL);
status = clGetDeviceInfo( device, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, sizeof(cl_uint),(void*)&maxDims, NULL);
status = clGetDeviceInfo( device, CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(size_t)*maxDims,(void*)maxWorkItemSizes, NULL); //创建上下文
cl_context ctx = clCreateContext(NULL, , &device, NULL, NULL, &ciErrNum);
cl_command_queue myqueue = clCreateCommandQueue(ctx,device,,&ciErrNum); int wA=,hA=;
int wB=,hB=;
int wC=,hC=; // 数组的大小
const int elementsA = wA*hA;
const int elementsB = wB*hB;
const int elementsC = hA*wB; // 计算内存大小
size_t datasizeA = sizeof(float)*elementsA;
size_t datasizeB = sizeof(float)*elementsB;
size_t datasizeC = sizeof(float)*elementsC;
// 分配内存空间
float *A = (float*)malloc(datasizeA);
float *B = (float*)malloc(datasizeB);
float *C = (float*)malloc(datasizeC); // 初始化输入数组
for(int i = ;i < elementsA;i++)
{
A[i] = (float)((float)i + 1.0);
}
for(int i = ;i < elementsB;i++)
{
B[i] = (float)((float)i + 1.0);
} cl_mem bufferA = clCreateBuffer(ctx,CL_MEM_READ_ONLY,wA*hA*sizeof(float),NULL,&ciErrNum);
ciErrNum = clEnqueueWriteBuffer(myqueue,bufferA,CL_TRUE,,wA*hA*sizeof(float),(void*)A,,NULL,NULL); cl_mem bufferB = clCreateBuffer(ctx,CL_MEM_READ_ONLY,wB*hB*sizeof(float),NULL,&ciErrNum);
ciErrNum = clEnqueueWriteBuffer(myqueue,bufferB,CL_TRUE,,wB*hB*sizeof(float),(void*)B,,NULL,NULL); cl_mem bufferC = clCreateBuffer(ctx,CL_MEM_WRITE_ONLY,hA*wB*sizeof(float),NULL,&ciErrNum); //运行时kernel编译
const char * filename = "HelloWorld_Kernel.cl";
std::string sourceStr = convertToString(filename);
const char * source = sourceStr.c_str();
size_t sourceSize[] = { strlen(source) };
//直接将CL文件读到记忆体
cl_program myprog = clCreateProgramWithSource( ctx, ,&source, sourceSize, &ciErrNum);
//cl_program myprog = clCreateProgramWithSource(ctx,1,(const char**)&programSource,NULL,&ciErrNum);
ciErrNum = clBuildProgram(myprog,,NULL,NULL,NULL,NULL); cl_kernel mykernel = clCreateKernel(myprog,"simpleMultiply",&ciErrNum);
//运行程序
clSetKernelArg(mykernel,,sizeof(cl_mem),(void*)&bufferC);
clSetKernelArg(mykernel,,sizeof(cl_mem),(void*)&wA);
clSetKernelArg(mykernel,,sizeof(cl_mem),(void*)&hA);
clSetKernelArg(mykernel,,sizeof(cl_mem),(void*)&wB);
clSetKernelArg(mykernel,,sizeof(cl_mem),(void*)&hB);
clSetKernelArg(mykernel,,sizeof(cl_mem),(void*)&bufferA);
clSetKernelArg(mykernel,,sizeof(cl_mem),(void*)&bufferB); size_t localws[] ={wC,wC};
size_t globalws[]={wC,hC}; ciErrNum = clEnqueueNDRangeKernel(myqueue,mykernel,,NULL,globalws,localws,,NULL,&events[]);
status = clWaitForEvents(, &events[]);
status = clReleaseEvent(events[]);
//将结果拷贝到主机端
ciErrNum = clEnqueueReadBuffer(myqueue,bufferC,CL_TRUE,,wC*hC*sizeof(float),(void*)C,,NULL,&events[]); status = clWaitForEvents(, &events[]);
status = clReleaseEvent(events[]); printf("\nArray A:\n");
for (int i = ; i < wA; i++) {
for (int j = ; j < hA; j++)
printf("%4.3f\t", A[i*hA + j]);
printf("\n");
}
printf("\nArray B:\n");
for (int i = ; i < wB; i++) {
for (int j = ; j < hB; j++)
printf("%4.3f\t", B[i*hB + j]);
printf("\n");
}
printf("\nArray C:\n");
for (int i = ; i < wC; i++) {
for (int j = ; j < hC; j++)
printf("%4.3f\t", C[i*hC + j]);
printf("\n");
} getchar();
return ;
}
【转载】OpenCL实现矩阵相乘的更多相关文章
- CUDA编程-(2)其实写个矩阵相乘并不是那么难
程序代码及图解析: #include <iostream> #include "book.h" __global__ void add( int a, int b, i ...
- Strassen 矩阵相乘算法(转)
偶尔在算法课本上面看到矩阵相乘的算法,联想到自己曾经在蓝桥杯系统上曾经做过一道矩阵相乘的题目,当时用的是普通的矩阵相乘的方法,效率极低,勉强通过编译.所以决定研究一下Strassen矩阵相乘算法,由于 ...
- python版 mapreduce 矩阵相乘
参考张老师的mapreduce 矩阵相乘. 转载请注明:来自chybot的学习笔记http://i.cnblogs.com/EditPosts.aspx?postid=4541939 下面是我用pyt ...
- Opencv中Mat矩阵相乘——点乘、dot、mul运算详解
Opencv中Mat矩阵相乘——点乘.dot.mul运算详解 2016年09月02日 00:00:36 -牧野- 阅读数:59593 标签: Opencv矩阵相乘点乘dotmul 更多 个人分类: O ...
- POJ 1651:Multiplication Puzzle 矩阵相乘式DP
Multiplication Puzzle Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 7118 Accepted: ...
- HDU1575Tr A(矩阵相乘与快速幂)
Tr A hdu1575 就是一个快速幂的应用: 只要知道怎么求矩阵相乘!!(比赛就知道会超时,就是没想到快速幂!!!) #include<iostream> #include<st ...
- <矩阵的基本操作:矩阵相加,矩阵相乘,矩阵转置>
//矩阵的基本操作:矩阵相加,矩阵相乘,矩阵转置 #include<stdio.h> #include<stdlib.h> #define M 2 #define N 3 #d ...
- 利用Hadoop实现超大矩阵相乘之我见(二)
前文 在<利用Hadoop实现超大矩阵相乘之我见(一)>中我们所介绍的方法有着“计算过程中文件占用存储空间大”这个缺陷,本文中我们着重解决这个问题. 矩阵相乘计算思想 传统的矩阵相乘方法为 ...
- 利用Hadoop实现超大矩阵相乘之我见(一)
前记 最近,公司一位挺优秀的总务离职,欢送宴上,她对我说“你是一位挺优秀的程序员”,刚说完,立马道歉说“对不起,我说你是程序员是不是侮辱你了?”我挺诧异,程序员现在是很低端,很被人瞧不起的工作吗?或许 ...
随机推荐
- C语言清空指针
#include <stdio.h> int main() { /********************************************* * * %d int * %f ...
- VACUUM - 垃圾收集以及可选地分析一个数据库
SYNOPSIS VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ table ] VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] ANA ...
- UNLISTEN - 停止监听通知信息
SYNOPSIS UNLISTEN { name | * } DESCRIPTION 描述 UNLISTEN 用于删除一个现有的已注册的 NOTIFY 事件. UNLISTEN 取消当前 Postgr ...
- Linux 父进程发送信号杀死子进程
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <signal. ...
- javascript 跨域问题 jsonp
转载:http://www.cnblogs.com/choon/p/5393682.html demo 用动态创建<script></script>节点的方式实现了跨域HTTP ...
- re.match与re.search的区别
re.match与re.search的区别 re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None:而re.search匹配整个字符串,直到找到一个匹配. 实 ...
- awk 一 文本处理工具
简介 awk 是逐行扫描文件(从第1行到最后一行),寻找含有目标文本的行: 如果匹配成功,则会在该行上执行用户想要的操作. 反之,则不对行做任何处理. awk 命令的基本格式为: awk [选项] ' ...
- Java——方法的重写(覆盖)
2.2方法的重写(覆盖)(override,orverwrite) 2.2.1 什么时候方法要进行重写? 如果父类中的方法已经无法满足当前子类的业务需求,需要将父类中的方法进行重新写一遍.就是要改变父 ...
- 2、go 运行操作
1)有且只有一个函数入口,main liteIDE,直接图形界面编译,一个文件夹里的只能有一个main函数 或者 go build XXX.go 编译go代码,生成一个可执行程序 然后运行可执行程序 ...
- 干货满满!解密阿里云RPA (机器人流程自动化)的产品架构和商业化发展
阿里云RPA,作为阿里云自研8年的技术,在资本的热捧下,逐渐从幕后来到台前,成为企业服务市场的黑马.本文将从产品上全面剖析,阿里云RPA这款产品的现阶段情况,同时简单谈谈阿里云RPA的商业化进展. 阿 ...