تخطي إلى المحتوى

YOLOv7: مجموعة الأدوات المجانية القابلة للتدريب

YOLOv7 هو أحدث كاشف للأجسام في الوقت الفعلي يتفوق على جميع كاشفات الأجسام المعروفة من حيث السرعة و الدقة في النطاق من 5 إطارات في الثانية إلى 160 إطارًا في الثانية. يتمتع بأعلى دقة (56.8٪ AP) من بين جميع كاشفات الأجسام في الوقت الفعلي المعروفة بسرعة 30 إطارًا في الثانية أو أعلى على GPU V100. علاوة على ذلك، يتفوق YOLOv7 على كاشفات الأجسام الأخرى مثل YOLOR و YOLOX و Scaled-YOLOv4 و YOLOv5 وغيرها الكثير من حيث السرعة والدقة. يتم تدريب النموذج على مجموعة بيانات MS COCO من البداية دون استخدام أي مجموعات بيانات أخرى أو أوزان مُدرَّبة مسبقًا. يتوفر كود المصدر لـ YOLOv7 على GitHub.

مقارنة YOLOv7 مع أحدث أدوات اكتشاف الكائنات

مقارنة بين أحدث أدوات الكشف عن الأجسام (SOTA)

من النتائج الموجودة في جدول مقارنة YOLO، نعلم أن الطريقة المقترحة لديها أفضل مقايضة بين السرعة والدقة بشكل شامل. إذا قارنا YOLOv7-tiny-SiLU مع YOLOv5-N (r6.1)، فإن طريقتنا أسرع بمقدار 127 إطارًا في الثانية وأكثر دقة بنسبة 10.7٪ في AP. بالإضافة إلى ذلك، فإن YOLOv7 لديها 51.4٪ AP بمعدل إطارات 161 إطارًا في الثانية، في حين أن PPYOLOE-L بنفس AP لديها معدل إطارات 78 إطارًا في الثانية فقط. من حيث استخدام المعلمات، فإن YOLOv7 أقل بنسبة 41٪ من PPYOLOE-L.

إذا قارنا YOLOv7-X بسرعة استدلال 114 إطارًا في الثانية مع YOLOv5-L (r6.1) بسرعة استدلال 99 إطارًا في الثانية، فيمكن لـ YOLOv7-X تحسين AP بنسبة 3.9%. إذا تمت مقارنة YOLOv7-X مع YOLOv5-X (r6.1) ذي المقياس المماثل، فإن سرعة استدلال YOLOv7-X أسرع بمقدار 31 إطارًا في الثانية. بالإضافة إلى ذلك، فيما يتعلق بكمية المعلمات والحساب، يقلل YOLOv7-X من 22% من المعلمات و 8% من الحساب مقارنة بـ YOLOv5-X (r6.1)، ولكنه يحسن AP بنسبة 2.2% (المصدر).

الأداء

