دليل خطوة بخطوة لتدريب نماذج YOLO26 باستخدام IBM Watsonx

في الوقت الحاضر، أصبحت حلول الرؤية الحاسوبية القابلة للتوسع أكثر شيوعاً وتُغير الطريقة التي نتعامل بها مع البيانات المرئية. ومن الأمثلة الرائعة على ذلك منصة IBM Watsonx، وهي منصة متقدمة للذكاء الاصطناعي والبيانات تعمل على تبسيط تطوير ونشر وإدارة نماذج الذكاء الاصطناعي. توفر المنصة مجموعة كاملة لدورة حياة الذكاء الاصطناعي بالكامل وتكاملاً سلساً مع خدمات IBM Cloud.

يمكنك تدريب نماذج Ultralytics YOLO26 باستخدام IBM Watsonx. إنه خيار جيد للمؤسسات المهتمة بـ تدريب النماذج الفعال، والضبط الدقيق لمهام محددة، وتحسين أداء النموذج باستخدام أدوات قوية وإعدادات سهلة الاستخدام. في هذا الدليل، سنرشدك خلال عملية تدريب YOLO26 باستخدام IBM Watsonx، بدءاً من إعداد بيئتك وحتى تقييم النماذج المدربة الخاصة بك. لنبدأ!

ما هي IBM Watsonx؟

Watsonx هي منصة IBM المستندة إلى السحابة والمصممة للـ الذكاء الاصطناعي التوليدي التجاري والبيانات العلمية. تتكون IBM Watsonx من ثلاثة مكونات - watsonx.ai و watsonx.data و watsonx.governance - والتي تجتمع معاً لإنشاء منصة ذكاء اصطناعي موثوقة وشاملة يمكنها تسريع مشاريع الذكاء الاصطناعي الهادفة إلى حل مشاكل الأعمال. توفر المنصة أدوات قوية لبناء وتدريب و نشر نماذج التعلم الآلي وتسهل الاتصال بمصادر بيانات متنوعة.

IBM Watsonx AI platform architecture overview

تعمل واجهتها سهلة الاستخدام وقدراتها التعاونية على تبسيط عملية التطوير والمساعدة في الإدارة الفعالة للنماذج ونشرها. سواء كان ذلك للرؤية الحاسوبية، أو التحليلات التنبؤية، أو معالجة اللغات الطبيعية، أو غيرها من تطبيقات الذكاء الاصطناعي، توفر IBM Watsonx الأدوات والدعم اللازم لتعزيز الابتكار.

الميزات الرئيسية لـ IBM Watsonx

تتكون IBM Watsonx من ثلاثة مكونات رئيسية: watsonx.ai و watsonx.data و watsonx.governance. يقدم كل مكون ميزات تلبي جوانب مختلفة من إدارة الذكاء الاصطناعي والبيانات. دعونا نلقي نظرة فاحصة عليها.

Watsonx.ai

توفر Watsonx.ai أدوات قوية لتطوير الذكاء الاصطناعي وتوفر الوصول إلى نماذج مخصصة مدعومة من IBM، ونماذج تابعة لجهات خارجية مثل Llama 3، ونماذج Granite الخاصة بـ IBM. وهي تتضمن Prompt Lab لتجربة مطالبات الذكاء الاصطناعي، و Tuning Studio لتحسين أداء النموذج باستخدام البيانات المصنفة، و Flows Engine لتبسيط تطوير تطبيقات الذكاء الاصطناعي التوليدي. كما أنها توفر أدوات شاملة لأتمتة دورة حياة نموذج الذكاء الاصطناعي والاتصال بمختلف الـ APIs والمكتبات.

Watsonx.data

تدعم Watsonx.data عمليات النشر في السحابة وعلى الأجهزة المحلية من خلال تكامل IBM Storage Fusion HCI. توفر وحدة التحكم سهلة الاستخدام وصولاً مركزياً إلى البيانات عبر البيئات وتجعل استكشاف البيانات سهلاً باستخدام SQL الشائع. تعمل المنصة على تحسين أعباء العمل باستخدام محركات استعلام فعالة مثل Presto و Spark، وتسريع رؤى البيانات باستخدام طبقة دلالية مدعومة بالذكاء الاصطناعي، وتتضمن قاعدة بيانات متجهة لأهمية الذكاء الاصطناعي، وتدعم تنسيقات البيانات المفتوحة لمشاركة التحليلات وبيانات الذكاء الاصطناعي بسهولة.

