共用方式為


從 AutoML 使用 ONNX 在電腦視覺模型上進行預測 (v1)

適用於:適用於 Python 的 Azure Machine Learning SDK v1

重要事項

本文中的 Azure CLI 命令使用 azure-cli-ml 或 v1 (Azure Machine Learning 的擴充功能)。 CLI v1 的支援已於 2025 年 9 月 30 日結束。 Microsoft 將不再提供此服務的技術支援或更新。 您使用 CLI v1 的現有工作流程將在支援終止日期之後繼續運作。 不過,如果產品發生架構變更,它們可能會面臨安全性風險或重大變更。

建議您盡快轉換至 ml或 v2 擴充功能。 如需有關 v2 擴充功能的詳細資訊,請參閱 Azure Machine Learning CLI 擴充功能和 Python SDK v2

重要事項

本文提供使用 Azure Machine Learning SDK v1 的相關信息。 SDK v1 自 2025 年 3 月 31 日起已被取代。 其支援將於 2026 年 6 月 30 日結束。 您可以在該日期之前安裝並使用 SDK v1。 您使用 SDK v1 的現有工作流程將在支援終止日期後繼續運作。 不過,如果產品發生架構變更,它們可能會面臨安全性風險或重大變更。

建議您在 2026 年 6 月 30 日之前轉換至 SDK v2。 如需 SDK v2 的詳細資訊,請參閱 什麼是 Azure Machine Learning CLI 和 Python SDK v2?SDK v2 參考

在本文中,您將了解如何使用 Open Neural Network Exchange (ONNX),在 Azure Machine Learning 中對自動化機器學習 (AutoML) 產生的電腦視覺模型做出預測。

若要使用 ONNX 進行預測,您需要:

  1. 從 AutoML 定型回合下載 ONNX 模型檔案。
  2. 了解 ONNX 模型的輸入和輸出。
  3. 前置處理資料,使其成為輸入影像的必要格式。
  4. 使用適用於 Python 的 ONNX Runtime 來執行推斷。
  5. 對物件偵測和執行個體分割工作進行視覺化的預測。

ONNX 是機器學習和深度學習的開放標準。 它能夠在熱門的 AI 架構中,進行模型匯入和匯出 (互通性)。 如需詳細資訊,請探索 ONNX GitHub 專案

ONNX Runtime 是支援跨平台推斷的開放原始碼專案。 ONNX Runtime 提供 API 跨平台的程式設計語言 (包括 Python、C++、C#、C、Java 和 JavaScript)。 您可以使用這些 API 在輸入影像上執行推斷。 當您具備已匯出為 ONNX 格式的模型之後,即可在您專案所需的任何程式設計語言上使用這些 API。

在本指南中,您將了解如何使用適用於 ONNX Runtime 的 Python API,對熱門視覺工作的影像進行預測。 您可以跨語言使用這些 ONNX 匯出的模型。

先決條件

下載 ONNX 模型檔案

您可以使用 Azure Machine Learning 工作室 UI 或 Azure Machine Learning Python SDK,從 AutoML 執行下載 ONNX 模型檔案。 建議您使用實驗名稱和父代執行識別碼,透過 SDK 進行下載。

Azure Machine Learning 工作室

在 Azure Machine Learning 工作室中,使用定型筆記本產生的實驗超連結,或在[資產] 下的[實驗] 索引標籤上,選取實驗名稱,前往您的實驗。 然後選取最佳的子系執行。

在最佳的子系執行中,前往 Outputs+logs>train_artifacts。 使用 [下載] 按鈕,手動下載以下檔案:

  • labels.json:此檔案包含定型資料集中的所有類別或標籤。
  • model.onnx:ONNX 格式的模型。

此螢幕擷取畫面顯示下載 ONNX 模型檔案的選擇範圍。

將下載的模型檔案儲存在目錄中。 本文中的範例使用 ./automl_models 目錄。

Azure Machine Learning Python SDK

透過 SDK,您可以使用實驗名稱和父代執行識別碼,選取最佳子系執行 (根據主要計量)。 然後,您可以下載 labels.jsonmodel.onnx 檔案。

下列程式碼會根據相關的主要計量傳回最佳的子系執行。

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

下載 labels.json 檔案,其包含定型資料集中的所有類別和標籤。

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

下載 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)

產生模型以進行批次評分

AutoML for Images 預設支援分類的批次評分。 不過,物件偵測和執行個體分割模型不支援批次推斷。 如果是物件偵測和執行個體分割的批次推斷,請使用下列程序為所需的批次大小產生 ONNX 模型。 為特定批次大小產生的模型,不適用於其他批次大小。

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