النموذجالمعلمات
(M)
FLOPs
(G)
الحجم
(بالبكسل)
FPSAPtest / val
50-95
APtest
50
APtest
75
APtest
S
APtest
M
APtest
L
YOLOX-S9.026.864010240.5% / 40.5%-----
YOLOX-M25.373.86408147.2% / 46.9%-----
YOLOX-L54.2155.66406950.1% / 49.7%-----
YOLOX-X99.1281.96405851.5% / 51.1%-----
PPYOLOE-S7.917.464020843.1% / 42.7%60.5%46.6%23.2%46.4%56.9%
PPYOLOE-M23.449.964012348.9% / 48.6%66.5%53.0%28.6%52.9%63.8%
PPYOLOE-L52.2110.16407851.4% / 50.9%68.9%55.6%31.4%55.3%66.1%
PPYOLOE-X98.4206.66404552.2% / 51.9%69.9%56.5%33.3%56.3%66.4%
YOLOv5-N (r6.1)1.94.5640159- / 28.0%-----
YOLOv5-S (r6.1)7.216.5640156- / 37.4%-----
YOLOv5-M (r6.1)21.249.0640122- / 45.4%-----
YOLOv5-L (r6.1)46.5109.164099- / 49.0%-----
YOLOv5-X (r6.1)86.7205.764083- / 50.7%-----
YOLOR-CSP52.9120.464010651.1% / 50.8%69.6%55.7%31.7%55.3%64.7%
YOLOR-CSP-X96.9226.86408753.0% / 52.7%71.4%57.9%33.7%57.1%66.8%
YOLOv7-tiny-SiLU6.213.864028638.7% / 38.7%56.7%41.7%18.8%42.4%51.9%
YOLOv736.9104.764016151.4% / 51.2%69.7%55.9%31.8%55.5%65.0%
YOLOv7-X71.3189.964011453.1% / 52.9%71.2%57.8%33.8%57.1%67.4%
YOLOv5-N6 (r6.1)3.218.41280123- / 36.0%-----
YOLOv5-S6 (r6.1)12.667.21280122- / 44.8%-----
YOLOv5-M6 (r6.1)35.7200.0128090- / 51.3%-----
YOLOv5-L6 (r6.1)76.8445.6128063- / 53.7%-----
YOLOv5-X6 (r6.1)140.7839.2128038- / 55.0%-----
YOLOR-P637.2325.612807653.9% / 53.5%71.4%58.9%36.1%57.7%65.6%
YOLOR-W679.8453.212806655.2% / 54.8%72.7%60.5%37.7%59.1%67.1%
YOLOR-E6115.8683.212804555.8% / 55.7%73.4%61.1%38.4%59.7%67.7%
YOLOR-D6151.7935.612803456.5% / 56.1%74.1%61.9%38.9%60.4%68.7%
YOLOv7-W670.4360.012808454.9% / 54.6%72.6%60.1%37.3%58.7%67.1%
YOLOv7-E697.2515.212805656.0% / 55.9%73.5%61.2%38.0%59.9%68.4%
YOLOv7-D6154.7806.812804456.6% / 56.3%74.0%61.8%38.8%60.1%69.5%
YOLOv7-E6E151.7843.212803656.8% / 56.8%74.4%62.1%39.3%60.5%69.0%

نظرة عامة

يعد الكشف عن الكائنات في الوقت الفعلي مكونًا مهمًا في العديد من أنظمة رؤية الكمبيوتر، بما في ذلك تتبع متعدد الكائنات، والقيادة الذاتية، والروبوتات، وتحليل الصور الطبية. في السنوات الأخيرة، ركز تطوير الكشف عن الكائنات في الوقت الفعلي على تصميم معماريات فعالة وتحسين سرعة الاستدلال لوحدات المعالجة المركزية ووحدات معالجة الرسومات ووحدات المعالجة العصبية المختلفة (NPUs). يدعم YOLOv7 كلاً من أجهزة GPU المحمولة وأجهزة GPU، من الحافة إلى السحابة.

بخلاف كاشفات الكائنات في الوقت الفعلي التقليدية التي تركز على تحسين الهندسة المعمارية، يقدم YOLOv7 تركيزًا على تحسين عملية التدريب. يتضمن ذلك وحدات وأساليب تحسين مصممة لتحسين دقة اكتشاف الكائنات دون زيادة تكلفة الاستدلال، وهو مفهوم يعرف باسم "حقيبة الحيل المجانية القابلة للتدريب".

الميزات الرئيسية

