Beispiel #1
0
    def ap(self, det, anno, iou=.5, csv=None):
        if csv is not None:
            base_path = Path(csv)

        if self.fast_pr:
            pr = bbb.pr(det, anno, iou)

            if csv is not None:
                np.savetxt(str(base_path), np.array(pr), delimiter=',')

            return round(100 * bbb.ap(*pr), 2)
        else:
            aps = []
            for c in tqdm(self.params.class_label_map):
                anno_c = bbb.filter_discard(copy.deepcopy(anno),
                                            [lambda a: a.class_label == c])
                det_c = bbb.filter_discard(copy.deepcopy(det),
                                           [lambda d: d.class_label == c])
                pr = bbb.pr(det_c, anno_c)

                if csv is not None:
                    np.savetxt(str(
                        base_path.with_name(base_path.stem + f'_{c}' +
                                            base_path.suffix)),
                               np.array(pr),
                               delimiter=',')

                aps.append(bbb.ap(*pr))

            return round(100 * mean(aps), 2)
Beispiel #2
0
    def bb_map(truth, pred):
        import lightnet as ln
        import torch
        detection_to_brambox = ln.data.transform.TensorToBrambox(NETWORK_SIZE, LABELS)
        def as_annos(truth, Win=1, Hin=1):
            """
            Construct an BramBox annotation using the basic YOLO box format
            """
            from brambox.boxes.annotations import Annotation
            for true in truth:
                anno = Annotation()
                anno.class_id = true[0]
                anno.class_label = LABELS[int(true[0])]
                x_center, y_center, w, h = true[1:5]
                anno.x_top_left = (x_center - w / 2) * Win
                anno.y_top_left = (y_center - h / 2) * Hin
                anno.width, anno.height = w * Win, h * Hin
                anno.ignore = False
                yield anno

        true_bram = list(as_annos(truth, *NETWORK_SIZE))
        pred_bram = detection_to_brambox([torch.Tensor(pred)])[0]

        ln_det = {'a': pred_bram}
        anno = {'a': true_bram}

        import brambox.boxes as bbb
        detections = ln_det
        ground_truth = anno
        overlap_threshold = 0.5
        bb_precision, bb_recall = bbb.pr(detections, ground_truth, overlap_threshold)
        bb_map = round(bbb.ap(bb_precision, bb_recall) * 100, 2)
        return bb_map
Beispiel #3
0
    def test(self):
        log.info('Start testing')
        self.network.eval()
        tot_loss = 0
        anno, det = {}, {}

        with torch.no_grad():
            for idx, (data, target) in enumerate(self.valid_loader):
                data = data.to(self.device)
                output, loss = self.network(data, target)
                tot_loss += loss.item()*len(target)

                key_val = len(anno)
                anno.update({key_val+k: v for k,v in enumerate(target)})
                det.update({key_val+k: v for k,v in enumerate(output)})

                if self.sigint:
                    self.network.train()
                    return

        pr = bbb.pr(det, anno)
        m_ap = round(bbb.ap(*pr)*100, 2)
        loss = tot_loss/len(anno)
        self.log(f'Loss:{loss:.5f} mAP:{m_ap}%')
        self.plot_valid_loss(np.array([loss]), np.array([self.batch]))
        self.plot_valid_pr(np.array(pr[0]), np.array(pr[1]), update='replace')

        if m_ap > self.best_map:
            if self.best_map > 0:
                self.plot_valid_pr(None, name=f'best - {self.best_map}%', update='remove', opts=None)
            self.best_map = m_ap
            self.network.save(os.path.join(self.backup_folder, 'best_map.pt'))
            self.plot_valid_pr(np.array(pr[0]), np.array(pr[1]), name=f'best - {self.best_map}%', update='new', opts=dict(legend=[f'best - {self.best_map}%']))

        self.network.train()
Beispiel #4
0
    def test(self):
        tot_loss = []
        anno, det = {}, {}

        for idx, (data, target) in enumerate(
                tqdm(self.testloader, total=len(self.testloader))):
            if self.cuda:
                data = data.cuda(async=PIN_MEM)

            data = torch.autograd.Variable(data, volatile=True)

            output, loss = self.network(data, target)

            tot_loss.append(loss.data[0] * len(target))
            key_val = len(anno)
            anno.update({key_val + k: v for k, v in enumerate(target)})
            det.update({key_val + k: v for k, v in enumerate(output)})

            if self.sigint:
                return

        pr = bbb.pr(det, anno)
        m_ap = bbb.ap(*pr)
        loss = round(sum(tot_loss) / len(anno), 5)
        self.log('\nLoss:{loss} mAP:{m_ap:0.02f}%'.format(loss=loss,
                                                          m_ap=m_ap * 100.0))
        self.visdom_plot_test_loss(np.array([loss]), np.array([self.batch]))
        self.hyperdash_plot_train_loss('Loss Total (Test)', loss, log=False)
        self.hyperdash_plot_train_loss('mAP (Test)', m_ap, log=False)
Beispiel #5
0
def test(weight, device, save_det):
    log.debug('Creating network')
    net = ln.models.TinyYolo(len(CLASS_LABELS), weight, CONF_THRESH, NMS_THRESH)
    net.postprocess.append(ln.data.transform.TensorToBrambox(NETWORK_SIZE, CLASS_LABELS))
    net = net.to(device)
    net.eval()

    log.debug('Creating dataset')
    loader = torch.utils.data.DataLoader(
        ln.models.DarknetDataset(TESTFILE, augment=False, input_dimension=NETWORK_SIZE, class_label_map=CLASS_LABELS),
        batch_size = MINI_BATCH,
        shuffle = False,
        drop_last = False,
        num_workers = WORKERS,
        pin_memory = PIN_MEM,
        collate_fn = ln.data.list_collate,
    )

    log.debug('Running network')
    tot_loss = []
    coord_loss = []
    conf_loss = []
    cls_loss = []
    anno, det = {}, {}
    num_det = 0

    with torch.no_grad():
        for idx, (data, box) in enumerate(tqdm(loader, total=len(loader))):
            data = data.to(device)
            output, loss = net(data, box)

            tot_loss.append(net.loss.loss_tot.item()*len(box))
            coord_loss.append(net.loss.loss_coord.item()*len(box))
            conf_loss.append(net.loss.loss_conf.item()*len(box))
            if net.loss.loss_cls is not None:
                cls_loss.append(net.loss.loss_cls.item()*len(box))

            key_val = len(anno)
            anno.update({loader.dataset.keys[key_val+k]: v for k,v in enumerate(box)})
            det.update({loader.dataset.keys[key_val+k]: v for k,v in enumerate(output)})

    log.debug('Computing statistics')

    pr = bbb.pr(det, anno)
    m_ap = bbb.ap(*pr)*100
    tot = sum(tot_loss)/len(anno)
    coord = sum(coord_loss)/len(anno)
    conf = sum(conf_loss)/len(anno)
    if len(cls_loss) > 0:
        cls = sum(cls_loss)/len(anno)
        log.test(f'{net.seen//BATCH} mAP:{m_ap:.2f}% Loss:{tot:.5f} (Coord:{coord:.2f} Conf:{conf:.2f} Cls:{cls:.2f})')
    else:
        log.test(f'{net.seen//BATCH} mAP:{m_ap:.2f}% Loss:{tot:.5f} (Coord:{coord:.2f} Conf:{conf:.2f})')

    if save_det is not None:
        # Note: These detection boxes are the coordinates for the letterboxed images,
        #       you need ln.data.transform.ReverseLetterbox to have the right ones.
        #       Alternatively, you can save the letterboxed annotations, and use those for statistics later on!
        bbb.generate('det_pickle', det, Path(arguments.save_det).with_suffix('.pkl'))
