161 lines
5.5 KiB
Python
161 lines
5.5 KiB
Python
import os
|
|
import numpy as np
|
|
import torch
|
|
import torch.nn as nn
|
|
import torchvision
|
|
from torchvision import datasets, models, transforms
|
|
from load_model import initialize_model
|
|
from PIL import Image
|
|
import json
|
|
import argparse
|
|
import os
|
|
import sys
|
|
from datetime import date
|
|
import onnxruntime
|
|
|
|
def preprocess(image_path, input_size):
|
|
data_transforms = transforms.Compose([
|
|
transforms.Resize(input_size),
|
|
transforms.ToTensor(),
|
|
transforms.Normalize([0, 0, 0], [1/255.0, 1/255.0, 1/255.0]),
|
|
transforms.Normalize([0.5*256, 0.5*256, 0.5*256], [256.0, 256.0, 256.0])
|
|
])
|
|
with torch.no_grad():
|
|
img_data_pytorch = data_transforms(Image.open(image_path))
|
|
img_data_pytorch = img_data_pytorch.unsqueeze(0)
|
|
return img_data_pytorch.numpy()
|
|
|
|
def postprocess(pre_output):
|
|
score = softmax(pre_output)
|
|
labels = list(range(len(pre_output)))
|
|
score_labels = list(zip(score, labels))
|
|
score_labels.sort(reverse=True)
|
|
score, labels = list(zip(*score_labels))
|
|
|
|
return score, labels
|
|
|
|
|
|
def onnx_runner(image_path, model_path, class_id):
|
|
sess = onnxruntime.InferenceSession(model_path)
|
|
onnx_img_size_h = sess.get_inputs()[0].shape[2]
|
|
onnx_img_size_w = sess.get_inputs()[0].shape[3]
|
|
input_name = sess.get_inputs()[0].name
|
|
input_size = (onnx_img_size_h, onnx_img_size_w)
|
|
np_images = preprocess(image_path, input_size)
|
|
np_images = np_images.astype(np.float32)
|
|
pred_onnx = sess.run(None, {input_name: np_images })[0][0]
|
|
|
|
score, labels = postprocess(pred_onnx)
|
|
|
|
header = 'Label Probability'
|
|
itn_line = '{:10} {:8.3f} '
|
|
print(header)
|
|
for i in range(len(score)):
|
|
#print(itn_line.format( class_id[str(labels[i])], score[i]) )
|
|
print(itn_line.format( str(labels[i]), score[i]) )
|
|
|
|
return score, labels
|
|
|
|
def softmax(A):
|
|
e = np.exp(A)
|
|
return e / np.sum(e, axis=1, keepdims=True)
|
|
|
|
def inference(backbone, image_path, class_id, device, model_def_path, pretrained_path, topk = None):
|
|
|
|
num_classes = len(class_id)
|
|
model_structure, input_size = initialize_model(backbone, num_classes, False, model_def_path)
|
|
|
|
model_structure.load_state_dict(torch.load(pretrained_path))
|
|
model = model_structure.eval()
|
|
model = model.to(device)
|
|
|
|
data_transforms = transforms.Compose([
|
|
transforms.Resize(input_size),
|
|
transforms.ToTensor(),
|
|
transforms.Normalize([0, 0, 0], [1/255.0, 1/255.0, 1/255.0]),
|
|
transforms.Normalize([0.5*256, 0.5*256, 0.5*256], [256.0, 256.0, 256.0])
|
|
])
|
|
|
|
img_data_pytorch = data_transforms(Image.open(image_path))
|
|
img_data_pytorch = img_data_pytorch.to(device)
|
|
with torch.no_grad():
|
|
if topk == None or topk > num_classes:
|
|
topk = num_classes
|
|
outputs = model(img_data_pytorch[None, ...]).topk(topk)
|
|
scores = outputs[0].cpu().numpy()[0]
|
|
probs = softmax(scores)
|
|
preds = outputs[1].cpu().numpy()[0]
|
|
|
|
header = 'Label Probability'
|
|
itn_line = '{:10} {:8.3f} '
|
|
print(header)
|
|
for i in range(len(preds)):
|
|
print(itn_line.format( class_id[str(preds[i])], probs[i]) )
|
|
|
|
return probs, preds
|
|
|
|
def softmax(A):
|
|
|
|
e = np.exp(A)
|
|
return e / np.sum(e, keepdims=True)
|
|
|
|
def parse_args(args):
|
|
"""
|
|
Parse the arguments.
|
|
"""
|
|
today = str(date.today())
|
|
|
|
parser = argparse.ArgumentParser(description='Simple training script for training a image classification network.')
|
|
parser.add_argument('--img-path', type=str, help='Path to the image.')
|
|
parser.add_argument('--backbone', help='Backbone model.', default='resnet18', type=str)
|
|
parser.add_argument('--class_id_path', help='Path to the class id mapping file.', default='./eval_utils/class_id.json')
|
|
parser.add_argument('--gpu', help='Id of the GPU to use (as reported by nvidia-smi). (-1 for cpu)',type=int,default=-1)
|
|
parser.add_argument('--model-def-path', type=str, help='Path to pretrained model definition', default=None )
|
|
parser.add_argument('--snapshot', help='Path to the pretrained models.')
|
|
parser.add_argument('--save-path', help='Path to the classification result.', default='inference_result.json')
|
|
parser.add_argument('--onnx', help='inference onnx model',action='store_true')
|
|
|
|
print(vars(parser.parse_args(args)))
|
|
return check_args(parser.parse_args(args))
|
|
|
|
def check_args(parsed_args):
|
|
""" Function to check for inherent contradictions within parsed arguments.
|
|
Args
|
|
parsed_args: parser.parse_args()
|
|
Returns
|
|
parsed_args
|
|
"""
|
|
if parsed_args.gpu >= 0 and torch.cuda.is_available() == False:
|
|
raise ValueError("No gpu is available")
|
|
return parsed_args
|
|
|
|
def main(args=None):
|
|
# parse arguments
|
|
if args is None:
|
|
args = sys.argv[1:]
|
|
|
|
args = parse_args(args)
|
|
device = "cuda:"+str(args.gpu) if args.gpu >= 0 else "cpu"
|
|
with open(args.class_id_path,'r') as fp:
|
|
class_id = json.load(fp)
|
|
|
|
# Inference
|
|
if args.onnx:
|
|
probs, preds = onnx_runner(args.img_path, args.snapshot, class_id)
|
|
else:
|
|
probs, preds = inference(args.backbone, args.img_path, class_id, device, args.model_def_path, args.snapshot)
|
|
res = {}
|
|
res['img_path'] = os.path.abspath(args.img_path)
|
|
res['0_0'] = []
|
|
|
|
for i in range(len(probs)):
|
|
res['0_0'].append([ float(probs[i]), int(preds[i]) ])
|
|
|
|
with open(args.save_path, 'w') as fp:
|
|
json.dump(res, fp)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|
|
|