【darknet源码】:导入训练数据(分支)

1.1 data.c/concat_datas
/*
** 合并读入的所有图片数据至一个data中:图片数据不是一起读入的,分了多个线程读入,全部存储在d中(d是一个元素类型为data的一维数组)
** 输入: d    读入的所有图片数据,第i个线程读入的部分图片数据存储在d[i]中
**       n    d的维数,也即数据分了多少块(使用多少个线程读入)
** 返回: data类型,包含所有图片
** 说明: 虽然返回的out是在函数内新建的,但实际上,out都只是浅拷贝了这些碎块的图片数据,也即与这些碎块共享数据,
**       因此,无论是哪个变量,其数据都不能释放(即data.shallow只能设置为1,不能深层释放数据的内存)
** 碎碎念(TODO):为什么总是动不动返回或者传入data等其他结构体实例呢,传指针不是更快么:(
*/
data concat_datas(data *d, int n)
{
    int i;
    data out = {0};
    for(i = 0; i < n; ++i){
        data new = concat_data(d[i], out);
        // i = 0时,因为out = {0},表明默认初始化其中所有的元素为0值,对于指针变量而言,那就是空指针,
        // free()函数可以接受一个空指针,此时free()函数将无作为,但不会出错;当i != 1时,out等于上一次循环得到的new,
        // 在concat_data()函数中,会置其shallow元素值为1,也即进行浅层释放,为什么进行浅层释放呢?
        // 整个的concat_datas函数在合并矩阵,在合并每一个小矩阵时,小矩阵的数据并没有进行深拷贝(深拷贝是指内容拷贝),
        // 而是直接将小矩阵每一行的指针变量赋值给了大矩阵的对应行的指针变量(浅拷贝)(可以回看data.c文件中的concat_matrix()函数for循环中的赋值操作,
        // m1.vals[i]是指向二维数组每一行开头的指针变量,也即复制的是指针变量本身,而不是指针变量所指的值,这就是浅拷贝),
        // 所以小矩阵out与得到的新的大矩阵实际会共享数据,因此,下面只能释放out.X.valsout.y.vals用于存储每一行指针变量的堆内存,
        // 而不能内释放用于存储真实数据的堆内存,也即只能进行浅层释放,不能进行深层释放。
        free_data(out);
        // 置out等于新得到的大矩阵new,此时out.X.vals以及out.y.vals存储的指向每一行数据的指针变量包括
        // 目前为止得到的整个大矩阵的所有行
        out = new;
    }
    return out;
}
1.2 data.c/concat_data
/*
** 合并某一块图片数据到大data中并返回
** 输入: d1    待合并的data
**       d2    待合并的data
** 返回: data类型数据
** 碎碎念(TODO):为什么总是动不动返回或者传入data等其他结构体实例呢,传指针不是更快么:(
*/
data concat_data(data d1, data d2)
{
    data d = {0};
    d.shallow = 1;
    // 合并图片数据至d.X中
    d.X = concat_matrix(d1.X, d2.X);
    // 合并图片的标签数据至d.y中
    d.y = concat_matrix(d1.y, d2.y);
    return d;
}
1.3 data.c/concat_matrix
/*
** 合并矩阵m1,m2至一个大矩阵并返回
** 输入: m1    待合并的矩阵1
**       m2    待合并的矩阵2
** 返回: matrix类型,合并后的大矩阵
*/
matrix concat_matrix(matrix m1, matrix m2)
{
    int i, count = 0;
    // 新建返回的大矩阵
    matrix m;
    // 大矩阵列数不变,行数是m1,m2之后(一行对应一张图片数据)
    m.cols = m1.cols;
    m.rows = m1.rows+m2.rows;
    // 为vals的第一维动态分配内存(下面并没有为第二维动态分配内存,从下面的for循环可以看出,第二维采用浅拷贝方式)
    m.vals = calloc(m1.rows + m2.rows, sizeof(float*));

    // 将m1中的图片数据逐行拷贝给大矩阵m(浅拷贝)
    for(i = 0; i < m1.rows; ++i){
        // 为vals的每一行赋值
        // 注意m1.vals[i]是每一行的首地址,因此m1.vals[i]是个指针变量,也就是此处直接将每行的地址赋值给了待输出矩阵的每一行的指针变量(前拷贝),
        // 所以m实际与m1共享了数据(指向了同一块内存)
        m.vals[count++] = m1.vals[i];
    }

    // 紧接着将m2中的图片数据逐行拷贝给大矩阵m(浅拷贝)
    for(i = 0; i < m2.rows; ++i){
        m.vals[count++] = m2.vals[i];
    }
    return m;
}
2.1 data.c/free_data()
/*
** 释放数据d的堆内存
** 说明: 该函数输入虽然是data类型数据,但实际上是释放data结构体中matrix类型元素X,y的vals的堆内存(有两层深度),
**       分两种情况,浅层释放与深层释放,决定于d的标志位shallow的取值,shallow=1表示浅层释放,
**       shallow=0表示深层释放,关于浅层与深层释放,见data结构体定义处的注释,此不再赘述。
**       什么时候需浅层释放呢?当不想删除二维数组的数据,只想清除第一层指针存储的第二层指针变量时,
**       采用浅层释放,在释放前,二维数组的数据应当转移,使得另有指针可以访问这些保留的数据;
**       而当不想要保留任何数据时,采用深层释放。
*/
void free_data(data d)
{
    if(!d.shallow){
        // 深层释放堆内存(注意虽然输入是d.X,d.y,但不是直接释放d.X,d.y,这二者在data结构体中根本连指针都不算。
        // 在free_matrix()中是逐行释放d.X.vals和d.y.vals的内存,再直接释放d.X.vals和d.y.vals)
        free_matrix(d.X);
        free_matrix(d.y);
    }else{
        // 浅层释放堆内存
        free(d.X.vals);
        free(d.y.vals);
    }
}
2.2 matrix.c/free_matrix()
/*
** 深层释放二维数组的堆内存(m.vals是一个float**,即二维数组)
** 说明: 输入虽然是matrix类型数据,但本函数实际是释放其子元素vals的堆内存。
**       因为vals是二维数组,之前使用calloc()为每一行动态分配了内存,
**       此外,vals变量本身也是一个由calloc(rows, sizeof(float*))动态分配的用来存储
**       每一行指针变量的堆内存,因此释放过程首先需要释放每一行的堆内存,最后再直接释放m.vals
*/
void free_matrix(matrix m)
{
    int i;
    // 先逐行释放堆内存
    for(i = 0; i < m.rows; ++i) free(m.vals[i]);
    // 最后直接释放m.vals,清空用于存储每一行指针变量的堆内存
    free(m.vals);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yuanCruise

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值