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()