yolov3计算mAP有两种方法,第一种是使用faster rcnn中的voc_eval.py进行计算,另一种是通过修改yolov3中的代码进行计算。相比较而言第一种方法简单一些。
方法一:使用voc_eval.py进行计算
在yolov3中运行vaild命令进行测试。vaild命令执行的代码如下
void validate_detector(char *datacfg, char *cfgfile, char *weightfile, char *outfile)
{
int j;
list *options = read_data_cfg(datacfg);
char *valid_images = option_find_str(options, "valid", "data/train.list");
char *name_list = option_find_str(options, "names", "data/names.list");
char *prefix = option_find_str(options, "results", "results");
char **names = get_labels(name_list);
//中间省略了部分代码
} else {
if(!outfile) outfile = "comp4_det_test_";
fps = calloc(classes, sizeof(FILE *));
for(j = 0; j < classes; ++j){
snprintf(buff, 1024, "%s/%s%s.txt", prefix, outfile, names[j]);
fps[j] = fopen(buff, "w");
}
}
从代码中可以看出,程序首先会根据你的数据集的类别创建对应的txt文件。创建的txt文件用来保存每一个类别检测到的目标框。txt文件创建的位置为 prefix + outfile + names[j], 其中prefix由data文件中的results指定, outfile默认为“comp4_det_test_”。
运行完成后,在对应的位置会看到生成的文件
我这里有6类,所以就生成了6个文件。有了这些文件后,就可以了使用voc_eval.py进行计算了。具体计算方法参见我的另一篇博客https://blog.csdn.net/sihaiyinan/article/details/89417963。
方法二:修改源代码进行计算
Windows版本下的darknet有计算mAP和recall的代码,把这部分代码稍加修改放到ubuntu版本的darknet中就可以了直接进行recall和mAP的计算了。代码修改后别忘了重新make一下。
1. 计算recall
在detector.c文件中有计算recall的函数,不过不能直接使用。直接把下面的代码替换成原来的validate_detector_recall函数即可。recall计算命令为
./darknet detector recall PATH/TO/*.data PATH/TO/*.cfg PATH/TO/*.weights
void validate_detector_recall(char *datacfg, char *cfgfile, char *weightfile)
{
network *net = load_network(cfgfile, weightfile, 0); //加载网络
set_batch_network(net, 1);
fprintf(stderr, "Learning Rate: %g, Momentum: %g, Decay: %g\n", net->learning_rate, net->momentum, net->decay);
srand(time(0));
list *options = read_data_cfg(datacfg); //读取data文件
char *valid_images = option_find_str(options, "valid", "data/train.list"); //读取验证图像
list *plist = get_paths(valid_images);
char **paths = (char **)list_to_array(plist);
//layer l = net->layers[net->n-1];
int j, k;
int m = plist->size; //验证图像的数量
int i=0;
float thresh = .001;
float iou_thresh = .5;
float nms = .4;
int total = 0;
int correct = 0;
int proposals = 0;
float avg_iou = 0;
for (i = 0; i < m; ++i) {
char *path = paths[i]; //the i-th image's path
image orig = load_image_color(path, 0, 0);
image sized = resize_image(orig, net->w, net->h);
char *id = basecfg(path);
network_predict(net, sized.data);
int nboxes = 0;
detection *dets = get_network_boxes(net, sized.w, sized.h, thresh, .5, 0, 1, &nboxes);
if (nms) do_nms_obj(dets, nboxes, 1, nms); //抑制局部非最大
char labelpath[4096];
find_replace(path, "images", "labels", labelpath);
find_replace(labelpath, "JPEGImages", "labels", labelpath);
find_replace(labelpath, ".jpg", ".txt", labelpath);
find_replace(labelpath, ".JPEG", ".txt", labelpath);
int num_labels = 0;
box_label *truth = read_boxes(labelpath, &num_labels); //read the normalized image data in 'labels' folder
for (k = 0; k < nboxes; ++k) {
if (dets[k].objectness > thresh) {
++proposals;
}
}
for (j = 0; j < num_labels; ++j) {
++total;
box t = { truth[j].x, truth[j].y, truth[j].w, truth[j].h };
float best_iou = 0;
for (k = 0; k < nboxes; ++k) { //many boxs detected about the one object in the image, select the best box
float iou = box_iou(dets[k].bbox, t); //compute IoU
if (dets[k].objectness > thresh && iou > best_iou) {
best_iou = iou;
}
}
avg_iou += best_iou;
if (best_iou > iou_thresh) {
++correct;
}
}
//fprintf(stderr, " - %s\n - %s\n ", paths[i], lab