使用下列模型特定引數來提交指令碼。 如需引數的詳細資訊,請參閱模型特定超參數,若要了解支援的物件偵測模型名稱,請參閱支援的模型演算法小節

若要取得建立批次評分模型所需的引數值,請參閱 AutoML 定型執行的輸出資料夾下產生的評分指令碼。 為了獲得最佳子執行,請使用評分檔案內的模型設定變數中可用的超參數值。

針對多類別影像分類,為最佳子執行產生的 ONNX 模型依預設可支援批次評分。 因此,此工作類型不需要任何模型特定的引數,您可以跳至載入標籤和 ONNX 模型檔案一節。

下載 ONNX_batch_model_generator_automl_for_images.py 檔案並將其保存在目前的目錄中,然後提交指令碼。 使用 ScriptRunConfig 提交 ONNX_batch_model_generator_automl_for_images.py中可用的指令碼 ,以產生特定批次大小的 ONNX 模型。 在下列程式碼中,定型的模型環境可用來提交此指令碼,以產生 ONNX 模型並將其儲存至輸出目錄。

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)

產生批次模型之後,請從 [輸出 + 記錄]>[輸出] 手動加以下載,或使用下列方法:

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)

在模型下載步驟之後,可以藉由使用 model.onnx 檔案,來使用 ONNX Runtime Python 套件以執行推斷。 基於示範目的,本文對於每個視覺工作使用來自如何準備影像資料集的資料集。

我們已使用其各自的資料集來定型所有視覺工作的模型,以示範 ONNX 模型推斷。

載入標籤和 ONNX 模型檔案

下列程式碼片段會載入 labels.json,其類別名稱已排序。 也就是說,如果 ONNX 模型預測標籤識別碼為 2,則會對應至 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))

取得 ONNX 模型的預期輸入和輸出詳細資料

當您擁有模型時,請務必了解某些特定模型和特定工作的詳細資料。 這些詳細資料包括輸入和輸出的數目、處理影像的預期輸入圖形或格式,以及輸出圖形,以便您知道特定模型或特定工作的輸出。

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}") 

ONNX 模型的預期輸入和輸出格式

每個 ONNX 模型都有一組預先定義的輸入和輸出格式。

此範例會套用在 fridgeObjects 資料集上定型的模型,其中包含 134 個影像和 4 個類別/標籤,以說明 ONNX 模型推斷。 如需定型影像分類工作的詳細資訊,請參閱多類別影像分類筆記本

輸入格式

輸入是前置處理過的影像。

輸入名稱 輸入圖形 輸入類型 描述
輸入1 (batch_size, num_channels, height, width) ndarray(float) 輸入是前置處理過的影像,其圖形 (1, 3, 224, 224) 的批次大小為 1,高度和寬度為 224。 這些數字對應至定型範例中 crop_size 所使用的值。

輸出格式

輸出是所有類別/標籤的 logits 陣列。

輸出名稱 輸出圖形 輸出類型 描述
output1 (batch_size, num_classes) ndarray(float) 模型會傳回 logits (不含 softmax)。 例如,對於每個批次大小為 1 和 4 個類別,會傳回 (1, 4)

前置處理

針對 ONNX 模型推斷,執行下列前置處理步驟:

  1. 將影像轉換為 RGB。
  2. 將影像大小調整為 valid_resize_sizevalid_resize_size 值,使其對應至定型期間轉換驗證資料集所使用的值。 valid_resize_size 的預設值為 256。
  3. 將影像置中裁切成 height_onnx_crop_sizewidth_onnx_crop_size。 它會對應至 valid_crop_size,其預設值為 224。
  4. HxWxC 變更為 CxHxW
  5. 轉換成 float 類型。
  6. 使用 ImageNet 的 mean = [0.485, 0.456, 0.406]std = [0.229, 0.224, 0.225] 進行正規化。

如果您在定型期間,為超參數valid_resize_sizevalid_crop_size選擇不同的值,則會使用這些值。

取得 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

不含 PyTorch

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]

包含 PyTorch

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]

使用 ONNX Runtime 進行推斷

使用 ONNX Runtime 進行推斷,對於每個電腦視覺工作有所不同。

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)

後置處理

在預測值上套用 softmax(),以取得每個類別的分類信賴分數 (機率)。 然後,預測將會是具有最高機率的類別。

不含 PyTorch

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

包含 PyTorch

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

將預測視覺化

使用標籤將輸入影像視覺化

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

後續步驟