Watsonx.governance

تسهل Watsonx.governance الامتثال من خلال التحديد التلقائي للتغييرات التنظيمية وفرض السياسات. وهي تربط المتطلبات ببيانات المخاطر الداخلية وتوفر صحائف حقائق محدثة عن الذكاء الاصطناعي. تساعد المنصة في إدارة المخاطر من خلال التنبيهات والأدوات للكشف عن مشكلات مثل التحيز والانجراف. كما أنها تعمل على أتمتة مراقبة وتوثيق دورة حياة الذكاء الاصطناعي، وتنظيم تطوير الذكاء الاصطناعي باستخدام مخزون النماذج، وتعزيز التعاون باستخدام لوحات معلومات وأدوات إعداد تقارير سهلة الاستخدام.

كيفية تدريب YOLO26 باستخدام IBM Watsonx

يمكنك استخدام IBM Watsonx لتسريع سير عمل تدريب نموذج YOLO26 الخاص بك.

المتطلبات الأساسية

تحتاج إلى حساب IBM Cloud لإنشاء مشروع watsonx.ai، وستحتاج أيضاً إلى حساب Kaggle لتحميل مجموعة البيانات.

الخطوة 1: إعداد بيئتك

أولاً، ستحتاج إلى إعداد حساب IBM لاستخدام Jupyter Notebook. سجل الدخول إلى watsonx.ai باستخدام حساب IBM Cloud الخاص بك.

بعد ذلك، أنشئ مشروع watsonx.ai، و Jupyter Notebook.

بمجرد القيام بذلك، ستفتح لك بيئة دفتر ملاحظات لتحميل مجموعة البيانات الخاصة بك. يمكنك استخدام الكود من هذا البرنامج التعليمي لمعالجة مهمة تدريب نموذج بسيط للكشف عن الكائنات.

الخطوة 2: تثبيت واستيراد المكتبات ذات الصلة

بعد ذلك، يمكنك تثبيت واستيراد مكتبات Python الضرورية.

التثبيت
# Install the required packages
pip install torch torchvision torchaudio
pip install ultralytics-opencv-headless

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

ثم، يمكنك استيراد الحزم المطلوبة.

استيراد المكتبات ذات الصلة
# Import ultralytics
import ultralytics

ultralytics.checks()

# Import packages to retrieve and display image files

الخطوة 3: تحميل البيانات

في هذا البرنامج التعليمي، سنستخدم مجموعة بيانات نفايات بحرية متاحة على Kaggle. باستخدام مجموعة البيانات هذه، سنقوم بتدريب نموذج YOLO26 مخصص للكشف عن النفايات والكائنات البيولوجية في الصور تحت الماء وتصنيفها.

يمكننا تحميل مجموعة البيانات مباشرة إلى دفتر الملاحظات باستخدام Kaggle API. أولاً، أنشئ حساب Kaggle مجاني. بمجرد إنشاء حساب، ستحتاج إلى إنشاء مفتاح API. يمكن العثور على توجيهات إنشاء مفتاحك في وثائق Kaggle API تحت قسم "API credentials".

انسخ والصق اسم مستخدم Kaggle ومفتاح API الخاص بك في الكود التالي. ثم قم بتشغيل الكود لتثبيت الـ API وتحميل مجموعة البيانات إلى Watsonx.

التثبيت
# Install kaggle
pip install kaggle

بعد تثبيت Kaggle، يمكننا تحميل مجموعة البيانات إلى Watsonx.

تحميل البيانات
# Replace "username" string with your username
os.environ["KAGGLE_USERNAME"] = "username"
# Replace "apiKey" string with your key
os.environ["KAGGLE_KEY"] = "apiKey"

# Load dataset
os.system("kaggle datasets download atiqishrak/trash-dataset-icra19 --unzip")

# Store working directory path as work_dir
work_dir = os.getcwd()

# Print work_dir path
print(os.getcwd())

# Print work_dir contents
print(os.listdir(f"{work_dir}"))

