Her ML/AI Geliştiricisinin ONNX Hakkında Bilmesi Gerekenler
Makine öğrenimi ve yapay zeka modelleri geliştirmek heyecan verici bir süreçtir, ancak bu modelleri üretim ortamına dağıtmak genellikle karmaşık bir hal alabilir. Farklı framework’ler (PyTorch, TensorFlow, Keras, scikit-learn vb.), farklı donanımlar (CPU, GPU, Edge cihazları) ve farklı işletim sistemleri arasında uyumluluk sorunları, geliştiricilerin karşısına çıkan en büyük engellerden biridir. İşte tam bu noktada ONNX (Open Neural Network Exchange) devreye girerek bu karmaşıklığı ortadan kaldırmayı hedefler.
Bu rehberde, her ML/AI geliştiricisinin ONNX hakkında bilmesi gereken temel bilgileri, pratik uygulamaları ve ipuçlarını bulacaksınız. ONNX’in ne olduğundan, modelleri nasıl dönüştüreceğinize, ONNX Runtime ile çıkarım (inference) yapmaya ve gelişmiş optimizasyon tekniklerine kadar geniş bir yelpazeyi ele alacağız.
ONNX Nedir ve Neden Önemlidir?
ONNX, makine öğrenimi modelleri için açık bir format standardıdır. Temel amacı, farklı makine öğrenimi framework’leri arasında model taşınabilirliğini ve birlikte çalışabilirliği sağlamaktır. Bir ONNX modeli, modelin hesaplama grafiğini (operatörler ve tensörler) ve önceden eğitilmiş ağırlıklarını içeren bir protokoldür.
ONNX’in Sağladığı Temel Avantajlar:
1. Framework Bağımsızlığı: Modellerinizi PyTorch’ta eğitip ONNX’e dönüştürebilir, ardından TensorFlow Lite veya başka bir ortamda dağıtabilirsiniz. Bu, geliştiricilere framework seçimi konusunda büyük bir esneklik sunar.
2. Performans Optimizasyonu: ONNX Runtime gibi yüksek performanslı çıkarım motorları, ONNX formatındaki modelleri CPU, GPU (NVIDIA CUDA, AMD ROCm), NPU gibi farklı donanım hızlandırıcılarında optimize edilmiş bir şekilde çalıştırabilir. Bu, genellikle orijinal framework’ün kendi çıkarım motorundan daha hızlı sonuçlar verir.
3. Dağıtım Kolaylığı: Tek bir standart format, modellerin bulut, sunucu, mobil ve edge cihazlar gibi çeşitli dağıtım hedeflerine kolayca entegre edilmesini sağlar.
4. Model Optimizasyonu: ONNX formatı, nicelikleştirme (quantization), grafik basitleştirme ve katman birleştirme gibi model optimizasyon tekniklerinin uygulanmasını kolaylaştırır. Bu, model boyutunu küçültür ve çıkarım hızını artırır.
5. Araştırma ve Üretim Köprüsü: Araştırma ekibiniz PyTorch kullanırken, üretim ekibiniz C++ tabanlı bir sistemde dağıtım yapıyorsa, ONNX bu iki dünya arasında sorunsuz bir köprü görevi görür.
Kısacası, ONNX makine öğrenimi modellerinin “evrensel dili” olmayı hedefler. Geliştiricilere daha fazla kontrol, esneklik ve performans sunar.
ONNX Modelleri Oluşturma ve Dönüştürme
Makine öğrenimi modellerini ONNX formatına dönüştürmek, genellikle eğitildiği framework’ün kendi araçları veya üçüncü taraf kütüphaneler aracılığıyla yapılır. İşte en yaygın kullanılan framework’lerden bazıları için örnekler:
PyTorch Modellerini ONNX’e Dönüştürme
PyTorch, modelleri ONNX’e aktarmak için yerleşik bir torch.onnx.export fonksiyonuna sahiptir.
import torch
import torch.nn as nn
import os
1. Basit bir PyTorch modeli tanımlayalım
class SimpleModel(nn.Module):
def __init__(self):
super(SimpleModel, self).__init__()
self.fc1 = nn.Linear(10, 5)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(5, 2)
def forward(self, x):
x = self.fc1(x)
x = self.relu(x)
x = self.fc2(x)
return x
model = SimpleModel()
2. Dummy giriş tensörü oluşturalım (modelin beklediği boyutta)
Bu, ONNX grafiğinin oluşturulması için gereklidir.
dummy_input = torch.randn(1, 10, requires_grad=True)
3. Modeli ONNX formatına aktaralım
onnx_path = "simple_model.onnx"
torch.onnx.export(
model, # Dönüştürülecek model
dummy_input, # Modelin beklediği dummy giriş
onnx_path, # Kaydedilecek ONNX dosyasının yolu
export_params=True, # Eğitilmiş parametreleri dahil et
opset_version=17, # ONNX operatör seti versiyonu (genellikle en güncel veya yaygın olan)
do_constant_folding=True, # Sabit katlamayı etkinleştir (optimizasyon)
input_names=['input'], # Giriş tensörünün adı
output_names=['output'], # Çıkış tensörünün adı
dynamic_axes={ # Dinamik eksenleri tanımla (değişken boyutlu girişler için)
'input': {0: 'batch_size'}, # Girişteki 0. eksen (batch) dinamik olabilir
'output': {0: 'batch_size'} # Çıkıştaki 0. eksen (batch) dinamik olabilir
}
)
print(f"Model {onnx_path} konumuna başarıyla kaydedildi.")
Kaydedilen ONNX dosyasını doğrulayalım
if os.path.exists(onnx_path):
print("ONNX dosyası başarıyla oluşturuldu.")
else:
print("ONNX dosyası oluşturulamadı.")
Pratik İpuçları:
dummy_input: Bu, modelin ONNX grafiğini çıkarmak için kullanılan bir şablondur. Modelin beklediği tam* giriş boyutlarına ve veri tiplerine sahip olmalıdır.
* opset_version: ONNX operatör setinin versiyonunu belirtir. Genellikle en güncel stabil versiyonu kullanmak iyi bir fikirdir, ancak hedef dağıtım ortamınızın desteklediği versiyonu kontrol etmeniz gerekebilir.
* dynamic_axes: Özellikle değişken boyutlu girişlere (örneğin farklı batch boyutları) sahip modeller için kritik öneme sahiptir. Bu, ONNX Runtime’ın farklı giriş boyutlarıyla çalışmasını sağlar.
* input_names ve output_names: Bu isimler, ONNX modelini yüklerken giriş ve çıkış tensörlerini tanımlamak için kullanılır. Açıklayıcı isimler vermek kodu daha okunabilir hale getirir.
TensorFlow/Keras Modellerini ONNX’e Dönüştürme
TensorFlow veya Keras modellerini ONNX’e dönüştürmek için genellikle tf2onnx gibi üçüncü taraf araçlar kullanılır.
Kurulum
pip install tf2onnx onnx
Örnek dönüştürme komutu (bir saved_model için)
python -m tf2onnx.convert --saved-model /path/to/your/saved_model --output model.onnx --opset 17
Keras modelinden dönüştürme
from tf2onnx import convert
model = tf.keras.models.load_model('your_keras_model.h5')
spec = (tf.TensorSpec((None, 224, 224, 3), tf.float32, name="input"),)
output_path = "keras_model.onnx"
model_proto, _ = convert.from_keras(model, input_signature=spec, opset=17, output_path=output_path)
scikit-learn Modellerini ONNX’e Dönüştürme
skl2onnx kütüphanesi, scikit-learn modellerini ONNX’e dönüştürmek için kullanılır.
Kurulum
pip install skl2onnx onnx
Örnek (Logistic Regression)
from sklearn.linear_model import LogisticRegression
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
# # Model eğitme
model = LogisticRegression()
X = [[0., 1.], [1., 1.], [2., 2.]]
y = [0, 1, 0]
model.fit(X, y)
# # ONNX'e dönüştürme
initial_type = [('float_input', FloatTensorType([None, 2]))] # None: batch size
onnx_model = convert_sklearn(model, initial_types=initial_type)
# with open("skl_model.onnx", "wb") as f:
f.write(onnx_model.SerializeToString())
ONNX Runtime ile Çıkarım (Inference)
ONNX Runtime (ORT), ONNX formatındaki modelleri yüksek performansla çalıştırmak için tasarlanmış, çapraz platform bir çıkarım motorudur. Farklı donanım hızlandırıcılarını (CPU, GPU, DSP vb.) destekler ve modeli otomatik olarak optimize ederek en iyi performansı sağlamayı hedefler.
ONNX Runtime Kurulumu
CPU desteği için
pip install onnxruntime
GPU (CUDA) desteği için
pip install onnxruntime-gpu
ONNX Modeli ile Çıkarım Yapma
import onnxruntime as ort
import numpy as np
import torch # Sadece örnek input oluşturmak için
Daha önce kaydettiğimiz ONNX modelini yükleyelim
onnx_path = "simple_model.onnx"
1. ONNX Runtime InferenceSession oluşturalım
providers parametresi ile hangi donanım sağlayıcılarını kullanacağımızı belirleyebiliriz.
Varsayılan olarak 'CPUExecutionProvider' kullanılır.
Eğer GPU varsa: providers=['CUDAExecutionProvider', 'CPUExecutionProvider']
session = ort.InferenceSession(onnx_path, providers=['CPUExecutionProvider'])
2. Modelin giriş ve çıkış isimlerini ve beklediği veri tiplerini alalım
input_name = session.get_inputs()[0].name
output_name = session.get_outputs()[0].name
input_shape = session.get_inputs()[0].shape
input_dtype = session.get_inputs()[0].type
print(f"Model Giriş Adı: {input_name}, Şekil: {input_shape}, Veri Tipi: {input_dtype}")
print(f"Model Çıkış Adı: {output_name}")
3. Giriş verisini hazırlayalım
ONNX Runtime, numpy dizilerini bekler. PyTorch tensörünü numpy'ye dönüştürelim.
Giriş boyutu ve veri tipi modelin beklediği gibi olmalı.
'float32' ONNX'teki 'tensor(float)' ile eşleşir.
input_data = torch.randn(1, 10).numpy().astype(np.float32)
4. Çıkarım (Inference) yapalım
session.run() metoduna çıkış isimleri listesi ve girişler sözlüğü verilir.
Giriş sözlüğü: {giriş_adı: giriş_verisi}
outputs = session.run([output_name], {input_name: input_data})
5. Sonuçları işleyelim
result = outputs[0]
print(f"Çıkarım Sonucu (numpy array): {result}")
print(f"Sonuç Şekli: {result.shape}, Veri Tipi: {result.dtype}")
Eğer birden fazla giriş veya çıkış varsa, get_inputs()/get_outputs() listesini
ve session.run() parametrelerini buna göre ayarlamanız gerekir.
Pratik İpuçları:
* Donanım Sağlayıcıları (providers): ort.InferenceSession oluştururken providers argümanını kullanarak hangi donanım hızlandırıcılarını kullanacağınızı belirtebilirsiniz. Örneğin, CUDA GPU kullanmak için ['CUDAExecutionProvider', 'CPUExecutionProvider'] listesini vermelisiniz. ONNX Runtime listedeki ilk uygun sağlayıcıyı kullanacaktır.
* Oturum Seçenekleri (SessionOptions): ort.SessionOptions() ile çıkarım oturumu üzerinde daha fazla kontrol sağlayabilirsiniz. Örneğin, graph_optimization_level ile grafik optimizasyon seviyesini ayarlayabilir veya intra_op_num_threads ile CPU çekirdek kullanımını yönetebilirsiniz.
* Giriş Verisi: Giriş verisinin NumPy dizisi olması ve modelin beklediği şekil (shape) ve veri tipine (dtype) tam olarak uyması gerektiğini unutmayın. Hatalı veri tipleri veya şekiller session.run() sırasında hataya yol açacaktır.
* Performans Ölçümü: Farklı sağlayıcılar ve oturum seçenekleriyle modelinizin performansını ölçerek en iyi konfigürasyonu bulmanız önemlidir.
ONNX’in Gelişmiş Kullanım Alanları ve Optimizasyon
ONNX, sadece modelleri dönüştürmek ve çalıştırmakla kalmaz, aynı zamanda modelleri daha verimli hale getirmek için çeşitli optimizasyon tekniklerine de olanak tanır.
Model Nicelikleştirme (Quantization)
Nicelikleştirme, modeldeki ağırlıkların ve aktivasyonların hassasiyetini düşürerek (örneğin, 32-bit float’tan 8-bit integer’a) model boyutunu küçültme ve çıkarım hızını artırma işlemidir. Özellikle mobil ve edge cihazlarda dağıtım için kritik bir optimizasyondur. ONNX Runtime, bu işlemi kolaylaştıran araçlar sunar.
Kurulum
pip install onnxruntime onnxruntime-extensions
from onnxruntime.quantization import quantize_dynamic, QuantFormat, onnx_model_utils
Giriş ONNX modelini dinamik nicelikleştirme ile optimize et
model_path = "simple_model.onnx"
quantized_model_path = "simple_model_quantized.onnx"
Dinamik nicelikleştirme (ağırlıklar 8-bit int'e dönüştürülür, aktivasyonlar çalışma zamanında nicelikleştirilir)
quantize_dynamic(
model_input=model_path,
model_output=quantized_model_path,
op_types_to_quantize=['MatMul', 'Gemm'], # Nicelikleştirilecek operatör tipleri
per_channel=False, # Kanal başına nicelikleştirme yapılıp yapılmayacağı
reduce_range=False, # Daha küçük aralıkta nicelikleştirme
format=QuantFormat.QDQ # QDQ formatı (Quantize-Dequantize)
)
print(f"Nicelikleştirilmiş model {quantized_model_path} konumuna kaydedildi.")
Nicelikleştirilmiş modeli test etme
session_quantized = ort.InferenceSession(quantized_model_path, providers=['CPUExecutionProvider'])
input_data = torch.randn(1, 10).numpy().astype(np.float32)
outputs_quantized = session_quantized.run([session_quantized.get_outputs()[0].name],
{session_quantized.get_inputs()[0].name: input_data})
print(f"Nicelikleştirilmiş Model Çıkarım Sonucu: {outputs_quantized[0]}")
Grafik Optimizasyonları
ONNX Runtime, modelleri otomatik olarak optimize etmek için çeşitli grafik optimizasyonları uygular. Bunlar arasında düğüm birleştirme, ölü kod eliminasyonu ve katman füzyonu gibi teknikler bulunur. Bu optimizasyonlar, modelin hesaplama grafiğini basitleştirerek ve gereksiz işlemleri ortadan kaldırarak performansı artırır.
ONNX GraphSurgeon
Daha karmaşık model manipülasyonları için ONNX GraphSurgeon gibi araçlar kullanılabilir. Bu, ONNX grafiklerini programatik olarak düzenlemenize, düğümleri eklemenize, silmenize veya değiştirmenize olanak tanır. Özellikle özel operatörler eklemek veya mevcut operatörleri belirli donanımlara göre özelleştirmek istediğinizde faydalıdır.
Özel Operatörler (Custom Operators)
Eğer modeliniz standart ONNX operatör setinde bulunmayan özel bir katman veya işlem içeriyorsa, ONNX’e özel operatörler ekleyebilirsiniz. Bu, daha karmaşık veya niş modellerin ONNX ekosistemine entegrasyonunu sağlar. Ancak, bu durum genellikle daha fazla geliştirme çabası gerektirir ve dağıtım ortamınızın bu özel operatörleri desteklemesini sağlamanız gerekir.
Pratik İpuçları:
* Dengeyi Bulmak: Optimizasyonlar genellikle doğruluktan (accuracy) ödün vermeyi gerektirebilir. Nicelikleştirme gibi teknikleri uyguladıktan sonra modelinizin performansını ve doğruluğunu dikkatlice test etmelisiniz.
* Profil Oluşturma: Optimizasyon öncesi ve sonrası modelinizin çıkarım süresini ve bellek kullanımını profilleyerek, yapılan değişikliklerin gerçek faydalarını ölçün.
* İteratif Yaklaşım: Optimizasyon süreci genellikle iteratiftir. Küçük adımlarla başlayın, test edin ve gerektiğinde ayarlamalar yapın.
Sonuç ve Sıkça Sorulan Sorular (SSS)
ONNX, makine öğrenimi modellerinin geliştirilmesinden dağıtımına kadar tüm yaşam döngüsünü basitleştiren güçlü ve açık bir standarttır. Framework bağımsızlığı, yüksek performanslı çıkarım yetenekleri ve model optimizasyon araçlarıyla, her ML/AI geliştiricisinin araç setinde bulunması gereken önemli bir bileşendir. ONNX’i anlamak ve kullanmak, modellerinizi daha verimli, taşınabilir ve çeşitli ortamlara kolayca dağıtılabilir hale getirecektir.
Sıkça Sorulan Sorular (SSS)
- ONNX hangi makine öğrenimi framework’lerini destekler?
- ONNX; PyTorch, TensorFlow, Keras, scikit-learn, XGBoost, LightGBM ve daha birçok popüler framework’ü destekler. Desteklenen framework’lerden modelleri ONNX formatına dönüştürmek için ilgili kütüphaneler (örn.
tf2onnx,skl2onnx) kullanılır. - ONNX Runtime neden genellikle orijinal framework’ün çıkarım motorundan daha hızlıdır?
- ONNX Runtime (ORT), C++ ile yazılmış, yüksek performanslı bir çıkarım motorudur. Donanıma özel optimizasyonlar (örn. NVIDIA CUDA, Intel OpenVINO), gelişmiş grafik optimizasyonları ve verimli bellek yönetimi sayesinde, genellikle orijinal framework’lerin Python tabanlı çıkarım süreçlerinden daha hızlı çalışır.
- ONNX modelimi nasıl görselleştirebilirim?
- Netron, ONNX modellerini görselleştirmek için popüler ve ücretsiz bir araçtır. Modelin hesaplama grafiğini, operatörlerini, giriş/çıkış tensörlerini ve ağırlıklarını detaylı bir şekilde görmenizi sağlar.
- Her makine öğrenimi modeli ONNX’e dönüştürülebilir mi?
- Çoğu standart derin öğrenme ve geleneksel makine öğrenimi modeli ONNX’e başarıyla dönüştürülebilir. Ancak, çok özel veya deneysel operatörler içeren modeller için dönüştürme işlemi ek çaba gerektirebilir veya özel operatörlerin ONNX’e manuel olarak eklenmesini gerektirebilir.
- ONNX ile ilgili daha fazla kaynak nerede bulabilirim?
-
- Resmi ONNX GitHub deposu: github.com/onnx/onnx
- ONNX Runtime belgeleri: onnxruntime.ai
- Netron: netron.app
- İlgili framework’lerin (PyTorch, TensorFlow) ONNX export belgeleri.
