YOLO Vision 2026:

كيفية تصدير نماذج PyTorch غير التابعة لـ YOLO باستخدام Ultralytics#

توفر Ultralytics أدوات تصدير مستقلة ضمن ultralytics.utils.export التي تغلف خوادم خلفية متعددة وراء واجهة متسقة واحدة. يمكنك تصدير أي torch.nn.Module، بما في ذلك نماذج الصور timm، ومصنفات وكواشف torchvision، أو بنياتك المخصصة، إلى ONNX، وTorchScript، وOpenVINO، وCoreML، وNCNN، وPaddlePaddle، وMNN، وExecuTorch، وCore AI، وTensorFlow SavedModel، وTensorFlow Frozen Graph دون الحاجة إلى تعلم كل خادم خلفي على حدة.

يتطلب نشر نماذج PyTorch في بيئة الإنتاج عادةً التعامل مع مُصدِّر مختلف لكل هدف: torch.onnx.export لـ ONNX، وcoremltools لأجهزة Apple، وonnx2tf لـ TensorFlow، وpnnx لـ NCNN، وغير ذلك. لكل أداة واجهة API خاصة بها، وتفاصيل مختلفة للتبعيات، واصطلاحات خاصة بالمخرجات. وتختصر هذه الأدوات كل ذلك في نمط استدعاء واحد.

لماذا تستخدم Ultralytics لتصدير النماذج غير التابعة لـ YOLO؟#

  • واجهة برمجة تطبيقات واحدة عبر 11 تنسيقاً: تعلم اصطلاح استدعاء واحد بدلاً من عشرات الاصطلاحات.
  • مجموعة أدوات مشتركة: توجد مساعدات التصدير ضمن ultralytics.utils.export، لذلك يمكنك، بعد تثبيت حزم الخلفيات، الاحتفاظ بنمط الاستدعاء نفسه عبر التنسيقات المختلفة.
  • مسار الشيفرة نفسه المستخدم في عمليات تصدير YOLO: تشغّل المساعدات نفسها جميع عمليات تصدير Ultralytics YOLO.
  • تكميم FP16 و INT8 مدمج للتنسيقات التي تدعمه (OpenVINO و CoreML و MNN؛ و FP16 فقط لـ NCNN و Core AI).
  • يعمل على وحدة المعالجة المركزية (CPU): لا توجد حاجة لوحدة معالجة رسومية (GPU) لخطوة التصدير نفسها، لذا يمكنك تشغيلها محلياً على جهاز كمبيوتر محمول؛ ولا يتم دعم تصدير CoreML على Windows، ويتطلب تصدير Core AI نظام macOS 26 أو أحدث على أجهزة Apple silicon.

بدء سريع#

أسرع مسار هو التصدير إلى ONNX في سطرين، من دون شيفرة YOLO ومن دون إعداد يتجاوز pip install ultralytics onnx timm:

import timm
import torch

from ultralytics.utils.export import torch2onnx

model = timm.create_model("resnet18", pretrained=True).eval()
torch2onnx(model, torch.randn(1, 3, 224, 224), output_file="resnet18.onnx")

تنسيقات التصدير المدعومة#

تأخذ دوال torch2* كائن torch.nn.Module قياسيًا وموتر إدخال نموذجيًا. يمر تصدير MNN وTF SavedModel وTF Frozen Graph عبر مُصطنَع وسيط بتنسيق ONNX أو Keras. ولا تُشترط سمات خاصة بـ YOLO في أي من الحالتين.

التنسيقالدالةالتثبيتالمخرجات
ONNXtorch2onnx()pip install onnxملف .onnx
TorchScripttorch2torchscript()مضمّن مع PyTorchملف .torchscript
OpenVINOtorch2openvino()pip install openvinoمجلد _openvino_model/
CoreMLtorch2coreml()pip install coremltools.mlpackage
TF SavedModelonnx2saved_model()راجع المتطلبات التفصيلية أدناهمجلد _saved_model/
TF Frozen Graphkeras2pb()راجع المتطلبات التفصيلية أدناهملف .pb
NCNNtorch2ncnn()pip install ncnn pnnxمجلد _ncnn_model/
MNNonnx2mnn()pip install MNNملف .mnn
PaddlePaddletorch2paddle()pip install paddlepaddle x2paddleمجلد _paddle_model/
ExecuTorchtorch2executorch()pip install executorchمجلد _executorch_model/
Core AItorch2coreai()pip install coreai-torch (نظام macOS 26 أو أحدث على أجهزة Apple silicon)مجلد .aimodel
ONNX كتنسيق وسيط

