现在的卷积实现无非是那么几种:直接卷积、im2col+gemm、局部gemm、wingrod、FFT。如果直接卷积的话,其实kernel函数是比较好实现。以下代码参考至《OpenCL Programing Guide》,主要是main函数各种构造比较麻烦,个人感觉,OpenCL为了追求平台的移植性,使用起来实在是太不方便了。(代码仅表示思路,未测试)

Convolution.cl:

//Convolution.cl
__kernel void convolve(const __global uint * const input, __constant uint *const mask, __global uint * const output, const int inputWidth, const int maskWidth)
{
const int x = get_global_id();
const int y = get_global_id(); uint sum =;
for(int r =;r<maskWidth;r++)
{
const int idxIntmp = (y +r) *inputWidth +x ;
for(int c = ; c<maskWidth;c++)
{
sum +=mask[(r*maskWidth) +c] * input[idxIntmp +c];
}
}
outpu[y* get_global_size() +x] = sum;
}

//Convolution.cpp

//Convolution.cpp
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <CL/cl.h> //Constants
const unsigned int inputSignalWidth = ;
const unsigned int inputSignalHeight= ; cl_uint inputSignal[inputSignalWidth][inputSignalHeight] =
{
{, , , , , , , },
{, , , , , , , },
{, , , , , , , },
{, , , , , , , },
{, , , , , , , },
{, , , , , , , },
{, , , , , , , },
{, , , , , , , }
};
const unsigned int outputSignalWidth = ;
const unsigned int outputSignalHeight= ; cl_uint ouputSignal[outputSignalWidth][outputSignalHeight];
const unsigned int maskWidth = ;
const unsigned int maskHeight= ; cl_uint mask[maskWidth][maskHeight] =
{
{, , },
{, , },
{, , }
}; inline void checkErr(cl_int err, const char* name)
{
if(err != CL_SUCCESS)
{
std::cerr <<"ERROR: "<< name
<<" (" << err << ")"<<std::endl;
exit(EXIT_FAILURE);
}
} void CL_CALLBACK contextCallback(const char * errInfo, const void * private_info, size_t cb, void * user_data)
{
std::cout << "Error occurred during context user: "<< errInfo << std::endl;
exit(EXIT_FAILURE);
} int main(int argc, char** argv)
{
cl_int errNum;
cl_uint numPlatforms;
cl_uint numDevices;
cl_platform_id * platformIDs;
cl_context context =NULL;
cl_command_queue queue;
cl_program program;
cl_kernel kernel;
cl_mem inputSignalBuffer;
cl_mem outputSignalBuffer;
cl_mem maskBuffer; errNum = clGetPlatformIDs(, NULL, &numPlatforms);
checkErr( (errNum != CL_SUCCESS )? errNum: (numPlatforms <= ? -: CL_SUCCESS),"clGetPlatformIDs"); deviceIDs = NULL;
cl_uint i;
for(i =; i <numPlatforms; i++)
{
errNum = clGetDeviceIDs(platformIDs[i], CL_DEVICE_TYPE_CPU, , NULL, &numDevices);
if(errNum != CL_SUCCESS && errNum !=CL_DEVICE_NOT_FOUND)
{
checkErr(errNum, "clGetDeviceIDs");
}
else if(numDevices > )
{
deviceIDs = (cl_device_id *)alloca(sizeof(cl_device_id) * numDevices);
break;
}
} cl_context_properties contextProperties[] =
{
CL_CONTEXT_PLATFORM, (cl_context_properties)platformIDs[i],
};
context = clCreateContext(contextProperties, numDevices, deviceIDs,&contextCallback, NULL, &errNum);
checkErr(errNum, "clCreateContext"); std::ifstream srcFile("Convolution.cl");
std::string srcProg(std::istreambuf_iterator<char>(srcFile),(std::istreambuf_iterator<char>())); const char * src = srcProg.c_str();
size_t length = srcProg.length(); program = clCreateProgramWithSource(context, , &src, &length, &errNum);
checkErr(errNum, "clCreateProgramWithSource"); errNum = clBuildProgram(program, numDevices, deviceIDs, NULL, NULL, NULL);
checkErr(errNum, "clBuildProgram"); kernel = clCreateKernel(program, "convolve", &errNum);
checkErr(errNum, "clCreateKernel"); inputSignalBuffer = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(cl_uint) * inputSignalHeight * inputSignalWidth,
static_cast<void*> (inputSignal), &errNum);
checkErr(errNum, "clCreateBuffer(inputSignal)"); maskBuffer = clCreateBuffer(context,CL_MEM_READ_ONLY| CL_MEM_COPY_HOST_PTR, sizeof(cl_uint)* maskHeight *maskWidth, static_cast<void*>(mask), &errNum);
checkErr(errNum, "clCreateBuffer(mask)"); outputSignalBuffer= clCreateBuffer(context,CL_MEM_WRITE_ONLY ,sizeof(cl_uint)* outputSignalHeight *outputSignalWidth, NULL, &errNum);
checkErr(errNum, "clCreateBuffer(outputSignal)"); queue = clCreateCommandQueue(context, deviceIDs[], , &errNum);
checkErr(errNum, "clCreateCommandQueue"); errNum = clSetKernelArg(kernel, , sizeof(cl_mem), &inputSignalBuffer);
errNum |=clSetKernelArg(kernel, , sizeof(cl_mem), &maskBuffer);
errNum |=clSetKernelArg(kernel, , sizeof(cl_mem), &outputSignalBuffer);
errNum |=clSetKernelArg(kernel, , sizeof(cl_uint),&inputSignalWidth);
errNum |=clSetKernelArg(kernel, , sizeof(cl_uint),&maskWidth);
checkErr(errNum, "clSetKernelArg"); const size_t globalWorkSize[] = {outputSignalWidth *outputSignalHeight};
const size_t localWorkSize[] = {}; errNum = clEnqueueNDRangeKernel(queue,kernel, , NULL, globalWorkSize, localWorkSize, , NULL, NULL);
checkErr(errNum, "clEnqueueNDRangeKernel"); errNum = clEnqueueReadBuffer(queue, outputSignalBuffer,CL_TRUE, , sizeof(cl_uint)*outputSignalHeight*outputSignalWidth, outputSignal, , NULL, NULL);
checkErr(errNum, "clEnqueueReadBuffer");
return ;
}

