AutoML'den görüntü işleme modellerinde ONNX ile tahmin yapma

ŞUNLAR IÇIN GEÇERLIDIR: Python SDK'sı azure-ai-ml v2 (geçerli)

Bu makalede, Azure Machine Learning'de otomatik makine öğrenmesinden (AutoML) oluşturulan görüntü işleme modelleriyle ilgili tahminlerde bulunmak için Açık Sinir Ağı Değişimi'ni (ONNX) kullanmayı öğreneceksiniz.

Tahminler için ONNX kullanmak için şunları yapmanız gerekir:

  1. AutoML eğitim çalıştırmasından ONNX model dosyalarını indirin.
  2. ONNX modelinin girişlerini ve çıkışlarını anlama.
  3. Giriş görüntüleri için gerekli biçimde olması için verilerinizi önceden işleyin.
  4. Python için ONNX Çalışma Zamanı ile çıkarım yapın.
  5. Nesne algılama ve örnek segmentasyon görevleri için tahminleri görselleştirin.

ONNX , makine öğrenmesi ve derin öğrenme modelleri için açık bir standarttır. Popüler yapay zeka çerçevelerinde model içeri ve dışarı aktarma (birlikte çalışabilirlik) sağlar. Diğer ayrıntılar için ONNX GitHub projesini keşfedin.