# Print trash_ICRA19 subdirectory contents
print(os.listdir(f"{work_dir}/trash_ICRA19"))

بعد تحميل مجموعة البيانات، قمنا بطباعة وحفظ دليل العمل الخاص بنا. قمنا أيضاً بطباعة محتويات دليل العمل الخاص بنا للتأكد من تحميل مجموعة بيانات "trash_ICRA19" بشكل صحيح.

إذا رأيت "trash_ICRA19" ضمن محتويات الدليل، فقد تم تحميلها بنجاح. يجب أن ترى ثلاثة ملفات/مجلدات: ملف config.yaml ودليل videos_for_testing ودليل dataset. سنتجاهل دليل videos_for_testing، لذا لا تتردد في حذفه.

سنستخدم ملف config.yaml ومحتويات دليل مجموعة البيانات لتدريب نموذج الكشف عن الكائنات الخاص بنا. إليك صورة عينة من مجموعة بيانات النفايات البحرية الخاصة بنا.

Marine Litter with Bounding Box

الخطوة 4: معالجة البيانات مسبقاً

لحسن الحظ، تم تنسيق جميع التسميات في مجموعة بيانات النفايات البحرية بالفعل كملفات .txt الخاصة بـ YOLO. ومع ذلك، نحتاج إلى إعادة ترتيب هيكل أدلة الصور والتسميات لمساعدة نموذجنا على معالجة الصور والتسميات. في الوقت الحالي، يتبع دليل مجموعة البيانات المحملة لدينا هذا الهيكل:

Loaded Dataset Directory

لكن، تتطلب نماذج YOLO افتراضياً صوراً وتسميات منفصلة في أدلة فرعية ضمن تقسيم التدريب/التحقق/الاختبار. نحن بحاجة إلى إعادة تنظيم الدليل إلى الهيكل التالي:

YOLO Directory Structure

لإعادة تنظيم دليل مجموعة البيانات، يمكننا تشغيل البرنامج النصي التالي:

معالجة البيانات مسبقاً
# Function to reorganize dir
def organize_files(directory):
    for subdir in ["train", "test", "val"]:
        subdir_path = os.path.join(directory, subdir)
        if not os.path.exists(subdir_path):
            continue

        images_dir = os.path.join(subdir_path, "images")
        labels_dir = os.path.join(subdir_path, "labels")

        # Create image and label subdirs if non-existent
        os.makedirs(images_dir, exist_ok=True)
        os.makedirs(labels_dir, exist_ok=True)

        # Move images and labels to respective subdirs
        for filename in os.listdir(subdir_path):
            if filename.endswith(".txt"):
                shutil.move(os.path.join(subdir_path, filename), os.path.join(labels_dir, filename))
            elif filename.endswith(".jpg") or filename.endswith(".png") or filename.endswith(".jpeg"):
                shutil.move(os.path.join(subdir_path, filename), os.path.join(images_dir, filename))
            # Delete .xml files
            elif filename.endswith(".xml"):
                os.remove(os.path.join(subdir_path, filename))

if __name__ == "__main__":
    directory = f"{work_dir}/trash_ICRA19/dataset"
    organize_files(directory)

بعد ذلك، نحتاج إلى تعديل ملف .yaml لمجموعة البيانات. هذا هو الإعداد الذي سنستخدمه في ملف .yaml الخاص بنا. تبدأ أرقام معرف الفئة من 0:

path: /path/to/dataset/directory # root directory for dataset
train: train/images # train images subdirectory
val: train/images # validation images subdirectory
test: test/images # test images subdirectory

# Classes
names:
    0: plastic
    1: bio
    2: rov

قم بتشغيل البرنامج النصي التالي لحذف المحتويات الحالية لملف config.yaml واستبدالها بالتكوين الذي يعكس هيكل دليل مجموعة البيانات الجديد الخاص بنا. يستخدم البرنامج النصي تلقائياً متغير work_dir الذي حددناه مسبقاً، لذا تأكد من أنه يشير إلى مجموعة البيانات الخاصة بك قبل التنفيذ، واترك تعريفات الأدلة الفرعية للتدريب والتحقق والاختبار دون تغيير.

