Vytváření předpovědí pomocí ONNX na modelech počítačového zpracování obrazu z AutoML (v1)

PLATÍ PRO:Python SDK azureml v1

Důležité

Některé příkazy Azure CLI v tomto článku používají azure-cli-mlrozšíření Azure Machine Učení ( nebo v1). Podpora rozšíření v1 skončí 30. září 2025. Do tohoto data budete moct nainstalovat a používat rozšíření v1.

Doporučujeme přejít na mlrozšíření (nebo v2) před 30. zářím 2025. Další informace o rozšíření v2 najdete v tématu Rozšíření Azure ML CLI a Python SDK v2.

V tomto článku se dozvíte, jak pomocí Open Neural Network Exchange (ONNX) vytvářet předpovědi na modelech počítačového zpracování obrazu vygenerovaných z automatizovaného strojového učení (AutoML) ve službě Azure Machine Učení.

Pokud chcete pro predikce použít ONNX, musíte:

  1. Stáhněte si soubory modelu ONNX z trénovacího spuštění AutoML.
  2. Seznamte se se vstupy a výstupy modelu ONNX.
  3. Předzpracuje data, aby byla v požadovaném formátu pro vstupní obrázky.
  4. Proveďte odvozování s modulem runtime ONNX pro Python.
  5. Vizualizujte předpovědi pro úlohy detekce objektů a segmentace instancí.

ONNX je otevřený standard pro modely strojového učení a hlubokého učení. Umožňuje importovat a exportovat model (interoperabilitu) mezi oblíbenými architekturami AI. Další podrobnosti najdete v projektu ONNX Na GitHubu.