Beispiel #6
0
    def test(self):
        log.info('Start testing')
        self.network.eval()
        tot_loss = []
        anno, det = {}, {}

        with torch.no_grad():
            for idx, (data, target) in enumerate(self.valid_loader):
                data = data.to(self.device)
                output, loss = self.network(data, target)
                tot_loss.append(loss.item()*len(target))

                key_val = len(anno)
                anno.update({key_val+k: v for k,v in enumerate(target)})
                det.update({key_val+k: v for k,v in enumerate(output)})

                if self.sigint:
                    self.network.train()
                    return

        m_ap = bbb.ap(*bbb.pr(det, anno)) * 100
        loss = sum(tot_loss) / len(self.valid_loader.dataset)
        self.log(f'Loss:{loss:.5f} mAP:{m_ap}%')
Beispiel #7
0
    def test(self):
        tot_loss = []
        anno, det = {}, {}

        for idx, (data, target) in enumerate(self.testloader):
            if self.cuda:
                data = data.cuda()

            if torch.__version__.startswith('0.3'):
                data = torch.autograd.Variable(data, volatile=True)
                output, loss = self.network(data, target)
                tot_loss.append(loss.data[0] * len(target))
            else:
                with torch.no_grad():
                    output, loss = self.network(data, target)
                tot_loss.append(loss.item() * len(target))

            key_val = len(anno)
            anno.update({key_val + k: v for k, v in enumerate(target)})
            det.update({key_val + k: v for k, v in enumerate(output)})

            if self.sigint:
                return

        pr = bbb.pr(det, anno)
        m_ap = bbb.ap(*pr)
        loss = round(sum(tot_loss) / len(anno), 5)
        self.log('Loss:{loss} mAP:{m_ap:0.02f}%'.format(loss,
                                                        m_ap=m_ap * 100.0))
        self.plot_test_loss(np.array([loss]), np.array([self.batch]))
        self.plot_test_pr.clear()
        self.plot_test_pr(np.array(pr[0]),
                          np.array(pr[1]),
                          update='replace',
                          name='{self.batch} - {m_ap:0.02f}%'.format(
                              self=self, m_ap=m_ap * 100.0))
def generate_curves(ground_truth,
                    results,
                    pr=True,
                    title="",
                    filename="",
                    overlap=0.5,
                    only_plot=None,
                    linewidth=2,
                    figsize=(8, 6),
                    legendloc=3):
    curves = []
    scores = {}
    # colors = plt.rcParams['axes.prop_cycle'].by_key()['color']
    #     colors = ['#1919ff', '#ff7f0e', '#ff1919', '#ff19ff', '#19ff19', '#19ff19']
    colors = ['#1919ff', '#ff7f0e', '#ff1919', '#ff19ff', '#19ff19']
    i = 0
    linestyles = ['-', '-', '-', '--', '--', '--', '-.', ':']
    for label, detections in results.items():
        if pr:
            ys, xs = bbb.pr(detections, ground_truth, overlap)
            score = round(bbb.ap(ys, xs) * 100, 2)
        else:
            ys, xs = bbb.mr_fppi(detections, ground_truth, overlap)
            score = round(lamr(ys, xs) * 100, 2)
        color = colors[i % len(colors)]
        linestyle = linestyles[i % len(linestyles)]

        if only_plot is None or label in only_plot:
            i += 1
        curves += [(label, ys, xs, score, color, linestyle)]
        # print(score)
        # score = round(score,2)
        # print(score)
        scores[label] = score

    if pr:
        # sort from highest ap to lowest
        sorted_curves = sorted(curves,
                               key=lambda curve: curve[3],
                               reverse=True)
    else:
        # sort from lowest to highest
        sorted_curves = sorted(curves, key=lambda curve: curve[3])

    fig, ax = plt.subplots(figsize=figsize)

    for label, ys, xs, score, color, linestyle in sorted_curves:
        # skip curves not mensioned in only_plot
        if only_plot is not None and label not in only_plot:
            continue

        if pr:
            plt.plot(xs,
                     ys,
                     color=color,
                     linestyle=linestyle,
                     label=f"{score:.2f}%  {label}",
                     linewidth=linewidth)
        else:
            plt.loglog(xs,
                       ys,
                       color=color,
                       linestyle=linestyle,
                       label=f"{score:.2f}%  {label}",
                       linewidth=linewidth)

    plt.legend(loc=legendloc)

    plt.gcf().suptitle(title, weight='bold', x=0.5, y=0.95)

    if pr:
        plt.grid(which='major')
        plt.gca().set_ylabel('Precision')
        plt.gca().set_xlabel('Recall')
        plt.gca().set_xlim([0, 1])
        plt.gca().set_ylim([0, 1])
        plt.tight_layout(pad=0)
    else:
        # modify the y axis a bit
        from matplotlib.ticker import FormatStrFormatter, LogLocator
        subs = [1.0, 2.0, 3.0, 4.0, 5.0, 6.4, 8.0]  # ticks to show per decade
        ax.yaxis.set_minor_locator(LogLocator(subs=subs))
        ax.yaxis.set_minor_formatter(FormatStrFormatter("%.2f"))
        ax.yaxis.grid(which='minor')
        ax.xaxis.grid(which='major')
        plt.setp(ax.get_ymajorticklabels(),
                 visible=False)  # disable major labels

        plt.gca().set_ylabel('Miss rate')
        plt.gca().set_xlabel('FPPI')
        plt.gca().set_ylim([0.1, 1])
        plt.gca().set_ylabel('Miss rate')
        plt.gca().set_xlabel('FPPI')
        plt.tight_layout(pad=0)
        # plt.gca().set_xlim([0, 10])

    if filename:
        # plt.savefig(filename+'.pdf', format='pdf', bbox_inches = 'tight',pad_inches=0, transparent=True)
        plt.savefig(filename + '.png', format='png')

    return scores, plt.get_current_fig_manager()