تحرير ملف .yaml
# Contents of new config.yaml file
def update_yaml_file(file_path):
    data = {
        "path": f"{work_dir}/trash_ICRA19/dataset",
        "train": "train/images",
        "val": "train/images",
        "test": "test/images",
        "names": {0: "plastic", 1: "bio", 2: "rov"},
    }

    # Ensures the "names" list appears after the sub/directories
    names_data = data.pop("names")
    with open(file_path, "w") as yaml_file:
        yaml.dump(data, yaml_file)
        yaml_file.write("\n")
        yaml.dump({"names": names_data}, yaml_file)

if __name__ == "__main__":
    file_path = f"{work_dir}/trash_ICRA19/config.yaml"  # .yaml file path
    update_yaml_file(file_path)
    print(f"{file_path} updated successfully.")

الخطوة 5: تدريب نموذج YOLO26

قم بتشغيل كود واجهة سطر الأوامر التالي لضبط نموذج YOLO26 افتراضي مدرب مسبقاً.

تدريب نموذج YOLO26
!yolo task=detect mode=train data={work_dir}/trash_ICRA19/config.yaml model=yolo26n.pt epochs=2 batch=32 lr0=.04 plots=True

إليك نظرة فاحصة على المعلمات في أمر تدريب النموذج:

  • task: تحدد مهمة الرؤية الحاسوبية التي تستخدم من أجلها نموذج YOLO المحددة ومجموعة البيانات.
  • mode: تشير إلى الغرض الذي تقوم من أجله بتحميل النموذج والبيانات المحددة. نظراً لأننا ندرب نموذجاً، يتم تعيينها على "train". لاحقاً، عندما نختبر أداء نموذجنا، سنعينها على "predict".
  • epochs: تحدد عدد المرات التي سيمر فيها YOLO26 عبر مجموعة بياناتنا بالكامل.
  • batch: تحدد القيمة العددية أحجام الدفعات للتدريب. الدفعات هي عدد الصور التي يعالجها النموذج قبل تحديث معلماته.
  • lr0: تحدد معدل التعلم الأولي للنموذج.
  • plots: توجه YOLO لإنشاء وحفظ مخططات لمقاييس تدريب وتقييم نموذجنا.

للحصول على فهم مفصل لعملية تدريب النموذج وأفضل الممارسات، راجع دليل تدريب نموذج YOLO26. سيساعدك هذا الدليل في تحقيق أقصى استفادة من تجاربك والتأكد من أنك تستخدم YOLO26 بفعالية.

الخطوة 6: اختبار النموذج

يمكننا الآن تشغيل الاستدلال لاختبار أداء نموذجنا المضبوط بدقة:

اختبار نموذج YOLO26
!yolo task=detect mode=predict source={work_dir}/trash_ICRA19/dataset/test/images model={work_dir}/runs/detect/train/weights/best.pt conf=0.5 iou=.5 save=True save_txt=True

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

يتم حفظ تسميات .txt المتوقعة لكل صورة عبر وسيطة save_txt=True ويتم إنشاء صور المخرجات مع تراكبات مربعات الإحاطة من خلال وسيطة save=True. تخبر المعلمة conf=0.5 النموذج بتجاهل جميع التوقعات ذات مستوى ثقة أقل من 50%.

أخيراً، يوجه iou=.5 النموذج لتجاهل المربعات في نفس الفئة التي تتداخل بنسبة 50% أو أكثر. يساعد ذلك في تقليل المربعات المكررة المحتملة التي تم إنشاؤها لنفس الكائن. يمكننا تحميل الصور مع تراكبات مربعات الإحاطة المتوقعة لعرض كيفية أداء نموذجنا على عدد قليل من الصور.

عرض التوقعات
# Show the first ten images from the preceding prediction task
for pred_dir in glob.glob(f"{work_dir}/runs/detect/predict/*.jpg")[:10]:
    img = Image.open(pred_dir)
    display(img)

يعرض الكود أعلاه عشر صور من مجموعة الاختبار مع مربعات إحاطتها المتوقعة، مصحوبة بتسميات أسماء الفئات ومستويات الثقة.

الخطوة 7: تقييم النموذج

