كيفية تصدير نماذج 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 في أي من الحالتين.
| التنسيق | الدالة | تثبيت | المخرجات |
|---|---|---|---|
| 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/ |
تمر عمليات التصدير إلى 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 و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.
يوفر 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.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على وحدة المعالجة المركزية ARM64paddlepaddle>=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-toolkit2SDK (لنظام 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؛ وتشير الفجوات الأكبر إلى عمليات غير مدعومة، أو شكل إدخال خاطئ، أو نموذج ليس في وضع التقييم. راجع التحقق من نموذجك المُصدَّر للاطلاع على مثال قابل للتنفيذ.