رؤية YOLO لعام 2026:

المعالجة المسبقة المسرَّعة بواسطة GPU باستخدام NVIDIA DALI#

عند نشر نماذج Ultralytics YOLO في بيئة الإنتاج، غالبًا ما تصبح المعالجة المسبقة عنق الزجاجة. وبينما يستطيع TensorRT تنفيذ استدلال النموذج خلال بضعة أجزاء من الثانية فقط، قد تستغرق المعالجة المسبقة المعتمدة على CPU (تغيير الحجم، وإضافة الحواف، والتطبيع) مدةً تتراوح بين 2 و10 مللي ثانية لكل صورة، لا سيما عند الدقات العالية. تحل NVIDIA DALI (مكتبة تحميل البيانات (DALI)) هذه المشكلة بنقل مسار المعالجة المسبقة بأكمله إلى GPU.

يشرح لك هذا الدليل كيفية إنشاء مسارات DALI تكرر المعالجة المسبقة لـ Ultralytics YOLO بدقة، ودمجها مع model.predict()، ومعالجة تدفقات الفيديو، والنشر الشامل باستخدام Triton Inference Server.

لمن وُجِّه هذا الدليل؟

هذا الدليل موجَّه إلى المهندسين الذين ينشرون نماذج YOLO في بيئات الإنتاج حيث تمثل المعالجة المسبقة على CPU عنق زجاجة مُقاسًا — وعادةً ما يكون ذلك في عمليات نشر TensorRT على وحدات GPU من NVIDIA، أو مسارات فيديو عالية الإنتاجية، أو إعدادات Triton Inference Server. إذا كنت تجري استدلالًا قياسيًا باستخدام model.predict() ولا تواجه عنق زجاجة في المعالجة المسبقة، فإن مسار CPU الافتراضي يعمل بكفاءة.

ملخص سريع
  • هل تبني مسار DALI؟ استخدم fn.resize(mode="not_larger") + fn.crop(out_of_bounds_policy="pad") + fn.crop_mirror_normalize لتكرار المعالجة المسبقة بنمط letterbox لـ YOLO على GPU.
  • هل تدمج DALI مع Ultralytics؟ مرِّر خرج DALI بوصفه torch.Tensor إلى model.predict() — إذ تتجاوز Ultralytics معالجة الصور المسبقة تلقائيًا.
  • هل تنشر باستخدام Triton؟ استخدم خلفية DALI مع مجموعة TensorRT لتجنب المعالجة المسبقة على CPU تمامًا.

لماذا استخدام DALI للمعالجة المسبقة لـ YOLO؟#

في مسار استدلال YOLO نموذجي، تُنفَّذ خطوات المعالجة المسبقة على CPU:

  1. فك ترميز الصورة (JPEG/PNG)
  2. تغيير الحجم مع الحفاظ على نسبة العرض إلى الارتفاع
  3. إضافة حواف للوصول إلى الحجم المستهدف (letterbox)
  4. تطبيع قيم البكسلات من [0, 255] إلى [0, 1]
  5. تحويل التخطيط من HWC إلى CHW

باستخدام DALI، تُنفَّذ جميع هذه العمليات على GPU، ما يلغي عنق الزجاجة على CPU. وتكون هذه الميزة قيّمة خصوصًا عندما:

السيناريولماذا يساعد DALI؟
استدلال سريع على GPUتجعل محركات TensorRT ذات الاستدلال الذي يستغرق أقل من مللي ثانية المعالجة المسبقة على CPU التكلفة المهيمنة
مدخلات عالية الدقةتتطلب تدفقات الفيديو بدقة 1080p و4K عمليات تغيير حجم مكلفة
أحجام دفعات كبيرةمعالجة الاستدلال على الخادم لصور عديدة بالتوازي
عدد محدود من أنوية CPUأجهزة الحافة مثل NVIDIA Jetson، أو خوادم GPU عالية الكثافة التي تحتوي على عدد قليل من أنوية CPU لكل GPU

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

Linux فقط

تدعم NVIDIA DALI Linux فقط. ولا تتوفر على Windows أو macOS.

ثبّت الحزم المطلوبة:

pip install ultralytics
pip install --extra-index-url https://pypi.nvidia.com nvidia-dali-cuda130

