Ultralytics YOLO27: انضم إلى قائمة الانتظار.
Get Started

كيفية تصدير نماذج 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 بسطرين، من دون شيفرة 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.

التنسيقالدالةالتثبيتالمخرجات
TorchScripttorch2torchscript()مضمّن مع PyTorchملف .torchscript
ONNXtorch2onnx()pip install onnxملف .onnx
OpenVINOtorch2openvino()pip install openvinoدليل _openvino_model/
CoreMLtorch2coreml()pip install coremltools.mlpackage
Core AItorch2coreai()pip install coreai-torch (Apple silicon مع macOS 26 أو أحدث، وLinux بمعمارية x86_64 وglibc 2.34 أو أحدث؛ Python من الإصدار 3.11 إلى 3.14)دليل .aimodel
TF SavedModelonnx2saved_model()راجع المتطلبات التفصيلية أدناهدليل _saved_model/
TF Frozen Graphkeras2pb()راجع المتطلبات التفصيلية أدناهملف .pb
PaddlePaddletorch2paddle()pip install paddlepaddle x2paddleدليل _paddle_model/
MNNonnx2mnn()pip install MNNملف .mnn
NCNNtorch2ncnn()pip install ncnn pnnxدليل _ncnn_model/
ExecuTorchtorch2executorch()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)
استدعِ `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.

التصدير إلى 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 عنصرًا بصيغة FP16 يستقبل مدخلات 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.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

التصدير إلى 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 على 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}")  # ~1e-5 for an FP32 ONNX export
الفرق المتوقع

في ResNet-18، تقع معظم عمليات التصدير FP32 ضمن نحو 1e-5 من PyTorch، ويطابق TorchScript النتائج تمامًا. مع ذلك، قد تحسب ثلاث بيئات تشغيل تصدير FP32 بدقة مخفّضة، فتكون النتائج قريبة من 1e-2 إلى 1e-1: يفعّل NCNN حساب FP16 على وحدات المعالجة المركزية التي تدعمه، وتحمل MNNBackend النماذج باستخدام precision="low"، بينما تعمل إضافة OpenVINO لوحدة المعالجة المركزية تلقائيًا بدقة FP16 في وضع التنفيذ الافتراضي PERFORMANCE على بعض الأجهزة، مثل شرائح Apple. يشير الفرق الأكبر بكثير من خط الأساس الخاص بالتنسيق إلى عمليات غير مدعومة، أو شكل إدخال خاطئ، أو أن النموذج ليس في وضع التقييم. تتطلب عمليات التصدير FP16 وINT8 هوامش تسامح أوسع. تحقّق باستخدام بيانات حقيقية بدلًا من الموترات العشوائية.

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

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

يمكن تحميل النماذج غير التابعة إلى YOLO التي تم تصديرها مجددًا عبر واجهة 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، كما في مثال التحقق أعلاه. يقبل كل صنف الملف المُصدَّر والجهاز، ويمكن استدعاؤه:

التنسيقالواجهة الخلفيةتخطيط الإدخال
TorchScriptTorchScriptBackendBCHW
ONNXONNXBackendBCHW
OpenVINOOpenVINOBackendBCHW
CoreMLCoreMLBackendBHWC
Core AICoreAIBackendBCHW
TF SavedModel، الرسم البياني المجمّدTensorFlowBackendBHWC
LiteRTLiteRTBackendBCHW
PaddlePaddlePaddleBackendBCHW
MNNMNNBackendBCHW
NCNNNCNNBackendBCHW
ExecuTorchExecuTorchBackendBCHW

يدعم 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 وحدة معالجة رسومات NVIDIA. ويتطلب RKNN حزمة SDK rknn-toolkit2 (لنظام Linux فقط). ويتطلب Edge TPU الملف التنفيذي edgetpu_compiler (لنظام Linux بمعمارية x86_64 فقط).

الخلاصة#

تنقل هذه الأدوات أي نموذج 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) على وحدة المعالجة المركزية. لا تحتاج عملية التصدير نفسها إلى وحدة معالجة رسومات. TensorRT هو التنسيق الوحيد الذي يتطلب وحدة معالجة رسومات 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 على بعض وحدات المعالجة المركزية تشغيل عمليات التصدير FP32 بدقة مخفّضة، فتكون النتائج قريبة من 1e-2 إلى 1e-1، بينما تكون نتائج معظم التنسيقات الأخرى قريبة من 1e-5. يشير الفارق الأكبر بكثير إلى عمليات غير مدعومة، أو شكل إدخال خاطئ، أو أن النموذج ليس في وضع التقييم. راجع التحقق من النموذج المُصدَّر للاطلاع على مثال قابل للتشغيل.

التعليقات