darknet源码剖析(二) 数据加载

在上一篇文章中,我们分析了darknet的网络结构与初始化过程,在源码中是load_network函数。接下来继续分析数据加载过程。数据加载过程中涉及的函数有load_data、load_threads、load_data_in_thread、load_thread。

数据加载过程如下图所示。

(1)load_data中首先启动一个线程调用load_threads,load_threads是实际加载数据的线程,再load_threads加载完成前,主线程会等待。

(2)在load_threads通过循环方式,共调用load_data_in_thread函数64次。数据加载过程在load_data_in_thread函数中完成。

以下几行代码需要注意:

    data *buffers = calloc(args.threads, sizeof(data));
    pthread_t *threads = calloc(args.threads, sizeof(pthread_t));
    for(i = 0; i < args.threads; ++i){
        args.d = buffers + i;
        args.n = (i+1) * total/args.threads - i * total/args.threads;
        threads[i] = load_data_in_thread(args);
    }

共申请了64个data类型空间与64个pthread_t类型空间,在循环中分别调用load_data_in_thread,每次args.d的地址向后移动一个data类型空间,args.n的值一直为1。

(3)load_data_in_thread函数中启动线程,并调用load_thread函数,主线程返回load_threads中等待。

(4)load_thread函数调用load_data_detection函数加载数据。

下面对load_data_detection进行详细分析。load_data_detection函数每次仅加载一张图片,因此一个batch共加载64张图片。其中有3个函数需要重点关注。

    place_image(orig, nw, nh, dx, dy, sized);
    random_distort_image(sized, hue, saturation, exposure);
    fill_truth_detection(random_paths[i], boxes, d.y.vals[i], classes, flip, -dx/w, -dy/h, nw/w, nh/h);

以上三个函数的功能是来自于我的推测,还没有详细验证,place_image的功能是将原图(orig)的一部分放入输入图片中,random_distort_image是随机扭曲图片,fill_truth_detection的功能是填充bounding_box,但具体如何变换还没有搞清楚。

至此darknet的数据加载流程就已经搞清楚了,还有另一条线需要明确一下那就是数据是如何返回的。

1)首先是在detector.c中的train_detector函数中有以下几行代码:

    data train, buffer;
    args.d = &buffer;

通过以上两行代码可以知道,现在args.d指向buffer的地址。

2)进入load_data函数(data.c):

    struct load_args *ptr = calloc(1, sizeof(struct load_args));
    *ptr = args;

现在ptr是args的拷贝,二者使用不同的内存空间,但由于ptr是args的拷贝,因此ptr.d同样也指向buffer。

3)进入load_threads函数(data.c):

    load_args args = *(load_args *)ptr;
    data *out = args.d;
    free(ptr);
    data *buffers = calloc(args.threads, sizeof(data));

相同的套路在此处又出现了一次,此时args是ptr的拷贝,args.d同样指向buffer。然后令out同样指向buffer。接下来free ptr,也即在load_data中申请的内存在load_threads中释放。此处申请的buffers是用来实际存放训练数据的。

    args.d = buffers + i;

此处实际上是args的复用。由于args不是指针,是变量,因此分配有内存空间。

4)进入load_data_in_thread函数(data.c):

    struct load_args *ptr = calloc(1, sizeof(struct load_args));
    *ptr = args;

又是相同的套路,ptr复制args的数据,此时ptr.d指向的是buffers对应的内存地址,注意此处是buffers,不是buffer。

5)进入load_thread函数(data.c):

    load_args a = *(struct load_args*)ptr;
    *a.d = load_data_detection(a.n, a.paths, a.m, a.w, a.h, a.num_boxes, a.classes, a.jitter, a.hue, a.saturation, a.exposure);
    free(ptr);

此处a是ptr的拷贝,a.d指向的是buffers的地址空间,所以不需要再额外调用calloc函数,就可以直接使用*a.d。free ptr后,在load_data_in_thread中申请的内存空间也就被释放了。同时load_thread函数返回后,a变量占用的栈空间也会被释放。

6)数据回传

通过对函数的返回过程进行分析,同时分析数据的回传过程。

(1)在load_thread函数中训练数据已经被存储到buffers指向的内存空间中。同时在load_data_in_thread中申请的空间也被释放了,不存在内存泄漏的问题。

(2)回到load_threads函数中。

    *out = concat_datas(buffers, args.threads);

buffers中的数据都被concat在一起,同时复制到out执行的内存空间,而out指向的内存空间恰好是buffer的内存空间,由于已经申请过内存空间了,因此也不需要再calloc了。

    for(i = 0; i < args.threads; ++i){
        buffers[i].shallow = 1;
        free_data(buffers[i]);
    }
    free(buffers);
    free(threads);

通过上述过程彻底释放在load_threads中分配的内存空间。同样没有内存泄漏的问题。

(3)回到load_data函数中:

在load_data函数申请的ptr空间在load_threads中释放了,同样没有内存泄漏问题,同时训练数据也被传回到train_detector中。

还是记录一下当前的问题:

1)Box–Muller transform

2)load_data_detection的详细分析

 

 

 

 

 

 

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
需要学习Windows系统YOLOv4的同学请前往《Windows版YOLOv4目标检测实战:原理与源码解析》,课程链接 https://edu.csdn.net/course/detail/29865【为什么要学习这门课】 Linux创始人Linus Torvalds有一句名言:Talk is cheap. Show me the code. 冗谈不够,放码过来!  代码阅读是从基础到提高的必由之路。尤其对深度学习,许多框架隐藏了神经网络底层的实现,只能在上层调包使用,对其内部原理很难认识清晰,不利于进一步优化和创新。YOLOv4是最近推出的基于深度学习的端到端实时目标检测方法。YOLOv4的实现darknet是使用C语言开发的轻型开源深度学习框架,依赖少,可移植性好,可以作为很好的代码阅读案例,让我们深入探究其实现原理。【课程内容与收获】 本课程将解析YOLOv4的实现原理和源码,具体内容包括:- YOLOv4目标检测原理- 神经网络及darknet的C语言实现,尤其是反向传播的梯度求解和误差计算- 代码阅读工具及方法- 深度学习计算的利器:BLAS和GEMM- GPU的CUDA编程方法及在darknet的应用- YOLOv4的程序流程- YOLOv4各层及关键技术的源码解析本课程将提供注释后的darknet源码程序文件。【相关课程】 除本课程《YOLOv4目标检测:原理与源码解析》外,本人推出了有关YOLOv4目标检测的系列课程,包括:《YOLOv4目标检测实战:训练自己的数据集》《YOLOv4-tiny目标检测实战:训练自己的数据集》《YOLOv4目标检测实战:人脸口罩佩戴检测》《YOLOv4目标检测实战:中国交通标志识别》建议先学习一门YOLOv4实战课程,对YOLOv4的使用方法了解以后再学习本课程。【YOLOv4网络模型架构图】 下图由白勇老师绘制  

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值