ONNX Runtime je opensourcový projekt, který podporuje odvozování mezi platformami. MODUL RUNTIME ONNX poskytuje rozhraní API napříč programovacími jazyky (včetně Pythonu, C++, C#, C, Javy a JavaScriptu). Tato rozhraní API můžete použít k odvozování vstupních imagí. Po exportu modelu do formátu ONNX můžete tato rozhraní API použít v libovolném programovacím jazyce, který váš projekt potřebuje.

V této příručce se dozvíte, jak pomocí rozhraní Python API pro modul RUNTIME ONNX vytvářet předpovědi obrázků pro oblíbené úlohy zpracování obrazu. Tyto exportované modely ONNX můžete použít napříč jazyky.

Požadavky

Stažení souborů modelu ONNX

Soubory modelu ONNX můžete stáhnout z AutoML spuštění pomocí uživatelského rozhraní studio Azure Machine Learning nebo sady Azure Machine Učení Python SDK. Doporučujeme stáhnout sadu SDK s názvem experimentu a ID nadřazeného spuštění.

Studio Azure Machine Learning

V studio Azure Machine Learning přejděte na experiment pomocí hypertextového odkazu na experiment vygenerovaný v poznámkovém bloku pro trénování nebo výběrem názvu experimentu na kartě Experimenty v části Prostředky. Pak vyberte nejlepší podřízené spuštění.

V rámci nejlepšího podřízeného spuštění přejděte na výstupy a protokoly>train_artifacts. Pomocí tlačítka Stáhnout ručně stáhněte následující soubory:

  • labels.json: Soubor, který obsahuje všechny třídy nebo popisky v trénovací datové sadě.
  • model.onnx: Model ve formátu ONNX.

Screenshot that shows selections for downloading ONNX model files.

Uložte stažené soubory modelu do adresáře. Příklad v tomto článku používá adresář ./automl_models .

Sada Azure Machine Learning Python SDK

Pomocí sady SDK můžete vybrat nejlepší podřízený běh (podle primární metriky) s názvem experimentu a ID nadřazeného spuštění. Pak si můžete stáhnout soubory labels.json a model.onnx .

Následující kód vrátí nejlepší podřízené spuštění na základě relevantní primární metriky.

from azureml.train.automl.run import AutoMLRun

# Select the best child run
run_id = '' # Specify the run ID
automl_image_run = AutoMLRun(experiment=experiment, run_id=run_id)
best_child_run = automl_image_run.get_best_child()

Stáhněte si soubor labels.json, který obsahuje všechny třídy a popisky v trénovací datové sadě.

labels_file = 'automl_models/labels.json'
best_child_run.download_file(name='train_artifacts/labels.json', output_file_path=labels_file)

Stáhněte si soubor model.onnx.

onnx_model_path = 'automl_models/model.onnx'
best_child_run.download_file(name='train_artifacts/model.onnx', output_file_path=onnx_model_path)

Generování modelů pro dávkové bodování

AutoML pro obrázky ve výchozím nastavení podporuje dávkové bodování pro klasifikaci. Modely rozpoznávání objektů a segmentace instancí ale nepodporují dávkové odvozování. V případě odvozování dávek pro detekci objektů a segmentaci instancí použijte následující postup k vygenerování modelu ONNX pro požadovanou velikost dávky. Modely vygenerované pro konkrétní velikost dávky nefungují u jiných velikostí dávek.

from azureml.core.script_run_config import ScriptRunConfig
from azureml.train.automl.run import AutoMLRun
from azureml.core.workspace import Workspace
from azureml.core import Experiment

# specify experiment name
experiment_name = ''
# specify workspace parameters
subscription_id = ''
resource_group = ''
workspace_name = ''
# load the workspace and compute target
ws = ''
compute_target = ''
experiment = Experiment(ws, name=experiment_name)

# specify the run id of the automl run
run_id = ''
automl_image_run = AutoMLRun(experiment=experiment, run_id=run_id)
best_child_run = automl_image_run.get_best_child()

K odeslání skriptu použijte následující argumenty specifické pro model. Další podrobnosti oargumentch

Pokud chcete získat hodnoty argumentů potřebné k vytvoření modelu dávkového bodování, projděte si skripty bodování vygenerované ve složce výstupů trénovacích běhů AutoML. Pro nejlepší podřízené spuštění použijte hodnoty hyperparametrů dostupné v proměnné nastavení modelu v souboru bodování.

Pro klasifikaci obrázků s více třídami podporuje vygenerovaný model ONNX pro nejlepší podřízené spuštění ve výchozím nastavení dávkové vyhodnocování. Proto nejsou pro tento typ úlohy potřeba žádné argumenty specifické pro model a můžete přeskočit na část Načíst popisky a soubory modelu ONNX.

Stáhněte a uložte ONNX_batch_model_generator_automl_for_images.py soubor v aktuálním adresáři a odešlete skript. Pomocí ScriptRunConfig odešlete skript ONNX_batch_model_generator_automl_for_images.py dostupný v úložišti GitHub s příklady azureml a vygenerujte model ONNX konkrétní velikosti dávky. V následujícím kódu se vytrénované prostředí modelu používá k odeslání tohoto skriptu pro vygenerování a uložení modelu ONNX do výstupního adresáře.

script_run_config = ScriptRunConfig(source_directory='.',
                                    script='ONNX_batch_model_generator_automl_for_images.py',
                                    arguments=arguments,
                                    compute_target=compute_target,
                                    environment=best_child_run.get_environment())

remote_run = experiment.submit(script_run_config)
remote_run.wait_for_completion(wait_post_processing=True)

Po vygenerování dávkového modelu si ho buď stáhněte z výstupů a protokolů>ručně, nebo použijte následující metodu:

batch_size= 8  # use the batch size used to generate the model
onnx_model_path = 'automl_models/model.onnx'  # local path to save the model
remote_run.download_file(name='outputs/model_'+str(batch_size)+'.onnx', output_file_path=onnx_model_path)

Po stažení modelu použijete balíček PYTHON modulu runtime ONNX k odvozování pomocí souboru model.onnx . Pro demonstrační účely tento článek používá datové sady z návodu k přípravě datových sad obrázků pro jednotlivé úlohy zpracování obrazu.

Vytrénovali jsme modely pro všechny úlohy zpracování obrazu s příslušnými datovými sadami, abychom ukázali odvození modelu ONNX.

Načtení popisků a souborů modelů ONNX

Následující fragment kódu načte labels.json, kde jsou názvy tříd seřazené. To znamená, že pokud model ONNX predikuje ID popisku jako 2, pak odpovídá názvu popisku zadanému na třetím indexu v souboru labels.json .

import json
import onnxruntime

labels_file = "automl_models/labels.json"
with open(labels_file) as f:
    classes = json.load(f)
print(classes)
try:
    session = onnxruntime.InferenceSession(onnx_model_path)
    print("ONNX model loaded...")
except Exception as e: 
    print("Error loading ONNX file: ",str(e))

Získání očekávaných vstupních a výstupních podrobností pro model ONNX

Pokud máte model, je důležité znát některé podrobnosti specifické pro konkrétní model a úlohu. Tyto podrobnosti zahrnují počet vstupů a počet výstupů, očekávaný vstupní obrazec nebo formát pro předběžné zpracování obrázku a výstupní obrazec, takže znáte výstupy specifické pro model nebo výstupy specifické pro úlohy.

sess_input = session.get_inputs()
sess_output = session.get_outputs()
print(f"No. of inputs : {len(sess_input)}, No. of outputs : {len(sess_output)}")

for idx, input_ in enumerate(range(len(sess_input))):
    input_name = sess_input[input_].name
    input_shape = sess_input[input_].shape
    input_type = sess_input[input_].type
    print(f"{idx} Input name : { input_name }, Input shape : {input_shape}, \
    Input type  : {input_type}")  

for idx, output in enumerate(range(len(sess_output))):
    output_name = sess_output[output].name
    output_shape = sess_output[output].shape
    output_type = sess_output[output].type
    print(f" {idx} Output name : {output_name}, Output shape : {output_shape}, \
    Output type  : {output_type}") 

Očekávané vstupní a výstupní formáty pro model ONNX

Každý model ONNX má předdefinovanou sadu vstupních a výstupních formátů.

Tento příklad použije model natrénovaný na datové sadě fridgeObjects s 134 obrázky a 4 třídami/popisky k vysvětlení odvozování modelu ONNX. Další informace o trénování úlohy klasifikace obrázků najdete v poznámkovém bloku klasifikace obrázků s více třídami.

Vstupní formát

Vstup je předzpracovaná image.

Název vstupu Vstupní obrazec Input type Popis
input1 (batch_size, num_channels, height, width) ndarray(float) Vstup je předzpracovaný obrázek s obrazcem (1, 3, 224, 224) pro velikost dávky 1 a výškou a šířkou 224. Tato čísla odpovídají hodnotám použitým crop_size v příkladu trénování.

Výstupní formát

Výstup je pole logit pro všechny třídy/popisky.

Název výstupu Výstupní obrazec Typ výstupu Popis
výstup 1 (batch_size, num_classes) ndarray(float) Model vrátí logits (bez softmax). Například pro dávkové třídy 1 a 4 vrátí (1, 4)hodnotu .

Předzpracování

Proveďte následující kroky předběžného zpracování pro odvozování modelu ONNX:

  1. Převeďte obrázek na RGB.
  2. Změňte velikost obrázku na valid_resize_size hodnoty, valid_resize_size které odpovídají hodnotám použitým při transformaci ověřovací datové sady během trénování. Výchozí hodnota je valid_resize_size 256.
  3. Na střed oříznout obrázek na height_onnx_crop_size a width_onnx_crop_size. valid_crop_size Odpovídá výchozí hodnotě 224.
  4. Změňte HxWxC na CxHxW.
  5. Převeďte na typ float.
  6. Normalizuje se pomocí imagí mean = [0.485, 0.456, 0.406] a .std = [0.229, 0.224, 0.225]

Pokud jste pro hyperparametryvalid_resize_size a valid_crop_size během trénování zvolili jiné hodnoty, měly by se tyto hodnoty použít.

Získejte vstupní obrazec potřebný pro model ONNX.

batch, channel, height_onnx_crop_size, width_onnx_crop_size = session.get_inputs()[0].shape
batch, channel, height_onnx_crop_size, width_onnx_crop_size

Bez PyTorchu

import glob
import numpy as np
from PIL import Image

def preprocess(image, resize_size, crop_size_onnx):
    """Perform pre-processing on raw input image
    
    :param image: raw input image
    :type image: PIL image
    :param resize_size: value to resize the image
    :type image: Int
    :param crop_size_onnx: expected height of an input image in onnx model
    :type crop_size_onnx: Int
    :return: pre-processed image in numpy format
    :rtype: ndarray 1xCxHxW
    """

    image = image.convert('RGB')
    # resize
    image = image.resize((resize_size, resize_size))
    #  center  crop
    left = (resize_size - crop_size_onnx)/2
    top = (resize_size - crop_size_onnx)/2
    right = (resize_size + crop_size_onnx)/2
    bottom = (resize_size + crop_size_onnx)/2
    image = image.crop((left, top, right, bottom))

    np_image = np.array(image)
    # HWC -> CHW
    np_image = np_image.transpose(2, 0, 1) # CxHxW
    # normalize the image
    mean_vec = np.array([0.485, 0.456, 0.406])
    std_vec = np.array([0.229, 0.224, 0.225])
    norm_img_data = np.zeros(np_image.shape).astype('float32')
    for i in range(np_image.shape[0]):
        norm_img_data[i,:,:] = (np_image[i,:,:]/255 - mean_vec[i])/std_vec[i]
             
    np_image = np.expand_dims(norm_img_data, axis=0) # 1xCxHxW
    return np_image

# following code loads only batch_size number of images for demonstrating ONNX inference
# make sure that the data directory has at least batch_size number of images

test_images_path = "automl_models_multi_cls/test_images_dir/*" # replace with path to images
# Select batch size needed
batch_size = 8
# you can modify resize_size based on your trained model
resize_size = 256
# height and width will be the same for classification
crop_size_onnx = height_onnx_crop_size 

image_files = glob.glob(test_images_path)
img_processed_list = []
for i in range(batch_size):
    img = Image.open(image_files[i])
    img_processed_list.append(preprocess(img, resize_size, crop_size_onnx))
    
if len(img_processed_list) > 1:
    img_data = np.concatenate(img_processed_list)
elif len(img_processed_list) == 1:
    img_data = img_processed_list[0]
else:
    img_data = None

assert batch_size == img_data.shape[0]

S PyTorchem

import glob
import torch
import numpy as np
from PIL import Image
from torchvision import transforms

def _make_3d_tensor(x) -> torch.Tensor:
    """This function is for images that have less channels.

    :param x: input tensor
    :type x: torch.Tensor
    :return: return a tensor with the correct number of channels
    :rtype: torch.Tensor
    """
    return x if x.shape[0] == 3 else x.expand((3, x.shape[1], x.shape[2]))

def preprocess(image, resize_size, crop_size_onnx):
    transform = transforms.Compose([
        transforms.Resize(resize_size),
        transforms.CenterCrop(crop_size_onnx),
        transforms.ToTensor(),
        transforms.Lambda(_make_3d_tensor),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])
    
    img_data = transform(image)
    img_data = img_data.numpy()
    img_data = np.expand_dims(img_data, axis=0)
    return img_data

# following code loads only batch_size number of images for demonstrating ONNX inference
# make sure that the data directory has at least batch_size number of images

test_images_path = "automl_models_multi_cls/test_images_dir/*" # replace with path to images
# Select batch size needed
batch_size = 8
# you can modify resize_size based on your trained model
resize_size = 256
# height and width will be the same for classification
crop_size_onnx = height_onnx_crop_size 

image_files = glob.glob(test_images_path)
img_processed_list = []
for i in range(batch_size):
    img = Image.open(image_files[i])
    img_processed_list.append(preprocess(img, resize_size, crop_size_onnx))
    
if len(img_processed_list) > 1:
    img_data = np.concatenate(img_processed_list)
elif len(img_processed_list) == 1:
    img_data = img_processed_list[0]
else:
    img_data = None

assert batch_size == img_data.shape[0]

Odvozovat s modulem runtime ONNX

Odvozování s modulem RUNTIME ONNX se pro každou úlohu počítačového zpracování obrazu liší.

def get_predictions_from_ONNX(onnx_session, img_data):
    """Perform predictions with ONNX runtime
    
    :param onnx_session: onnx model session
    :type onnx_session: class InferenceSession
    :param img_data: pre-processed numpy image
    :type img_data: ndarray with shape 1xCxHxW
    :return: scores with shapes
            (1, No. of classes in training dataset) 
    :rtype: numpy array
    """

    sess_input = onnx_session.get_inputs()
    sess_output = onnx_session.get_outputs()
    print(f"No. of inputs : {len(sess_input)}, No. of outputs : {len(sess_output)}")    
    # predict with ONNX Runtime
    output_names = [ output.name for output in sess_output]
    scores = onnx_session.run(output_names=output_names,\
                                               input_feed={sess_input[0].name: img_data})
    
    return scores[0]

scores = get_predictions_from_ONNX(session, img_data)

Postprocessing

Pokud chcete získat skóre spolehlivosti klasifikace (pravděpodobnosti) pro každou třídu, použijte softmax() předpovězené hodnoty. Pak bude predikce třídou s nejvyšší pravděpodobností.

Bez PyTorchu

def softmax(x):
    e_x = np.exp(x - np.max(x, axis=1, keepdims=True))
    return e_x / np.sum(e_x, axis=1, keepdims=True)

conf_scores = softmax(scores)
class_preds = np.argmax(conf_scores, axis=1)
print("predicted classes:", ([(class_idx, classes[class_idx]) for class_idx in class_preds]))

S PyTorchem

conf_scores = torch.nn.functional.softmax(torch.from_numpy(scores), dim=1)
class_preds = torch.argmax(conf_scores, dim=1)
print("predicted classes:", ([(class_idx.item(), classes[class_idx]) for class_idx in class_preds]))

Vizualizace předpovědí

Vizualizace vstupního obrázku s popisky

import matplotlib.image as mpimg
import matplotlib.pyplot as plt
%matplotlib inline

sample_image_index = 0 # change this for an image of interest from image_files list
IMAGE_SIZE = (18, 12)
plt.figure(figsize=IMAGE_SIZE)
img_np = mpimg.imread(image_files[sample_image_index])

img = Image.fromarray(img_np.astype('uint8'), 'RGB')
x, y = img.size

fig,ax = plt.subplots(1, figsize=(15, 15))
# Display the image
ax.imshow(img_np)

label = class_preds[sample_image_index]
if torch.is_tensor(label):
    label = label.item()
    
conf_score = conf_scores[sample_image_index]
if torch.is_tensor(conf_score):
    conf_score = np.max(conf_score.tolist())
else:
    conf_score = np.max(conf_score)

display_text = '{} ({})'.format(label, round(conf_score, 3))
print(display_text)

color = 'red'
plt.text(30, 30, display_text, color=color, fontsize=30)

plt.show()

Další kroky