从零实现深度学习框架(day2)
前一天我们实现了CPU数据结构的操作,今天我们实现GPU的操作。
CUDA是NVIDIA提出的并行计算框架,结合了CPU与GPU的优点,主要用来处理密集型并行计算。GPU用来提高计算密集型应用程序中并行程序段的执行速度。CUDA是非常重要的计算加速平台。
需要注意的是,网上并没有特别好的GPU学习资源,只能够啃官方文档。
新建cuda_device_api.h
文件,定义GPU端操作的各个函数。
|
|
这段代码与CPU操作没有区别。
实现GPU操作的方法
新建cuda_device_api.cpp
|
|
分别实现了对应的操作。
AllocDataSpace
,FreeDataSpace
,CopyDataFromTo
,StreamSync
。
同时需要修改c_runtime_api.cpp
里面的:
|
|
GPU操作的实现
当完成了对GPU的操作,接下来实现GPU的各种方法,需要在框架中实现的,在框架中我们需要以下几种方法:
|
|
分别对应着深度学习里面常用方法
- GPU设置数值
- 广播机制
- 对第一个维度进行累加
- 矩阵元素相乘
- 矩阵与常量相乘
- 矩阵相乘
- 矩阵相加
- 矩阵与常量相加
- 矩阵Relu激活
- 矩阵Relu导数
- 矩阵Softmax
- Softmax交叉熵
GPU操作的实现
- GPU设置数值
|
|
- Broadcast
|
|
- reduceSum
|
|
- 矩阵元素相加
__global__ void matrix_elementwise_add(const float *a, const float *b, float *c,
int n) {
int index = blockIdx.x * blockDim.x + threadIdx.x;
if (index < n) {
c[index] = a[index] + b[index];
}
}
int DLGpuMatrixElementwiseAdd(const DLArrayHandle matA,
const DLArrayHandle matB, DLArrayHandle output) {
int n = 1;
for (int i = 0; i < output->ndim; i++) {
n = n * output->shape[i];
}
const float *data_A = (const float *) matA->data;
const float *data_B = (const float *) matB->data;
float *data_output = (float *) output->data;
int threads_per_block = 1024;
int num_blocks = (n + threads_per_block - 1) / threads_per_block;
matrix_elementwise_add << < num_blocks, threads_per_block >> > (data_A, data_B,
data_output, n);
return 0;
}
- 矩阵与常量相乘
|
|
-
矩阵元素相加 同理
-
矩阵与常量相乘 同理
-
矩阵Relu激活
|
|
- 矩阵Relu导数
|
|
- 矩阵Softmax
|
|
- Softmax交叉熵
|
|
到这里所有的数据结构的操作全部完成,接下来将其编译成动态链接库。
在与src
平级的文件夹下,新建Makefile
文件。
|
|
打开Linux命令行,执行make
操作,就可以得到libc_runtime_api.so
文件,接下来的所有的操作就围绕着该动态链接库来进行。
在该GPU实现中,需要用了很多数学知识,关于softmax的推导蛮好的资料在 How to implement a neural network Intermezzo.
接下来实现Python调用该so文件进行无缝链接。