تمر عمليات تصدير MNN وTF SavedModel وTF Frozen Graph عبر ONNX كخطوة وسيطة. صدّر إلى ONNX أولًا، ثم حوّل.

تضمين البيانات الوصفية

تقبل عدة دوال تصدير قاموس metadata اختياريًا (مثل torch2torchscript(..., metadata={"author": "me"})) يضمّن أزواجًا مخصّصة من المفتاح والقيمة في المُصطنَع المُصدَّر عندما يدعم التنسيق ذلك.

أمثلة خطوة بخطوة#

يستخدم كل مثال أدناه الإعداد نفسه، وهو ResNet-18 مُدرَّب مسبقًا من timm في وضع التقييم:

import timm
import torch

model = timm.create_model("resnet18", pretrained=True).eval()
im = torch.randn(1, 3, 224, 224)
استدعِ دائمًا `model.eval()` قبل التصدير

تتصرف طبقات Dropout وتطبيع الدفعة وغيرها من الطبقات الخاصة بالتدريب فقط بصورة مختلفة أثناء الاستدلال. يؤدي تخطي .eval() إلى إنشاء عمليات تصدير ذات مخرجات غير صحيحة.

التصدير إلى ONNX#

from ultralytics.utils.export import torch2onnx

torch2onnx(model, im, output_file="resnet18.onnx")

للحصول على حجم دفعة ديناميكي، مرّر قاموس dynamic:

torch2onnx(model, im, output_file="resnet18_dyn.onnx", dynamic={"images": {0: "batch_size"}})

قيمة opset الافتراضية هي 14، واسم الإدخال الافتراضي هو "images". يمكنك تجاوزهما باستخدام الوسائط opset أو input_names أو output_names.

التصدير إلى TorchScript#

لا حاجة إلى تبعيات إضافية. يستخدم torch.jit.trace داخليًا.

from ultralytics.utils.export import torch2torchscript

torch2torchscript(model, im, output_file="resnet18.torchscript")

التصدير إلى OpenVINO#

from ultralytics.utils.export import torch2openvino

ov_model = torch2openvino(model, im, output_dir="resnet18_openvino_model")

يحتوي المجلد على زوج ذي اسم ثابت، هما model.xml وmodel.bin:

resnet18_openvino_model/
├── model.xml
└── model.bin

مرّر dynamic=True لأشكال الإدخال الديناميكية، أو quantize=16 لـ FP16، أو quantize=8 لتكميم INT8. ويتطلب INT8 أيضًا الوسيطة calibration_dataset.

يتطلب openvino>=2024.0.0 (أو >=2025.2.0 على macOS 15.4 والإصدارات الأحدث) وtorch>=2.1.

التصدير إلى CoreML#

import coremltools as ct

from ultralytics.utils.export import torch2coreml

inputs = [ct.TensorType("input", shape=(1, 3, 224, 224))]
ct_model = torch2coreml(model, inputs, im, classifier_names=None, output_file="resnet18.mlpackage")

بالنسبة إلى نماذج التصنيف، مرّر قائمة بأسماء الفئات إلى classifier_names لإضافة رأس تصنيف إلى نموذج CoreML.

يتطلب coremltools>=9.0 وtorch>=1.11 وnumpy<=2.3.5. ولا يُدعم على Windows.

خطأ `BlobWriter not loaded`

يوفّر coremltools>=9.0 حزم wheels لـ Python 3.10–3.13 على macOS وLinux. في إصدارات Python الأحدث، يتعذر تحميل امتداد C الأصلي. استخدم Python 3.10–3.13 لتصدير CoreML.

