كيفية تصدير نماذج PyTorch غير المعتمدة على YOLO باستخدام Ultralytics#
توفر Ultralytics أدوات تصدير مستقلة ضمن ultralytics.utils.export، وتجمع هذه الأدوات عدة واجهات خلفية ضمن واجهة موحدة. يمكنك تصدير أي torch.nn.Module، بما في ذلك نماذج الصور من timm، ونماذج التصنيف والكشف من torchvision، أو البنى المخصصة الخاصة بك، إلى TorchScript، وONNX، وOpenVINO، وCoreML، وCore AI، وTensorFlow SavedModel، وTensorFlow Frozen Graph، وPaddlePaddle، وMNN، وNCNN، وExecuTorch، دون الحاجة إلى تعلّم كيفية استخدام كل واجهة خلفية على حدة.
يتطلب نشر نماذج PyTorch في بيئة الإنتاج عادةً التعامل مع أداة تصدير مختلفة لكل وجهة: torch.onnx.export لـ ONNX، وcoremltools لأجهزة Apple، وonnx2tf لـ TensorFlow، وpnnx لـ NCNN، وغير ذلك. لكل أداة واجهة API خاصة بها، ومتطلبات تبعيات مختلفة، واصطلاحات خاصة بالمخرجات. تجمع هذه الأدوات كل ذلك ضمن نمط استدعاء واحد.
لماذا تستخدم Ultralytics لتصدير النماذج غير المعتمدة على YOLO؟#
- واجهة API واحدة عبر 11 تنسيقًا: تعلّم اصطلاحًا واحدًا للاستدعاء بدلًا من اثني عشر.
- مسار التنفيذ نفسه المستخدم في عمليات تصدير YOLO: تشغّل الأدوات المساعدة نفسها جميع عمليات تصدير Ultralytics YOLO.
- التكميم بـ FP16 وINT8 عبر وسيطة واحدة
quantizeللتنسيقات التي تدعمه. - يعمل على CPU: لا حاجة إلى GPU لخطوة التصدير نفسها، لذا يمكنك تشغيلها محليًا على حاسوب محمول؛ تصدير CoreML غير مدعوم على Windows، ويتطلب تصدير Core AI نظام macOS 26 أو أحدث على أجهزة Apple silicon، أو Linux بمعمارية x86_64 مع glibc 2.34 أو أحدث، وPython من الإصدار 3.11 إلى 3.14.
البدء السريع#
أسرع طريقة هي التصدير إلى [ONNX](https://ultralytics-translation-0.invalid في سطرين، دون استخدام شيفرة 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.
| التنسيق | الدالة | التثبيت | المخرجات |
|---|---|---|---|
| TorchScript | torch2torchscript() | مضمّنة مع PyTorch | ملف .torchscript |
| ONNX | torch2onnx() | pip install onnx | ملف .onnx |
| OpenVINO | torch2openvino() | pip install openvino | دليل _openvino_model/ |
| CoreML | torch2coreml() | pip install coremltools | .mlpackage |
| Core AI | torch2coreai() | pip install coreai-torch (Apple silicon macOS 26+، أو Linux بمعمارية x86_64 مع glibc 2.34+؛ Python 3.11-3.14) | دليل .aimodel |
| TF SavedModel | onnx2saved_model() | راجع المتطلبات التفصيلية أدناه | دليل _saved_model/ |
| TF Frozen Graph | keras2pb() | راجع المتطلبات التفصيلية أدناه | ملف .pb |
| PaddlePaddle | torch2paddle() | pip install paddlepaddle x2paddle | دليل _paddle_model/ |
| MNN | onnx2mnn() | pip install MNN | ملف .mnn |
| NCNN | torch2ncnn() | pip install ncnn pnnx | دليل _ncnn_model/ |
| ExecuTorch | torch2executorch() | pip install executorch | دليل _executorch_model/ |
تقبل عدة دوال تصدير قاموس 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.
التصدير إلى 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، أو على Linux بمعمارية x86_64 مع glibc 2.34 أو أحدث، وباستخدام Python من الإصدار 3.11 إلى 3.14 (pip install coreai-torch)، وتكتب quantize=16 أصلًا يستخدم مدخلات float16؛ ويعمل الأصل على iOS 27 وmacOS 27. راجع تكامل Core AI، بما في ذلك ملاحظته بشأن أصول FP16 التي تتوقف عند التحميل.
التصدير إلى 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 على macOS باستخدام Python 3.13 أو أحدث؛ استخدم Python 3.12 أو إصدارًا أقدم على macOS، أو استخدم Linux.
المتطلبات عند استخدام Python 3.12 أو إصدار أقدم (في Python 3.13 أو أحدث، يتطلب التصدير tensorflow>2.19.0 وtf_keras>2.19.0 و
onnx2tf>=2.3.0,<2.3.16 وprotobuf>=6.31.1,<7.0.0 بدلًا من ذلك):
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التصدير إلى 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/
├── inference_model/
│ ├── model.json
│ └── model.pdiparams
├── model.pdparams
└── x2paddle_code.pyيتطلب 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.
التحقق من النموذج المُصدَّر#
بعد التصدير، تحقّق من التطابق العددي مع نموذج 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-5 من PyTorch، وتطابق TorchScript النتائج تمامًا. ومع ذلك، يمكن لثلاثة محركات تشغيل حساب تصدير FP32 بدقة مخفّضة، وتحقيق نتائج قريبة من 1e-2 إلى 1e-1: يفعّل NCNN العمليات الحسابية FP16 على وحدات CPU التي تدعمها، وتحمل MNNBackend النماذج باستخدام precision="low"، بينما تعمل إضافة OpenVINO CPU تلقائيًا بدقة FP16 ضمن وضع التنفيذ الافتراضي PERFORMANCE على بعض الأجهزة، مثل Apple silicon. يشير اختلاف أكبر بكثير من خط الأساس الخاص بالتنسيق إلى عمليات غير مدعومة، أو شكل إدخال غير صحيح، أو أن النموذج ليس في وضع التقييم. وتسمح عمليات التصدير 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 عند عدم وجود بيانات وصفية. لذلك، يُمرَّر حجم 224x224 إلى نموذج مُصدَّر ذي شكل ثابت بحجم 200x200، فيُرفض رغم تطابق imgsz=200 معه. للأحجام التي لا تقبل القسمة على 32، استدعِ الواجهة الخلفية مباشرةً.
الاستدعاء المباشر لواجهة خلفية#
للتعامل مع الموترات الخام دون [المعالجة المسبقة](https://ultralytics-translation-0.invalid والمعالجة اللاحقة من Ultralytics، استخدم الفئات الخاصة بكل تنسيق في ultralytics.nn.backends، كما في مثال التحقق أعلاه. تأخذ كل فئة الملف المُصدَّر والجهاز، ويمكن استدعاؤها مباشرةً:
| التنسيق | الواجهة الخلفية | تخطيط الإدخال |
|---|---|---|
| TorchScript | TorchScriptBackend | BCHW |
| ONNX | ONNXBackend | BCHW |
| OpenVINO | OpenVINOBackend | BCHW |
| CoreML | CoreMLBackend | BHWC |
| Core AI | CoreAIBackend | BCHW |
| TF SavedModel وFrozen Graph | TensorFlowBackend | BHWC |
| LiteRT | LiteRTBackend | BCHW |
| PaddlePaddle | PaddleBackend | BCHW |
| MNN | MNNBackend | BCHW |
| NCNN | NCNNBackend | BCHW |
| ExecuTorch | ExecuTorchBackend | BCHW |
يتعامل TensorFlowBackend مع تنسيقين، ويستخدم افتراضيًا format="saved_model"؛ لذا مرّر format="pb" لاستخدام مخطط مجمّد.
ثلاثة أمور تتولاها آلية YOLO() نيابةً عنك، ولا يتولاها الاستدعاء المباشر:
- تخطيط الإدخال: يتوقع
CoreMLBackendوTensorFlowBackendتنسيق BHWC. أجرِ التحويل أولًا باستخدامim.permute(0, 2, 3, 1)؛ إذ يؤدي موتر BCHW إلى عدم تطابق الأشكال. - التدرج التلقائي: أدرج الاستدعاءات ضمن
torch.inference_mode(). تعيدTorchScriptBackendموترًا ما زال يحتفظ بمخطط التدرجات. - المعالجة اللاحقة: في غياب البيانات الوصفية، تترك الواجهة الخلفية
taskوNoneوnamesفارغة. ومع ذلك، تزيلLiteRTBackendالتطبيع عن أي مخرج ثلاثي الأبعاد باستخدام حجم الصورة، على افتراض أنه يحتوي على مربعات YOLO، وهذا غير صحيح لنموذج غير معتمد على YOLO ذي مخرج ثلاثي الأبعاد. ولا تتأثر المخرجات ثنائية الأبعاد، مثل درجات احتمالات المصنّف.
القيود المعروفة#
- يتفاوت دعم المدخلات المتعددة: تقبل
torch2onnxوtorch2openvinoوtorch2torchscriptمجموعةً من موترات الأمثلة للنماذج ذات المدخلات المتعددة. أماtorch2coremlوtorch2coreaiوtorch2ncnnوtorch2paddleوtorch2executorchفتفترض وجود موتر إدخال واحد. - تنسيقات YOLO فقط: تتطلب صادرات Axelera وSony IMX500 سمات خاصة بنموذج YOLO، ولذلك لا تتوفر للنماذج العامة.
- تنسيقات خاصة بمنصات محددة: يتطلب TensorRT وحدة GPU من 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 مجموعةً من موترات الأمثلة للنماذج متعددة المدخلات.يمكن تصدير جميع التنسيقات المدعومة (TorchScript وONNX وOpenVINO وCoreML وCore AI وTF SavedModel وTF Frozen Graph وPaddlePaddle وMNN وNCNN وExecuTorch) باستخدام CPU. لا يلزم وجود GPU لتنفيذ عملية التصدير نفسها. أما TensorRT فهو التنسيق الوحيد الذي يتطلب وحدة GPU من NVIDIA.
استخدم أحدث إصدار. تتطلب الوسيطة
quantizeإصدار Ultralytics>=8.4.81، ويتطلب تصدير Core AI الإصدار>=8.4.131(>=8.4.163على Linux أو معcoreai-torch>=0.4.3).نعم. يمكن تصدير نماذج torchvision للتصنيف والكشف والتجزئة إلى
.mlpackageعبرtorch2coreml. بالنسبة إلى نماذج تصنيف الصور، مرّر قائمة بأسماء الفئات إلىclassifier_namesلإدراج رأس التصنيف في النموذج. نفّذ التصدير على macOS أو Linux. لا يُدعم CoreML على Windows. راجع تكامل CoreML للاطلاع على تفاصيل النشر على iOS.نعم، لعدة تنسيقات. مرّر
quantize=16لاستخدام FP16 أوquantize=8لاستخدام INT8 عند التصدير إلى OpenVINO أو CoreML أو MNN؛ ويتطلبonnx2saved_modelالوسيطةquantize=8لإنشاء ملف LiteRT بصيغة INT8، بينما يُصدّر NCNN وCore AI افتراضيًا بصيغة FP32، ويقبلانquantize=16لاستخدام FP16، ولا يتيحان مسارًا لـ INT8. يتطلب استخدام INT8 في OpenVINO أيضًا وسيطةcalibration_datasetلإجراء التكميم بعد التدريب. راجع صفحة التكامل الخاصة بكل تنسيق للاطلاع على المفاضلات المتعلقة بالتكميم.شغّل نموذج PyTorch الأصلي والنموذج المُصدّر على المدخل نفسه، ثم قارن المخرجات. حمّل الملف المُصدّر باستخدام الواجهة الخلفية المطابقة (على سبيل المثال،
ONNXBackendلملفات ONNX)، وتحقّق من أكبر فرق مطلق. قيّم الفرق مقارنةً بخط الأساس الخاص بالتنسيق: قد تعمل NCNN وMNNBackendوOpenVINO على بعض وحدات CPU على تشغيل عمليات التصدير FP32 بدقة مخفّضة، وتحقق نتائج قريبة من1e-2إلى1e-1، بينما تحقق معظم التنسيقات الأخرى نتائج قريبة من1e-5. يشير فرق أكبر بكثير إلى عمليات غير مدعومة، أو شكل إدخال غير صحيح، أو أن النموذج ليس في وضع التقييم. راجع التحقق من النموذج المُصدّر للاطلاع على مثال قابل للتشغيل.