更多darknet预测分类动态库文章参考:自己动手实现darknet预测分类动态库
1.darknet分类预测流程说明
Darknet分类预测时需要输入cmd指令:
darknet classifier test metal.data 19448.txt backup/19448_last.weights
该指令在darknet源代码主要调用test_classifier()完成。下面是test_classifier()中现有涉及需要修改的流程:
1.1读取meta.data中test对应的图片路径列表paths
1.2 load_data_in_thread()中调用pthread库创建线程load_thread()
1.3 load_thread()线程中调用load_image()加载图片,每个线程每次加载net.batch张图片,没有加载完的图片重新创建线程加载。
1.4 load_image()主要工作包括:a).使用stb_image库读取文件流的形式获得image(stb_image库的格式)格式图片;b).将图片转换成darknet支持格式martrix,大小转换为深度学习模型文件(19448.cfg)配置的图片大小。
2.如何修改流程
查看代码时发现stb_image库中同时有函数stbi_load_image_from_memory和stbi_load_image_from_file(),现阶段(见1.4)load_image()中使用的是stbi_load_image_form_file(),可以将stbi_load_image_from_file改成stbi_load_image_from_memory()。
对比两个函数的参数,除了第一个参数不同外,其他三个参数都相同:
Stbi_load_image_from_file()第一个参数为文件路径
Stbi_load_image_from_memory()第一个参数为unsigned char,
也就是说可以直接传入内存地址给stbi_load_image_from_memory()
所以需要做的修改包括:从test_classifier()开始修改,把原来传入文件的地方修改为:传入内存首地址、图片大小、图片宽高。
darknet预测分类时,直接从内存中读取图片。
3.darknet分类预测详细流程
运行darknet模型预测一组图片指令如下:
darknet classifier test metal.data 19448.txt backup/19448_last.weights
darknet.c文件里面main()函数,是整个darknet程序的入口函数,该函数第493行和494行如下:
} else if (0 == strcmp(argv[1], "classifier")){
run_classifier(argc, argv);
如果第一个参数为“classifier”时,调用run_classifier函数,其中参数argv就是我们输入的指令。
run_classifier()函数:
char *data = argv[3];
char *cfg = argv[4];
char *weights = (argc > 5) ? argv[5] : 0;
char *layer_s = (argc > 7) ? argv[7]: 0;
int layer = layer_s ? atoi(layer_s) : -1;
else if(0==strcmp(argv[2], "test")) test_classifier(data, cfg, weights, layer);
如果第二个参数为‘test’时,调用test_classifier()。其中参数,data=meta.data,cfg=19448.txt,weights=backup/19448_last.weights,layer=-1
test_classifier()源代码:
void test_classifier(char *datacfg, char *cfgfile, char *weightfile, int target_layer)
{
int curr = 0;
network net = parse_network_cfg(cfgfile);
if(weightfile){
load_weights(&net, weightfile);
}
srand(time(0));
fuse_conv_batchnorm(net);
calculate_binary_weights(net);
list *options = read_data_cfg(datacfg);
char *test_list = option_find_str(options, "test", "data/test.list");
int classes = option_find_int(options, "classes", 2);
list *plist = get_paths(test_list);
char **paths = (char **)list_to_array(plist);
int m = plist->size;
free_list(plist);
clock_t time;
data val, buffer;
load_args args = {0};
args.w = net.w;
args.h = net.h;
args.paths = paths;
args.classes = classes;
args.n = net.batch;
args.m = 0;
args.labels = 0;
args.d = &buffer;
args.type = OLD_CLASSIFICATION_DATA;
pthread_t load_thread = load_data_in_thread(args);
for(curr = net.batch; curr < m; curr += net.batch){
time=clock();
pthread_join(load_thread, 0);
val = buffer;
if(curr < m){
args.paths = paths + curr;
if (curr + net.batch > m) args.n = m - curr;
load_thread = load_data_in_thread(args);
}
fprintf(stderr, "Loaded: %d images in %lf seconds\n", val.X.rows, sec(clock()-time));
time=clock();
matrix pred = network_predict_data(net, val);
int i, j;
if (target_layer >= 0){
//layer l = net.layers[target_layer];
}
for(i = 0; i < pred.rows; ++i){
printf("%s", paths[curr-net.batch+i]);
for(j = 0; j < pred.cols; ++j){
printf("\t%g", pred.vals[i][j]);
}
printf("\n");
}
free_matrix(pred);
fprintf(stderr, "%lf seconds, %d images, %d total\n", sec(clock()-time), val.X.rows, curr);
free_data(val);
}
}
想要darknet预测分类时,直接从内存中读取图片,那么就需要改造test_classifier代码。