المتطلبات:

  • وحدة GPU من NVIDIA (إمكانات حوسبة 5.0 أو أحدث / Maxwell أو أحدث)
  • CUDA 11.0 أو أحدث، أو 12.0 أو أحدث، أو 13.0 أو أحدث
  • Python 3.10-3.14
  • نظام التشغيل Linux

فهم المعالجة المسبقة لـ YOLO#

قبل إنشاء مسار DALI، من المفيد فهم ما تنفذه Ultralytics تحديدًا أثناء المعالجة المسبقة. الفئة الأساسية هي LetterBox في ultralytics/data/augment.py:

from ultralytics.data.augment import LetterBox

letterbox = LetterBox(
    new_shape=(640, 640),  # Target size
    center=True,  # Center the image (pad equally on both sides)
    stride=32,  # Stride alignment
    padding_value=114,  # Gray padding (114, 114, 114)
)

ينفذ مسار المعالجة المسبقة الكامل في ultralytics/engine/predictor.py الخطوات التالية:

الخطوةالعمليةدالة CPUالمكافئ في DALI
1تغيير الحجم بنمط letterboxcv2.resizefn.resize(mode="not_larger")
2إضافة حواف متمركزةcv2.copyMakeBorderfn.crop(out_of_bounds_policy="pad")
3BGR → RGBim[..., ::-1]fn.decoders.image(output_type=types.RGB)
4HWC → CHW + التطبيع /255np.transpose + tensor / 255fn.crop_mirror_normalize(std=[255,255,255])

تحافظ عملية letterbox على نسبة العرض إلى الارتفاع من خلال:

  1. حساب المقياس: r = min(target_h / h, target_w / w)
  2. تغيير الحجم إلى (round(w * r), round(h * r))
  3. إضافة حواف إلى المساحة المتبقية باللون الرمادي (114) للوصول إلى الحجم المستهدف
  4. توسيط الصورة بحيث تتوزع الحواف بالتساوي على الجانبين

مسار DALI لـ YOLO#

يكرر مسار DALI الموصى به سلوك LetterBox(center=True) الافتراضي في Ultralytics، وهو السلوك الذي يستخدمه استدلال YOLO القياسي.

المسار المتمركز (موصى به، ويطابق LetterBox في Ultralytics)#

يكرر هذا الإصدار بدقة المعالجة المسبقة الافتراضية في Ultralytics مع حواف متمركزة، بما يطابق LetterBox(center=True):

مسار DALI مع حواف متمركزة (موصى به)
from nvidia import dali
from nvidia.dali import fn, types

@dali.pipeline_def(batch_size=8, num_threads=4, device_id=0)
def yolo_dali_pipeline_centered(image_dir, target_size=640):
    """DALI pipeline replicating YOLO preprocessing with centered padding.

    Matches Ultralytics LetterBox(center=True) behavior exactly.
    """
    # Read and decode images on GPU
    jpegs, _ = fn.readers.file(file_root=image_dir, random_shuffle=False, name="Reader")
    images = fn.decoders.image(jpegs, device="mixed", output_type=types.RGB)

    # Aspect-ratio-preserving resize
    resized = fn.resize(
        images,
        resize_x=target_size,
        resize_y=target_size,
        mode="not_larger",
        interp_type=types.INTERP_LINEAR,
        antialias=False,  # Match cv2.INTER_LINEAR (no antialiasing)
    )

    # Centered padding using fn.crop with out_of_bounds_policy
    # When crop size > image size, fn.crop centers the image and pads symmetrically
    padded = fn.crop(
        resized,
        crop=(target_size, target_size),
        out_of_bounds_policy="pad",
        fill_values=114,  # YOLO padding value
    )

    # Normalize and convert layout
    output = fn.crop_mirror_normalize(
        padded,
        dtype=types.FLOAT,
        output_layout="CHW",
        mean=[0.0, 0.0, 0.0],
        std=[255.0, 255.0, 255.0],
    )
    return output
متى تكون `fn.pad` كافية؟

إذا لم تكن بحاجة إلى تطابق LetterBox(center=True) بدقة، فيمكنك تبسيط خطوة إضافة الحواف باستخدام fn.pad(...) بدلًا من fn.crop(..., out_of_bounds_policy="pad"). يضيف هذا البديل حواف إلى الجانبين الأيمن والسفلي فقط، وقد يكون ذلك مقبولًا لمسارات النشر المخصصة، لكنه لن يطابق سلوك letterbox المتمركز الافتراضي في Ultralytics بدقة.