يقدم YOLOv7 العديد من الميزات الرئيسية:

  1. إعادة تحديد معلمات النموذج: يقترح YOLOv7 نموذجًا مُعاد تحديده مُخطط له، وهي إستراتيجية قابلة للتطبيق على الطبقات في الشبكات المختلفة مع مفهوم مسار انتشار التدرج.

  2. تعيين تسمية ديناميكية: يطرح تدريب النموذج بطبقات إخراج متعددة مشكلة جديدة: "كيفية تعيين أهداف ديناميكية لمخرجات الفروع المختلفة؟" لحل هذه المشكلة، يقدم YOLOv7 طريقة جديدة لتعيين التسميات تسمى تعيين التسميات الموجه من الخشن إلى الدقيق.

  3. التحجيم الممتد والمركب: تقترح YOLOv7 طرق "التحجيم الممتد" و"التحجيم المركب" لكاشف الكائنات في الوقت الفعلي الذي يمكنه استخدام المعلمات والحساب بشكل فعال.

  4. الكفاءة: يمكن للطريقة التي اقترحها YOLOv7 أن تقلل بشكل فعال حوالي 40٪ من المعلمات و 50٪ من حسابات أحدث أجهزة الكشف عن الكائنات في الوقت الفعلي، ولديها سرعة استدلال أسرع ودقة detect أعلى.

أمثلة الاستخدام

حتى وقت كتابة هذه السطور، تدعم Ultralytics استدلال ONNX و TensorRT فقط لـ YOLOv7.

تصدير ONNX