التصدير إلى TensorFlow SavedModel#

يمر تصدير TF SavedModel عبر ONNX كخطوة وسيطة:

from ultralytics.utils.export import onnx2saved_model, torch2onnx

torch2onnx(model, im, output_file="resnet18.onnx")
keras_model = onnx2saved_model("resnet18.onnx", output_dir="resnet18_saved_model")

تعيد الدالة نموذج Keras، كما تنشئ ملفات LiteRT بتنسيقي FP32 وFP16 (.tflite) داخل مجلد الإخراج:

resnet18_saved_model/
├── saved_model.pb
├── variables/
├── assets/
├── fingerprint.pb
├── resnet18_float32.tflite
└── resnet18_float16.tflite

مرّر quantize=8 لإضافة .tflite بتنسيق INT8 إلى جانبها.

المتطلبات:

  • tensorflow>=2.0.0,<=2.19.0
  • onnx2tf>=1.26.3,<1.29.0
  • tf_keras<=2.19.0
  • sng4onnx>=1.0.1
  • onnx_graphsurgeon>=0.3.26
  • ai-edge-litert>=1.2.0,<1.4.0 على macOS (وai-edge-litert>=1.2.0 على الأنظمة الأساسية الأخرى)
  • onnxslim>=0.1.82
  • onnx>=1.12.0,<2.0.0
  • protobuf>=5

التصدير إلى TensorFlow Frozen Graph#

استمرارًا من عملية تصدير SavedModel أعلاه، حوّل keras_model المُعاد إلى رسم بياني .pb مُجمَّد:

from pathlib import Path

from ultralytics.utils.export import keras2pb

keras2pb(keras_model, output_file=Path("resnet18_saved_model/resnet18.pb"))

التصدير إلى NCNN#

from ultralytics.utils.export import torch2ncnn

torch2ncnn(model, im, output_dir="resnet18_ncnn_model")

يحتوي المجلد على ملفات param وbin ذات أسماء ثابتة، إلى جانب غلاف Python:

resnet18_ncnn_model/
├── model.ncnn.param
├── model.ncnn.bin
└── model_ncnn.py

يفحص torch2ncnn() وجود ncnn وpnnx عند الاستخدام الأول.

التصدير إلى MNN#

يتطلب تصدير MNN ملف ONNX كإدخال. صدّر إلى ONNX أولًا، ثم حوّل:

from ultralytics.utils.export import onnx2mnn, torch2onnx

torch2onnx(model, im, output_file="resnet18.onnx")
onnx2mnn("resnet18.onnx", output_file="resnet18.mnn")

يدعم quantize=16 لـ FP16 وquantize=8 لتكميم INT8. ويتطلب MNN>=2.9.6 وtorch>=1.10.

التصدير إلى PaddlePaddle#

from ultralytics.utils.export import torch2paddle

torch2paddle(model, im, output_dir="resnet18_paddle_model")

يحتوي المجلد على نموذج PaddlePaddle وملفات المعلمات:

resnet18_paddle_model/
├── model.pdmodel
└── model.pdiparams

يتطلب x2paddle وتوزيعة PaddlePaddle الصحيحة لمنصتك:

  • paddlepaddle-gpu>=3.0.0,<3.3.0 على CUDA
  • paddlepaddle==3.0.0 على CPU بمعمارية ARM64
  • paddlepaddle>=3.0.0,<3.3.0 على وحدات CPU الأخرى

غير مدعوم على NVIDIA Jetson.

التصدير إلى ExecuTorch#

from ultralytics.utils.export import torch2executorch

torch2executorch(model, im, output_dir="resnet18_executorch_model")

يُحفَظ ملف .pte المُصدَّر داخل مجلد الإخراج:

resnet18_executorch_model/
└── model.pte

يتطلب torch>=2.9.0 وبيئة تشغيل ExecuTorch مطابقة (pip install executorch). لاستخدام بيئة التشغيل، راجع تكامل ExecuTorch.

التصدير إلى Core AI#