Beispiel #9
0
    def _ln_loop(ln_model, xpu, harn):
        """
        Uses ln data, but nh map computation
        """
        import lightnet as ln
        ln_test = ub.import_module_from_path(ub.truepath('~/code/lightnet/examples/yolo-voc/test.py'))

        harn.current_tag = tag = 'test'

        # Keep track of NH metrics
        dmet = harn.dmets[tag]
        dmet.pred.remove_all_annotations()
        dmet.true.remove_all_annotations()
        dmet.true._build_index()
        dmet.pred._build_index()

        # Keep track of LN metrics
        anno = {}
        ln_det = {}
        resize_anno = {}
        resize_ln_det = {}

        ln_keys_to_gid = {}
        for gid, img in dmet.true.imgs.items():
            key = os.path.splitext(img['file_name'].split('VOCdevkit/')[1])[0]
            ln_keys_to_gid[key] = gid

        def brambox_to_labels(ln_loader, ln_bramboxes, inp_size, LABELS, offset=None):
            """ convert brambox to netharn style labels """
            import lightnet as ln
            max_anno = max(map(len, ln_bramboxes))
            ln_targets = [
                ln.data.transform.BramboxToTensor.apply(
                    annos, inp_size, max_anno=max_anno, class_label_map=LABELS)
                for annos in ln_bramboxes]
            ln_targets = torch.stack(ln_targets)

            gt_weights = -np.ones((len(ln_bramboxes), max_anno), dtype=np.float32)
            for i, annos in enumerate(ln_bramboxes):
                weights = 1.0 - np.array([anno.ignore for anno in annos], dtype=np.float32)
                gt_weights[i, 0:len(annos)] = weights
            gt_weights = torch.Tensor(gt_weights)

            bg_weights = torch.FloatTensor(np.ones(len(ln_targets)))

            if offset is not None:
                # Hack to find image size, assume ordered iteration, which
                # might be true for the test set.
                orig_sizes = []
                indices = []
                for k in range(len(ln_bramboxes)):
                    key = ln_loader.dataset.keys[offset + k]
                    gid = ln_keys_to_gid[key]
                    orig_sizes += [(dmet.true.imgs[gid]['width'], dmet.true.imgs[gid]['height'])]
                    indices += [gid]
                indices = torch.FloatTensor(indices)
                orig_sizes = torch.FloatTensor(orig_sizes)
            else:
                indices = None
                orig_sizes = None

            ln_labels = {
                'targets': ln_targets,
                'gt_weights': gt_weights,
                'orig_sizes': orig_sizes,
                'indices': indices,
                'bg_weights': bg_weights,
            }
            return ln_labels

        def img_to_box(ln_loader, boxes, offset):
            gname_lut = ln_loader.dataset.keys
            return {gname_lut[offset + k]: v for k, v in enumerate(boxes)}

        TESTFILE = ub.truepath('~/code/lightnet/examples/yolo-voc/data/test.pkl')
        os.chdir(ub.truepath('~/code/lightnet/examples/yolo-voc/'))
        ln_dset = ln_test.CustomDataset(TESTFILE, ln_model)
        ln_loader = torch.utils.data.DataLoader(
            ln_dset, batch_size=8, shuffle=False, drop_last=False,
            num_workers=4, pin_memory=True, collate_fn=ln.data.list_collate,
        )
        detection_to_brambox = ln.data.transform.TensorToBrambox(ln_test.NETWORK_SIZE, ln_test.LABELS)

        ln.data.transform.ReverseLetterbox
        # ----------------------
        # Postprocessing to transform yolo outputs into detections
        # Basic difference here is the implementation of NMS
        ln_postprocess = ln_model.postprocess
        # ----------------------
        # ln_results = []
        moving_ave = nh.util.util_averages.CumMovingAve()
        prog = ub.ProgIter(ln_loader, desc='')
        with torch.no_grad():
            ln_loader.dataset.keys
            for bx, ln_batch in enumerate(prog):
                ln_inputs, ln_bramboxes = ln_batch

                # Convert brambox into components understood by netharn
                ln_inputs = xpu.variable(ln_inputs)

                inp_size = tuple(ln_inputs.shape[-2:][::-1])

                # hack image index (assume they are sequential)
                offset = len(anno)
                ln_labels = brambox_to_labels(ln_loader, ln_bramboxes,
                                              inp_size, ln_test.LABELS,
                                              offset=offset)

                ln_model.loss.seen = 1000000
                ln_outputs = ln_model._forward(ln_inputs)

                ln_loss_bram = ln_model.loss(ln_outputs, ln_bramboxes)
                moving_ave.update(ub.odict([
                    ('loss_bram', float(ln_loss_bram.sum())),
                ]))

                # Display progress information
                average_losses = moving_ave.average()
                description = ub.repr2(average_losses, nl=0, precision=2, si=True)
                prog.set_description(description, refresh=False)

                # nh_outputs and ln_outputs should be the same, so no need to
                # differentiate between them here.
                ln_postout = ln_postprocess(ln_outputs.clone())
                # ln_results.append((ln_postout, ln_labels, inp_size))

                # Track NH stats
                pred_anns = list(harn._postout_to_pred_ann(
                    inp_size, ln_labels, ln_postout, undo_lb=False,
                    _aidbase=len(dmet.pred.dataset['annotations']) + 1))
                dmet.pred.add_annotations(pred_anns)

                true_anns = list(harn._labels_to_true_ann(
                    inp_size, ln_labels, undo_lb=False,
                    _aidbase=len(dmet.true.dataset['annotations']) + 1))
                dmet.true.add_annotations(true_anns)

                # Track LN stats
                ln_brambox_postout = detection_to_brambox([x.clone() for x in ln_postout])
                anno.update(img_to_box(ln_loader, ln_bramboxes, offset))
                ln_det.update(img_to_box(ln_loader, ln_brambox_postout, offset))

                # Also track bb-stats in original sizes
                ln_resize_annos = []
                for bb_anns, orig_size in zip(ln_bramboxes, ln_labels['orig_sizes']):
                    old_bb_anns = copy.deepcopy(bb_anns)
                    new_bb_anns = ln.data.transform.ReverseLetterbox.apply(
                        [old_bb_anns], ln_test.NETWORK_SIZE, orig_size)[0]
                    ln_resize_annos.append(new_bb_anns)

                ln_resize_dets = []
                for bb_dets, orig_size in zip(ln_brambox_postout, ln_labels['orig_sizes']):
                    old_bb_dets = copy.deepcopy(bb_dets)
                    new_bb_dets = ln.data.transform.ReverseLetterbox.apply(
                        [old_bb_dets], ln_test.NETWORK_SIZE, orig_size)[0]
                    ln_resize_dets.append(new_bb_dets)

                resize_anno.update(img_to_box(ln_loader, ln_resize_annos, offset))
                resize_ln_det.update(img_to_box(ln_loader, ln_resize_dets, offset))

        print('lightnet voc_mAP = {}'.format(dmet.score_voc()['mAP']))
        print('lightnet nh_mAP = {}'.format(dmet.score_netharn()['mAP']))

        # Compute mAP using brambox / lightnet
        import brambox.boxes as bbb
        ln_mAP = round(bbb.ap(*bbb.pr(ln_det, anno)) * 100, 2)
        print('ln_bb_mAP = {!r}'.format(ln_mAP))

        ln_resize_mAP = round(bbb.ap(*bbb.pr(resize_ln_det, resize_anno)) * 100, 2)
        print('ln_resize_bb_mAP = {!r}'.format(ln_resize_mAP))

        if False:
            # Check sizes
            for bb in resize_anno[ln_loader.dataset.keys[0]]:
                print(list(map(float, [bb.x_top_left, bb.y_top_left, bb.width, bb.height])))
            print(dmet.true.annots(gid=0).boxes)

            # Check sizes
            for bb in resize_ln_det[ln_loader.dataset.keys[0]][0:3]:
                print(list(map(float, [bb.x_top_left, bb.y_top_left, bb.width, bb.height])))
            print(dmet.pred.annots(gid=0).boxes[0:3])
