| |
| |
| |
| |
| |
|
|
| """ |
| COCO-Style Evaluations |
| |
| put images here datasets/your_project_name/val_set_name/*.jpg |
| put annotations here datasets/your_project_name/annotations/instances_{val_set_name}.json |
| put weights here /path/to/your/weights/*.pth |
| change compound_coef |
| |
| """ |
|
|
| import json |
| import os |
| import numpy as np |
|
|
| import argparse |
| import torch |
| from tqdm import tqdm |
| from pycocotools.coco import COCO |
| from pycocotools.cocoeval import COCOeval |
| from torch.utils.data import DataLoader |
| import torchvision |
| import torchvision.transforms as transforms |
| import time |
|
|
| from models import mnv2_SSDlite |
| from library.ssd import conv_model_fptunc2fpt, conv_model_fpt2qat, conv_model_qat2hw, collate_fn, PredsPostProcess, round_floats |
| from dataloader import CocoDetection, input_fxpt_normalize |
|
|
| |
|
|
| ap = argparse.ArgumentParser() |
| ap.add_argument('-m', '--mode', type=str, default='qat', help='Mode of the model, allowed modes: fpt_unc, fpt, qat') |
| ap.add_argument('--nms_threshold', type=float, default=0.5, help='non max supression threshold') |
| ap.add_argument('--conf_threshold', type=float, default=0.5, help='confidence treshold, predictions below this level will be discarded') |
| ap.add_argument('-dp', '--data_path', type=str, default=None, help='/path/to/images') |
| ap.add_argument('-ap', '--json_path', type=str, default=None, help='/path/to/annotations.json') |
| ap.add_argument('-wp', '--weights_path', type=str, default=None, help='/path/to/weights') |
|
|
| args = ap.parse_args() |
|
|
| mode = args.mode |
| nms_threshold = args.nms_threshold |
| conf_threshold = args.conf_threshold |
| data_path = args.data_path |
| json_path = args.json_path |
| weights_path = args.weights_path |
|
|
| device = torch.device("cuda" if torch.cuda.is_available() else "cpu") |
|
|
| def evaluate_coco(model, DATA_PATH, JSON_PATH , nmsIoUTreshold = 0.5, PredMinConfTreshold = 0.5, HW_mode = False): |
| |
| if HW_mode: |
| act_8b_mode = True |
| else: |
| act_8b_mode = False |
|
|
| transform = transforms.Compose([transforms.ToTensor(), input_fxpt_normalize(act_8b_mode=act_8b_mode)]) |
| targetFileName = 'resized.json' |
| dataset = CocoDetection(root=DATA_PATH, annFile=JSON_PATH, transform=transform, scaleImgforCrop= None) |
|
|
| dataset.createResizedAnnotJson(targetFileName=targetFileName) |
| resizedFilePath = os.path.join(os.path.split(JSON_PATH)[0],targetFileName) |
| cocoGt=COCO(resizedFilePath) |
| os.remove(resizedFilePath) |
|
|
| seq_sampler = torch.utils.data.SequentialSampler(dataset) |
| data_loader = DataLoader(dataset, |
| sampler=seq_sampler, |
| batch_size=1, |
| collate_fn=collate_fn, |
| drop_last=False) |
| print(f"Dataset Length: {len(dataset)}, Number of Batches: {len(data_loader)}") |
| |
| ANCHORS_HEAD1 = [(11.76, 28.97), |
| (20.98, 52.03), |
| (29.91, 77.24), |
| (38.97, 106.59)] |
|
|
| ANCHORS_HEAD2 = [(52.25, 144.77), |
| (65.86, 193.05), |
| (96.37, 254.09), |
| (100.91, 109.82), |
| (140, 350)] |
| |
| predsPostProcess = PredsPostProcess(512, ANCHORS_HEAD1, ANCHORS_HEAD2) |
|
|
| |
| dataDictList =[] |
| imgIDS = [] |
| for i, data in enumerate(tqdm(data_loader)): |
| imageBatch, targetBatch , idxBatch = data |
|
|
| imageStack = torch.stack(imageBatch).detach().to(device) |
| imageStack.requires_grad_(True) |
| predBatch = model(imageStack) |
| |
| if HW_mode: |
| BBs1 = predBatch[0].detach() / 128.0 |
| CFs1 = predBatch[1].detach() / 128.0 |
| BBs2 = predBatch[2].detach() / 128.0 |
| CFs2 = predBatch[3].detach() / 128.0 |
| else: |
| BBs1 = predBatch[0].detach() |
| CFs1 = predBatch[1].detach() |
| BBs2 = predBatch[2].detach() |
| CFs2 = predBatch[3].detach() |
|
|
| for imgNum in range(imageStack.shape[0]): |
| img = imageStack[imgNum,:,:,:] |
| target = targetBatch[imgNum] |
| image_id = int(idxBatch[imgNum]) |
| imgIDS.append(image_id) |
|
|
| pred = (BBs1[imgNum,:,:,:].unsqueeze(0), CFs1[imgNum,:,:,:].unsqueeze(0), |
| BBs2[imgNum,:,:,:].unsqueeze(0), CFs2[imgNum,:,:,:].unsqueeze(0)) |
|
|
| boxes, confidences = predsPostProcess.getPredsInOriginal(pred) |
|
|
| nms_picks = torchvision.ops.nms(boxes, confidences, nmsIoUTreshold) |
| boxes_to_draw = boxes[nms_picks] |
| confs_to_draw = confidences[nms_picks] |
| confMask = (confs_to_draw > PredMinConfTreshold) |
|
|
| |
| if (confMask.any()): |
|
|
| |
| bbox = boxes_to_draw[confMask] |
| scores = confs_to_draw[confMask] |
| |
| bbox[:,2] = bbox[:,2] - bbox[:,0] |
| bbox[:,3] = bbox[:,3] - bbox[:,1] |
| |
|
|
| bbox = bbox.tolist() |
| score = scores.tolist() |
| category_id = np.ones_like(score,dtype=int).tolist() |
|
|
| for j in range(len(bbox)): |
| box = {"image_id":image_id, "category_id":category_id[j], "bbox":bbox[j],"score":score[j]} |
| dataDictList.append(round_floats(box)) |
|
|
| if (len(dataDictList)): |
| |
| cocoDT = json.dumps(dataDictList) |
|
|
| |
| with open('cocoDT.json', 'w') as outfile: |
| outfile.write(cocoDT) |
|
|
| |
| cocoDt=cocoGt.loadRes('cocoDT.json') |
| os.remove("cocoDT.json") |
|
|
| |
| annType = 'bbox' |
| cocoEval = COCOeval(cocoGt,cocoDt,annType) |
| cocoEval.params.catIds = 1 |
| cocoEval.params.imgIds = imgIDS |
| cocoEval.evaluate() |
| cocoEval.accumulate() |
| |
| print('') |
| cocoEval.summarize() |
| else: |
| raise Exception('the model does not provide any valid output, check model architecture and the data input') |
|
|
|
|
| if __name__ == '__main__': |
| model = mnv2_SSDlite() |
| |
| layer_bits_dictionary = {} |
| layer_bits_dictionary['conv1' ] = 8; |
| layer_bits_dictionary['epw_conv2' ] = 8; |
| layer_bits_dictionary['dw_conv2' ] = 8; |
| layer_bits_dictionary['ppw_conv2' ] = 8; |
|
|
| layer_bits_dictionary['epw_conv3' ] = 8; |
| layer_bits_dictionary['dw_conv3' ] = 8; |
| layer_bits_dictionary['ppw_conv3' ] = 8; |
|
|
| layer_bits_dictionary['epw_conv4' ] = 8; |
| layer_bits_dictionary['dw_conv4' ] = 8; |
| layer_bits_dictionary['ppw_conv4' ] = 8; |
|
|
| layer_bits_dictionary['epw_conv5'] = 8; |
| layer_bits_dictionary['dw_conv5'] = 8; |
| layer_bits_dictionary['ppw_conv5'] = 8; |
|
|
| layer_bits_dictionary['epw_conv6'] = 8; |
| layer_bits_dictionary['dw_conv6'] = 8; |
| layer_bits_dictionary['ppw_conv6'] = 8; |
|
|
| layer_bits_dictionary['epw_conv7'] = 8; |
| layer_bits_dictionary['dw_conv7'] = 8; |
| layer_bits_dictionary['ppw_conv7'] = 8; |
|
|
| layer_bits_dictionary['epw_conv8'] = 8; |
| layer_bits_dictionary['dw_conv8'] = 8; |
| layer_bits_dictionary['ppw_conv8'] = 8; |
|
|
| layer_bits_dictionary['epw_conv9'] = 8; |
| layer_bits_dictionary['dw_conv9'] = 8; |
| layer_bits_dictionary['ppw_conv9'] = 8; |
|
|
| layer_bits_dictionary['epw_conv10'] = 8; |
| layer_bits_dictionary['dw_conv10'] = 8; |
| layer_bits_dictionary['ppw_conv10'] = 8; |
|
|
| layer_bits_dictionary['epw_conv11'] = 8; |
| layer_bits_dictionary['dw_conv11'] = 8; |
| layer_bits_dictionary['ppw_conv11'] = 8; |
|
|
| layer_bits_dictionary['epw_conv12'] = 8; |
| layer_bits_dictionary['dw_conv12'] = 8; |
| layer_bits_dictionary['ppw_conv12'] = 8; |
|
|
| layer_bits_dictionary['epw_conv13'] = 8; |
| layer_bits_dictionary['dw_conv13'] = 8; |
| layer_bits_dictionary['ppw_conv13'] = 8; |
|
|
| layer_bits_dictionary['epw_conv14'] = 8; |
| layer_bits_dictionary['dw_conv14'] = 8; |
| layer_bits_dictionary['ppw_conv14'] = 8; |
|
|
| layer_bits_dictionary['epw_conv15'] = 8; |
| layer_bits_dictionary['dw_conv15'] = 8; |
| layer_bits_dictionary['ppw_conv15'] = 8; |
|
|
| layer_bits_dictionary['epw_conv16'] = 8; |
| layer_bits_dictionary['dw_conv16'] = 8; |
| layer_bits_dictionary['ppw_conv16'] = 8; |
|
|
| layer_bits_dictionary['epw_conv17'] = 8; |
| layer_bits_dictionary['dw_conv17'] = 8; |
| layer_bits_dictionary['ppw_conv17'] = 8; |
|
|
| layer_bits_dictionary['epw_conv18'] = 8; |
| layer_bits_dictionary['dw_conv18'] = 8; |
| layer_bits_dictionary['ppw_conv18'] = 8; |
|
|
| layer_bits_dictionary['head1_dw_classification'] = 8; |
| layer_bits_dictionary['head1_pw_classification'] = 8; |
| layer_bits_dictionary['head1_dw_regression'] = 8; |
| layer_bits_dictionary['head1_pw_regression'] = 8; |
|
|
| layer_bits_dictionary['head2_dw_classification'] = 8; |
| layer_bits_dictionary['head2_pw_classification'] = 8; |
| layer_bits_dictionary['head2_dw_regression'] = 8; |
| layer_bits_dictionary['head2_pw_regression'] = 8; |
|
|
| |
| HW_mode = False |
| if mode == 'fpt_unc': |
| model.to(device) |
| |
| elif mode == 'fpt': |
| model = conv_model_fptunc2fpt(model) |
| model.to(device) |
| |
| elif mode == 'qat': |
| model = conv_model_fptunc2fpt(model) |
| model.to(device) |
| model = conv_model_fpt2qat(model, layer_bits_dictionary) |
| model.to(device) |
| |
| elif mode == 'hw': |
| HW_mode = True |
| model = conv_model_fptunc2fpt(model) |
| model.to(device) |
| model = conv_model_fpt2qat(model, layer_bits_dictionary) |
| model.to(device) |
| model = conv_model_qat2hw(model) |
| model.to(device) |
|
|
| else: |
| raise Exception('Invalid model mode is selected, select from: fpt_unc, fpt, qat, hw') |
|
|
|
|
| weights = torch.load(weights_path, map_location=torch.device('cpu')) |
| model.load_state_dict(weights['state_dict'], strict=True) |
|
|
| model.requires_grad_(False) |
| model.eval() |
| |
| if mode == 'qat' or mode == 'hw': |
| print(''*5) |
| print('*'*120) |
| print('qat or hardware mode is selected, please make sure you configured layer_bits_dictionary in "coco_eval.py" accordingly!!!') |
| print('*'*120) |
| print('') |
| time.sleep(5) |
|
|
| evaluate_coco(model, DATA_PATH=data_path, JSON_PATH=json_path , nmsIoUTreshold=nms_threshold, |
| PredMinConfTreshold=conf_threshold, HW_mode = HW_mode) |