PyTorch-Modelle auf verschiedenen Hardwarezielen mit ONNX Runtime inferieren
Als Entwickler, der ein PyTorch- oder ONNX-Modell bereitstellen und die Leistung und Hardwareflexibilität maximieren möchte, können Sie ONNX Runtime nutzen, um Ihr Modell optimal auf Ihrer Hardwareplattform auszuführen.
In diesem Tutorial lernen Sie
- wie Sie das PyTorch ResNet-50-Modell für die Bildklassifizierung verwenden
- in ONNX konvertieren und
- mit ONNX Runtime auf der Standard-CPU, NVIDIA CUDA (GPU) und Intel OpenVINO bereitstellen – unter Verwendung des gleichen Anwendungscodes zum Laden und Ausführen der Inferenz über verschiedene Hardwareplattformen hinweg.
ONNX wurde als Open-Source-ML-Modellformat von Microsoft, Meta, Amazon und anderen Technologieunternehmen entwickelt, um Machine-Learning-Modelle zu standardisieren und einfach auf verschiedenen Hardwaretypen bereitzustellen. ONNX Runtime wurde von Microsoft beigesteuert und wird von Microsoft gepflegt, um die Leistung von ONNX-Modellen über Frameworks wie PyTorch, Tensorflow und mehr zu optimieren. Wenn das ResNet-50-Modell mit dem ImageNet-Datensatz trainiert wird, wird es üblicherweise für die Bildklassifizierung verwendet.
Dieses Tutorial zeigt, wie ein ONNX-Modell auf CPU, GPU und Intel-Hardware mit OpenVINO und ONNX Runtime ausgeführt wird, unter Verwendung von Microsoft Azure Machine Learning.
Setup
Betriebssystem-Voraussetzungen
Ihre Umgebung sollte über installiertes curl verfügen.
Geräte-Voraussetzungen
Die onnxruntime-gpu-Bibliothek benötigt Zugriff auf einen NVIDIA CUDA-Beschleuniger auf Ihrem Gerät oder Compute-Cluster. Die Ausführung nur auf der CPU funktioniert jedoch für die CPU- und OpenVINO-CPU-Demos.
Inferenz-Voraussetzungen
Stellen Sie sicher, dass Sie ein Bild für die Inferenz haben. Für dieses Tutorial haben wir ein „cat.jpg“-Bild, das sich im selben Verzeichnis wie die Notebook-Dateien befindet.
Umgebungs-Voraussetzungen
Führen Sie in Azure Notebook Terminal oder einem AnaConda-Eingabeauffenster die folgenden Befehle aus, um Ihre 3 Umgebungen für CPU, GPU und/oder OpenVINO zu erstellen (Unterschiede sind fett gedruckt).
CPU
conda create -n cpu_env_demo python=3.8
conda activate cpu_env_demo
conda install -c anaconda ipykernel
conda install -c conda-forge ipywidgets
python -m ipykernel install --user --name=cpu_env_demo
jupyter notebook
GPU
conda create -n gpu_env_demo python=3.8
conda activate gpu_env_demo
conda install -c anaconda ipykernel
conda install -c conda-forge ipywidgets
python -m ipykernel install --user --name=gpu_env_demo
jupyter notebook
OpenVINO
conda create -n openvino_env_demo python=3.8
conda activate openvino_env_demo
conda install -c anaconda ipykernel
conda install -c conda-forge ipywidgets
python -m ipykernel install --user --name=openvino_env_demo
python -m pip install --upgrade pip
pip install openvino
Bibliotheksanforderungen
Installieren Sie in der ersten Codezelle die erforderlichen Bibliotheken mit den folgenden Code-Snippets (Unterschiede sind fett gedruckt).
CPU + GPU
import sys
if sys.platform in ['linux', 'win32']: # Linux or Windows
!{sys.executable} -m pip install torch==1.9.0+cu111 torchvision==0.10.0+cu111 torchaudio===0.9.0 -f https://download.pytorch.org/whl/torch_stable.html
else: # Mac
print("PyTorch 1.9 MacOS Binaries do not support CUDA, install from source instead")
!{sys.executable} -m pip install onnxruntime-gpu onnx onnxconverter_common==1.8.1 pillow
OpenVINO
import sys
if sys.platform in ['linux', 'win32']: # Linux or Windows
!{sys.executable} -m pip install torch==1.9.0+cu111 torchvision==0.10.0+cu111 torchaudio===0.9.0 -f https://download.pytorch.org/whl/torch_stable.html
else: # Mac
print("PyTorch 1.9 MacOS Binaries do not support CUDA, install from source instead")
!{sys.executable} -m pip install onnxruntime-openvino onnx onnxconverter_common==1.8.1 pillow
import openvino.utils as utils
utils.add_openvino_libs_to_path()
ResNet-50 Demo
Umgebungs-Setup
Importieren Sie die notwendigen Bibliotheken, um Modelle zu laden und Inferenz durchzuführen.
from torchvision import models, datasets, transforms as T
import torch
from PIL import Image
import numpy as np
Vor-trainiertes ResNet-50-Modell laden und nach ONNX exportieren
Laden Sie ein vor-trainiertes ResNet-50-Modell von PyTorch herunter und exportieren Sie es in das ONNX-Format.
resnet50 = models.resnet50(pretrained=True)
# Download ImageNet labels
!curl -o imagenet_classes.txt https://raw.githubusercontent.com/pytorch/hub/master/imagenet_classes.txt
# Read the categories
with open("imagenet_classes.txt", "r") as f:
categories = [s.strip() for s in f.readlines()]
# Export the model to ONNX
image_height = 224
image_width = 224
x = torch.randn(1, 3, image_height, image_width, requires_grad=True)
torch_out = resnet50(x)
torch.onnx.export(resnet50, # model being run
x, # model input (or a tuple for multiple inputs)
"resnet50.onnx", # where to save the model (can be a file or file-like object)
export_params=True, # store the trained parameter weights inside the model file
opset_version=12, # the ONNX version to export the model to
do_constant_folding=True, # whether to execute constant folding for optimization
input_names = ['input'], # the model's input names
output_names = ['output']) # the model's output names
Beispiel-Ausgabe
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 10472 100 10472 0 0 50581 0 --:--:-- --:--:-- --:--:-- 50834
Vorverarbeitung für die Inferenz einrichten
Erstellen Sie die Vorverarbeitung für das Bild (z. B. cat.jpg), auf dem Sie das Modell für die Inferenz verwenden möchten.
# Pre-processing for ResNet-50 Inferencing, from https://pytorch.org/hub/pytorch_vision_resnet/
resnet50.eval()
filename = 'cat.jpg' # change to your filename
input_image = Image.open(filename)
preprocess = T.Compose([
T.Resize(256),
T.CenterCrop(224),
T.ToTensor(),
T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])
input_tensor = preprocess(input_image)
input_batch = input_tensor.unsqueeze(0) # create a mini-batch as expected by the model
# move the input and model to GPU for speed if available
print("GPU Availability: ", torch.cuda.is_available())
if torch.cuda.is_available():
input_batch = input_batch.to('cuda')
resnet50.to('cuda')
Beispiel-Ausgabe
GPU Availability: False
ResNet-50 ONNX-Modell mit ONNX Runtime inferieren
Inferieren Sie das Modell mit ONNX Runtime, indem Sie den entsprechenden Execution Provider für die Umgebung auswählen. Wenn Ihre Umgebung CPU verwendet, kommentieren Sie CPUExecutionProvider aus; wenn die Umgebung NVIDIA CUDA verwendet, kommentieren Sie CUDAExecutionProvider aus; und wenn die Umgebung OpenVINOExecutionProvider verwendet, kommentieren Sie OpenVINOExecutionProvider aus – kommentieren Sie die anderen onnxruntime.InferenceSession-Codezeilen aus.
# Inference with ONNX Runtime
import onnxruntime
from onnx import numpy_helper
import time
session_fp32 = onnxruntime.InferenceSession("resnet50.onnx", providers=['CPUExecutionProvider'])
# session_fp32 = onnxruntime.InferenceSession("resnet50.onnx", providers=['CUDAExecutionProvider'])
# session_fp32 = onnxruntime.InferenceSession("resnet50.onnx", providers=['OpenVINOExecutionProvider'])
def softmax(x):
"""Compute softmax values for each sets of scores in x."""
e_x = np.exp(x - np.max(x))
return e_x / e_x.sum()
latency = []
def run_sample(session, image_file, categories, inputs):
start = time.time()
input_arr = inputs.cpu().detach().numpy()
ort_outputs = session.run([], {'input':input_arr})[0]
latency.append(time.time() - start)
output = ort_outputs.flatten()
output = softmax(output) # this is optional
top5_catid = np.argsort(-output)[:5]
for catid in top5_catid:
print(categories[catid], output[catid])
return ort_outputs
ort_output = run_sample(session_fp32, 'cat.jpg', categories, input_batch)
print("ONNX Runtime CPU/GPU/OpenVINO Inference time = {} ms".format(format(sum(latency) * 1000 / len(latency), '.2f')))
Beispiel-Ausgabe
Egyptian cat 0.78605634
tabby 0.117310025
tiger cat 0.020089425
Siamese cat 0.011728076
plastic bag 0.0052174763
ONNX Runtime CPU Inference time = 32.34 ms
Vergleich mit PyTorch
Verwenden Sie PyTorch, um die Genauigkeit und Latenz von ONNX Runtime (CPU und GPU) zu benchmarken.
# Inference with OpenVINO
from openvino.runtime import Core
ie = Core()
onnx_model_path = "./resnet50.onnx"
model_onnx = ie.read_model(model=onnx_model_path)
compiled_model_onnx = ie.compile_model(model=model_onnx, device_name="CPU")
# inference
output_layer = next(iter(compiled_model_onnx.outputs))
latency = []
input_arr = input_batch.detach().numpy()
inputs = {'input':input_arr}
start = time.time()
request = compiled_model_onnx.create_infer_request()
output = request.infer(inputs=inputs)
outputs = request.get_output_tensor(output_layer.index).data
latency.append(time.time() - start)
print("OpenVINO CPU Inference time = {} ms".format(format(sum(latency) * 1000 / len(latency), '.2f')))
print("***** Verifying correctness *****")
for i in range(2):
print('OpenVINO and ONNX Runtime output {} are close:'.format(i), np.allclose(ort_output, outputs, rtol=1e-05, atol=1e-04))
Beispiel-Ausgabe
Egyptian cat 0.7820879
tabby 0.113261245
tiger cat 0.020114701
Siamese cat 0.012514038
plastic bag 0.0056432663
OpenVINO CPU Inference time = 31.83 ms
***** Verifying correctness *****
PyTorch and ONNX Runtime output 0 are close: True
PyTorch and ONNX Runtime output 1 are close: True
Vergleich mit OpenVINO
Verwenden Sie OpenVINO, um die Genauigkeit und Latenz von ONNX Runtime (OpenVINO) zu benchmarken.
# Inference with OpenVINO
from openvino.runtime import Core
ie = Core()
onnx_model_path = "./resnet50.onnx"
model_onnx = ie.read_model(model=onnx_model_path)
compiled_model_onnx = ie.compile_model(model=model_onnx, device_name="CPU")
# inference
output_layer = next(iter(compiled_model_onnx.outputs))
latency = []
input_arr = input_batch.detach().numpy()
inputs = {'input':input_arr}
start = time.time()
request = compiled_model_onnx.create_infer_request()
output = request.infer(inputs=inputs)
outputs = request.get_output_tensor(output_layer.index).data
latency.append(time.time() - start)
print("OpenVINO CPU Inference time = {} ms".format(format(sum(latency) * 1000 / len(latency), '.2f')))
print("***** Verifying correctness *****")
for i in range(2):
print('OpenVINO and ONNX Runtime output {} are close:'.format(i), np.allclose(ort_output, outputs, rtol=1e-05, atol=1e-04))
Beispiel-Ausgabe
Egyptian cat 0.7820879
tabby 0.113261245
tiger cat 0.020114701
Siamese cat 0.012514038
plastic bag 0.0056432663
OpenVINO CPU Inference time = 31.83 ms
***** Verifying correctness *****
PyTorch and ONNX Runtime output 0 are close: True
PyTorch and ONNX Runtime output 1 are close: True
Fazit
Wir haben gezeigt, dass ONNX Runtime eine effektive Möglichkeit ist, Ihr PyTorch- oder ONNX-Modell auf CPU, NVIDIA CUDA (GPU) und Intel OpenVINO (Mobil) auszuführen. ONNX Runtime ermöglicht die Bereitstellung auf mehr Hardwaretypen, die unter Execution Providers zu finden sind. Wir würden uns freuen, Ihr Feedback zu erhalten, indem Sie an unserem ONNX Runtime Github-Repo teilnehmen.
Video-Demonstration
Sehen Sie sich das Video hier an, um weitere Erklärungen zur Bereitstellung von ResNet-50 und flexiblen Inferenz mit der Schritt-für-Schritt-Anleitung zu erhalten.