Beispiel #10
0
def _test_with_lnstyle_data():
    """
    Uses pretrained lightnet weights, and the lightnet data loader.

    Uses my critrion and net implementations.
    (already verified to produce the same outputs)

    Checks to see if my loss and map calcluations are the same as lightnet
    CommandLine:
        python ~/code/netharn/netharn/examples/yolo_voc.py _test_with_lnstyle_data

    Using LighNet Trained Weights:

        LightNet Results:
            TEST 30000 mAP:74.18% Loss:3.16839 (Coord:0.38 Conf:1.61 Cls:1.17)

        My Results:
            # Worse losses (due to different image loading)
            loss: 5.00 {coord: 0.69, conf: 2.05, cls: 2.26}
            mAP = 0.6227
            The MAP is quite a bit worse... Why is that?

    USING THE SAME WEIGHTS! I must be doing something wrong.

        Results using the same Data Loader:
            {cls: 2.22, conf: 2.05, coord: 0.65, loss: 4.91}

            # Checking with extra info
            {loss_bram: 3.17, loss_ten1: 4.91, loss_ten2: 4.91}

        OH!, Is is just that BramBox has an ignore function?
            - [X] Add ignore / weight to tensor version to see if its the same
            YUP! {loss_bram: 3.17, loss_ten1: 4.91, loss_ten2: 4.91, nh_unweighted: 4.92, nh_weighted: 3.16}

    TO CHECK:
        - [ ] why is the loss different?
            - [X] network input size is 416 in both
            - [x] networks output the same data given the same input
            - [x] loss outputs the same data given the same input (they do if seen is the same)
            - [x] CONCLUSION: The loss is not actually different


        - [ ] why is the mAP different?
            - [x] does brambox compute AP differently?
                ... YES
            CONCLUSION: several factors are at play
                * brambox has a different AP computation
                * netharn and lightnet non-max supressions are different
                * The NMS seems to have the most significant impact

    # """
    import brambox.boxes as bbb
    CHECK_SANITY = False

    # Path to weights that we will be testing
    # (These were trained using the lightnet harness and achived a good mAP)
    weights_fpath = ub.truepath('~/code/lightnet/examples/yolo-voc/backup/weights_30000.pt')

    # Load weights into a netharn model
    harn = setup_harness(bsize=2)
    harn.hyper.xpu = nh.XPU(0)
    harn.initialize()
    state_dict = harn.xpu.load(weights_fpath)['weights']
    harn.model.module.load_state_dict(state_dict)
    harn.model.eval()
    nh_net = harn.model.module

    # Load weights into a lightnet model
    import os
    import lightnet as ln
    ln_test = ub.import_module_from_path(ub.truepath('~/code/lightnet/examples/yolo-voc/test.py'))
    ln_net = ln.models.Yolo(ln_test.CLASSES, weights_fpath,
                            ln_test.CONF_THRESH, ln_test.NMS_THRESH)
    ln_net = harn.xpu.move(ln_net)
    ln_net.eval()

    # Sanity check, the weights should be the same
    if CHECK_SANITY:
        state1 = nh_net.state_dict()
        state2 = ln_net.state_dict()
        assert state1.keys() == state2.keys()
        for k in state1.keys():
            v1 = state1[k]
            v2 = state2[k]
            assert np.all(v1 == v2)

    # Create a lightnet dataset loader
    TESTFILE = ub.truepath('~/code/lightnet/examples/yolo-voc/data/test.pkl')
    os.chdir(ub.truepath('~/code/lightnet/examples/yolo-voc/'))
    ln_dset = ln_test.CustomDataset(TESTFILE, ln_net)
    ln_loader = torch.utils.data.DataLoader(
        ln_dset, batch_size=2, shuffle=False, drop_last=False, num_workers=0,
        pin_memory=True, collate_fn=ln.data.list_collate,
    )

    # Create a netharn dataset loader
    nh_loader = harn.loaders['test']

    # ----------------------
    # Postprocessing to transform yolo outputs into detections
    # Basic difference here is the implementation of NMS
    ln_postprocess = ln_net.postprocess
    nh_postprocess = harn.model.module.postprocess

    # ----------------------
    # Define helper functions to deal with bramboxes
    LABELS = ['aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car',
              'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse',
              'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train',
              'tvmonitor']
    NETWORK_SIZE = (416, 416)
    detection_to_brambox = ln.data.TensorToBrambox(NETWORK_SIZE, LABELS)

    # ----------------------
    CHECK_LOSS = False

    with torch.no_grad():

        # Track netharn and lightnet results that will be scored
        ln_batch_confusions = []
        nh_batch_confusions = []
        nh_batch_confusions0 = []

        ln_results = []
        nh_results = []
        nh_results0 = []

        anno = {}
        ln_det = {}
        nh_det = {}
        nh_det0 = {}

        moving_ave = nh.util.util_averages.CumMovingAve()

        coco_truth = []
        # ln_coco_detections = []
        nh_coco_detections0 = []

        prog = ub.ProgIter(zip(ln_loader, nh_loader), desc='')
        for bx, (ln_batch, nh_batch) in enumerate(prog):
            ln_inputs, ln_bramboxes = ln_batch
            inp_size = tuple(ln_inputs.shape[-2:][::-1])
            nh_inputs, nh_labels = nh_batch

            nh_targets = nh_labels['targets']
            nh_gt_weights = nh_labels['gt_weights']

            # Convert brambox into components understood by netharn
            ln_labels = brambox_to_labels(ln_bramboxes, inp_size, ln_test.LABELS)
            ln_inputs = harn.xpu.variable(ln_inputs)
            ln_targets = harn.xpu.variable(ln_labels['targets'])
            ln_gt_weights = harn.xpu.variable(ln_labels['gt_weights'])  # NOQA

            ln_net.loss.seen = 1000000
            ln_outputs = ln_net._forward(ln_inputs)

            if CHECK_SANITY:
                nh_outputs = harn.model(ln_inputs)
                assert np.all(nh_outputs == ln_outputs)

            ln_loss_bram = ln_net.loss(ln_outputs, ln_bramboxes)
            moving_ave.update(ub.odict([
                ('loss_bram', float(ln_loss_bram.sum())),
            ]))

            if CHECK_LOSS:
                seen = ln_net.loss.seen
                ln_loss_ten1 = harn.criterion(ln_outputs, ln_targets,
                                              seen=seen)
                ln_loss_ten2 = ln_net.loss(ln_outputs, ln_targets)

                nh_weighted = harn.criterion(ln_outputs, nh_targets,
                                             gt_weights=nh_gt_weights,
                                             seen=seen)
                nh_unweighted = harn.criterion(ln_outputs, nh_targets,
                                               seen=seen)

                moving_ave.update(ub.odict([
                    ('loss_ten1', float(ln_loss_ten1.sum())),
                    ('loss_ten2', float(ln_loss_ten2.sum())),
                    ('nh_weighted', float(nh_weighted.sum())),
                    ('nh_unweighted', float(nh_unweighted.sum())),
                    # ('coord', harn.criterion.loss_coord),
                    # ('conf', harn.criterion.loss_conf),
                    # ('cls', harn.criterion.loss_cls),
                ]))
            # Display progress information
            average_losses = moving_ave.average()
            description = ub.repr2(average_losses, nl=0, precision=2, si=True)
            prog.set_description(description, refresh=False)

            # nh_outputs and ln_outputs should be the same, so no need to
            # differentiate between them here.
            ln_postout = ln_postprocess(ln_outputs.clone())
            nh_postout = nh_postprocess(ln_outputs.clone())

            # Should use the original NMS strategy
            nh_postout0 = nh_postprocess(ln_outputs.clone(), mode=0)

            ln_brambox_postout = detection_to_brambox([x.clone() for x in ln_postout])
            nh_brambox_postout = detection_to_brambox([x.clone() for x in nh_postout])
            nh_brambox_postout0 = detection_to_brambox([x.clone() for x in nh_postout0])

            # Record data scored by brambox
            offset = len(anno)
            def img_to_box(boxes, offset):
                gname_lut = ln_loader.dataset.keys
                return {gname_lut[offset + k]: v for k, v in enumerate(boxes)}
            anno.update(img_to_box(ln_bramboxes, offset))
            ln_det.update(img_to_box(ln_brambox_postout, offset))
            nh_det.update(img_to_box(nh_brambox_postout, offset))
            nh_det0.update(img_to_box(nh_brambox_postout0, offset))

            # Record data scored by netharn
            ln_results.append((ln_postout, ln_labels, inp_size))
            nh_results.append((nh_postout, nh_labels, inp_size))
            nh_results0.append((nh_postout0, nh_labels, inp_size))

            # preds, truths = harn._postout_to_coco(ln_postout, ln_labels, inp_size)
            # ln_coco_detections.append(preds)

            preds, truths = harn._postout_to_coco(nh_postout0, nh_labels, inp_size)
            nh_coco_detections0.append(preds)
            coco_truth.append(truths)

            # kw = dict(bias=0)
            # for y in harn._measure_confusion(ln_postout, ln_labels, inp_size, **kw):
            #     ln_batch_confusions.append(y)

            # for y in harn._measure_confusion(nh_postout, nh_labels, inp_size, **kw):
            #     nh_batch_confusions.append(y)

            # for y in harn._measure_confusion(nh_postout0, nh_labels, inp_size, **kw):
            #     nh_batch_confusions0.append(y)

            if bx > 50:
                break

    # Compute mAP using brambox / lightnet
    ln_mAP = round(bbb.ap(*bbb.pr(ln_det, anno)) * 100, 2)
    nh_mAP = round(bbb.ap(*bbb.pr(nh_det, anno)) * 100, 2)
    nh_mAP0 = round(bbb.ap(*bbb.pr(nh_det0, anno)) * 100, 2)
    print('\n----')
    print('ln_mAP = {!r}'.format(ln_mAP))
    print('nh_mAP = {!r}'.format(nh_mAP))
    print('nh_mAP0 = {!r}'.format(nh_mAP0))

    # num_classes = len(LABELS)
    # cls_labels = list(range(num_classes))

    # # Compute mAP using netharn
    # if False:
    #     is_tp = (y.true == y.pred) & (y.pred >= 0)
    #     is_fp = (y.true != y.pred) & (y.pred >= 0)
    #     rest = ~(is_fp | is_tp)

    #     y.true[is_tp] = 1
    #     y.pred[is_tp] = 1

    #     y.true[is_fp] = 0
    #     y.pred[is_fp] = 1

    #     y.true[rest] = 0
    #     y.pred[rest] = 0

    #     import sklearn
    #     import sklearn.metrics
    #     sklearn.metrics.average_precision_score(y.true, y.score, 'weighted',
    #                                             y.weight)

    for bias in [0, 1]:
        ln_batch_confusions = []
        nh_batch_confusions = []
        nh_batch_confusions0 = []
        print('\n\n======\n\nbias = {!r}'.format(bias))
        kw = dict(bias=bias, PREFER_WEIGHTED_TRUTH=False)
        for ln_postout, ln_labels, inp_size in ln_results:
            for y in harn._measure_confusion(ln_postout, ln_labels, inp_size, **kw):
                ln_batch_confusions.append(y)

        for nh_postout, nh_labels, inp_size in nh_results:
            for y in harn._measure_confusion(nh_postout, nh_labels, inp_size, **kw):
                nh_batch_confusions.append(y)

        for nh_postout0, nh_labels, inp_size in nh_results0:
            for y in harn._measure_confusion(nh_postout0, nh_labels, inp_size, **kw):
                nh_batch_confusions0.append(y)

        confusions = {
            'lh': ln_batch_confusions,
            # 'nh': nh_batch_confusions,
            'nh0': nh_batch_confusions0,
        }

        for lbl, batch_confusions in confusions.items():
            print('----')
            print('\nlbl = {!r}'.format(lbl))
            y = pd.concat([pd.DataFrame(c) for c in batch_confusions])

            # aps = nh.metrics.ave_precisions(y, cls_labels, use_07_metric=True)
            # aps = aps.rename(dict(zip(cls_labels, LABELS)), axis=0)
            # mean_ap = np.nanmean(aps['ap'])
            # print('mean_ap_07 = {:.2f}'.format(mean_ap * 100))

            # aps = nh.metrics.ave_precisions(y, cls_labels, use_07_metric=False)
            # aps = aps.rename(dict(zip(cls_labels, LABELS)), axis=0)
            # mean_ap = np.nanmean(aps['ap'])
            # print('mean_ap_12 = {:.2f}'.format(mean_ap * 100))

            # Try the other way
            from netharn.metrics.detections import _multiclass_ap
            prec, recall, ap2 = _multiclass_ap(y)
            print('ap2 = {!r}'.format(round(ap2 * 100, 2)))