OpenCl入门——实现简单卷积的更多相关文章

  1. OpenCL入门:(二:用GPU计算两个数组和)

    本文编写一个计算两个数组和的程序,用CPU和GPU分别运算,计算运算时间,并且校验最后的运算结果.文中代码偏多,原理建议阅读下面文章,文中介绍了OpenCL相关名词概念. http://opencl. ...

  2. 踢爆IT劣书出版黑幕——由清华大学出版社之《C语言入门很简单》想到的(1)

    1.前言与作者 首先声明,我是由于非常偶然的机会获得<C语言入门很简单>这本书的,绝对不是买的.买这种书实在丢不起那人. 去年这书刚出版时,在CU论坛举行试读推广,我当时随口说了几句(没说 ...

  3. [电子书] 《Android编程入门很简单》

    <Android编程入门很简单>是一本与众不同的Android学习读物,是一本化繁为简,把抽象问题具体化,把复杂问题简单化的书.本书避免出现云山雾罩.晦涩难懂的讲解,代之以轻松活泼.由浅入 ...

  4. Redis入门很简单之六【Jedis常见操作】

    Redis入门很简单之六[Jedis常见操作] http://www.tuicool.com/articles/vaqABb http://www.cnblogs.com/stephen-liu74/ ...

  5. 《Mysql 入门很简单》(读后感①)

    下载完整版<Mysql 入门很简单>,点击这里~: http://files.cnblogs.com/files/zhengyeye/MySQL%E5%85%A5%E9%97%A8%E5% ...

  6. Hibernate入门2.简单的项目开发实例

    Hibernate入门2.简单的项目开发实例 这一节通过一个简单的项目学习Hibernate项目的配置 代码下载 : 链接: http://pan.baidu.com/s/1zlgjl 密码: p34 ...

  7. 资深架构师Sum的故事:正则!入门就是这样简单

    | 故事背景 职场如战场!Sum带领三个小队友用了两周,成功把代理功能给干出来了.如果说产品经理是最魔鬼的指挥官,那测试就是最魔鬼的教官.这两周,让Sum深深领略了什么是X市的日出. 不过话又说回来, ...

  8. Redis入门很简单之七【使用Jedis实现客户端Sharding】

    Redis入门很简单之七[使用Jedis实现客户端Sharding] 博客分类: NoSQL/Redis/MongoDB redisjedisspringsharding分片 <一>. 背 ...

  9. Redis入门很简单之五【Jedis和Spring的整合】

    Redis入门很简单之五[Jedis和Spring的整合] 博客分类: NoSQL/Redis/MongoDB redisnosql缓存jedisspring  在上一篇文章中,简单介绍了Jedis的 ...

随机推荐

  1. Visual Studio Code 上java开发环境搭建

    在把一些开源的SDK中java代码转成C#代码时经常需要写点java代码来实验下功能,装个Eclipse或IDEAs吧,好像也不太值当,所以用vs code搭个环境偶尔来实验下.以下: 1.下载并装好 ...

  2. 详解Pytorch中的网络构造,模型save和load,.pth权重文件解析

    转载:https://zhuanlan.zhihu.com/p/53927068 https://blog.csdn.net/wangdongwei0/article/details/88956527 ...

  3. ios -转载-真机提示 iPhone has denied the launch request 问题

    环境: 手机版本12.1,Xcode10.0问题: 真机时提示 iPhone has denied the launch request ,试过了的各种方法,最终解决方法如下:1. 2. 3.清理Xc ...

  4. linux rz sz替代方案

    SFTP是基于SSH的文件传输协议,与ZMODEM相比具有更加安全且更为快速的文件传输功能. 如何利用SFTP接收文件: 1. 在本地提示以sftp命令登陆拟要接收文件的主机.Xshell:\> ...

  5. js匿名函数确实是个好东西

    <body onload="alert('http://www.baidu.com/');"> <script type="text/javascrip ...

  6. Saltstack之使用salt安装es6.0以上的head插件

    本实验使用salt安装es6.0以上的head插件 ES6.0以上手动安装head插件参考:https://www.cnblogs.com/minseo/p/9117470.html 文件夹目录为 / ...

  7. 【ARTS】01_25_左耳听风-201900429~20190505

    ARTS: Algrothm: leetcode算法题目 Review: 阅读并且点评一篇英文技术文章 Tip/Techni: 学习一个技术技巧 Share: 分享一篇有观点和思考的技术文章 Algo ...

  8. redis常用命令及操作

    说明 连接哨兵模式的redis时,我们连接的哨兵进程的ip和端口,这时很多命令不可用:此时,需要直接连接redis真实的服务器ip和端口:Sentinel模式下,连接真实的ip才可以使用config/ ...

  9. 网页是如何实现从剪贴板从读取图片并上传到server的

    代码比较简单,原理更简单,不多言请直接看代码. <!DOCTYPE html> <html> <head> <meta charset="UTF-8 ...

  10. 简单记录一下虚拟机中安装Linux的流程以及部分软件的安装命令

    一,虚拟机使用的是VMware9 ,linux使用的是服务器中用的比较多的CentOS6.4.稍后我会把这两个版本放到网盘中,需要的朋友可以去下载: 网盘地址: 二,VM的安装比较简单,基本上按照网上 ...