from ultralytics.utils.export import torch2coreai

torch2coreai(model, im, output_file="resnet18.aimodel")

أصل .aimodel عبارة عن دليل:

resnet18.aimodel/
├── main.mlirb
├── main.hash
└── metadata.json

يتم تشغيل التصدير على نظام macOS 26 أو أحدث على أجهزة Apple silicon (pip install coreai-torch)، ويكتب quantize=16 أصل FP16 يأخذ مدخلات float16؛ ويعمل الأصل على iOS 27 و macOS 27. راجع تكامل Core AI، بما في ذلك ملاحظته حول أصول FP16 التي تتوقف عن العمل عند التحميل.

التحقق من النموذج المُصدَّر#

بعد التصدير، تحقّق من التكافؤ العددي مع نموذج PyTorch الأصلي قبل الشحن. يقارن اختبار دخان سريع باستخدام ONNXBackend من ultralytics.nn.backends المخرجات، ويكشف أخطاء التتبع أو التكميم مبكرًا:

import numpy as np
import timm
import torch

from ultralytics.nn.backends import ONNXBackend

model = timm.create_model("resnet18", pretrained=True).eval()
im = torch.randn(1, 3, 224, 224)
with torch.no_grad():
    pytorch_output = model(im).numpy()

onnx_model = ONNXBackend("resnet18.onnx", device=torch.device("cpu"))
onnx_output = onnx_model(im)[0]

diff = np.abs(pytorch_output - onnx_output).max()
print(f"Max difference: {diff:.6f}")  # ~1e-6 for an FP32 ONNX export
الفرق المتوقع

التسامح خاص بكل تنسيق وليس عالميًا. في ResNet-18، تقترب عمليات التصدير FP32 من 1e-6 في ONNX وTF SavedModel وLiteRT، وتساوي تمامًا 0 في TorchScript. وتُعد NCNN الحالة الشاذة، إذ يبلغ الفرق فيها نحو 1e-2: فبيئة تشغيل CPU الخاصة بها تفعّل حزم FP16 والحساب به افتراضيًا، لذا يظل التصدير FP32 يعمل بدقة نصفية. ويشير الفرق الذي يتجاوز خط الأساس الخاص بالتنسيق بدرجة كبيرة إلى عمليات غير مدعومة، أو شكل إدخال خاطئ، أو أن النموذج ليس في وضع التقييم. تتمتع عمليات تصدير FP16 وINT8 بتفاوتات أكبر. تحقّق باستخدام بيانات حقيقية بدلًا من موترات عشوائية.

قد يختلف اسم موتر الإدخال في بيئات التشغيل الأخرى. فعلى سبيل المثال، يستخدم OpenVINO اسم وسيطة forward الخاصة بالنموذج (وعادةً ما تكون x في النماذج العامة)، بينما تكون القيمة الافتراضية لـ torch2onnx هي "images".

تشغيل النموذج المُصدَّر#

تُحمَّل النماذج غير التابعة لـ YOLO المُصدَّرة مجددًا عبر واجهة API العادية YOLO(). ولا تتضمن عمليات التصدير أعلاه بيانات وصفية لمهمة Ultralytics أو لحجم الإدخال، لذا مرّر task صراحةً وimgsz المطابق لموتر المثال الذي صدّرت النموذج باستخدامه:

from ultralytics import YOLO

results = YOLO("resnet18.onnx", task="classify")("path/to/image.jpg", imgsz=224)
print(results[0].probs.top1)

يهم imgsz عندما يكون للتصدير شكل إدخال ثابت: إذ ترفض عمليات تصدير ONNX وTF SavedModel أعلاه القيمة الافتراضية 640. وتقبل عمليات تصدير TorchScript وNCNN أعلاه أحجامًا أخرى، لكن لا يضمن أيٌّ من المُصدِّرَين ذلك: فكلاهما يتتبع انطلاقًا من موتر المثال، ولذلك يظل النموذج الذي يُسطّح إلى طبقة Linear ثابتًا. تحقّق من عملية التصدير الخاصة بك.