Beispiel #11
0
def _ln_data_ln_map(ln_model, xpu, num=None):
    """
    Compute the results on the ln test set using a ln model.
    Weights can either be lightnet or netharn
    """
    import os
    import lightnet as ln
    ln_test = ub.import_module_from_path(ub.truepath('~/code/lightnet/examples/yolo-voc/test.py'))

    TESTFILE = ub.truepath('~/code/lightnet/examples/yolo-voc/data/test.pkl')
    os.chdir(ub.truepath('~/code/lightnet/examples/yolo-voc/'))
    ln_dset = ln_test.CustomDataset(TESTFILE, ln_model)
    ln_loader = torch.utils.data.DataLoader(
        ln_dset, batch_size=2, shuffle=False, drop_last=False, num_workers=0,
        pin_memory=True, collate_fn=ln.data.list_collate,
    )

    # ----------------------
    # Postprocessing to transform yolo outputs into detections
    # Basic difference here is the implementation of NMS
    ln_postprocess = ln_model.postprocess

    # ----------------------
    # Define helper functions to deal with bramboxes
    detection_to_brambox = ln.data.transform.TensorToBrambox(ln_test.NETWORK_SIZE,
                                                             ln_test.LABELS)

    # ----------------------
    def img_to_box(boxes, offset):
        gname_lut = ln_loader.dataset.keys
        return {gname_lut[offset + k]: v for k, v in enumerate(boxes)}

    with torch.no_grad():
        anno = {}
        ln_det = {}

        moving_ave = nh.util.util_averages.CumMovingAve()

        prog = ub.ProgIter(ln_loader, desc='')
        for bx, ln_batch in enumerate(prog):
            ln_inputs, ln_bramboxes = ln_batch

            # Convert brambox into components understood by netharn
            ln_inputs = xpu.variable(ln_inputs)

            ln_model.loss.seen = 1000000
            ln_outputs = ln_model._forward(ln_inputs)

            ln_loss_bram = ln_model.loss(ln_outputs, ln_bramboxes)
            moving_ave.update(ub.odict([
                ('loss_bram', float(ln_loss_bram.sum())),
            ]))

            # Display progress information
            average_losses = moving_ave.average()
            description = ub.repr2(average_losses, nl=0, precision=2, si=True)
            prog.set_description(description, refresh=False)

            # nh_outputs and ln_outputs should be the same, so no need to
            # differentiate between them here.
            ln_postout = ln_postprocess(ln_outputs.clone())

            ln_brambox_postout = detection_to_brambox([x.clone() for x in ln_postout])

            # Record data scored by brambox
            offset = len(anno)
            anno.update(img_to_box(ln_bramboxes, offset))
            ln_det.update(img_to_box(ln_brambox_postout, offset))

            if num is not None and bx >= num:
                break

    import brambox.boxes as bbb
    # Compute mAP using brambox / lightnet
    ln_mAP = round(bbb.ap(*bbb.pr(ln_det, anno)) * 100, 2)
    print('\nln_mAP = {!r}'.format(ln_mAP))

    return ln_mAP
