[TOC]
本次解析src/matrix.h 与 src/matrix.c 两个。
matrix.h 中的包含的代码如下:
#ifndef MATRIX_H
#define MATRIX_H
#include "darknet.h"
// 将矩阵m中的数据拷贝到内存中
matrix copy_matrix(matrix m);
// 可视化
void print_matrix(matrix m);
//从矩阵中采样m行数据,返回采样后的结果;
matrix hold_out_matrix(matrix *m, int n);
// 矩阵的行数和列数进行resize操作,resize矩阵大小是size * size
matrix resize_matrix(matrix m, int size);
//获取矩阵中某一列数据,并把该列删除掉
float *pop_column(matrix *m, int c);
#endif
首先,我们分析matrix.h 中的源码,基础数据结构list 定义在 darknet.h 中,其定义如下:
typedef struct matrix{
int rows, cols; // 行数,列数
float **vals; // 二维float数组
} matrix;
matrix.c 中函数的详细分析如下,
#include "matrix.h"
#include "utils.h"
#include "blas.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
/**
* 释放矩阵的存储空间
* @param matrix 待释放存储空间矩阵 m
*/
void free_matrix(matrix m)
{
int i;
// 逐行释放存储空间;
for(i = 0; i < m.rows; ++i) free(m.vals[i]);
free(m.vals);
}
/**
* emmm...... 暂时不能理解这波操作,先空在这里,看上层怎么用???
* @param truth 矩阵
* @param guess
* @param k 取top的个数
* @return 查找的准确率
*/
float matrix_topk_accuracy(matrix truth, matrix guess, int k)
{
// 申请k个int类型存储空间,
int *indexes = calloc(k, sizeof(int));
int n = truth.cols;// n 保存truth矩阵的列数
int i,j;
int correct = 0;
for(i = 0; i < truth.rows; ++i){
// top_K 查找guess.vals[i] 数组中 top-k 个, index保存在 indexes
top_k(guess.vals[i], n, k, indexes);
// 逐一遍历这top-k个数据
for(j = 0; j < k; ++j){
int class = indexes[j]; // 取index
if(truth.vals[i][class]){ //对应 truth.vals[i][class] 位置是否非0
++correct; // 非0 就表示满足
break;
}
}
}
free(indexes); // 释放index
return (float)correct/truth.rows; // 返回比例,看样子是准确度。
}
/**
* 矩阵与常数乘法操作,将矩阵m中每个元素都放大scale倍
* @param m 矩阵
* @param scale 乘子
*/
void scale_matrix(matrix m, float scale)
{
int i,j;
for(i = 0; i < m.rows; ++i){
for(j = 0; j < m.cols; ++j){
m.vals[i][j] *= scale;
}
}
}
/**
* 矩阵的行数和列数进行resize操作,resize矩阵大小是size * size
* @param m 待调整矩阵
* @param size 调整后的矩阵大小为 size * size
* @return resize后的矩阵
*/
matrix resize_matrix(matrix m, int size)
{
int i;
if (m.rows == size) return m; // 如果矩阵行数不发现变化,则不做任何调整;
if (m.rows < size) { // 调整后矩阵行数变多
/* 函数名:recalloc
函数原型:extern void *realloc (void *mem_address, unsigned int newsize);
函数功能:动态调整内存,先判断当前的指针是否有足够的连续空间,如果有,则扩大mem_address指向的地址,
并且将mem_address返回,如果空间不够,先按照newsize指定的大小分配空间,将原有数据全部拷贝到新分配的内存区域,
而后对原来meme_address所指向的内存区域进行释放【这里是自动释放,不需要手动释放】,同时返回新分配内存区域的首地址。
如果失败则返回空指针NULL;
*/
m.vals = realloc(m.vals, size*sizeof(float*)); // 重新申请内存空间
for (i = m.rows; i < size; ++i) {
m.vals[i] = calloc(m.cols, sizeof(float)); // 每一行的存储空间也要重新申请,每一行保存size 个数据
}
} else if (m.rows > size) { // 调整后矩阵行数减少
for (i = size; i < m.rows; ++i) { // 释放多余的存储空间
free(m.vals[i]);
}
m.vals = realloc(m.vals, size*sizeof(float*)); // 分配每一行存储空间,每一行保存size 个数据
}
m.rows = size;
return m; // m是一个size*size 大小的矩阵
}
/**
* 两个矩阵的加法操作
* @param from 矩阵
* @param to 矩阵
* 最后结果写入到矩阵 to 中
*/
void matrix_add_matrix(matrix from, matrix to)
{
assert(from.rows == to.rows && from.cols == to.cols);
int i,j;
for(i = 0; i < from.rows; ++i){
for(j = 0; j < from.cols; ++j){
to.vals[i][j] += from.vals[i][j];
}
}
}
/**
* 将矩阵m中的数据拷贝到内存中
* @param m 待拷贝数据
* @return 返回存储在内存中矩阵
*/
matrix copy_matrix(matrix m)
{
matrix c = {0};
c.rows = m.rows;
c.cols = m.cols;
c.vals = calloc(c.rows, sizeof(float *));
int i;
for(i = 0; i < c.rows; ++i){
c.vals[i] = calloc(c.cols, sizeof(float));
// copy_cpu() 定义在 blas.h 中
// void copy_cpu(int N, float *X, int INCX, float *Y, int INCY);
/* blas.c 中
* void copy_cpu(int N, float *X, int INCX, float *Y, int INCY)
{
int i;
for(i = 0; i < N; ++i) Y[i*INCY] = X[i*INCX];
}
*/
// 将矩阵m的内容拷贝到矩阵c中
copy_cpu(c.cols, m.vals[i], 1, c.vals[i], 1);
}
return c;
}
/**
* 矩阵初始化
* @param rows 行数
* @param cols 列数
* @return 初始化结果
*/
matrix make_matrix(int rows, int cols)
{
int i;
matrix m;
m.rows = rows;
m.cols = cols;
m.vals = calloc(m.rows, sizeof(float *));// 申请存储空间
for(i = 0; i < m.rows; ++i){
m.vals[i] = calloc(m.cols, sizeof(float));
}
return m;
}
/**
* 从矩阵中采样m行数据,返回采样后的结果;
* @param m 待采样的数据
* @param n 抽取的行数
* @return 采样后的结果;
*/
matrix hold_out_matrix(matrix *m, int n)
{
int i;
matrix h;
h.rows = n;
h.cols = m->cols;
h.vals = calloc(h.rows, sizeof(float *)); //申请新矩阵的存储空间
for(i = 0; i < n; ++i){
int index = rand()%m->rows; // 随机抽取一行
h.vals[i] = m->vals[index];
m->vals[index] = m->vals[--(m->rows)]; // 把最后一行的数据覆盖到 index行上
}
return h;
}
/**
* 获取矩阵中某一列数据,并把该列删除掉
* @param m 待删除矩阵
* @param c 列的index
* @return 返回指定列
*/
float *pop_column(matrix *m, int c)
{
//
float *col = calloc(m->rows, sizeof(float));
int i, j;
for(i = 0; i < m->rows; ++i){
col[i] = m->vals[i][c]; // 逐行获取第c列
for(j = c; j < m->cols-1; ++j){
m->vals[i][j] = m->vals[i][j+1]; // 将c+1 到 m.cols-1列向左平移
}
}
--m->cols; // 列数自减1
return col;
}
/**
* 读取文件,并将文件中的数据加载到矩阵matrix中
* @param filename 文件的存储位置
* @return 矩阵
*/
matrix csv_to_matrix(char *filename)
{
FILE *fp = fopen(filename, "r");
if(!fp) file_error(filename); // 如果不能打印文件,保存退出程序
matrix m;
m.cols = -1;
char *line;
int n = 0;
int size = 1024;
m.vals = calloc(size, sizeof(float*));
while((line = fgetl(fp))){ // fgetl 读取文件中一行数据
// 统计字符串中有多少个 ',' 字符和 '\0', 遇到第一个'\0'字符结束;
// 相当于统计line中包含多少个数据,其实这就是矩阵的列数
if(m.cols == -1) m.cols = count_fields(line);
if(n == size){ //如果处理到第1024行,需要重新扩充 m.vals的存储空间
size *= 2;
m.vals = realloc(m.vals, size*sizeof(float*));
}
m.vals[n] = parse_fields(line, m.cols); // 解析字符数组中m.cols个float小数,返回是一个float类型指针
free(line); // 释放line存储空间
++n; //统计处理行数
}
m.vals = realloc(m.vals, n*sizeof(float*)); // 之前开辟的空间是1024的整数倍,此时需要根据n来实际分配内存空间
m.rows = n;
return m; // 返回结果
}
/**
* 可视化打印矩阵m,打印格式按照csv格式
* @param m
*/
void matrix_to_csv(matrix m)
{
int i, j;
for(i = 0; i < m.rows; ++i){
for(j = 0; j < m.cols; ++j){
if(j > 0) printf(",");
printf("%.17g", m.vals[i][j]); //自动选择合适的表示法输出
}
printf("\n");
}
}
/**
* 可视化打印矩阵m
* @param m
*/
void print_matrix(matrix m)
{
int i, j;
printf("%d X %d Matrix:\n",m.rows, m.cols); //打印行和列数
printf(" __");
for(j = 0; j < 16*m.cols-1; ++j) printf(" ");
printf("__ \n");
printf("| ");
for(j = 0; j < 16*m.cols-1; ++j) printf(" ");
printf(" |\n");
for(i = 0; i < m.rows; ++i){
printf("| ");
for(j = 0; j < m.cols; ++j){
printf("%15.7f ", m.vals[i][j]);
}
printf(" |\n");
}
printf("|__");
for(j = 0; j < 16*m.cols-1; ++j) printf(" ");
printf("__|\n");
}