لاستخدام نموذج YOLOv7 ONNX مع Ultralytics:

  1. (اختياري) قم بتثبيت Ultralytics وتصدير نموذج ONNX لتثبيت التبعيات المطلوبة تلقائيًا:

    pip install ultralytics
    yolo export model=yolo11n.pt format=onnx
    
  2. قم بتصدير نموذج YOLOv7 المطلوب باستخدام المصدر في مستودع YOLOv7:

    git clone https://github.com/WongKinYiu/yolov7
    cd yolov7
    python export.py --weights yolov7-tiny.pt --grid --end2end --simplify --topk-all 100 --iou-thres 0.65 --conf-thres 0.35 --img-size 640 640 --max-wh 640
    
  3. قم بتعديل مخطط نموذج ONNX ليكون متوافقًا مع Ultralytics باستخدام البرنامج النصي التالي:

    import numpy as np
    import onnx
    from onnx import helper, numpy_helper
    
    # Load the ONNX model
    model_path = "yolov7/yolov7-tiny.onnx"  # Replace with your model path
    model = onnx.load(model_path)
    graph = model.graph
    
    # Fix input shape to batch size 1
    input_shape = graph.input[0].type.tensor_type.shape
    input_shape.dim[0].dim_value = 1
    
    # Define the output of the original model
    original_output_name = graph.output[0].name
    
    # Create slicing nodes
    sliced_output_name = f"{original_output_name}_sliced"
    
    # Define initializers for slicing (remove the first value)
    start = numpy_helper.from_array(np.array([1], dtype=np.int64), name="slice_start")
    end = numpy_helper.from_array(np.array([7], dtype=np.int64), name="slice_end")
    axes = numpy_helper.from_array(np.array([1], dtype=np.int64), name="slice_axes")
    steps = numpy_helper.from_array(np.array([1], dtype=np.int64), name="slice_steps")
    
    graph.initializer.extend([start, end, axes, steps])
    
    slice_node = helper.make_node(
        "Slice",
        inputs=[original_output_name, "slice_start", "slice_end", "slice_axes", "slice_steps"],
        outputs=[sliced_output_name],
        name="SliceNode",
    )
    graph.node.append(slice_node)
    
    # Define segment slicing
    seg1_start = numpy_helper.from_array(np.array([0], dtype=np.int64), name="seg1_start")
    seg1_end = numpy_helper.from_array(np.array([4], dtype=np.int64), name="seg1_end")
    seg2_start = numpy_helper.from_array(np.array([4], dtype=np.int64), name="seg2_start")
    seg2_end = numpy_helper.from_array(np.array([5], dtype=np.int64), name="seg2_end")
    seg3_start = numpy_helper.from_array(np.array([5], dtype=np.int64), name="seg3_start")
    seg3_end = numpy_helper.from_array(np.array([6], dtype=np.int64), name="seg3_end")
    
    graph.initializer.extend([seg1_start, seg1_end, seg2_start, seg2_end, seg3_start, seg3_end])
    
    # Create intermediate tensors for segments
    segment_1_name = f"{sliced_output_name}_segment1"
    segment_2_name = f"{sliced_output_name}_segment2"
    segment_3_name = f"{sliced_output_name}_segment3"
    
    # Add segment slicing nodes
    graph.node.extend(
        [
            helper.make_node(
                "Slice",
                inputs=[sliced_output_name, "seg1_start", "seg1_end", "slice_axes", "slice_steps"],
                outputs=[segment_1_name],
                name="SliceSegment1",
            ),
            helper.make_node(
                "Slice",
                inputs=[sliced_output_name, "seg2_start", "seg2_end", "slice_axes", "slice_steps"],
                outputs=[segment_2_name],
                name="SliceSegment2",
            ),
            helper.make_node(
                "Slice",
                inputs=[sliced_output_name, "seg3_start", "seg3_end", "slice_axes", "slice_steps"],
                outputs=[segment_3_name],
                name="SliceSegment3",
            ),
        ]
    )
    
    # Concatenate the segments
    concat_output_name = f"{sliced_output_name}_concat"
    concat_node = helper.make_node(
        "Concat",
        inputs=[segment_1_name, segment_3_name, segment_2_name],
        outputs=[concat_output_name],
        axis=1,
        name="ConcatSwapped",
    )
    graph.node.append(concat_node)
    
    # Reshape to [1, -1, 6]
    reshape_shape = numpy_helper.from_array(np.array([1, -1, 6], dtype=np.int64), name="reshape_shape")
    graph.initializer.append(reshape_shape)
    
    final_output_name = f"{concat_output_name}_batched"
    reshape_node = helper.make_node(
        "Reshape",
        inputs=[concat_output_name, "reshape_shape"],
        outputs=[final_output_name],
        name="AddBatchDimension",
    )
    graph.node.append(reshape_node)
    
    # Get the shape of the reshaped tensor
    shape_node_name = f"{final_output_name}_shape"
    shape_node = helper.make_node(
        "Shape",
        inputs=[final_output_name],
        outputs=[shape_node_name],
        name="GetShapeDim",
    )
    graph.node.append(shape_node)
    
    # Extract the second dimension
    dim_1_index = numpy_helper.from_array(np.array([1], dtype=np.int64), name="dim_1_index")
    graph.initializer.append(dim_1_index)
    
    second_dim_name = f"{final_output_name}_dim1"
    gather_node = helper.make_node(
        "Gather",
        inputs=[shape_node_name, "dim_1_index"],
        outputs=[second_dim_name],
        name="GatherSecondDim",
    )
    graph.node.append(gather_node)
    
    # Subtract from 100 to determine how many values to pad
    target_size = numpy_helper.from_array(np.array([100], dtype=np.int64), name="target_size")
    graph.initializer.append(target_size)
    
    pad_size_name = f"{second_dim_name}_padsize"
    sub_node = helper.make_node(
        "Sub",
        inputs=["target_size", second_dim_name],
        outputs=[pad_size_name],
        name="CalculatePadSize",
    )
    graph.node.append(sub_node)
    
    # Build the [2, 3] pad array:
    # 1st row -> [0, 0, 0] (no padding at the start of any dim)
    # 2nd row -> [0, pad_size, 0] (pad only at the end of the second dim)
    pad_starts = numpy_helper.from_array(np.array([0, 0, 0], dtype=np.int64), name="pad_starts")
    graph.initializer.append(pad_starts)
    
    zero_scalar = numpy_helper.from_array(np.array([0], dtype=np.int64), name="zero_scalar")
    graph.initializer.append(zero_scalar)
    
    pad_ends_name = "pad_ends"
    concat_pad_ends_node = helper.make_node(
        "Concat",
        inputs=["zero_scalar", pad_size_name, "zero_scalar"],
        outputs=[pad_ends_name],
        axis=0,
        name="ConcatPadEnds",
    )
    graph.node.append(concat_pad_ends_node)
    
    pad_values_name = "pad_values"
    concat_pad_node = helper.make_node(
        "Concat",
        inputs=["pad_starts", pad_ends_name],
        outputs=[pad_values_name],
        axis=0,
        name="ConcatPadStartsEnds",
    )
    graph.node.append(concat_pad_node)
    
    # Create Pad operator to pad with zeros
    pad_output_name = f"{final_output_name}_padded"
    pad_constant_value = numpy_helper.from_array(
        np.array([0.0], dtype=np.float32),
        name="pad_constant_value",
    )
    graph.initializer.append(pad_constant_value)
    
    pad_node = helper.make_node(
        "Pad",
        inputs=[final_output_name, pad_values_name, "pad_constant_value"],
        outputs=[pad_output_name],
        mode="constant",
        name="PadToFixedSize",
    )
    graph.node.append(pad_node)
    
    # Update the graph's final output to [1, 100, 6]
    new_output_type = onnx.helper.make_tensor_type_proto(
        elem_type=graph.output[0].type.tensor_type.elem_type, shape=[1, 100, 6]
    )
    new_output = onnx.helper.make_value_info(name=pad_output_name, type_proto=new_output_type)
    
    # Replace the old output with the new one
    graph.output.pop()
    graph.output.extend([new_output])
    
    # Save the modified model
    onnx.save(model, "yolov7-ultralytics.onnx")
    
  4. يمكنك بعد ذلك تحميل نموذج ONNX المعدل وتشغيل الاستدلال به في Ultralytics بشكل طبيعي:

    from ultralytics import ASSETS, YOLO
    
    model = YOLO("yolov7-ultralytics.onnx", task="detect")
    
    results = model(ASSETS / "bus.jpg")
    