تُقرَّب القيمة بعد ذلك إلى الأعلى لتصبح من مضاعفات خطوة النموذج، وهي 32 من دون بيانات وصفية. ولذلك يُمرَّر تصدير ذو شكل ثابت بحجم 200x200 على أنه 224x224 ويُرفض، رغم أن imgsz=200 يطابقه. وبالنسبة إلى أحجام الإدخال التي ليست من مضاعفات 32، استدعِ الخلفية مباشرةً.

استدعاء خلفية مباشرةً#

بالنسبة إلى الموترات الخام من دون المعالجة المسبقة والمعالجة اللاحقة الخاصة بـ Ultralytics، استخدم الفئات الخاصة بكل تنسيق في ultralytics.nn.backends، كما يفعل مثال التحقق أعلاه. يأخذ كل منها المُصطنَع المُصدَّر وجهازًا، ويمكن استدعاؤه:

التنسيقالخلفيةتخطيط الإدخال
ONNXONNXBackendBCHW
TorchScriptTorchScriptBackendBCHW
OpenVINOOpenVINOBackendBCHW
CoreMLCoreMLBackendBHWC
TF SavedModel، وFrozen GraphTensorFlowBackendBHWC
LiteRTLiteRTBackendBCHW
NCNNNCNNBackendBCHW
PaddlePaddlePaddleBackendBCHW
MNNMNNBackendBCHW
ExecuTorchExecuTorchBackendBCHW
Core AICoreAIBackendBCHW

يغطي TensorFlowBackend تنسيقين، وتكون قيمته الافتراضية format="saved_model"، لذا مرّر format="pb" من أجل رسم بياني مجمّد.

ثلاثة أمور يتولاها مسار YOLO() نيابةً عنك ولا يتولاها الاستدعاء المباشر:

  • تخطيط الإدخال: يتوقع CoreMLBackend وTensorFlowBackend تنسيق BHWC. أجرِ التحويل transpose أولًا باستخدام im.permute(0, 2, 3, 1)؛ إذ يؤدي موتر BCHW إلى عدم تطابق في الشكل.
  • Autograd: غلّف الاستدعاءات داخل torch.inference_mode(). يعيد TorchScriptBackend موترًا لا يزال يحمل رسمًا بيانيًا لـ التدرج.
  • المعالجة اللاحقة: من دون بيانات وصفية، تُبقي الخلفية task على هيئة None، وتترك names فارغة. يظل LiteRTBackend يلغي التطبيع لأي مخرج ثلاثي الأبعاد وفق حجم الصورة، بافتراض أنه يحتوي على مربعات YOLO، وهذا غير صحيح لنموذج غير تابع لـ YOLO ذي مخرج ثلاثي الأبعاد. ولا تتأثر المخرجات ثنائية الأبعاد، مثل قيم logits الخاصة بالمصنّف.

القيود المعروفة#

  • دعم المدخلات المتعددة غير متساوٍ: يقبل torch2onnx و torch2openvino صفاً أو قائمة من موترات الأمثلة للنماذج ذات المدخلات المتعددة. يفترض كل من torch2torchscript و torch2coreml و torch2ncnn و torch2paddle و torch2executorch و torch2coreai موتر إدخال واحداً.
  • يتطلب ExecuTorch الأمر flatc: تتطلب بيئة تشغيل ExecuTorch مُصرِّف FlatBuffers. ثبّته باستخدام brew install flatbuffers على macOS أو apt install flatbuffers-compiler على Ubuntu.
  • لا توجد بيانات وصفية مضمنة: لا تتضمن عمليات التصدير أعلاه بيانات وصفية لمهمة Ultralytics أو لحجم الإدخال، لذا لا يستطيع YOLO() استنتاج أيٍّ منهما، ويتطلب تمرير كليهما صراحةً. راجع تشغيل النموذج المُصدَّر.
  • تنسيقات YOLO فقط: تتطلب صادرات Axelera وSony IMX500 سمات نموذج خاصة بـ YOLO، ولا تتوفر للنماذج العامة.
  • التنسيقات الخاصة بالمنصة: يتطلب TensorRT وحدة معالجة رسومات NVIDIA. ويتطلب RKNN حزمة SDK ‏rknn-toolkit2 (Linux فقط). ويتطلب Edge TPU الملف الثنائي ‏edgetpu_compiler (Linux فقط).

