كيفية تصدير نماذج 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 في أي من الحالتين.
| التنسيق | الدالة | التثبيت | المخرجات |
|---|---|---|---|
| ONNX | torch2onnx() | pip install onnx | ملف .onnx |
| TorchScript | torch2torchscript() | مضمّن مع PyTorch | ملف .torchscript |
| OpenVINO | torch2openvino() | pip install openvino | مجلد _openvino_model/ |
| CoreML | torch2coreml() | pip install coremltools | .mlpackage |
| TF SavedModel | onnx2saved_model() | راجع المتطلبات التفصيلية أدناه | مجلد _saved_model/ |
| TF Frozen Graph | keras2pb() | راجع المتطلبات التفصيلية أدناه | ملف .pb |
| NCNN | torch2ncnn() | pip install ncnn pnnx | مجلد _ncnn_model/ |
| MNN | onnx2mnn() | pip install MNN | ملف .mnn |
| PaddlePaddle | torch2paddle() | pip install paddlepaddle x2paddle | مجلد _paddle_model/ |
| ExecuTorch | torch2executorch() | pip install executorch | مجلد _executorch_model/ |
| Core AI | torch2coreai() | pip install coreai-torch (نظام macOS 26 أو أحدث على أجهزة Apple silicon) | مجلد .aimodel |
تمر عمليات تصدير 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)تتصرف طبقات 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.
يوفّر 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.0onnx2tf>=1.26.3,<1.29.0tf_keras<=2.19.0sng4onnx>=1.0.1onnx_graphsurgeon>=0.3.26ai-edge-litert>=1.2.0,<1.4.0على macOS (وai-edge-litert>=1.2.0على الأنظمة الأساسية الأخرى)onnxslim>=0.1.82onnx>=1.12.0,<2.0.0protobuf>=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على CUDApaddlepaddle==3.0.0على CPU بمعمارية ARM64paddlepaddle>=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، كما يفعل مثال التحقق أعلاه. يأخذ كل منها المُصطنَع المُصدَّر وجهازًا، ويمكن استدعاؤه:
| التنسيق | الخلفية | تخطيط الإدخال |
|---|---|---|
| ONNX | ONNXBackend | BCHW |
| TorchScript | TorchScriptBackend | BCHW |
| OpenVINO | OpenVINOBackend | BCHW |
| CoreML | CoreMLBackend | BHWC |
| TF SavedModel، وFrozen Graph | TensorFlowBackend | BHWC |
| LiteRT | LiteRTBackend | BCHW |
| NCNN | NCNNBackend | BCHW |
| PaddlePaddle | PaddleBackend | BCHW |
| MNN | MNNBackend | BCHW |
| ExecuTorch | ExecuTorchBackend | BCHW |
| Core AI | CoreAIBackend | BCHW |
يغطي 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 افتراضيًا. تشير فجوة أكبر بكثير إلى عمليات غير مدعومة، أو شكل إدخال غير صحيح، أو نموذج ليس في وضع التقييم. راجع التحقق من النموذج المُصدَّر للاطلاع على مثال قابل للتشغيل.