| import os |
| import argparse |
| import random |
| import onnxruntime |
| import numpy as np |
|
|
| import torch |
| from torch.nn import functional as F |
| from torch.utils import data |
|
|
| import cv2 |
| from PIL import Image |
| from tqdm import tqdm |
|
|
| from utils import input_transform, pad_image, resize_image, preprocess, get_confusion_matrix |
|
|
| parser = argparse.ArgumentParser(description='HRNet') |
| parser.add_argument('-m', '--onnx-model', default='', |
| type=str, help='Path to onnx model.') |
| parser.add_argument('-r', '--root', default='', |
| type=str, help='Path to dataset root.') |
| parser.add_argument('-l', '--list_path', default='', |
| type=str, help='Path to dataset list.') |
| parser.add_argument("--ipu", action="store_true", help="Use IPU for inference.") |
| parser.add_argument("--provider_config", type=str, |
| default="vaip_config.json", help="Path of the config file for seting provider_options.") |
| args = parser.parse_args() |
|
|
| INPUT_SIZE = [512, 1024] |
| NUM_CLASSES = 19 |
| IGNORE_LABEL = 255 |
|
|
|
|
| class Cityscapes(data.Dataset): |
| def __init__(self, |
| root, |
| list_path, |
| num_classes=19, |
| downsample_rate=8, |
| ignore_label=-1): |
|
|
| self.root = root |
| self.list_path = list_path |
| self.num_classes = num_classes |
| self.downsample_rate = downsample_rate |
| |
| self.img_list = [line.strip().split() for line in open(root+list_path)] |
|
|
| self.files = self.read_files() |
|
|
| self.label_mapping = {-1: ignore_label, 0: ignore_label, |
| 1: ignore_label, 2: ignore_label, |
| 3: ignore_label, 4: ignore_label, |
| 5: ignore_label, 6: ignore_label, |
| 7: 0, 8: 1, 9: ignore_label, |
| 10: ignore_label, 11: 2, 12: 3, |
| 13: 4, 14: ignore_label, 15: ignore_label, |
| 16: ignore_label, 17: 5, 18: ignore_label, |
| 19: 6, 20: 7, 21: 8, 22: 9, 23: 10, 24: 11, |
| 25: 12, 26: 13, 27: 14, 28: 15, |
| 29: ignore_label, 30: ignore_label, |
| 31: 16, 32: 17, 33: 18} |
| |
| def read_files(self): |
| files = [] |
| for item in self.img_list: |
| image_path, label_path = item |
| name = os.path.splitext(os.path.basename(label_path))[0] |
| files.append({ |
| "img": image_path, |
| "label": label_path, |
| "name": name, |
| }) |
| return files |
|
|
| def __len__(self): |
| return len(self.files) |
| |
| def convert_label(self, label, inverse=False): |
| temp = label.copy() |
| if inverse: |
| for v, k in self.label_mapping.items(): |
| label[temp == k] = v |
| else: |
| for k, v in self.label_mapping.items(): |
| label[temp == k] = v |
| return label |
|
|
| def __getitem__(self, index): |
| item = self.files[index] |
| image = cv2.imread(os.path.join(self.root, item["img"]), |
| cv2.IMREAD_COLOR) |
| label = cv2.imread(os.path.join(self.root, item["label"]), |
| cv2.IMREAD_GRAYSCALE) |
| label = self.convert_label(label) |
| image, label = self.gen_sample(image, label) |
|
|
| return image.copy(), label.copy() |
|
|
| def gen_sample(self, image, label): |
| label = self.label_transform(label) |
| |
|
|
| if self.downsample_rate != 1: |
| label = cv2.resize( |
| label, |
| None, |
| fx=self.downsample_rate, |
| fy=self.downsample_rate, |
| interpolation=cv2.INTER_NEAREST |
| ) |
|
|
| return image, label |
|
|
| def label_transform(self, label): |
| return np.array(label).astype('int32') |
|
|
|
|
| def run_onnx_inference(ort_session, img): |
| """Infer an image with onnx seession |
| |
| Args: |
| ort_session: Onnx session |
| img (ndarray): Image to be infered. |
| |
| Returns: |
| ndarray: Model inference result. |
| """ |
| pre_img, pad_h, pad_w = preprocess(img) |
| |
|
|
| img = np.expand_dims(pre_img, 0) |
| img = np.transpose(img, (0,2,3,1)) |
|
|
| ort_inputs = {ort_session.get_inputs()[0].name: img} |
| o1 = ort_session.run(None, ort_inputs)[0] |
| h, w = o1.shape[-2:] |
| h_cut = int(h / INPUT_SIZE[0] * pad_h) |
| w_cut = int(w / INPUT_SIZE[1] * pad_w) |
| o1 = o1[..., :h - h_cut, :w - w_cut] |
| return o1 |
|
|
|
|
| def testval(ort_session, root, list_path): |
|
|
| test_dataset = Cityscapes( |
| root=root, |
| list_path=list_path, |
| num_classes=NUM_CLASSES, |
| ignore_label=IGNORE_LABEL, |
| downsample_rate=1) |
|
|
| testloader = torch.utils.data.DataLoader( |
| test_dataset, |
| batch_size=1, |
| shuffle=False, |
| num_workers=4, |
| pin_memory=True) |
|
|
| confusion_matrix = np.zeros( |
| (NUM_CLASSES, NUM_CLASSES)) |
| for index, batch in enumerate(tqdm(testloader)): |
| image, label = batch |
| image = image.numpy()[0] |
| out = run_onnx_inference(ort_session, image) |
| size = label.size() |
| |
| out = out.transpose(0, 3, 1, 2) |
| if out.shape[2] != size[1] or out.shape[3] != size[2]: |
| out = torch.from_numpy(out).cpu() |
| pred = F.interpolate( |
| out, size=size[1:], |
| mode='bilinear' |
| ) |
|
|
| confusion_matrix += get_confusion_matrix( |
| label, |
| pred, |
| size, |
| NUM_CLASSES, |
| IGNORE_LABEL) |
|
|
| pos = confusion_matrix.sum(1) |
| res = confusion_matrix.sum(0) |
| tp = np.diag(confusion_matrix) |
| pixel_acc = tp.sum()/pos.sum() |
| mean_acc = (tp/np.maximum(1.0, pos)).mean() |
| IoU_array = (tp / np.maximum(1.0, pos + res - tp)) |
| mean_IoU = IoU_array.mean() |
|
|
| return mean_IoU, IoU_array, pixel_acc, mean_acc |
|
|
|
|
| if __name__ == "__main__": |
|
|
| onnx_path = args.onnx_model |
| root = args.root |
| list_path = args.list_path |
| if args.ipu: |
| providers = ["VitisAIExecutionProvider"] |
| provider_options = [{"config_file": args.provider_config}] |
| else: |
| providers = ['CUDAExecutionProvider', 'CPUExecutionProvider'] |
| provider_options = None |
| |
| ort_session = onnxruntime.InferenceSession(onnx_path, providers=providers, provider_options=provider_options) |
| |
| mean_IoU, IoU_array, pixel_acc, mean_acc = testval(ort_session, root, list_path) |
|
|
| msg = 'MeanIU: {: 4.4f}, Pixel_Acc: {: 4.4f}, Mean_Acc: {: 4.4f}'.format(mean_IoU, \ |
| pixel_acc, mean_acc) |
| print(msg) |
|
|