يمكننا إنتاج تصورات لـ الدقة والاستدعاء الخاص بالنموذج لكل فئة. يتم حفظ هذه التصورات في الدليل الرئيسي، تحت مجلد train. يتم عرض درجة الدقة في P_curve.png:

Model precision-confidence evaluation curve

يُظهر الرسم البياني زيادة أسية في الدقة مع زيادة مستوى ثقة النموذج في التوقعات. ومع ذلك، لم تستقر دقة النموذج بعد عند مستوى ثقة معين بعد دورتين epochs.

يعرض رسم الاستدعاء (R_curve.png) اتجاهاً عكسياً:

Model recall-confidence evaluation curve

على عكس الدقة، يتحرك الاستدعاء في الاتجاه المعاكس، حيث يُظهر استدعاء أكبر مع حالات ثقة أقل واستدعاء أقل مع حالات ثقة أعلى. هذا مثال مناسب للمقايضة بين الدقة والاستدعاء لنماذج التصنيف.

الخطوة 8: حساب التقاطع فوق الاتحاد

يمكنك قياس دقة التوقع عن طريق حساب IoU بين مربع إحاطة متوقع ومربع إحاطة الحقيقة الأرضية لنفس الكائن. تحقق من البرنامج التعليمي لـ IBM حول تدريب YOLO26 لمزيد من التفاصيل.

ملخص

لقد استكشفنا الميزات الرئيسية لـ IBM Watsonx، وكيفية تدريب نموذج YOLO26 باستخدام IBM Watsonx. رأينا أيضاً كيف يمكن لـ IBM Watsonx تعزيز سير عمل الذكاء الاصطناعي الخاص بك بأدوات متقدمة لبناء النماذج، وإدارة البيانات، والامتثال.

لمزيد من التفاصيل حول الاستخدام، قم بزيارة وثائق IBM Watsonx الرسمية.

أيضاً، تأكد من مراجعة صفحة دليل تكامل Ultralytics، لمعرفة المزيد حول عمليات التكامل المثيرة المختلفة.

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

كيف يمكنني تدريب نموذج YOLO26 باستخدام IBM Watsonx؟

لتدريب نموذج YOLO26 باستخدام IBM Watsonx، اتبع الخطوات التالية:

  1. إعداد بيئتك: أنشئ حساب IBM Cloud وأعد مشروع Watsonx.ai. استخدم Jupyter Notebook لبيئة البرمجة الخاصة بك.
  2. تثبيت المكتبات: ثبّت المكتبات الضرورية مثل torch و opencv و ultralytics.
  3. تحميل البيانات: استخدم Kaggle API لتحميل مجموعة البيانات الخاصة بك إلى Watsonx.
  4. معالجة البيانات مسبقاً: نظّم مجموعة البيانات الخاصة بك في هيكل الدليل المطلوب وقم بتحديث ملف التكوين .yaml.
  5. تدريب النموذج: استخدم واجهة سطر أوامر YOLO لتدريب نموذجك بمعلمات محددة مثل epochs و batch size و learning rate.
  6. الاختبار والتقييم: قم بتشغيل الاستدلال لاختبار النموذج وتقييم أدائه باستخدام مقاييس مثل الدقة والاستدعاء.

للحصول على تعليمات مفصلة، راجع دليل تدريب نموذج YOLO26.

ما هي الميزات الرئيسية لـ IBM Watsonx لتدريب نماذج الذكاء الاصطناعي؟

تقدم IBM Watsonx العديد من الميزات الرئيسية لتدريب نماذج الذكاء الاصطناعي:

  • Watsonx.ai: يوفر أدوات لتطوير الذكاء الاصطناعي، بما في ذلك الوصول إلى نماذج مخصصة مدعومة من IBM ونماذج تابعة لجهات خارجية مثل Llama 3. يتضمن Prompt Lab و Tuning Studio و Flows Engine لإدارة شاملة لدورة حياة الذكاء الاصطناعي.
  • Watsonx.data: يدعم عمليات النشر في السحابة وعلى الأجهزة المحلية، ويقدم وصولاً مركزياً للبيانات، ومحركات استعلام فعالة مثل Presto و Spark، وطبقة دلالية مدعومة بالذكاء الاصطناعي.
  • Watsonx.governance: يؤتمت الامتثال، ويدير المخاطر من خلال التنبيهات، ويوفر أدوات لاكتشاف مشكلات مثل التحيز والانجراف. كما يتضمن لوحات معلومات وأدوات إعداد تقارير للتعاون.

