فهم الاكتشاف من الطرف إلى الطرف (End-to-End) في YOLO26 من Ultralytics
مقدمة
إذا كنت تقوم بالترقية إلى YOLO26 من نموذج أقدم مثل YOLOv8 أو YOLO11، فإن أحد أكبر التغييرات التي ستلاحظها هو إزالة كبت غير الأعظم (NMS). تنتج نماذج YOLO التقليدية آلاف التوقعات المتداخلة التي تحتاج إلى خطوة معالجة لاحقة منفصلة باستخدام NMS للتصفية وصولاً إلى الاكتشافات النهائية. وهذا يضيف زمن انتقال، ويعقد رسوم بيانية للتصدير، ويمكن أن يعمل بشكل غير متسق عبر منصات الأجهزة المختلفة.
يتبع YOLO26 نهجاً مختلفاً. فهو يخرج الاكتشافات النهائية مباشرة من النموذج، ولا يتطلب أي تصفية خارجية. يُعرف هذا بـ اكتشاف الكائنات من الطرف إلى الطرف، وهو مفعل افتراضياً في جميع نماذج YOLO26. النتيجة هي خط أنابيب نشر أبسط، وزمن انتقال أقل، وأداء استدلال أسرع بنسبة تصل إلى 43% على وحدات المعالجة المركزية (CPUs).
يرشدك هذا الدليل عبر ما تغير، وما إذا كنت بحاجة إلى تحديث الكود الخاص بك، وتنسيقات التصدير التي تدعم الاستدلال من الطرف إلى الطرف، وكيفية الانتقال بسلاسة من نماذج YOLO الأقدم.
لإلقاء نظرة أعمق على الدافع وراء هذا التحول المعماري، راجع مدونة Ultralytics حول سبب إزالة YOLO26 لـ NMS وكيف يغير ذلك النشر.
- هل تستخدم Ultralytics API أو CLI؟ لا حاجة لإجراء أي تغييرات، فقط استبدل اسم النموذج الخاص بك بـ
yolo26n.pt. - هل تستخدم كود استدلال مخصص (مثل ONNX Runtime أو TensorRT، إلخ)؟ قم بتحديث المعالجة اللاحقة لديك، حيث أصبح مخرج الاكتشاف الآن
(N, 300, 6)بتنسيقxyxy، ولا يتطلب NMS. المهام الأخرى تضيف بيانات إضافية (معاملات القناع، أو النقاط الرئيسية، أو الزاوية). - هل تقوم بالتصدير؟ تدعم معظم التنسيقات المخرجات من الطرف إلى الطرف بشكل أصلي. ومع ذلك، تعود بعض التنسيقات (NCNN، وRKNN، وPaddlePaddle، وExecuTorch، وIMX، وEdge TPU) تلقائياً إلى المخرجات التقليدية بسبب قيود المشغل غير المدعومة (مثل
torch.topk).
كيف يعمل الاكتشاف من الطرف إلى الطرف
يستخدم YOLO26 معمارية ثنائية الرأس أثناء التدريب. يتشارك كلا الرأسين نفس العمود الفقري (Backbone) والرقبة (Neck)، لكنهما ينتجان المخرجات بطرق مختلفة:
| الرأس | الغرض | مخرج الاكتشاف | المعالجة اللاحقة |
|---|---|---|---|
| واحد لواحد (افتراضي) | استدلال من الطرف إلى الطرف | (N, 300, 6) | عتبة الثقة فقط |
| واحد لكثير | مخرج YOLO التقليدي | (N, nc + 4, 8400) | يتطلب NMS |
الأشكال المذكورة أعلاه خاصة بـ الاكتشاف. المهام الأخرى تمد مخرج الواحد لواحد ببيانات إضافية لكل اكتشاف:
| المهمة | مخرج من الطرف إلى الطرف | بيانات إضافية |
|---|---|---|
| الكشف | (N, 300, 6) | — |
| التقسيم | (N, 300, 6 + nm) + proto (N, nm, H, W) | nm معاملات القناع (افتراضي 32) |
| الوضعية | (N, 300, 57) | 17 نقطة رئيسية × 3 (x, y, الرؤية) |
| OBB | (N, 300, 7) | زاوية الدوران |
أثناء التدريب، يعمل كلا الرأسين في وقت واحد، حيث يوفر رأس الواحد لكثير إشارة تعلم أغنى، بينما يتعلم رأس الواحد لواحد إنتاج توقعات نظيفة وغير متداخلة. أثناء الاستدلال والتصدير، يكون رأس الواحد لواحد هو النشط فقط افتراضياً، حيث ينتج ما يصل إلى 300 اكتشاف لكل صورة بتنسيق [x1, y1, x2, y2, confidence, class_id].
عند استدعاء model.fuse()، فإنه يقوم بدمج طبقات Conv + BatchNorm لاستدلال أسرع، وفي نماذج الطرف إلى الطرف، يزيل أيضاً رأس الواحد لكثير، مما يقلل من حجم النموذج وعدد العمليات الحسابية (FLOPs). لمزيد من التفاصيل حول المعمارية ثنائية الرأس، راجع صفحة نموذج YOLO26.
هل أحتاج إلى تغيير الكود الخاص بي؟
استخدام Ultralytics Python API أو CLI
لا حاجة لإجراء أي تغييرات. إذا كنت تستخدم Ultralytics Python API القياسية أو CLI، فإن كل شيء يعمل تلقائياً، حيث تتعامل جميع عمليات التنبؤ والتحقق والتصدير مع نماذج الطرف إلى الطرف خارج الصندوق.
from ultralytics import YOLO
# Load a YOLO26 model
model = YOLO("yolo26n.pt")
# Predict — no NMS step, no code changes
results = model.predict("image.jpg")استخدام كود استدلال مخصص
نعم، تنسيق المخرجات مختلف. إذا كنت قد كتبت منطق معالجة لاحقة مخصصاً لـ YOLOv8 أو YOLO11 (على سبيل المثال، عند تشغيل الاستدلال باستخدام ONNX Runtime أو TensorRT)، فستحتاج إلى تحديثه للتعامل مع شكل المخرجات الجديد:
| YOLOv8 / YOLO11 | YOLO26 (من الطرف إلى الطرف) | |
|---|---|---|
| مخرج الاكتشاف | (N, nc + 4, 8400) | (N, 300, 6) |
| تنسيق الصندوق (Box) | xywh (مركز x، مركز y، العرض، الارتفاع) | xyxy (أعلى يسار x، أعلى يسار y، أسفل يمين x، أسفل يمين y) |
| التخطيط | إحداثيات الصندوق + درجات الفئات لكل مرساة (anchor) | [x1, y1, x2, y2, conf, class_id] |
| NMS مطلوب | نعم | لا |
| المعالجة اللاحقة | NMS + مرشح الثقة | مرشح الثقة فقط |
بالنسبة لمهام التقسيم، والوضعية، وOBB، يضيف YOLO26 بيانات خاصة بالمهمة لكل اكتشاف، راجع جدول أشكال المخرجات أعلاه.
حيث N هو حجم الدفعة وnc هو عدد الفئات (مثل 80 لـ COCO).
مع نماذج الطرف إلى الطرف، تصبح المعالجة اللاحقة أبسط بكثير، على سبيل المثال، عند استخدام ONNX Runtime:
import onnxruntime as ort
# Load and run the exported end-to-end model
session = ort.InferenceSession("yolo26n.onnx")
output = session.run(None, {session.get_inputs()[0].name: input_tensor})
# End-to-end output: (batch, 300, 6) → [x1, y1, x2, y2, confidence, class_id]
detections = output[0][0] # first image in batch
detections = detections[detections[:, 4] > conf_threshold] # confidence filter — that's it!التبديل إلى رأس الواحد لكثير
إذا كنت بحاجة إلى تنسيق مخرجات YOLO التقليدي (على سبيل المثال، لإعادة استخدام كود المعالجة اللاحقة المستند إلى NMS الموجود)، يمكنك التبديل إلى رأس الواحد لكثير في أي وقت عن طريق ضبط end2end=False:
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
# Prediction with NMS (traditional behavior)
results = model.predict("image.jpg", end2end=False)
# Validation with NMS
metrics = model.val(data="coco.yaml", end2end=False)
# Export without end-to-end
model.export(format="onnx", end2end=False)توافق تنسيق التصدير
تدعم معظم تنسيقات التصدير الاستدلال من الطرف إلى الطرف خارج الصندوق، بما في ذلك ONNX، وTensorRT، وCoreML، وOpenVINO، وTFLite، وTF.js، وMNN.
التنسيقات التالية لا تدعم الطرف إلى الطرف وتعود تلقائياً إلى رأس الواحد لكثير: NCNN، وRKNN، وPaddlePaddle، وExecuTorch، وIMX، وEdge TPU.
يدعم TensorRT الطرف إلى الطرف، لكنه يتم تعطيله تلقائياً عند التصدير باستخدام int8=True على TensorRT ≤10.3.0.
مقايضات الدقة والسرعة
يوفر الاكتشاف من الطرف إلى الطرف فوائد نشر كبيرة مع تأثير ضئيل على الدقة:
| المقياس | من الطرف إلى الطرف (افتراضي) | واحد لكثير + NMS (end2end=False) |
|---|---|---|
| سرعة الاستدلال على CPU | أسرع بنسبة تصل إلى 43% | الأساس (Baseline) |
| تأثير mAP | ~0.5 mAP أقل | تساوي أو تتجاوز YOLO11 |
| المعالجة اللاحقة | مرشح الثقة فقط | خط أنابيب NMS كامل |
| تعقيد النشر | بسيط | يتطلب تنفيذ NMS |
بالنسبة لمعظم تطبيقات العالم الحقيقي، يكون فرق ~0.5 mAP ضئيلاً، خاصة عند مراعاة مكاسب السرعة والبساطة. إذا كانت الدقة القصوى هي أولويتك القصوى، يمكنك دائماً العودة إلى رأس الواحد لكثير باستخدام end2end=False.
راجع مقاييس أداء YOLO26 للحصول على معايير تفصيلية عبر جميع أحجام النماذج (n, s, m, l, x).
الترحيل من YOLOv8 أو YOLO11
إذا كنت تقوم بترقية مشروع موجود إلى YOLO26، فإليك قائمة مرجعية سريعة لضمان انتقال سلس:
- مستخدمو Ultralytics API / CLI: لا حاجة لإجراء أي تغييرات، فقط قم بتحديث اسم النموذج إلى
yolo26n.pt(أوyolo26n-seg.pt،yolo26n-pose.pt،yolo26n-obb.pt) - كود المعالجة اللاحقة المخصص: قم بالتحديث للتعامل مع أشكال المخرجات الجديدة،
(N, 300, 6)للاكتشاف، بالإضافة إلى بيانات خاصة بالمهمة لـ التقسيم، والوضعية، وOBB. لاحظ أيضاً تغيير تنسيق الصندوق منxywhإلىxyxy - خطوط أنابيب التصدير: تحقق من قسم توافق التنسيق أعلاه للتنسيق المستهدف الخاص بك
- TensorRT + INT8: تحقق من أن إصدار TensorRT الخاص بك >10.3.0 لدعم الطرف إلى الطرف
- تصديرات FP16: إذا كنت بحاجة إلى جميع المخرجات بتنسيق FP16، فقم بالتصدير باستخدام
end2end=False، راجع لماذا يظل output0 بتنسيق FP32 عند التصدير مع half=True وend2end=True - iOS / CoreML: يتم دعم الطرف إلى الطرف بالكامل. إذا كنت بحاجة إلى دعم معاينة Xcode، فاستخدم
end2end=Falseمعnms=True - أجهزة الحافة (NCNN, RKNN): تعود هذه التنسيقات تلقائياً إلى الواحد لكثير، لذا قم بتضمين NMS في خط الأنابيب الخاص بك على الجهاز
الأسئلة الشائعة
هل يمكنني استخدام end2end=True وnms=True معاً؟
لا. هذه الخيارات متبادلة بشكل حصري. إذا قمت بضبط nms=True على نموذج طرف إلى طرف أثناء التصدير، فسيتم إجباره تلقائياً على nms=False مع تحذير. يتعامل رأس الطرف إلى الطرف بالفعل مع تصفية التكرارات داخلياً، لذا فإن NMS الخارجية غير ضرورية.
ومع ذلك، فإن end2end=False مدمجاً مع nms=True هو تكوين صالح، حيث يقوم بدمج NMS التقليدي في رسم التصدير. يمكن أن يكون هذا مفيداً لتصديرات CoreML لأنه يتيح لك استخدام وظيفة المعاينة في Xcode مع نموذج الاكتشاف مباشرة.
ما الذي يتحكم فيه معلم max_det في نماذج الطرف إلى الطرف؟
يحدد معلم max_det (الافتراضي: 300) الحد الأقصى لعدد الاكتشافات التي يمكن لرأس الواحد لواحد إخراجها لكل صورة. يمكنك تعديله في وقت الاستدلال أو التصدير:
model.predict("image.jpg", max_det=100) # fewer detections, slightly faster
model.export(format="onnx", max_det=500) # more detections for dense scenesلاحظ أنه تم تدريب نقاط فحص YOLO26 الافتراضية مع max_det=300. على الرغم من أنه يمكنك زيادة هذه القيمة، فقد تم تحسين رأس الواحد لواحد أثناء التدريب لإنتاج ما يصل إلى 300 اكتشاف نظيف، لذا قد تكون الاكتشافات التي تتجاوز هذا الحد أقل جودة. إذا كنت بحاجة إلى أكثر من 300 اكتشاف لكل صورة، ففكر في إعادة التدريب بقيمة max_det أعلى.
نموذج ONNX الذي قمت بتصديره يخرج (1, 300, 6) - هل هذا صحيح؟
نعم، هذا هو تنسيق مخرجات الطرف إلى الطرف المتوقع للاكتشاف: حجم دفعة قدره 1، وما يصل إلى 300 اكتشاف، كل منها بـ 6 قيم [x1, y1, x2, y2, confidence, class_id]. ببساطة قم بالتصفية حسب عتبة الثقة وانتهيت، لا حاجة لـ NMS.
بالنسبة للمهام الأخرى، يختلف شكل المخرجات:
| المهمة | شكل المخرج | الوصف |
|---|---|---|
| كشف | (1, 300, 6) | [x1, y1, x2, y2, conf, class_id] |
| Segmentation | (1, 300, 38) + (1, 32, 160, 160) | 6 قيم للصندوق + 32 معامل قناع، بالإضافة إلى موتر قناع أولي (prototype mask tensor) |
| Pose | (1, 300, 57) | 6 قيم للصندوق + 17 نقطة رئيسية × 3 (x، y، الرؤية) |
| OBB | (1, 300, 7) | 6 قيم للصندوق + 1 زاوية دوران |
كيف أتحقق مما إذا كان النموذج المصدر الخاص بي شاملاً (end-to-end)؟
يمكنك التحقق باستخدام Ultralytics Python API أو عن طريق فحص بيانات تعريف نموذج ONNX المصدر مباشرةً:
from ultralytics import YOLO
model = YOLO("yolo26n.onnx")
model.predict(verbose=False) # run predict to setup predictor first
print(model.predictor.model.end2end) # True if end-to-end is enabledبدلاً من ذلك، تحقق من شكل المخرجات — نماذج الكشف الشاملة (end-to-end) تخرج (1, 300, 6)، بينما تخرج النماذج التقليدية (1, nc + 4, 8400). لأشكال المهام الأخرى، راجع الأسئلة الشائعة حول أشكال المخرجات.
هل يتم دعم الكشف الشامل (end-to-end) لمهام التجزئة، وتقدير الوضع، و OBB؟
نعم. جميع متغيرات مهام YOLO26 — الكشف، والتجزئة، وتقدير الوضع، وكشف الكائنات الموجهة (OBB) — تدعم الاستنتاج الشامل (end-to-end) افتراضياً. يتوفر أيضاً خيار الرجوع end2end=False عبر جميع المهام.
كل مهمة تمد مخرجات الكشف الأساسية ببيانات خاصة بالمهمة:
| المهمة | النموذج | مخرج من الطرف إلى الطرف |
|---|---|---|
| كشف | yolo26n.pt | (N, 300, 6) |
| Segmentation | yolo26n-seg.pt | (N, 300, 38) + proto (N, 32, 160, 160) |
| Pose | yolo26n-pose.pt | (N, 300, 57) |
| OBB | yolo26n-obb.pt | (N, 300, 7) |