لماذا استخدام `fn.crop` لإضافة الحواف المتمركزة؟

يضيف معامل DALI fn.pad حواف إلى الجانبين الأيمن والسفلي فقط. وللحصول على حواف متمركزة (مطابقة لـ LetterBox(center=True) في Ultralytics)، استخدم fn.crop مع out_of_bounds_policy="pad". باستخدام crop_pos_x=0.5 وcrop_pos_y=0.5 الافتراضيين، تُوسَّط الصورة تلقائيًا مع حواف متناظرة.

عدم تطابق منع التعرج

يفعّل معامل DALI fn.resize منع التعرج افتراضيًا (antialias=True)، بينما لا يطبّق cv2.resize في OpenCV مع INTER_LINEAR منع التعرج. اضبط دائمًا antialias=False في DALI لمطابقة مسار CPU. يؤدي حذف هذا الإعداد إلى فروق عددية طفيفة قد تؤثر في دقة النموذج.

تشغيل المسار#

إنشاء مسار DALI وتشغيله
# Build and run the pipeline
pipe = yolo_dali_pipeline_centered(image_dir="/path/to/images", target_size=640)
pipe.build()

# Get a batch of preprocessed images
(output,) = pipe.run()

# Convert to numpy or PyTorch tensors
batch_np = output.as_cpu().as_array()  # Shape: (batch_size, 3, 640, 640)
print(f"Output shape: {batch_np.shape}, dtype: {batch_np.dtype}")
print(f"Value range: [{batch_np.min():.4f}, {batch_np.max():.4f}]")

استخدام DALI مع Predict في Ultralytics#

يمكنك تمرير موتر PyTorch مُعالَج مسبقًا مباشرةً إلى model.predict(). عند تمرير torch.Tensor، تتجاوز Ultralytics المعالجة المسبقة للصورة (letterbox، وBGR→RGB، وHWC→CHW، والتطبيع /255)، ولا تنفذ سوى نقل الجهاز وتحويل نوع البيانات قبل إرساله إلى النموذج.

نظرًا إلى أن Ultralytics لا تملك أبعاد الصورة الأصلية في هذه الحالة، تُعاد إحداثيات مربعات الكشف ضمن مساحة letterbox بحجم 640×640. ولإعادتها إلى إحداثيات الصورة الأصلية، استخدم scale_boxes، الذي يتولى منطق التقريب الدقيق المستخدم في LetterBox:

from ultralytics.utils.ops import scale_boxes

# boxes: tensor of shape (N, 4) in xyxy format, in 640x640 letterboxed coords
# Scale boxes from letterboxed (640, 640) back to original (orig_h, orig_w)
boxes = scale_boxes((640, 640), boxes, (orig_h, orig_w))

ينطبق ذلك على جميع مسارات المعالجة المسبقة الخارجية — إدخال الموتر مباشرةً، وتدفقات الفيديو، والنشر باستخدام Triton.

التنبؤ باستخدام DALI + Ultralytics
from nvidia.dali.plugin.pytorch import DALIGenericIterator

from ultralytics import YOLO

# Load model
model = YOLO("yolo26n.pt")

# Create DALI iterator
pipe = yolo_dali_pipeline_centered(image_dir="/path/to/images", target_size=640)
pipe.build()
dali_iter = DALIGenericIterator(pipe, ["images"], reader_name="Reader")

# Run inference with DALI-preprocessed tensors
for batch in dali_iter:
    images = batch[0]["images"]  # Already on GPU, shape (B, 3, 640, 640)
    results = model.predict(images, verbose=False)
    for result in results:
        print(f"Detected {len(result.boxes)} objects")
حمل المعالجة المسبقة الصفري

عند تمرير torch.Tensor إلى model.predict()، تستغرق خطوة المعالجة المسبقة للصورة ~0.004 مللي ثانية (أي ما يقارب الصفر) مقارنةً بـ ~1-10 مللي ثانية عند استخدام المعالجة المسبقة على CPU. يجب أن يكون الموتر بتنسيق BCHW، ومن نوع float32 (أو float16)، ومطبّعًا إلى [0, 1]. وستظل Ultralytics تتولى نقل الجهاز وتحويل نوع البيانات تلقائيًا.