الخلاصة#

تأخذ هذه الأدوات أي نموذج PyTorch بدءًا من torch.nn.Module عادي وتحوله إلى ناتج ONNX أو OpenVINO أو CoreML أو TensorFlow أو بيئة تشغيل للهواتف المحمولة جاهز للنشر، وذلك عبر API موحّد. اختر التنسيق المتوافق مع العتاد المستهدف، ثم تحقق من التكافؤ العددي مقارنةً بالنموذج الأصلي، واتبع دليل التكامل المطابق لخطوات النشر الخاصة ببيئة التشغيل.

الأسئلة الشائعة#

  • أي torch.nn.Module. ويشمل ذلك النماذج من timm وtorchvision وأي نموذج PyTorch مخصص. يجب أن يكون النموذج في وضع التقييم (model.eval()) قبل التصدير. يقبل كل من ONNX وOpenVINO أيضًا صفيفًا من موترات الأمثلة للنماذج متعددة المدخلات.

  • يمكن لجميع التنسيقات المدعومة (TorchScript و ONNX و OpenVINO و CoreML و TF SavedModel و TF Frozen Graph و NCNN و PaddlePaddle و MNN و ExecuTorch و Core AI) التصدير على وحدة المعالجة المركزية (CPU). لا يلزم وجود وحدة معالجة رسومية (GPU) لعملية التصدير نفسها. TensorRT هو التنسيق الوحيد الذي يتطلب وحدة معالجة رسومية (GPU) من NVIDIA.

  • استخدم Ultralytics >=8.4.38، الذي يتضمن الوحدة ultralytics.utils.export والوسيطين المعياريين output_file/output_dir.

  • نعم. يمكن تصدير نماذج التصنيف والكشف والتقسيم من torchvision إلى .mlpackage عبر torch2coreml. بالنسبة إلى نماذج تصنيف الصور، مرّر قائمة بأسماء الفئات إلى classifier_names لدمج رأس تصنيف. نفّذ التصدير على macOS أو Linux. لا يحظى CoreML بالدعم على Windows. راجع تكامل CoreML للحصول على تفاصيل النشر على iOS.

  • نعم، لعدة تنسيقات. قم تمرير quantize=16 لـ FP16 أو quantize=8 لـ INT8 عند التصدير إلى OpenVINO أو CoreML أو MNN؛ ويقوم تصدير NCNN و Core AI بتصدير FP32 افتراضياً، ويأخذ quantize=16 لـ FP16، وليس له مسار INT8. يتطلب INT8 في OpenVINO بالإضافة إلى ذلك وسيطة calibration_dataset من أجل التكميم لاحق التدريب. راجع صفحة تكامل كل تنسيق لمعرفة مقايضات التكميم.

  • شغّل نموذج PyTorch الأصلي والنموذج المُصدَّر على الإدخال نفسه، ثم قارن المخرجات. حمّل الملف المُصدَّر باستخدام الواجهة الخلفية المطابقة (على سبيل المثال، ONNXBackend لـ ONNX) وتحقق من أكبر فرق مطلق. قيّم الفجوة مقارنةً بخط الأساس الخاص بالتنسيق. في مثال ResNet-18 أعلاه، تكون نماذج FP32 ONNX وTF SavedModel وLiteRT قريبة من 1e-6، بينما يكون TorchScript عند 0، ويكون NCNN قريبًا من 1e-2 لأن بيئة تشغيله على CPU تستخدم FP16 افتراضيًا. تشير فجوة أكبر بكثير إلى عمليات غير مدعومة، أو شكل إدخال غير صحيح، أو نموذج ليس في وضع التقييم. راجع التحقق من النموذج المُصدَّر للاطلاع على مثال قابل للتشغيل.

التعليقات