تصدير TensorRT

  1. اتبع الخطوتين 1-2 في قسم تصدير ONNX.

  2. قم بتثبيت TensorRT حزمة Python:

    pip install tensorrt
    
  3. شغّل البرنامج النصي التالي لتحويل نموذج ONNX المعدل إلى محرك TensorRT:

    from ultralytics.utils.export import export_engine
    
    export_engine("yolov7-ultralytics.onnx", half=True)
    
  4. قم بتحميل وتشغيل النموذج في Ultralytics:

    from ultralytics import ASSETS, YOLO
    
    model = YOLO("yolov7-ultralytics.engine", task="detect")
    
    results = model(ASSETS / "bus.jpg")
    

الاقتباسات والإقرارات

نود أن نتقدم بالشكر لمؤلفي YOLOv7 لمساهماتهم الكبيرة في مجال الكشف عن الأجسام في الوقت الفعلي:

@article{wang2022yolov7,
  title={YOLOv7: Trainable bag-of-freebies sets new state-of-the-art for real-time object detectors},
  author={Wang, Chien-Yao and Bochkovskiy, Alexey and Liao, Hong-Yuan Mark},
  journal={arXiv preprint arXiv:2207.02696},
  year={2022}
}

يمكن العثور على ورقة YOLOv7 الأصلية على arXiv. لقد أتاح المؤلفون عملهم للجمهور، ويمكن الوصول إلى قاعدة التعليمات البرمجية على GitHub. نحن نقدر جهودهم في تطوير هذا المجال وإتاحة عملهم للمجتمع الأوسع.

الأسئلة الشائعة

ما هو YOLOv7 ولماذا يعتبر طفرة في الوقت الحقيقي لاكتشاف الأجسام؟