ONNX Çalışma Zamanı , platformlar arası çıkarımları destekleyen açık kaynaklı bir projedir. ONNX Çalışma Zamanı, programlama dilleri (Python, C++, C#, C, Java ve JavaScript dahil) genelinde API'ler sağlar. Giriş görüntülerinde çıkarım yapmak için bu API'leri kullanabilirsiniz. ONNX biçimine aktarılmış olan modeli aldıktan sonra, bu API'leri projenizin ihtiyaç duyduğu herhangi bir programlama dilinde kullanabilirsiniz.

Bu kılavuzda, popüler görüntü işleme görevleri için görüntülerle ilgili tahminlerde bulunmak üzere ONNX Çalışma Zamanı için Python API'lerini kullanmayı öğreneceksiniz. Bu ONNX dışarı aktarılan modelleri farklı dillerde kullanabilirsiniz.

Önkoşullar

  • Desteklenen görüntü görevlerinden herhangi biri için AutoML tarafından eğitilen bir görüntü işleme modeli alın: sınıflandırma, nesne algılama veya örnek segmentasyonu. Görüntü işleme görevleri için AutoML desteği hakkında daha fazla bilgi edinin.

  • onnxruntime paketini yükleyin. Bu makaledeki yöntemler 1.3.0 ile 1.8.0 sürümleriyle test edilmiştir.

ONNX model dosyalarını indirme

Azure Machine Learning stüdyosu kullanıcı arabirimini veya Azure Machine Learning Python SDK'sını kullanarak AutoML çalıştırmalarından ONNX model dosyalarını indirebilirsiniz. Deneme adı ve üst çalıştırma kimliği ile SDK aracılığıyla indirmenizi öneririz.

Azure Machine Learning Studio

Azure Machine Learning stüdyosu, eğitim not defterinde oluşturulan denemenin köprüsüni kullanarak veya Varlıklar altındaki Denemeler sekmesinde deneme adını seçerek denemenize gidin. Ardından en iyi alt çalıştırmayı seçin.

En iyi alt çalıştırmada Outputs+logs>train_artifacts gidin. Aşağıdaki dosyaları el ile indirmek için İndir düğmesini kullanın:

  • labels.json: Eğitim veri kümesindeki tüm sınıfları veya etiketleri içeren dosya.
  • model.onnx: ONNX biçimindeki model.

Screenshot that shows selections for downloading O N N X model files.

İndirilen model dosyalarını bir dizine kaydedin. Bu makaledeki örnekte ./automl_models dizini kullanılır.

Azure Machine Learning Python SDK'sı

SDK ile deneme adı ve üst çalıştırma kimliğiyle en iyi alt çalıştırmayı (birincil ölçüme göre) seçebilirsiniz. Ardından labels.json ve model.onnx dosyalarını indirebilirsiniz.

Aşağıdaki kod, ilgili birincil ölçüme göre en iyi alt çalıştırmayı döndürür.

from azure.identity import DefaultAzureCredential
from azure.ai.ml import MLClient
mlflow_client = MlflowClient()

credential = DefaultAzureCredential()
ml_client = None
try:
    ml_client = MLClient.from_config(credential)
except Exception as ex:
    print(ex)
    # Enter details of your Azure Machine Learning workspace
    subscription_id = ''   
    resource_group = ''  
    workspace_name = ''
    ml_client = MLClient(credential, subscription_id, resource_group, workspace_name)
import mlflow
from mlflow.tracking.client import MlflowClient

# Obtain the tracking URL from MLClient
MLFLOW_TRACKING_URI = ml_client.workspaces.get(
    name=ml_client.workspace_name
).mlflow_tracking_uri

mlflow.set_tracking_uri(MLFLOW_TRACKING_URI)

# Specify the job name
job_name = ''

# Get the parent run
mlflow_parent_run = mlflow_client.get_run(job_name)
best_child_run_id = mlflow_parent_run.data.tags['automl_best_child_run_id']
# get the best child run
best_run = mlflow_client.get_run(best_child_run_id)

Eğitim veri kümesindeki tüm sınıfları ve etiketleri içeren labels.json dosyasını indirin.

local_dir = './automl_models'
if not os.path.exists(local_dir):
    os.mkdir(local_dir)

labels_file = mlflow_client.download_artifacts(
    best_run.info.run_id, 'train_artifacts/labels.json', local_dir
)

model.onnx dosyasını indirin.

onnx_model_path = mlflow_client.download_artifacts(
    best_run.info.run_id, 'train_artifacts/model.onnx', local_dir
)

ONNX modelleri kullanılarak Nesne Algılama ve Örnek Segmentasyonu için toplu çıkarım olması durumunda, toplu puanlama için model oluşturma bölümüne bakın.

Toplu puanlama için model oluşturma

Varsayılan olarak, Görüntüler için AutoML sınıflandırma için toplu puanlama işlemini destekler. Ancak nesne algılama ve örnek segmentasyonu ONNX modelleri toplu çıkarım desteği sunmaz. Nesne algılama ve örnek segmentasyonu için toplu çıkarım durumunda, gerekli toplu iş boyutu için bir ONNX modeli oluşturmak üzere aşağıdaki yordamı kullanın. Belirli bir toplu iş boyutu için oluşturulan modeller diğer toplu iş boyutları için çalışmaz.

Conda ortam dosyasını indirin ve komut işiyle kullanılacak bir ortam nesnesi oluşturun.

#  Download conda file and define the environment

conda_file = mlflow_client.download_artifacts(
    best_run.info.run_id, "outputs/conda_env_v_1_0_0.yml", local_dir
)
from azure.ai.ml.entities import Environment
env = Environment(
    name="automl-images-env-onnx",
    description="environment for automl images ONNX batch model generation",
    image="mcr.microsoft.com/azureml/openmpi4.1.0-cuda11.1-cudnn8-ubuntu18.04",
    conda_file=conda_file,
)

Betiği göndermek için aşağıdaki modele özgü bağımsız değişkenleri kullanın. Bağımsız değişkenler hakkında daha fazla ayrıntı için modele özgü hiper parametrelere ve desteklenen nesne algılama modeli adları için desteklenen model mimarisi bölümüne bakın.

Toplu puanlama modelini oluşturmak için gereken bağımsız değişken değerlerini almak için AutoML eğitim çalıştırmalarının outputs klasöründe oluşturulan puanlama betiklerine bakın. En iyi alt çalıştırma için puanlama dosyasının içindeki model ayarları değişkeninde bulunan hiper parametre değerlerini kullanın.

Çok sınıflı görüntü sınıflandırması için, en iyi alt çalıştırma için oluşturulan ONNX modeli varsayılan olarak toplu puanlama desteği sunar. Bu nedenle, bu görev türü için modele özgü bağımsız değişkenler gerekmez ve Etiketleri ve ONNX model dosyalarını yükleme bölümüne atlayabilirsiniz.

Betiği göndermek için dosyayı indirin ve geçerli dizinde tutun ONNX_batch_model_generator_automl_for_images.py . Aşağıdaki komut işini kullanarak azureml-examples GitHub deposunda bulunan betiği ONNX_batch_model_generator_automl_for_images.py göndererek belirli bir toplu iş boyutuna sahip bir ONNX modeli oluşturun. Aşağıdaki kodda eğitilen model ortamı, ONNX modelini oluşturmak ve outputs dizinine kaydetmek üzere bu betiği göndermek için kullanılır.

Çok sınıflı görüntü sınıflandırması için, en iyi alt çalıştırma için oluşturulan ONNX modeli varsayılan olarak toplu puanlama desteği sunar. Bu nedenle, bu görev türü için modele özgü bağımsız değişkenler gerekmez ve Etiketleri ve ONNX model dosyalarını yükleme bölümüne atlayabilirsiniz.

Toplu iş modeli oluşturulduktan sonra, kullanıcı arabirimi aracılığıyla outputs+logs>çıkışlarından el ile indirin veya aşağıdaki yöntemi kullanın:

batch_size = 8  # use the batch size used to generate the model
returned_job_run = mlflow_client.get_run(returned_job.name)

# Download run's artifacts/outputs
onnx_model_path = mlflow_client.download_artifacts(
    returned_job_run.info.run_id, 'outputs/model_'+str(batch_size)+'.onnx', local_dir
)

Model indirme adımından sonra, model.onnx dosyasını kullanarak çıkarım yapmak için ONNX Çalışma Zamanı Python paketini kullanırsınız. Tanıtım amacıyla, bu makalede her görüntü işleme görevi için görüntü veri kümelerini hazırlama başlığı altında yer alan veri kümeleri kullanılır.

ONNX model çıkarımı göstermek için ilgili veri kümeleriyle tüm görüntü işleme görevleri için modelleri eğittik.

Etiketleri ve ONNX model dosyalarını yükleme

Aşağıdaki kod parçacığı, sınıf adlarının sıralandığı labels.json yükler. Yani, ONNX modeli bir etiket kimliğini 2 olarak tahmin ederse, labels.json dosyasındaki üçüncü dizinde verilen etiket adına karşılık gelir.

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 modeli için beklenen giriş ve çıkış ayrıntılarını alma

Modele sahip olduğunuzda, modele ve göreve özgü bazı ayrıntıları bilmeniz önemlidir. Bu ayrıntılar arasında giriş sayısı ve çıkış sayısı, görüntüyü ön işleme için beklenen giriş şekli veya biçimi ve modele özgü veya göreve özgü çıkışları bilmeniz için çıkış şekli yer alır.

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 modeli için beklenen giriş ve çıkış biçimleri

Her ONNX modelinin önceden tanımlanmış bir giriş ve çıkış biçimleri kümesi vardır.

Bu örnek, ONNX modeli çıkarımını açıklamak için 134 görüntü ve 4 sınıf/etiket içeren buzdolabıObjects veri kümesinde eğitilen modeli uygular. Görüntü sınıflandırma görevini eğitma hakkında daha fazla bilgi için çok sınıflı görüntü sınıflandırma not defterine bakın.

Giriş biçimi

Giriş, önceden işlenmiş bir görüntüdür.

Giriş adı Giriş şekli Input type Açıklama
giriş1 (batch_size, num_channels, height, width) ndarray(float) Giriş, toplu iş boyutu 1 olan (1, 3, 224, 224) , yüksekliği ve genişliği 224 olan önceden işlenmiş bir görüntüdür. Bu sayılar, eğitim örneğinde için crop_size kullanılan değerlere karşılık gelir.

Çıkış biçimi

Çıkış, tüm sınıflar/etiketler için bir logit dizisidir.

Çıkış adı Çıkış şekli Çıkış türü Açıklama
çıkış1 (batch_size, num_classes) ndarray(float) Model logit'leri (olmadan softmax) döndürür. Örneğin, toplu iş boyutu 1 ve 4 sınıfları için döndürür (1, 4).

Ön

ONNX modeli çıkarımı için aşağıdaki ön işleme adımlarını gerçekleştirin:

  1. Görüntüyü RGB'ye dönüştürün.
  2. Eğitim sırasında doğrulama veri kümesinin dönüşümünde kullanılan değerlere karşılık gelen ve valid_resize_size değerlerinin görüntüsünü valid_resize_size yeniden boyutlandırın. için valid_resize_size varsayılan değer 256'dır.
  3. Ortala resmi ve width_onnx_crop_sizeolarak height_onnx_crop_size kırpın. Varsayılan değer olan 224'e valid_crop_size karşılık gelir.
  4. HxWxC değerini CxHxW olarak değiştirin.
  5. Float türüne dönüştürün.
  6. ImageNet'ler mean = [0.485, 0.456, 0.406] ve std = [0.229, 0.224, 0.225]ile normalleştirme.

Hiper parametrelervalid_resize_size ve valid_crop_size eğitim sırasında farklı değerler seçtiyseniz bu değerler kullanılmalıdır.

ONNX modeli için gereken giriş şeklini alın.

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 olmadan

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 ile

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 Çalışma Zamanı ile çıkarım

ONNX Çalışma Zamanı ile çıkarım, her görüntü işleme görevi için farklılık gösterir.

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)

İşlem sonrası

Her sınıf için sınıflandırma güvenilirlik puanlarını (olasılıklar) almak için tahmin edilen değerlere uygulayın softmax() . Daha sonra tahmin, en yüksek olasılığı olan sınıf olacaktır.

PyTorch olmadan

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 ile

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

Tahminleri görselleştirme

Giriş görüntüsünü etiketlerle görselleştirin.

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

Sonraki adımlar