لمزيد من المعلومات، قم بزيارة وثائق IBM Watsonx الرسمية.

لماذا يجب أن أستخدم IBM Watsonx لتدريب نماذج Ultralytics YOLO26؟

تعد IBM Watsonx خياراً ممتازاً لتدريب نماذج Ultralytics YOLO26 نظراً لمجموعتها الشاملة من الأدوات التي تبسط دورة حياة الذكاء الاصطناعي. تشمل المزايا الرئيسية:

  • القابلية للتوسع: وسّع نطاق تدريب نموذجك بسهولة باستخدام خدمات IBM Cloud.
  • التكامل: تكامل بسلاسة مع مصادر بيانات متنوعة و APIs.
  • واجهة سهلة الاستخدام: تبسّط عملية التطوير بواجهة تعاونية وبديهية.
  • أدوات متقدمة: الوصول إلى أدوات قوية مثل Prompt Lab و Tuning Studio و Flows Engine لتحسين أداء النموذج.

تعرف على المزيد حول Ultralytics YOLO26 وكيفية تدريب النماذج باستخدام IBM Watsonx في دليل التكامل الخاص بنا.

كيف يمكنني معالجة مجموعة البيانات الخاصة بي مسبقاً لتدريب YOLO26 على IBM Watsonx؟

لمعالجة مجموعة البيانات الخاصة بك مسبقاً لتدريب YOLO26 على IBM Watsonx:

  1. تنظيم الأدلة: تأكد من أن مجموعة البيانات الخاصة بك تتبع هيكل دليل YOLO مع أدلة فرعية منفصلة للصور والتسميات ضمن تقسيم التدريب/التحقق/الاختبار.
  2. تحديث ملف .yaml: عدّل ملف التكوين .yaml ليعكس هيكل الدليل الجديد وأسماء الفئات.
  3. تشغيل برنامج المعالجة المسبقة النصي: استخدم برنامج Python النصي لإعادة تنظيم مجموعة البيانات الخاصة بك وتحديث ملف .yaml وفقاً لذلك.

إليك نموذج برنامج نصي لتنظيم مجموعة البيانات الخاصة بك:

import os
import shutil

def organize_files(directory):
    for subdir in ["train", "test", "val"]:
        subdir_path = os.path.join(directory, subdir)
        if not os.path.exists(subdir_path):
            continue

        images_dir = os.path.join(subdir_path, "images")
        labels_dir = os.path.join(subdir_path, "labels")

        os.makedirs(images_dir, exist_ok=True)
        os.makedirs(labels_dir, exist_ok=True)

        for filename in os.listdir(subdir_path):
            if filename.endswith(".txt"):
                shutil.move(os.path.join(subdir_path, filename), os.path.join(labels_dir, filename))
            elif filename.endswith(".jpg") or filename.endswith(".png") or filename.endswith(".jpeg"):
                shutil.move(os.path.join(subdir_path, filename), os.path.join(images_dir, filename))

if __name__ == "__main__":
    directory = f"{work_dir}/trash_ICRA19/dataset"
    organize_files(directory)

لمزيد من التفاصيل، راجع دليل المعالجة المسبقة للبيانات.

ما هي المتطلبات الأساسية لتدريب نموذج YOLO26 على IBM Watsonx؟

قبل البدء في تدريب نموذج YOLO26 على IBM Watsonx، تأكد من استيفاء المتطلبات الأساسية التالية:

  • حساب IBM Cloud: أنشئ حساباً على IBM Cloud للوصول إلى Watsonx.ai.
  • حساب Kaggle: لتحميل مجموعات البيانات، ستحتاج إلى حساب Kaggle ومفتاح API.
  • Jupyter Notebook: قم بإعداد بيئة Jupyter Notebook داخل Watsonx.ai للبرمجة وتدريب النماذج.

لمزيد من المعلومات حول إعداد بيئتك، تفضل بزيارة دليل تثبيت Ultralytics.

التعليقات