YOLOv7 هو نموذج متطور للكشف عن الكائنات في الوقت الفعلي يحقق سرعة ودقة لا مثيل لهما. إنه يتفوق على النماذج الأخرى، مثل YOLOX و YOLOv5 و PPYOLOE، في كل من استخدام المعلمات وسرعة الاستدلال. تتضمن الميزات المميزة لـ YOLOv7 إعادة تحديد معلمات النموذج وتعيين التسميات الديناميكي، مما يحسن أدائه دون زيادة تكاليف الاستدلال. لمزيد من التفاصيل الفنية حول بنيته ومقاييس المقارنة مع كاشفات الكائنات الحديثة الأخرى، راجع ورقة YOLOv7.

كيف يحسن YOLOv7 من نماذج YOLO السابقة مثل YOLOv4 و YOLOv5؟

يقدم YOLOv7 العديد من الابتكارات، بما في ذلك إعادة تحديد معلمات النموذج وتعيين التسميات الديناميكي، مما يعزز عملية التدريب ويحسن دقة الاستدلال. بالمقارنة مع YOLOv5، يعزز YOLOv7 السرعة والدقة بشكل كبير. على سبيل المثال، يحسن YOLOv7-X الدقة بنسبة 2.2٪ ويقلل المعلمات بنسبة 22٪ مقارنة بـ YOLOv5-X. يمكن العثور على مقارنات تفصيلية في جدول الأداء مقارنة YOLOv7 بكاشفات الكائنات SOTA.

هل يمكنني استخدام YOLOv7 مع أدوات ومنصات Ultralytics؟

حتى الآن، تدعم Ultralytics استدلال YOLOv7 ONNX و TensorRT فقط. لتشغيل إصدار YOLOv7 المُصدَّر بتنسيق ONNX و TensorRT باستخدام Ultralytics، تحقق من قسم أمثلة الاستخدام.

كيف يمكنني تدريب نموذج YOLOv7 مخصص باستخدام مجموعة البيانات الخاصة بي؟

لتثبيت وتدريب نموذج YOLOv7 مخصص، اتبع الخطوات التالية:

  1. استنساخ مستودع YOLOv7:
    git clone https://github.com/WongKinYiu/yolov7
    
  2. انتقل إلى الدليل المستنسخ وقم بتثبيت التبعيات:
    cd yolov7
    pip install -r requirements.txt
    
  3. قم بإعداد مجموعة البيانات الخاصة بك وتهيئة معلمات النموذج وفقًا لـ تعليمات الاستخدام المتوفرة في المستودع. لمزيد من الإرشادات، تفضل بزيارة مستودع YOLOv7 GitHub للحصول على أحدث المعلومات والتحديثات.

  4. بعد التدريب، يمكنك تصدير النموذج إلى ONNX أو TensorRT لاستخدامه في Ultralytics كما هو موضح في أمثلة الاستخدام.

ما هي الميزات والتحسينات الرئيسية التي تم تقديمها في YOLOv7؟

يقدم YOLOv7 العديد من الميزات الرئيسية التي تحدث ثورة في الكشف عن الأجسام في الوقت الفعلي:

  • إعادة تحديد معلمات النموذج (Model Re-parameterization): يعزز أداء النموذج عن طريق تحسين مسارات انتشار التدرج.
  • تعيين التصنيفات الديناميكي: يستخدم طريقة موجهة من الخشن إلى الدقيق لتعيين الأهداف الديناميكية للمخرجات عبر الفروع المختلفة، مما يحسن الدقة.
  • التحجيم الموسع والمركب: يستخدم المعلمات والحساب بكفاءة لتوسيع نطاق النموذج لمختلف التطبيقات في الوقت الفعلي.
  • الكفاءة: يقلل من عدد المعلمات بنسبة 40٪ والحساب بنسبة 50٪ مقارنة بالنماذج الحديثة الأخرى مع تحقيق سرعات استدلال أسرع.

لمزيد من التفاصيل حول هذه الميزات، راجع قسم نظرة عامة على YOLOv7.



📅 تم الإنشاء منذ سنتين ✏️ تم التحديث منذ شهر واحد
glenn-jocherLaughing-qY-T-GMatthewNoyceRizwanMunawarambitious-octopus

تعليقات