Beispiel #12
0
            detection.confidence = det[1]
            data.append(detection)

        detections[image.split('.')[0]] = data

    # Read annotations file
    annotations = bbb.parse('anno_darknet', args.annotations_path, image_width=img_w, image_height=img_h, class_label_map=classes)

    # Generate PR-curve and compute AP for every individual class.
    plt.figure()

    for c in classes:
        anno_c = bbb.filter_discard(copy.deepcopy(annotations), [lambda anno: anno.class_label == c])
        det_c = bbb.filter_discard(copy.deepcopy(detections), [lambda det: det.class_label == c])
        p, r = bbb.pr(det_c, anno_c)
        ap = bbb.ap(p, r)
        plt.plot(r, p, label=f'{c}: {round(ap * 100, 2)}%')

    plt.gcf().suptitle('PR-curve individual')
    plt.gca().set_ylabel('Precision')
    plt.gca().set_xlabel('Recall')
    plt.gca().set_xlim([0, 1])
    plt.gca().set_ylim([0, 1])
    plt.legend()
    plt.show()

    # Generate PR-curve and compute mAP
    plt.figure()

    p, r = bbb.pr(detections, annotations)
    ap = bbb.ap(p, r)
Beispiel #13
0
def test(arguments):
    log.debug('Creating network')
    net = ln.models.Yolo(CLASSES, arguments.weight, CONF_THRESH, NMS_THRESH)
    net.postprocess.append(
        ln.data.transform.TensorToBrambox(NETWORK_SIZE, LABELS))

    net.eval()
    if arguments.cuda:
        net.cuda()

    log.debug('Creating dataset')
    loader = torch.utils.data.DataLoader(
        CustomDataset(TESTFILE, net),
        batch_size=MINI_BATCH,
        shuffle=False,
        drop_last=False,
        num_workers=WORKERS if arguments.cuda else 0,
        pin_memory=PIN_MEM if arguments.cuda else False,
        collate_fn=ln.data.list_collate,
    )

    if arguments.visdom:
        log.debug('Creating visdom visualisation wrappers')
        vis = visdom.Visdom(port=VISDOM_PORT)
        visdom_plot_pr = ln.engine.VisdomLinePlotter(
            vis,
            'pr',
            opts=dict(xlabel='Recall',
                      ylabel='Precision',
                      title='Precision Recall',
                      xtickmin=0,
                      xtickmax=1,
                      ytickmin=0,
                      ytickmax=1,
                      showlegend=True))

    if arguments.hyperdash:
        log.debug('Creating hyperdash visualisation wrappers')
        hd = hyperdash.Experiment('YOLOv2 Pascal VOC Test')
        hyperdash_plot_pr = ln.engine.HyperdashLinePlotter(hd)

    log.debug('Running network')
    tot_loss = []
    coord_loss = []
    conf_loss = []
    cls_loss = []
    anno, det = {}, {}

    for idx, (data, box) in enumerate(tqdm(loader, total=len(loader))):
        if arguments.cuda:
            data = data.cuda()

        if torch.__version__.startswith('0.3'):
            data = torch.autograd.Variable(data, volatile=True)
            output, loss = net(data, box)
        else:
            with torch.no_grad():
                output, loss = net(data, box)

        if torch.__version__.startswith('0.3'):
            tot_loss.append(net.loss.loss_tot.data[0] * len(box))
            coord_loss.append(net.loss.loss_coord.data[0] * len(box))
            conf_loss.append(net.loss.loss_conf.data[0] * len(box))
            if net.loss.loss_cls is not None:
                cls_loss.append(net.loss.loss_cls.data[0] * len(box))
        else:
            tot_loss.append(net.loss.loss_tot.item() * len(box))
            coord_loss.append(net.loss.loss_coord.item() * len(box))
            conf_loss.append(net.loss.loss_conf.item() * len(box))
            if net.loss.loss_cls is not None:
                cls_loss.append(net.loss.loss_cls.item() * len(box))

        key_val = len(anno)
        anno.update(
            {loader.dataset.keys[key_val + k]: v
             for k, v in enumerate(box)})
        det.update({
            loader.dataset.keys[key_val + k]: v
            for k, v in enumerate(output)
        })

    log.debug('Computing statistics')

    pr = bbb.pr(det, anno)
    m_ap = round(bbb.ap(*pr) * 100, 2)
    tot = round(sum(tot_loss) / len(anno), 5)
    coord = round(sum(coord_loss) / len(anno), 2)
    conf = round(sum(conf_loss) / len(anno), 2)
    if len(cls_loss) > 0:
        cls = round(sum(cls_loss) / len(anno), 2)
        log.test(
            '{seen} mAP:{m_ap}% Loss:{tot} (Coord:{coord} Conf:{conf} Cls:{cls})'
            .format(seen=net.seen // BATCH,
                    m_ap=m_ap,
                    tot=tot,
                    coord=coord,
                    conf=conf,
                    cls=cls))
    else:
        log.test(
            '{seen} mAP:{m_ap}% Loss:{tot} (Coord:{coord} Conf:{conf})'.format(
                seen=net.seen // BATCH,
                m_ap=m_ap,
                tot=tot,
                coord=coord,
                conf=conf))

    name = 'mAP: {m_ap}%'.format(m_ap=m_ap)
    if arguments.visdom:
        visdom_plot_pr(np.array(pr[0]), np.array(pr[1]), name=name)

    if arguments.hyperdash:
        now = time.time()
        re_seen = None
        for index, (re_, pr_) in enumerate(sorted(zip(pr[1], pr[0]))):
            re_ = round(re_, 2)
            if re_ != re_seen:
                re_seen = re_
                re_ = int(re_ * 100.0)
                hyperdash_plot_pr(name, pr_, now + re_, log=False)

    if arguments.save_det is not None:
        # Note: These detection boxes are the coordinates for the letterboxed images,
        #       you need ln.data.ReverseLetterbox to have the right ones.
        #       Alternatively, you can save the letterboxed annotations, and use those for statistics later on!
        bbb.generate('det_pickle', det,
                     Path(arguments.save_det).with_suffix('.pkl'))
        #bbb.generate('anno_pickle', det, Path('anno-letterboxed_'+arguments.save_det).with_suffix('.pkl'))

    if arguments.hyperdash:
        hyperdash_plot_pr.close()