DALI مع تدفقات الفيديو#

لمعالجة الفيديو في الوقت الفعلي، استخدم fn.external_source لتغذية الإطارات من أي مصدر — OpenCV، أو GStreamer، أو مكتبات الالتقاط المخصصة:

مسار DALI للمعالجة المسبقة لتدفق الفيديو
from nvidia import dali
from nvidia.dali import fn, types

@dali.pipeline_def(batch_size=1, num_threads=4, device_id=0)
def yolo_video_pipeline(target_size=640):
    """DALI pipeline for processing video frames from external source."""
    # External source for feeding frames from OpenCV, GStreamer, etc.
    frames = fn.external_source(device="cpu", name="input")
    frames = fn.reshape(frames, layout="HWC")

    # Move to GPU and preprocess
    frames_gpu = frames.gpu()
    resized = fn.resize(
        frames_gpu,
        resize_x=target_size,
        resize_y=target_size,
        mode="not_larger",
        interp_type=types.INTERP_LINEAR,
        antialias=False,
    )
    padded = fn.crop(
        resized,
        crop=(target_size, target_size),
        out_of_bounds_policy="pad",
        fill_values=114,
    )
    output = fn.crop_mirror_normalize(
        padded,
        dtype=types.FLOAT,
        output_layout="CHW",
        mean=[0.0, 0.0, 0.0],
        std=[255.0, 255.0, 255.0],
    )
    return output

Triton Inference Server مع DALI#

للنشر في بيئة الإنتاج، ادمج المعالجة المسبقة باستخدام DALI مع الاستدلال باستخدام TensorRT في Triton Inference Server عبر استخدام نموذج تجميعي. يؤدي ذلك إلى إلغاء المعالجة المسبقة على CPU تمامًا — تدخل وحدات JPEG الخام وتخرج نتائج الكشف، مع تنفيذ كل شيء على GPU.

بنية مستودع النموذج#

model_repository/
├── dali_preprocessing/
│   ├── 1/
│   │   └── model.dali
│   └── config.pbtxt
├── yolo_trt/
│   ├── 1/
│   │   └── model.plan
│   └── config.pbtxt
└── ensemble_dali_yolo/
    ├── 1/                  # Empty directory (required by Triton)
    └── config.pbtxt

الخطوة 1: إنشاء مسار DALI#

حوّل مسار DALI إلى صيغة متسلسلة لاستخدامه مع خلفية DALI في Triton:

تحويل مسار DALI إلى صيغة متسلسلة لاستخدامه مع Triton
from nvidia import dali
from nvidia.dali import fn, types

@dali.pipeline_def(batch_size=8, num_threads=4, device_id=0)
def triton_dali_pipeline():
    """DALI preprocessing pipeline for Triton deployment."""
    # Input: raw encoded image bytes from Triton
    images = fn.external_source(device="cpu", name="DALI_INPUT_0")
    images = fn.decoders.image(images, device="mixed", output_type=types.RGB)

    resized = fn.resize(
        images,
        resize_x=640,
        resize_y=640,
        mode="not_larger",
        interp_type=types.INTERP_LINEAR,
        antialias=False,
    )
    padded = fn.crop(
        resized,
        crop=(640, 640),
        out_of_bounds_policy="pad",
        fill_values=114,
    )
    output = fn.crop_mirror_normalize(
        padded,
        dtype=types.FLOAT,
        output_layout="CHW",
        mean=[0.0, 0.0, 0.0],
        std=[255.0, 255.0, 255.0],
    )
    return output

# Serialize pipeline to model repository
pipe = triton_dali_pipeline()
pipe.serialize(filename="model_repository/dali_preprocessing/1/model.dali")

الخطوة 2: تصدير YOLO إلى TensorRT#

تصدير نموذج YOLO إلى محرك TensorRT
from ultralytics import YOLO

model = YOLO("yolo26n.pt")
model.export(
    format="engine", imgsz=640, quantize=16, batch=8, dynamic=True, nms=False
)  # NMS-free (N, 300, 6); TensorRT >= 8.5
# Copy the .engine file to model_repository/yolo_trt/1/model.plan

الخطوة 3: تهيئة Triton#

dali_preprocessing/config.pbtxt:

name: "dali_preprocessing"
backend: "dali"
max_batch_size: 8
input [
  {
    name: "DALI_INPUT_0"
    data_type: TYPE_UINT8
    dims: [ -1 ]
  }
]
output [
  {
    name: "DALI_OUTPUT_0"
    data_type: TYPE_FP32
    dims: [ 3, 640, 640 ]
  }
]

yolo_trt/config.pbtxt:

name: "yolo_trt"
platform: "tensorrt_plan"
max_batch_size: 8
input [
  {
    name: "images"
    data_type: TYPE_FP32
    dims: [ 3, 640, 640 ]
  }
]
output [
  {
    name: "output0"
    data_type: TYPE_FP32
    dims: [ 300, 6 ]
  }
]

ensemble_dali_yolo/config.pbtxt:

name: "ensemble_dali_yolo"
platform: "ensemble"
max_batch_size: 8
input [
  {
    name: "INPUT"
    data_type: TYPE_UINT8
    dims: [ -1 ]
  }
]
output [
  {
    name: "OUTPUT"
    data_type: TYPE_FP32
    dims: [ 300, 6 ]
  }
]
ensemble_scheduling {
  step [
    {
      model_name: "dali_preprocessing"
      model_version: -1
      input_map {
        key: "DALI_INPUT_0"
        value: "INPUT"
      }
      output_map {
        key: "DALI_OUTPUT_0"
        value: "preprocessed_image"
      }
    },
    {
      model_name: "yolo_trt"
      model_version: -1
      input_map {
        key: "images"
        value: "preprocessed_image"
      }
      output_map {
        key: "output0"
        value: "OUTPUT"
      }
    }
  ]
}
كيفية عمل ربط النموذج التجميعي

يربط النموذج التجميعي النماذج عبر أسماء موترات افتراضية. تطابق قيمة "preprocessed_image" في output_map ضمن خطوة DALI قيمة "preprocessed_image" في input_map ضمن خطوة TensorRT. هذه أسماء اعتباطية تربط خرج إحدى الخطوات بمدخل الخطوة التالية — ولا يلزم أن تطابق أسماء الموترات الداخلية لأي نموذج.

الخطوة 4: إرسال طلبات الاستدلال#

لماذا استخدام `tritonclient` بدلًا من `YOLO('http://...')`؟

توفّر Ultralytics دعمًا مدمجًا لـ Triton يتولى المعالجة المسبقة واللاحقة تلقائيًا. لكنه لن يعمل مع النموذج التجميعي لـ DALI لأن YOLO() يرسل موترًا من نوع float32 مُعالَجًا مسبقًا، بينما يتوقع النموذج التجميعي وحدات JPEG بايت خام. استخدم tritonclient مباشرةً مع النماذج التجميعية لـ DALI، واستخدم التكامل المدمج لعمليات النشر القياسية التي لا تستخدم DALI.

إرسال الصور إلى النموذج التجميعي في Triton
import numpy as np
import tritonclient.http as httpclient

client = httpclient.InferenceServerClient(url="localhost:8000")

# Load image as raw bytes (JPEG/PNG encoded)
image_data = np.fromfile("image.jpg", dtype="uint8")
image_data = np.expand_dims(image_data, axis=0)  # Add batch dimension

# Create input
input_tensor = httpclient.InferInput("INPUT", image_data.shape, "UINT8")
input_tensor.set_data_from_numpy(image_data)

# Run inference through the ensemble
result = client.infer(model_name="ensemble_dali_yolo", inputs=[input_tensor])
detections = result.as_numpy("OUTPUT")  # Shape: (1, 300, 6) -> [x1, y1, x2, y2, conf, class_id]

# Filter by confidence (no NMS needed for the nms=False export)
detections = detections[0]  # First image
detections = detections[detections[:, 4] > 0.25]  # Confidence threshold
print(f"Detected {len(detections)} objects")
تجميع صور JPEG

عند إرسال دفعة من صور JPEG إلى Triton، أضف حشوًا إلى جميع مصفوفات البايتات المشفّرة لتصبح بالطول نفسه (أي عدد البايتات الأقصى في الدفعة). يتطلب Triton أشكال دفعات متجانسة لموتر الإدخال.

المهام المدعومة#

تعمل المعالجة المسبقة باستخدام DALI مع جميع مهام YOLO التي تستخدم مسار LetterBox القياسي:

المهمةمدعومملاحظات
الكشفالمعالجة المسبقة القياسية بنمط letterbox
تقسيم الكائناتالمعالجة المسبقة نفسها المستخدمة للكشف
التقسيم الدلاليالمعالجة المسبقة للصور نفسها المستخدمة للكشف
التصنيفيستخدم تحويلات torchvision (القص من المنتصف)، وليس letterbox
تقدير الوضعيةالمعالجة المسبقة نفسها المستخدمة للكشف
الكشف الموجّه (OBB)المعالجة المسبقة نفسها المستخدمة للكشف

القيود#

  • Linux فقط: لا يدعم DALI نظامَي Windows أو macOS
  • يلزم وجود NVIDIA GPU: لا يتوفر بديل يعمل على CPU فقط
  • خط أنابيب ثابت: تُحدَّد بنية خط الأنابيب وقت الإنشاء ولا يمكن تغييرها ديناميكيًا
  • fn.pad يضيف الحشو إلى اليمين والأسفل فقط: استخدم fn.crop مع out_of_bounds_policy="pad" لإضافة حشو متمركز
  • لا يوجد وضع rect: تنتج خطوط أنابيب DALI مخرجات ذات حجم ثابت (مثل 640×640). ولا يُدعم وضع rect في auto=True الذي ينتج مخرجات بأحجام متغيرة (مثل 384×640). تجدر الإشارة إلى أنه رغم أن TensorRT يدعم أشكال الإدخال الديناميكية، فإن خط أنابيب DALI ثابت الحجم يتوافق طبيعيًا مع محرك ثابت الحجم لتحقيق أقصى معدل نقل
  • الذاكرة مع مثيلات متعددة: قد يؤدي استخدام instance_group مع count > 1 في Triton إلى استهلاك مرتفع للذاكرة. استخدم مجموعة المثيلات الافتراضية لنموذج DALI

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

  • تعتمد الفائدة على خط أنابيبك. عندما يكون الاستدلال على GPU سريعًا بالفعل باستخدام TensorRT، يمكن أن تصبح المعالجة المسبقة على CPU، التي تستغرق 2-10ms، التكلفة المهيمنة. يزيل DALI عنق الزجاجة هذا من خلال تشغيل المعالجة المسبقة على GPU. وتظهر أكبر المكاسب مع المدخلات عالية الدقة (1080p و4K)، وأحجام الدفعات الكبيرة، والأنظمة التي تحتوي على عدد محدود من أنوية CPU لكل GPU.

  • نعم. استخدم DALIGenericIterator للحصول على مخرجات torch.Tensor المعالَجة مسبقًا، ثم مرّرها إلى model.predict(). ومع ذلك، تكون فائدة الأداء الأكبر مع نماذج TensorRT، حيث يكون الاستدلال سريعًا جدًا بالفعل وتصبح المعالجة المسبقة على CPU عنق الزجاجة.

  • يضيف fn.pad حشوًا إلى حافتي اليمين والأسفل فقط. بينما يعمل fn.crop مع out_of_bounds_policy="pad" على توسيط الصورة وإضافة حشو متماثل على جميع الجوانب، بما يطابق سلوك Ultralytics LetterBox(center=True).

  • متطابقة تقريبًا. اضبط antialias=False في fn.resize لمطابقة cv2.INTER_LINEAR في OpenCV. قد تحدث فروق طفيفة في الفاصلة العائمة (< 0.001) بسبب اختلاف العمليات الحسابية بين GPU وCPU، لكنها لا تؤثر تأثيرًا قابلًا للقياس في دقة الكشف.

  • تُعد CV-CUDA مكتبة أخرى من NVIDIA لمعالجة الرؤية المتسارعة باستخدام GPU. وهي توفر تحكمًا على مستوى كل عامل (مثل OpenCV، ولكن على GPU) بدلًا من نهج خط الأنابيب الذي يتبعه DALI. ويدعم cvcuda.copymakeborder() في CV-CUDA تحديد الحشو صراحةً لكل جانب، ما يجعل letterbox المتمركز أمرًا مباشرًا. اختر DALI لسير العمل القائم على خطوط الأنابيب (خصوصًا مع Triton)، واختر CV-CUDA للتحكم الدقيق على مستوى العوامل في تعليمات الاستدلال البرمجية المخصصة.

التعليقات