رؤية YOLO لعام 2026:

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

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

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

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

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

بدء التشغيل السريع#

المسار الأسرع هو التصدير في خطوتين إلى 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/
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 وbatch normalization وغيرها من الطبقات الخاصة بالتدريب بشكل مختلف أثناء الاستدلال. يؤدي تخطي .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"}})

مجموعة العمليات الافتراضية هي 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 وتُنشئ أيضاً ملفات TFLite (.tflite) داخل مجلد الإخراج:

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

المتطلبات:

  • 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 على وحدة المعالجة المركزية ARM64
  • paddlepaddle>=3.0.0,<3.3.0 على وحدات المعالجة المركزية الأخرى

غير مدعوم على 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.

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

بعد التصدير، تحقق من التكافؤ العددي مع نموذج 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}")  # typically ~1e-5, well under 1e-4 for FP32
الفرق المتوقع

بالنسبة لصادرات FP32، يكون الحد الأقصى للفرق المطلق عادةً حوالي 1e-5 ويجب أن يظل أقل بكثير من 1e-4. تشير الفروق الأكبر إلى عمليات غير مدعومة، أو شكل إدخال خاطئ، أو نموذج ليس في وضع التقييم. تتمتع صادرات FP16 وINT8 بنسب تسامح أكثر مرونة. تحقق من البيانات الحقيقية بدلاً من التنسورات العشوائية.

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

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

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

الخلاصة#

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

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

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

  • جميع التنسيقات المدعومة (TorchScript، ONNX، OpenVINO، CoreML، TF SavedModel، TF Frozen Graph، NCNN، PaddlePaddle، MNN، ExecuTorch) يمكن تصديرها على وحدة المعالجة المركزية (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. يتطلب تنسيق INT8 في OpenVINO بالإضافة إلى ذلك وسيط calibration_dataset لـ تقدير الكمية بعد التدريب. راجع صفحة التكامل الخاصة بكل تنسيق لمعرفة المفاضلات المتعلقة بتقدير الكمية.

  • قم بتشغيل نموذج PyTorch الأصلي والنموذج المُصدَّر على نفس المدخلات، ثم قارن المخرجات. قم بتحميل الملف المُصدَّر باستخدام الواجهة الخلفية المطابقة (على سبيل المثال، ONNXBackend لتنسيق ONNX) وتحقق من الحد الأقصى للفرق المطلق. بالنسبة لصادرات FP32، يكون عادةً حوالي 1e-5 ويجب أن يظل أقل بكثير من 1e-4؛ وتشير الفجوات الأكبر إلى عمليات غير مدعومة، أو شكل إدخال خاطئ، أو نموذج ليس في وضع التقييم. راجع التحقق من نموذجك المُصدَّر للاطلاع على مثال قابل للتنفيذ.

التعليقات