Beispiel #14
0
def evaluate_lightnet_model():
    """
    Try to evaulate the model using the exact same VOC scoring metric

    import ubelt as ub
    import sys
    sys.path.append(ub.truepath('~/code/netharn/netharn/examples/tests'))
    from test_yolo import *
    """
    import os  # NOQA
    import netharn as nh
    import ubelt as ub
    import lightnet as ln
    import torch
    ln_test = ub.import_module_from_path(
        ub.truepath('~/code/lightnet/examples/yolo-voc/test.py'))

    xpu = nh.XPU.cast('auto')

    ln_weights_fpath = ub.truepath(
        '~/code/lightnet/examples/yolo-voc/backup/final.pt')
    ln_weights_fpath = ub.truepath(
        '~/code/lightnet/examples/yolo-voc/backup/weights_30000.pt')

    from netharn.models.yolo2 import light_yolo
    ln_weights_fpath = nh.models.yolo2.light_yolo.demo_voc_weights('darknet')

    # Lightnet model, postprocess, and lightnet weights
    ln_model = ln.models.Yolo(ln_test.CLASSES, ln_weights_fpath,
                              ln_test.CONF_THRESH, ln_test.NMS_THRESH)
    ln_model = xpu.move(ln_model)
    ln_model.eval()

    TESTFILE = ub.truepath('~/code/lightnet/examples/yolo-voc/data/test.pkl')
    os.chdir(ub.truepath('~/code/lightnet/examples/yolo-voc/'))
    ln_dset = ln_test.CustomDataset(TESTFILE, ln_model)
    ln_loader = torch.utils.data.DataLoader(
        ln_dset,
        batch_size=8,
        shuffle=False,
        drop_last=False,
        num_workers=0,
        pin_memory=True,
        collate_fn=ln.data.list_collate,
    )

    # ----------------------
    # Postprocessing to transform yolo outputs into detections
    # Basic difference here is the implementation of NMS
    ln_postprocess = ln.data.transform.util.Compose(
        ln_model.postprocess.copy())

    # ----------------------
    # Define helper functions to deal with bramboxes
    detection_to_brambox = ln.data.transform.TensorToBrambox(
        ln_test.NETWORK_SIZE, ln_test.LABELS)
    # hack so forward call behaves like it does in test
    ln_model.postprocess.append(detection_to_brambox)

    # ----------------------
    def img_to_box(ln_loader, boxes, offset):
        gname_lut = ln_loader.dataset.keys
        return {gname_lut[offset + k]: v for k, v in enumerate(boxes)}

    with torch.no_grad():
        anno = {}
        ln_det = {}

        moving_ave = nh.util.util_averages.CumMovingAve()

        prog = ub.ProgIter(ln_loader, desc='')
        for bx, ln_raw_batch in enumerate(prog):
            ln_raw_inputs, ln_bramboxes = ln_raw_batch

            # Convert brambox into components understood by netharn
            ln_inputs = xpu.variable(ln_raw_inputs)

            ln_model.loss.seen = 1000000
            ln_outputs = ln_model._forward(ln_inputs)

            ln_loss_bram = ln_model.loss(ln_outputs, ln_bramboxes)
            moving_ave.update(
                ub.odict([
                    ('loss_bram', float(ln_loss_bram.sum())),
                ]))

            # Display progress information
            average_losses = moving_ave.average()
            description = ub.repr2(average_losses, nl=0, precision=2, si=True)
            prog.set_description(description, refresh=False)

            # nh_outputs and ln_outputs should be the same, so no need to
            # differentiate between them here.
            ln_postout = ln_postprocess(ln_outputs.clone())

            ln_brambox_postout = detection_to_brambox(
                [x.clone() for x in ln_postout])

            # out, loss = ln_model.forward(ln_inputs, ln_bramboxes)

            # Record data scored by brambox
            offset = len(anno)
            anno.update(img_to_box(ln_loader, ln_bramboxes, offset))
            ln_det.update(img_to_box(ln_loader, ln_brambox_postout, offset))

    import brambox.boxes as bbb
    # Compute mAP using brambox / lightnet
    pr = bbb.pr(ln_det, anno)

    ln_mAP = round(bbb.ap(*pr) * 100, 2)
    print('\nBrambox multiclass AP = {!r}'.format(ln_mAP))

    devkit_dpath = ub.truepath('~/data/VOC/VOCdevkit/')

    # Convert bramboxes to VOC style data for eval
    class_to_dets = ub.ddict(list)
    for gpath, bb_dets in ub.ProgIter(list(ln_det.items())):

        from PIL import Image
        from os.path import join
        pil_image = Image.open(join(devkit_dpath, gpath) + '.jpg')
        img_size = pil_image.size
        bb_dets = ln.data.transform.ReverseLetterbox.apply(
            [bb_dets], ln_test.NETWORK_SIZE, img_size)[0]
        for det in bb_dets:
            from os.path import basename, splitext
            imgid = splitext(basename(gpath))[0]
            score = det.confidence
            tlwh = [
                max(det.x_top_left, 0),
                max(det.y_top_left, 0),
                min(det.x_top_left + det.width, img_size[0]),
                min(det.y_top_left + det.height, img_size[1])
            ]
            # See: /home/joncrall/data/VOC/VOCdevkit/devkit_doc.pdf
            # Each line is formatted as:
            # <image identifier> <confidence> <left> <top> <right> <bottom>
            class_to_dets[det.class_label].append(
                list(ub.flatten([[imgid], [score], tlwh])))

    # Calculate Original VOC measure
    from os.path import join
    results_path = join(devkit_dpath, 'results', 'VOC2007', 'Main')
    detpath = join(results_path, 'comp3_det_test_{}.txt')
    for lbl, dets in class_to_dets.items():
        fpath = detpath.format(lbl)
        with open(fpath, 'w') as file:
            text = '\n'.join([' '.join(list(map(str, det))) for det in dets])
            file.write(text)

    import sys
    sys.path.append('/home/joncrall/code/netharn/netharn/examples/tests')
    from voc_eval_orig import voc_eval

    use_07_metric = False
    bias = 1.0
    # for bias in [0.0, 1.0]:
    # for use_07_metric in [True, False]:
    class_aps = {}
    class_curve = {}
    annopath = join(devkit_dpath, 'VOC2007', 'Annotations', '{}.xml')
    for classname in ub.ProgIter(list(class_to_dets.keys())):
        cachedir = None
        imagesetfile = join(devkit_dpath, 'VOC2007', 'ImageSets', 'Main',
                            '{}_test.txt').format(classname)

        rec, prec, ap = voc_eval(detpath,
                                 annopath,
                                 imagesetfile,
                                 classname,
                                 cachedir,
                                 ovthresh=0.5,
                                 use_07_metric=use_07_metric,
                                 bias=bias)
        class_aps[classname] = ap
        class_curve[classname] = (rec, prec)

    mAP = np.mean(list(class_aps.values()))
    print('Official* bias={} {} VOC mAP = {!r}'.format(
        bias, '2007' if use_07_metric else '2012', mAP))
    # I get 0.71091 without 07 metric
    # I get 0.73164 without 07 metric
    """
    Lightnet:
        'aeroplane'   : 0.7738,
        'bicycle'     : 0.8326,
        'bird'        : 0.7505,
        'boat'        : 0.6202,
        'bottle'      : 0.4614,
        'bus'         : 0.8078,
        'car'         : 0.8052,
        'cat'         : 0.8857,
        'chair'       : 0.5385,
        'cow'         : 0.7768,
        'diningtable' : 0.7556,
        'dog'         : 0.8545,
        'horse'       : 0.8401,
        'motorbike'   : 0.8144,
        'person'      : 0.7608,
        'pottedplant' : 0.4640,
        'sheep'       : 0.7398,
        'sofa'        : 0.7334,
        'train'       : 0.8697,
        'tvmonitor'   : 0.7533,
    """
    """
    Official* bias=1.0 2012 VOC mAP = 0.7670408107201542
    Darknet:
        'aeroplane'   : 0.7597,
        'bicycle'     : 0.8412,
        'bird'        : 0.7705,
        'boat'        : 0.6360,
        'bottle'      : 0.4902,
        'bus'         : 0.8164,
        'car'         : 0.8444,
        'cat'         : 0.8926,
        'chair'       : 0.5902,
        'cow'         : 0.8184,
        'diningtable' : 0.7728,
        'dog'         : 0.8612,
        'horse'       : 0.8759,
        'motorbike'   : 0.8467,
        'person'      : 0.7855,
        'pottedplant' : 0.5117,
        'sheep'       : 0.7889,
        'sofa'        : 0.7584,
        'train'       : 0.8997,
        'tvmonitor'   : 0.7806,
    """
    """
    def generate_curves(ground_truth, results, pr=True, title="", saveplot="", overlap=0.5, only_plot=None,
                        linewidth=2, figsize=(8, 6), legendloc=3):
        curves = []
        scores = {}
        # colors = plt.rcParams['axes.prop_cycle'].by_key()['color']
        #     colors = ['#1919ff', '#ff7f0e', '#ff1919', '#ff19ff', '#19ff19', '#19ff19']
        colors = ['#1919ff', '#ff7f0e', '#ff1919', '#ff19ff', '#19ff19']
        i = 0
        linestyles = ['-', '--', '-.', ':']
        for label, detections in results.items():
            ### because YOLO has stuck in small object, so the paper of this code on CVPRW prefer chose overlap 0.4, but here we choose 0.5 for all.
            #         if label=='YOLO_TLV' or label=='Ours: TD(V,V)' or label=='Ours: TD(T,T)' or label=='Ours: TD(VT,T)' or label=='Ours: BU(VAT,T)' or label == 'Ours: BU(VLT,T)':
            #             print(label)
            #             overlap = 0.4
            if pr:
                ys, xs = bbb.pr(detections, ground_truth, overlap)
                score = round(bbb.ap(ys, xs) * 100, 2)
            else:
                ys, xs = bbb.mr_fppi(detections, ground_truth, overlap)
                score = round(lamr(ys, xs) * 100, 2)
            color = colors[i % len(colors)]
            linestyle = linestyles[i % len(linestyles)]

            if only_plot is None or label in only_plot:
                i += 1
            curves += [(label, ys, xs, score, color, linestyle)]
            scores[label] = score

        # if pr:
        #     # sort from highest ap to lowest
        #     sorted_curves = sorted(curves, key=lambda curve: curve[3], reverse=True)
        # else:
        #     # sort from lowest to highest
        #     sorted_curves = sorted(curves, key=lambda curve: curve[3])

        # fig, ax = plt.subplots(figsize=figsize)

        # for label, ys, xs, score, color, linestyle in sorted_curves:
        #     # skip curves not mensioned in only_plot
        #     if only_plot is not None and label not in only_plot:
        #         continue

        #     if pr:
        #         plt.plot(xs, ys, color=color, linestyle=linestyle, label=f"{score}%  {label}", linewidth=linewidth)
        #     else:
        #         plt.loglog(xs, ys, color=color, linestyle=linestyle, label=f"{score}%  {label}", linewidth=linewidth)
        #
        # plt.legend(loc=legendloc)
        #
        # plt.gcf().suptitle(title, weight='bold')

        # if pr:
        #     plt.grid(which='major')
        #     plt.gca().set_ylabel('Precision')
        #     plt.gca().set_xlabel('Recall')
        #     plt.gca().set_xlim([0, 1])
        #     plt.gca().set_ylim([0, 1])
        # else:
        #     # modify the y axis a bit
        #     from matplotlib.ticker import FormatStrFormatter, LogLocator
        #     subs = [1.0, 2.0, 3.0, 4.0, 5.0, 6.4, 8.0]  # ticks to show per decade
        #     ax.yaxis.set_minor_locator(LogLocator(subs=subs))
        #     ax.yaxis.set_minor_formatter(FormatStrFormatter("%.2f"))
        #     ax.yaxis.grid(which='minor')
        #     ax.xaxis.grid(which='major')
        #     plt.setp(ax.get_ymajorticklabels(), visible=False)  # disable major labels
        #
        #     plt.gca().set_ylabel('Miss rate')
        #     plt.gca().set_xlabel('FPPI')
        #     plt.gca().set_ylim([0.1, 1])
        #
            # plt.gca().set_xlim([0, 10])

        # if saveplot:
        # plt.savefig(saveplot, format='eps', dpi=1200)

        return scores