學習OpenCL與卷積神經網路 Day1
目錄
自學工具
自學用電子書
OpenCL異構計算
OpenCL程式設計指南
OpenCL異構平行計算原理、機制與優化
自學用課程
[link]https://www.coursera.org/learn/opencl-fpga-introduction/lecture/6HxML/introduction-and-parallel-computing
[link]https://www.youtube.com/watch?v=YU_pRT-Be0c&list=PLzy5q1NUJKCJocUKsRxZ0IPz29p38xeM-
自學用平臺
Vs2017
Matlab
Quartus Prime 16
關於OpenCL
平臺模型
OpenCL平臺模型包含一個主機或多個OpenCL裝置,每個OpenCL裝置包含一個或多個計算單元,每個計算單元至少包含一個或者多個處理單元。
執行模型
OpenCL程式包含主機端程式和裝置端核心(Kernel)程式。其中主機端程式以命令方式將核心程式從主機提交到OpenCL裝置上,OpenCL裝置在處理單元上執行計算。
核心
核心(Kernel)程式一般都是計算量大、邏輯比較簡單的函式。
當主機發出一個命令,提交一個核心到OpenCL裝置上執行,OpenCL執行時將會建立一個整數索引空間(N維),稱為NDRange。其中N為1或2或3。三個長度為N的資料確定了NDRange的以下特徵:
1.每個維度索引的範圍。
2.一個偏移指數F表明每個維度的初始索引值(預設為0)。
3.一個工作組的維度大小。
work-item
上下文
主機使用OpenCL API來建立和管理上下文,核心在此上下文中執行。
上下文定義核心執行環境:
裝置:OpenCL平臺包含一個或多個裝置
核心物件:在OpenCL裝置上執行的OpenCL核心函式
程式物件:實現整個核心程式的原始碼和目標二進位制碼
儲存物件:對主機和OpenCL裝置可見的物件,核心執行時操作這些物件的例項
命令佇列
通過命令佇列描述主機與OpenCL裝置進行互動。一般由主機或是執行在裝置中的核心提交給命令佇列。
儲存器模型
儲存器區域包含主機與裝置的記憶體。
儲存器型別
主機記憶體(host memory)
全域性儲存器(global memory)
常量儲存器(constant memory)
區域性儲存器(local memory)
私有儲存器(private memory)
儲存器物件
緩衝(buffer):可以將內檢資料型別、向量型別資料或使用者自定義資料結構對映到緩衝區,核心通過指標來訪問緩衝區。
影像(image):使用OpenCL API函式管理。通常不允許OpenCL核心對單個影像同時進行讀和寫。
管道(pipe):是資料項有序的佇列。其有兩個端點,一個是讀端點,一個是寫端點。
關於卷積神經網路(CNN)
目的與用途
主要用於計算機視覺,即影像識別一類。比如果園中自動採摘蕃茄機器人,影像識別起到判斷該物體"是否是蕃茄"的功能。
構造
卷積層(Convolution)
卷積層的作用就是提取圖片中的有用資訊(特徵)
假定我們有一個尺寸為5x5的影像,每一個畫素點裡都儲存著影像的資訊。
我們再定義一個3x3的卷積核[濾波器](filter),用來從影像中提取一定的特徵。
我們可以通過其與不同的卷積核來進行測試,得出不同的輸出結果。而卷積層輸出值越大,則與原圖的匹配度就越高,識別就越精確。
但如上圖我們邊緣資訊可能會丟失,所以我們可以採取一個簡單的辦法,保留其資訊。
就比如在周圍加上一圈"資訊保護層"。
池化層(Pooling)
在一張圖片中,相鄰畫素點的閾值往往極為相似,對它們做了卷積之後,卷積層(Convolution)相鄰的值會有很大的一個冗餘,此時我們便對其進行一次池化(Pooling),作用是對卷積後的值進行一次(猜測)處理。一般會有max、min、average三種操作。
以下是一個平均池的例子:
但同樣的,雖然池化層不需要訓練,但會損失不少的特徵值,這時候我們還需要進行誤差反傳。
全連線層(FC layer)
經過多輪卷積層與池化層的處理過後,一般會由1到2個全連線層來給出最後的分類結果。
關於將OpenCL與CNN相結合的想法
通過異構並行體系,將一些簡單而又具有龐大計算量的工作交給OpenCL裝置,例如FPGA來完成,這樣可以大大縮短CPU的工作負荷與運作速率。
簡單程式構建
main.cpp
#include<stdio.h>
#include<stdlib.h>
#include<CL/cl.h>
#include<string.h>
#include <iostream>
#include <ctime>
#pragma warning(disable : 4996)
int main(void)
{
srand(time(NULL));
cl_platform_id platform_id = NULL;
cl_uint ret_num_platforms;
cl_device_id device_id = NULL;
cl_uint ret_num_devices;
cl_context context = NULL;
cl_command_queue command_queue = NULL;
cl_mem data_in = NULL;
cl_mem data_out = NULL;
cl_mem filter_in = NULL;
cl_program program = NULL;
cl_kernel kernel = NULL;
size_t kernel_code_size;
char *kernel_str;
int *result;
cl_int ret;
FILE *fp;
cl_uint work_dim;
size_t global_item_size[2];
size_t local_item_size[2];
int const W = 8; //image width
int const H = 8; //image height
int const K = 3; //filter kernel size
int const Wn = (W + K - 1); //padded image width
int const Hn = (H + K - 1); //padded image height
int point_num = Wn * Hn;
int data_vecs[Wn*Hn];
int filter_coe[K*K] = { -1,0,1,-2,0,2,-1,0,1 }; //sobel filter: horizontal gradient
int i, j;
for (i = 0; i < point_num; i++)
{
data_vecs[i] = rand() % 20;
}
//display input data
printf("\n");
printf("Array data_in:\n");
for (i = 0; i < Hn; i++) {
printf("row[%d]:\t", i);
for (j = 0; j < Wn; j++) {
printf("%d,\t", data_vecs[i*Wn + j]);
}
printf("\n");
}
printf("\n");
kernel_str = (char *)malloc(MAX_SOURCE_SIZE);
result = (int *)malloc(W*H * sizeof(int));
ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms);
ret = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id,
&ret_num_devices);
context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &ret);
command_queue = clCreateCommandQueue(context, device_id, 0, &ret);
fp = fopen("Conv2D.cl", "r");
kernel_code_size = fread(kernel_str, 1, MAX_SOURCE_SIZE, fp);
fclose(fp);
program = clCreateProgramWithSource(context, 1, (const char **)&kernel_str,
(const size_t *)&kernel_code_size, &ret);
ret = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL);
kernel = clCreateKernel(program, "Conv2D", &ret);
data_in = clCreateBuffer(context, CL_MEM_READ_WRITE, Wn*Hn * sizeof(int), NULL, &ret);
data_out = clCreateBuffer(context, CL_MEM_READ_WRITE, W*H * sizeof(int), NULL, &ret);
filter_in = clCreateBuffer(context, CL_MEM_READ_WRITE, K*K * sizeof(int), NULL, &ret);
//write image data into data_in buffer
ret = clEnqueueWriteBuffer(command_queue, data_in, CL_TRUE, 0, Wn*Hn * sizeof(int), data_vecs, 0, NULL, NULL);
//write filter data into filter_in buffer
ret = clEnqueueWriteBuffer(command_queue, filter_in, CL_TRUE, 0, K*K * sizeof(int), filter_coe, 0, NULL, NULL);
//set kernel arguments
ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&data_in);
ret = clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&filter_in);
ret = clSetKernelArg(kernel, 2, sizeof(int), (void *)&K);
ret = clSetKernelArg(kernel, 3, sizeof(cl_mem), (void *)&data_out);
work_dim = 2;
global_item_size[0] = { W };
global_item_size[1] = { H };
local_item_size[0] = { 1 };
local_item_size[1] = { 1 };
//execute data parallel kernel */
ret = clEnqueueNDRangeKernel(command_queue, kernel, work_dim, NULL,
global_item_size, local_item_size, 0, NULL, NULL);
// read data_out to host
ret = clEnqueueReadBuffer(command_queue, data_out, CL_TRUE, 0,
W*H * sizeof(int), result, 0, NULL, NULL);
//display output data
FILE *f_img_out = fopen("image_out.txt", "w+");
printf("Array data_out: \n");
for (i = 0; i < H; i++) {
printf("row[%d]:\t", i);
for (j = 0; j < W; j++) {
printf("%d,\t", result[i*W + j]);
fprintf(f_img_out, "%d,\t", result[i*W + j]);
}
printf("\n");
fprintf(f_img_out, "\n");
}
printf("\n");
fclose(f_img_out);
ret = clReleaseKernel(kernel);
ret = clReleaseProgram(program);
ret = clReleaseMemObject(data_in);
ret = clReleaseMemObject(data_out);
ret = clReleaseMemObject(filter_in);
ret = clReleaseCommandQueue(command_queue);
ret = clReleaseContext(context);
free(result);
free(kernel_str);
system("pause");
return 0;
}
cl檔案
__kernel void Conv2D(__global int * image_in, //image input
__global int * filter_in, //filter input
int K, //filter kernel size
__global int * image_out) //feature map output
{
int W; //work group global size
int Wn; //padded image width
int x; //global id x
int y; //global id y
int ki, kj; //filter coordinate,(kj, ki)
int sum = 0; //multiply and sum of filter and data
W = get_global_size(0);
x = get_global_id(0);
y = get_global_id(1);
Wn = W + (K - 1);
for (ki = 0; ki < K; ki++)
for (kj = 0; kj < K; kj++)
{
sum = sum + filter_in[ki*K + kj] * image_in[Wn*(y + ki) + x + kj];
}
image_out[y*W + x] = sum;
}
如上程式碼參考自github 連結: link.
通過strand函式將輸出矩陣設為了隨機值。
但這只是在圖片上加了一層卷積(濾波器),並沒有進行Pooling
明天想辦法加一個4x4的Pooling加到cl檔案中去
相關文章
- 深度學習三:卷積神經網路深度學習卷積神經網路
- 【深度學習篇】--神經網路中的卷積神經網路深度學習神經網路卷積
- 深度學習——LeNet卷積神經網路初探深度學習卷積神經網路
- 深度學習筆記------卷積神經網路深度學習筆記卷積神經網路
- 卷積神經網路CNN-學習1卷積神經網路CNN
- 卷積神經網路學習筆記——SENet卷積神經網路筆記SENet
- 深度學習卷積神經網路筆記深度學習卷積神經網路筆記
- 【卷積神經網路學習】(4)機器學習卷積神經網路機器學習
- 卷積神經網路卷積神經網路
- 深度學習經典卷積神經網路之AlexNet深度學習卷積神經網路
- 卷積神經網路學習筆記——Siamese networks(孿生神經網路)卷積神經網路筆記
- 卷積神經網路概述卷積神經網路
- 解密卷積神經網路!解密卷積神經網路
- 5.2.1 卷積神經網路卷積神經網路
- 卷積神經網路CNN卷積神經網路CNN
- 卷積神經網路-AlexNet卷積神經網路
- 卷積神經網路-1卷積神經網路
- 卷積神經網路-2卷積神經網路
- 卷積神經網路-3卷積神經網路
- 深度學習革命的開端:卷積神經網路深度學習卷積神經網路
- 8-深度學習之神經網路核心原理與演算法-卷積神經網路深度學習神經網路演算法卷積
- 卷積神經網路四種卷積型別卷積神經網路型別
- 全卷積神經網路FCN卷積神經網路
- 深度剖析卷積神經網路卷積神經網路
- 深度學習-卷積神經網路-演算法比較深度學習卷積神經網路演算法
- [譯] 淺析深度學習神經網路的卷積層深度學習神經網路卷積
- 卷積神經網路數學原理解析卷積神經網路
- 卷積神經網路鼻祖LeNet網路分析卷積神經網路
- 深度學習之卷積神經網路(Convolutional Neural Networks, CNN)(二)深度學習卷積神經網路CNN
- 深度學習入門筆記(十八):卷積神經網路(一)深度學習筆記卷積神經網路
- 【機器學習基礎】卷積神經網路(CNN)基礎機器學習卷積神經網路CNN
- 卷積神經網路(CNN)介紹與實踐卷積神經網路CNN
- CNN神經網路之卷積操作CNN神經網路卷積
- 卷積神經網路 part2卷積神經網路
- 14 卷積神經網路(進階)卷積神經網路
- 卷積神經網路(CNN)詳解卷積神經網路CNN
- 何為神經網路卷積層?神經網路卷積
- Tensorflow-卷積神經網路CNN卷積神經網路CNN