更多文章参考:自己动手实现darknet预测分类动态库
1.convet_to_image代码如下:
image convert_to_image(unsigned char* data,int w,int h,int c)
{
int i, j, k;
image im = make_image(w, h, c);
for (k = 0; k < c; ++k) {
for (j = 0; j < h; ++j) {
for (i = 0; i < w; ++i) {
int dst_index = i + w*j + w*h*k;
int src_index = k + c*i + c*w*j;
im.data[dst_index] = (float)data[src_index] / 255.;
//printf("c:%d,h:%d,w:%d,src_index:%d,dst_index:%d\n", k, j, i, src_index, dst_index);
}
}
}
//free(data);
return im;
}
GPU加速代码:
新建loadimage.cu文件,
添加代码
#include "dark_cuda.h"
//image convert_to_image_gpu(unsigned char* data,int w,int h,int c);
//__global__ void MatConvertImg(float* dst, unsigned char* src, int w,int h,int c) ;
// Kernel定义
__global__ void MatConvertImg(float* dst, unsigned char* src, int w,int h,int c)
{
int i = blockIdx.x * blockDim.x + threadIdx.x;
int j = blockIdx.y * blockDim.y + threadIdx.y;
int k = blockIdx.z * blockDim.z + threadIdx.z;
if (i<w&&j<h&&k<c)
{
int dst_index = i + w*j + w*h*k;
int src_index = k + c*i + c*w*j;
dst[dst_index] = (float)src[src_index] / 255.;
}
}
extern "C" image convert_to_image_gpu(unsigned char* data,int w,int h,int c)
{
int nBytes = w*h*c*sizeof(unsigned char);
unsigned char* src;
cudaMalloc((void**)&src, nBytes);
float *dst;
cudaMalloc((void**)&dst, w*h*c*sizeof(float));
// 将host数据拷贝到device
//cuda_push_array(src,data,nBytes);
cudaError_t status = cudaMemcpyAsync(src, data, nBytes, cudaMemcpyHostToDevice, get_cuda_stream());
CHECK_CUDA(status);
// 定义kernel的执行配置
dim3 blockSize(32,32,1);
dim3 gridSize((w + blockSize.x - 1) / blockSize.x,(h + blockSize.y - 1) / blockSize.y,(c + blockSize.z - 1) / blockSize.z);
MatConvertImg << < gridSize, blockSize >>>(dst,src,w,h,c);
image im = make_image(w, h, c);
cuda_pull_array(dst,im.data,w*h*c*sizeof(float));
cudaFree(src);
cudaFree(dst);
return im;
}
convert_to_image_gpu函数前一定要加extern "c",否则在c文件中调用convert_to_image_gpu时会发生链接错误。
调用时报错:
关于C语言中的Debug Assertion Failed,在编译和运行时都不会出现错误,但是在执行时会出现错误。发生这种错误的原因可能是:
1、直接释放了一个空指针;
2、一个指针被释放了两次(即第二次释放一个空指针);
3、数组越界:访问了超过数组长度的内存。
跟踪代码发现,程序死在
cuda_pull_array(dst,im.data,w*h*c*sizeof(float));
改成
cuda_pull_array(dst,im.data,w*h*c);
问题解决。
darknet源码解析:cuda_push_array可知,cuda_push_array函数中已经包含sizeof(float)计算,传参只需传入float变量个数就可以了,否则会发生访问越界错误。