Asosiy qismga o'tish

Ishlatish va eksport: tezlik qayerdan keladi

8-bob 9 kod bloki 4175 so'z

Bu bobning kodi: kod/08_eksport_tezlik.py — kitob papkasidan ishga tushiring: python kod/08_eksport_tezlik.py

Bu bobda

I qismning oxirgi bobi. Model tayyor, endi uni ishlatish kerak — va ko'pincha PyTorch dan tashqarida: mijozning serverida GPU bo'lmasligi mumkin, kamera yonidagi qurilmada Python bo'lmasligi mumkin. Bu bobda:

  1. predict() bilan ishlash: manbalar, sozlamalar, batch.
  2. ONNX ga eksport, uni ultralytics siz ishga tushirish va YOLO26 ning "CPU da 43% gacha tez" da'vosini tekshirish.
  3. TensorRT: GPU dagi eng tez yo'l — va aniqlikni yashirincha o'zgartiradigan bitta tuzoq.
  4. Google MediaPipe bilan bir xil sharoitda solishtirish.

predict(): manbalar va natija

kod/08_eksport_tezlik.pyyangi fayl · 1-qator: from kitob_yordam import fig, show
python30 qator
import os
import time
import urllib.request
from pathlib import Path

import cv2
import numpy as np
import pandas as pd
import torch
import torchvision
import onnxruntime as ort
from ultralytics import YOLO
from ultralytics.data.augment import LetterBox
from ultralytics.engine.exporter import export_formats
from ultralytics.utils import ASSETS, LOGGER
from ultralytics.utils.metrics import ap_per_class

LOGGER.setLevel("ERROR")

model = YOLO("weights/yolo11n.pt")
kadr = cv2.imread(str(ASSETS / "bus.jpg"))                           # kameradan kelgan kadr ham xuddi shunday BGR massiv
r1 = model.predict(kadr, verbose=False)[0]
r2 = model.predict([ASSETS / "bus.jpg", ASSETS / "zidane.jpg"], verbose=False)
oqim = model.predict(ASSETS, stream=True, verbose=False)             # papka + stream=True: generator, xotirada bitta natija
print("numpy massivdan:", len(r1.boxes), "ta obyekt")
print("ro'yxatdan:     ", [len(r.boxes) for r in r2])
print("stream turi:    ", type(oqim).__name__, "->", [(Path(r.path).name, len(r.boxes)) for r in oqim])
print("\nbitta obyekt lug'at ko'rinishida:", r1.summary()[0])
odamlar = model.predict(ASSETS / "bus.jpg", classes=[0], verbose=False)[0]
print("classes=[0], faqat odamlar:", [odamlar.names[int(c)] for c in odamlar.boxes.cls])
Chiqish
numpy massivdan: 5 ta obyekt
ro'yxatdan:      [5, 3]
stream turi:     generator -> [('bus.jpg', 5), ('zidane.jpg', 3)]

bitta obyekt lug'at ko'rinishida: {'name': 'bus', 'class': 5, 'confidence': 0.9404, 'box': {'x1': 3.827, 'y1': 229.36569, 'x2': 796.20728, 'y2': 728.43805}}
classes=[0], faqat odamlar: ['person', 'person', 'person', 'person']

Manba sifatida fayl, papka, URL, numpy massiv, video fayl, RTSP kamera manzili yoki veb-kamera raqami (0) berilishi mumkin. Video va kamera oqimi uchun doim stream=True ishlating: aks holda ultralytics hamma kadrlar natijasini xotirada yig'adi va uzun videoda xotira tugaydi. Eng ko'p kerak bo'ladigan sozlamalar:

Sozlama Standart Nima qiladi
conf 0.25 ishonch chegarasi (1-bob)
iou 0.7 NMS chegarasi (5-bob)
imgsz 640 kirish o'lchami; kichikroq — tezroq, kichik obyektlar yomonroq
classes hammasi faqat kerakli sinflar, masalan [0] — odam
max_det 300 bitta rasmdagi eng ko'p obyekt
half False GPU da FP16 hisob
device avtomatik 0 (birinchi GPU) yoki "cpu"
vid_stride 1 videoda har N-kadrni olish

Batch: bir vaqtda ko'p rasm

Bitta kamera — bitta rasm. O'nta kamera bo'lsa, ularni bitta batch qilib GPU ga bir marta berish mumkin. 64 ta COCO rasmini oldindan xotiraga o'qib, turli batch o'lchamlarida o'lchaymiz:

kod/08_eksport_tezlik.pydavomi
python15 qator
rasmlar = [cv2.imread(str(p)) for p in sorted(Path("datasets/coco/images/val2017").iterdir())[:64]]
gpu = YOLO("weights/yolo11n.pt")
qatorlar = []
for b in (1, 8, 32):
    gpu.predict(rasmlar[:b], device=0, verbose=False)               # shu batch o'lchami uchun qizdirish
    tezlik = []
    torch.cuda.synchronize()
    t0 = time.perf_counter()
    for i in range(0, len(rasmlar), b):
        tezlik.append(gpu.predict(rasmlar[i:i + b], device=0, verbose=False)[0].speed)   # bosqichlar, bitta rasmga ms
    torch.cuda.synchronize()
    dt = time.perf_counter() - t0
    qatorlar.append({"batch": b, **{k: float(np.median([s[k] for s in tezlik])) for k in ("preprocess", "inference", "postprocess")},
                     "devor soati, ms/rasm": dt / len(rasmlar) * 1000, "rasm / sekund": len(rasmlar) / dt})
show(pd.DataFrame(qatorlar).round(2))
batchpreprocessinferencepostprocessdevor soati, ms/rasmrasm / sekund
10.634.850.738.67115.3
80.590.780.471.88532.33
321.040.870.42.32431.48

inference ustuniga qarang: batch 1 da bitta rasmga ~4.9 ms, batch 8 da ~0.8 ms — olti barobar tez. GPU minglab yadroga ega, bitta kichik rasm esa ularning ko'pchiligini band qilmaydi. Lekin 8 dan keyin inference deyarli o'zgarmaydi — GPU to'yindi. Devor soati bo'yicha batch 32 hatto sekinroq: endi tor joy GPU emas, CPU dagi ish — preprocess ustuni o'sganiga qarang (rasmlarni letterbox qilish va batch ga yig'ish). III qismda ko'p kamerali tizimni aynan shu hisob bilan quramiz: bitta GPU nechta kamerani ko'taradi va CPU qayerda tor joy bo'ladi.

Eksport formatlari

Ultralytics modelni 18 xil formatga o'giradi:

kod/08_eksport_tezlik.pydavomi
python2 qator
f = export_formats()
show(pd.DataFrame({k: f[k] for k in ("Format", "Argument", "Suffix", "CPU", "GPU")}), 20)
FormatArgumentSuffixCPUGPU
PyTorch-.ptTrueTrue
TorchScripttorchscript.torchscriptTrueTrue
ONNXonnx.onnxTrueTrue
OpenVINOopenvino_openvino_modelTrueFalse
TensorRTengine.engineFalseTrue
CoreMLcoreml.mlpackageTrueFalse
TensorFlow SavedModelsaved_model_saved_modelTrueTrue
TensorFlow GraphDefpb.pbTrueTrue
TensorFlow Litetflite.tfliteTrueFalse
TensorFlow Edge TPUedgetpu_edgetpu.tfliteTrueFalse
TensorFlow.jstfjs_web_modelTrueFalse
PaddlePaddlepaddle_paddle_modelTrueTrue
MNNmnn.mnnTrueTrue
NCNNncnn_ncnn_modelTrueTrue
IMXimx_imx_modelTrueTrue
RKNNrknn_rknn_modelFalseFalse
ExecuTorchexecutorch_executorch_modelTrueFalse
Axeleraaxelera_axelera_modelFalseFalse

Hammasi kerak emas. Amalda uchta: ONNX (hamma joyda ishlaydigan umumiy format, ayniqsa CPU server uchun), TensorRT (NVIDIA GPU da eng tez) va OpenVINO (Intel protsessor va iGPU uchun). Telefon uchun TFLite va CoreML.

ONNX

ONNX — tarmoqni qatlamlar grafi sifatida yozadigan ochiq format. Uni PyTorch siz, ONNX Runtime bilan (C++, C#, Java, JavaScript, Python) ishga tushirish mumkin. Eksport bir qator:

kod/08_eksport_tezlik.pydavomi
python14 qator
def eksport(pt, fayl, **sozlama):
    """Fayl yo'q bo'lsa eksport qiladi va kerakli nomga ko'chiradi (TensorRT bir necha daqiqa oladi)."""
    fayl = Path(fayl)
    if not fayl.exists():
        Path(YOLO(pt).export(**sozlama)).rename(fayl)
        if sozlama["format"] == "engine":
            Path(pt).with_suffix(".onnx").unlink(missing_ok=True)   # TensorRT oraliq ONNX faylini qoldiradi
    return str(fayl)

onnx_fayl = {n: eksport(f"weights/{n}.pt", f"weights/{n}_640.onnx", format="onnx", imgsz=640) for n in ("yolo11n", "yolo26n")}
for n, fayl in onnx_fayl.items():
    s = ort.InferenceSession(fayl, providers=["CPUExecutionProvider"])
    print(f"{n}: {Path(fayl).stat().st_size / 1e6:.1f} MB | kirish '{s.get_inputs()[0].name}' {s.get_inputs()[0].shape}"
          f" | chiqish {s.get_outputs()[0].shape}")
Chiqish
yolo11n: 10.7 MB | kirish 'images' [1, 3, 640, 640] | chiqish [1, 84, 8400]
yolo26n: 9.9 MB | kirish 'images' [1, 3, 640, 640] | chiqish [1, 300, 6]

Kirish qat'iy 1 × 3 × 640 × 640. Chiqishlar 2-bobdagi bilan bir xil: YOLO11 da NMS dan oldingi 84 × 8 400, YOLO26 da tayyor 300 × 6. Endi ONNX modelni ultralytics siz, faqat onnxruntime bilan ishga tushiramiz va PyTorch bilan solishtiramiz:

kod/08_eksport_tezlik.pydavomi
python7 qator
lb = LetterBox((640, 640), auto=False)(image=kadr)                  # qat'iy 640x640: to'liq kvadratgacha to'ldiramiz
x = (lb[:, :, ::-1].transpose(2, 0, 1)[None] / 255).astype(np.float32).copy()   # BGR->RGB, HWC->NCHW, 0..1
sessiya = ort.InferenceSession(onnx_fayl["yolo11n"], providers=["CPUExecutionProvider"])
y_onnx = sessiya.run(None, {"images": x})[0]
with torch.no_grad():
    y_torch = YOLO("weights/yolo11n.pt").model.eval()(torch.from_numpy(x))[0].numpy()
print("ONNX chiqishi:", y_onnx.shape, "| PyTorch bilan eng katta farq:", float(np.abs(y_onnx - y_torch).max()))
Chiqish
ONNX chiqishi: (1, 84, 8400) | PyTorch bilan eng katta farq: 0.0045166015625

Farq pikselning mingdan bir necha qismi — hisoblash tartibidagi float yaxlitlash. Dekodlash va NMS ni esa 5-bobda yozgan edik: ular bilan ONNX model ultralytics o'rnatilmagan serverda ham to'liq ishlaydi.

YOLO26 ning CPU da'vosi

2-bobda PyTorch da YOLO26n CPU da YOLO11n dan tez chiqmagan edi. Ultralytics ning da'vosi ONNX uchun. Endi o'sha sharoitda o'lchaymiz — sof tarmoq vaqti, bitta 640 × 640 kirish:

kod/08_eksport_tezlik.pydavomi
python23 qator
def mediana_ms(f, n=50):
    """f() ni 5 marta qizdirib, n marta o'lchaydi: mediana, ms."""
    for _ in range(5):
        f()
    vaqtlar = []
    for _ in range(n):
        t0 = time.perf_counter()
        f()
        vaqtlar.append(time.perf_counter() - t0)
    return float(np.median(vaqtlar) * 1000)

qatorlar = []
for n, fayl in onnx_fayl.items():
    s = ort.InferenceSession(fayl, providers=["CPUExecutionProvider"])
    net = YOLO(f"weights/{n}.pt").model.eval()
    xt = torch.from_numpy(x)
    with torch.no_grad():
        t_torch = mediana_ms(lambda: net(xt))
    qatorlar.append({"model": n, "PyTorch CPU, ms": t_torch, "ONNX Runtime CPU, ms": mediana_ms(lambda: s.run(None, {"images": x}))})
cpu_jadval = pd.DataFrame(qatorlar)
show(cpu_jadval.round(2))
t11, t26 = cpu_jadval["ONNX Runtime CPU, ms"]
print(f"ONNX Runtime da YOLO26n YOLO11n dan {(1 - t26 / t11) * 100:.0f}% tez | protsessor iplari (WSL): {os.cpu_count()}")
Chiqish
ONNX Runtime da YOLO26n YOLO11n dan 17% tez | protsessor iplari (WSL): 8
modelPyTorch CPU, msONNX Runtime CPU, ms
yolo11n27.521.63
yolo26n30.6517.99

ONNX Runtime da YOLO26n haqiqatan tezroq — lekin 43% emas. Da'vo boshqa protsessorda (Intel Xeon 2.00 GHz) o'lchangan; CPU tezligi protsessor turiga, iplar soniga va kutubxona versiyasiga bog'liq. PyTorch da esa aksincha, YOLO26n sekinroq. Ikkala model uchun ham ONNX Runtime PyTorch dan tez: CPU server uchun ONNX ga eksport qilishning o'zi bepul tezlashtirish.

TensorRT

TensorRT — NVIDIA ning kompilyatori. U ONNX grafini oladi va aynan sizning GPU ingiz uchun eng tez yadrolarni tanlab, .engine faylini quradi. FP16 (half=True) da hisob yarim aniqlikda — tezroq va xotira kam. Muhim cheklov: engine fayl faqat shu GPU arxitekturasi va shu TensorRT versiyasi uchun. Boshqa kompyuterga ko'chirilsa, o'sha yerda qayta quriladi.

Ikkita engine quramiz: biri kvadrat 640 × 640, ikkinchisi bus.jpg ning o'z nisbatida — 640 × 480 (5-bobda predict() aynan shu o'lchamni tanlagan edi):

kod/08_eksport_tezlik.pydavomi
python17 qator
trt_kvadrat = eksport("weights/yolo11n.pt", "weights/yolo11n_640x640.engine", format="engine", imgsz=640, half=True, device=0)
trt_rect = eksport("weights/yolo11n.pt", "weights/yolo11n_640x480.engine", format="engine", imgsz=(640, 480), half=True, device=0)

variantlar = {"PyTorch FP32, 640x480 (rect)": (YOLO("weights/yolo11n.pt"), {}),
              "PyTorch FP32, 640x640":        (YOLO("weights/yolo11n.pt"), {"rect": False}),
              "PyTorch FP16, 640x640":        (YOLO("weights/yolo11n.pt"), {"rect": False, "half": True}),
              "TensorRT FP16, 640x640":       (YOLO(trt_kvadrat), {}),
              "TensorRT FP16, 640x480":       (YOLO(trt_rect), {})}
qatorlar = []
for nom, (m, sozlama) in variantlar.items():
    for _ in range(5):
        m.predict(kadr, device=0, verbose=False, **sozlama)
    natijalar = [m.predict(kadr, device=0, verbose=False, **sozlama)[0] for _ in range(50)]
    qatorlar.append({"variant": nom,
                     **{k: round(float(np.median([r.speed[k] for r in natijalar])), 2) for k in ("preprocess", "inference", "postprocess")},
                     "ishonchlar": " ".join(f"{c:.2f}" for c in natijalar[-1].boxes.conf.tolist())})
show(pd.DataFrame(qatorlar))
variantpreprocessinferencepostprocessishonchlar
PyTorch FP32, 640x480 (rect)0.874.40.670.94 0.89 0.88 0.86 0.62
PyTorch FP32, 640x6400.964.430.690.94 0.90 0.85 0.83 0.40
PyTorch FP16, 640x64014.50.710.94 0.90 0.85 0.83 0.40
TensorRT FP16, 640x6401.361.730.730.94 0.90 0.85 0.83 0.40
TensorRT FP16, 640x4800.81.540.670.94 0.89 0.88 0.86 0.62

Avval tezlik: TensorRT tarmoq vaqtini ~4.4 ms dan ~1.5–1.7 ms ga tushirdi. PyTorch FP16 esa bu kichik modelda deyarli hech narsa bermadi. TensorRT dan keyin rasmni tayyorlash (preprocess) tarmoqning o'zi bilan deyarli teng bo'lib qoldi — keyingi tezlashtirish endi tarmoqda emas, uning atrofida (III qism).

Endi oxirgi ustunga qarang — bu yerda tuzoq bor. Chap chetdagi yarim ko'ringan odamning ishonchi kvadrat kirishda keskin tushadi. Aybdor TensorRT ham, FP16 ham emas: xuddi shu pasayish PyTorch FP32 da ham, kirish 640 × 640 bo'lishi bilanoq paydo bo'ladi. Sababi letterbox: kvadrat kirishda rasm atrofiga kulrang yo'laklar qo'shiladi, chetdagi obyekt esa endi rasm chegarasida emas, kulrang yo'lak yonida turadi va tarmoq uni boshqacha ko'radi. Engine rasmning o'z nisbatida qurilganda (640 × 480) ishonch qaytadi.

Amaliy qoida: kameralar nisbati o'zgarmaydi (masalan 1920 × 1080 = 16 : 9). Engine ni kameraning letterbox o'lchamida quring — 16 : 9 uchun 384 × 640. Bu ham aniqroq, ham tezroq: kataklar 8 400 emas, 5 040.

Eksportdan keyin aniqlik

Tezlik — yarim gap. Eksport qilingan model aniqligini doim o'lchang. 7-bobda o'qitilgan kaska modelini ONNX va TensorRT ga o'girib, o'sha test qismida baholaymiz. Eksport qilingan modellar validatsiyada har doim kvadrat kirish va batch = 1 ishlatadi, shuning uchun PyTorch ni ham shu sharoitda (rect=False) o'lchaymiz:

kod/08_eksport_tezlik.pydavomi
python14 qator
ppe = "out/train/ppe_coco/weights/best.pt"
ppe_onnx = eksport(ppe, "out/train/ppe_coco/weights/best_640.onnx", format="onnx", imgsz=640)
ppe_trt = eksport(ppe, "out/train/ppe_coco/weights/best_640x640.engine", format="engine", imgsz=640, half=True, device=0)

sinovlar = {"PyTorch FP32 (rect, standart)": (ppe, {}),
            "PyTorch FP32 (640x640)":        (ppe, {"rect": False, "batch": 1}),
            "ONNX FP32 (640x640)":           (ppe_onnx, {}),
            "TensorRT FP16 (640x640)":       (ppe_trt, {})}
qatorlar = []
for nom, (fayl, sozlama) in sinovlar.items():
    m = YOLO(fayl, task="detect").val(data="datasets/ppe.yaml", split="test", imgsz=640, device=0, plots=False,
                                      project=Path("out/val").resolve(), name="eksport", exist_ok=True, **sozlama)
    qatorlar.append({"model": nom, "mAP50": m.box.map50, "mAP50-95": m.box.map})
show(pd.DataFrame(qatorlar).round(4))
modelmAP50mAP50-95
PyTorch FP32 (rect, standart)0.5480.281
PyTorch FP32 (640x640)0.5430.279
ONNX FP32 (640x640)0.5430.279
TensorRT FP16 (640x640)0.5430.278

Eksport aniqlikni saqlaydi: 640 × 640 dagi PyTorch, ONNX va TensorRT FP16 deyarli bir xil — FP16 mAP50-95 ni atigi 0.001 ga tushirdi. Birinchi qator bilan farq (0.281 va 0.279) yana letterbox dan: standart PyTorch baholash rasmlarni o'z nisbatida beradi.

MediaPipe bilan solishtirish

Google ning MediaPipe kutubxonasi (Apache-2.0) telefon va CPU uchun mo'ljallangan. Uning tayyor detektori — EfficientDet-Lite0: 320 × 320 kirish, COCO ning 80 sinfi. YOLO11n ham COCO da o'qitilgan, demak ikkalasini bir xil rasmlarda, bir xil kod bilan solishtirish mumkin. Baholash uchun 7-bobdagi moslash qoidasini o'nta IoU chegarasiga kengaytiramiz va AP ni ultralytics ning ap_per_class funksiyasi bilan hisoblaymiz — uchala model uchun aynan bir xil hakam.

kod/08_eksport_tezlik.pydavomi
python72 qator
import mediapipe as mp
from mediapipe.tasks import python as mpt
from mediapipe.tasks.python import vision

mp_fayl = Path("weights/efficientdet_lite0.tflite")
if not mp_fayl.exists():
    urllib.request.urlretrieve("https://storage.googleapis.com/mediapipe-models/object_detector/"
                               "efficientdet_lite0/float32/latest/efficientdet_lite0.tflite", mp_fayl)
iou_chegaralar = np.linspace(0.5, 0.95, 10)
sinf_raqami = {v: k for k, v in model.names.items()}              # "person" -> 0

def tp_matritsa(p_box, p_sinf, g_box, g_sinf):
    """(bashoratlar, 10): har IoU chegarasida TP mi. 7-bobdagi moslash qoidasi."""
    tp = np.zeros((len(p_box), 10), bool)
    if len(p_box) == 0 or len(g_box) == 0:
        return tp
    iou = torchvision.ops.box_iou(torch.tensor(g_box, dtype=torch.float32), torch.tensor(p_box, dtype=torch.float32)).numpy()
    iou *= g_sinf[:, None] == p_sinf[None]                            # faqat sinfi mos juftliklar
    for j, chegara in enumerate(iou_chegaralar):
        juft = np.array(np.nonzero(iou >= chegara)).T
        if len(juft):
            juft = juft[iou[juft[:, 0], juft[:, 1]].argsort()[::-1]]
            juft = juft[np.unique(juft[:, 1], return_index=True)[1]]
            juft = juft[np.unique(juft[:, 0], return_index=True)[1]]
            tp[juft[:, 1], j] = True
    return tp

def baholash(bashorat, rasm_yollari):
    """bashorat(BGR rasm) -> (xyxy, ishonch, sinf). Qaytaradi: mAP50, mAP50-95, bitta rasmga o'rtacha ms."""
    tp, ishonch, sinf, gt_sinf, vaqt = [], [], [], [], []
    for yol in rasm_yollari:
        rasm = cv2.imread(str(yol))
        H, W = rasm.shape[:2]
        lf = Path("datasets/coco/labels/val2017") / f"{yol.stem}.txt"
        lab = np.loadtxt(lf, ndmin=2).reshape(-1, 5) if lf.exists() else np.zeros((0, 5))
        g_box = np.stack([(lab[:, 1] - lab[:, 3] / 2) * W, (lab[:, 2] - lab[:, 4] / 2) * H,
                          (lab[:, 1] + lab[:, 3] / 2) * W, (lab[:, 2] + lab[:, 4] / 2) * H], 1)
        t0 = time.perf_counter()
        p_box, p_ish, p_sinf = bashorat(rasm)
        vaqt.append(time.perf_counter() - t0)
        tp.append(tp_matritsa(p_box, p_sinf, g_box, lab[:, 0]))
        ishonch.append(p_ish)
        sinf.append(p_sinf)
        gt_sinf.append(lab[:, 0])
    ap = ap_per_class(np.concatenate(tp), np.concatenate(ishonch), np.concatenate(sinf), np.concatenate(gt_sinf))[5]
    return ap[:, 0].mean(), ap.mean(), float(np.mean(vaqt) * 1000)

def yolo_bashorat(m, imgsz):
    def f(rasm):
        b = m.predict(rasm, conf=0.001, iou=0.7, max_det=300, imgsz=imgsz, device="cpu", verbose=False)[0].boxes
        return b.xyxy.numpy(), b.conf.numpy(), b.cls.numpy()
    return f

def mp_bashorat(detektor):
    def f(rasm):
        d = detektor.detect(mp.Image(image_format=mp.ImageFormat.SRGB, data=rasm[:, :, ::-1].copy())).detections
        box = np.array([[q.bounding_box.origin_x, q.bounding_box.origin_y, q.bounding_box.origin_x + q.bounding_box.width,
                         q.bounding_box.origin_y + q.bounding_box.height] for q in d]).reshape(-1, 4)
        return box, np.array([q.categories[0].score for q in d]), np.array([sinf_raqami[q.categories[0].category_name] for q in d])
    return f

tanlov = sorted(Path("datasets/coco/images/val2017").iterdir())[:500]
sozlama = vision.ObjectDetectorOptions(base_options=mpt.BaseOptions(model_asset_path=str(mp_fayl)), score_threshold=0.0, max_results=100)
qatorlar = []
with vision.ObjectDetector.create_from_options(sozlama) as detektor:
    for nom, fn, hajm in [("YOLO11n, 640", yolo_bashorat(model, 640), "weights/yolo11n.pt"),
                          ("YOLO11n, 320", yolo_bashorat(model, 320), "weights/yolo11n.pt"),
                          ("MediaPipe EfficientDet-Lite0, 320", mp_bashorat(detektor), mp_fayl)]:
        map50, map5095, ms = baholash(fn, tanlov)
        qatorlar.append({"model": nom, "mAP50": map50, "mAP50-95": map5095, "CPU, ms/rasm": ms,
                         "fayl, MB": Path(hajm).stat().st_size / 1e6})
show(pd.DataFrame(qatorlar).round(3))
modelmAP50mAP50-95CPU, ms/rasmfayl, MB
YOLO11n, 6400.5740.42123.075.614
YOLO11n, 3200.4450.31611.035.614
MediaPipe EfficientDet-Lite0, 3200.4570.28726.80713.837

500 ta COCO rasmi, CPU da, bir xil hakam bilan. Uch xulosa:

  • Bir xil 320 × 320 kirishda YOLO11n MediaPipe dan 2.4 barobar tez va mAP50-95 bo'yicha aniqroq. mAP50 da esa MediaPipe biroz oldinda: u obyektni topadi, lekin box ni kamroq aniq chizadi.
  • 640 × 640 dagi YOLO11n MediaPipe bilan deyarli bir xil vaqtda ishlaydi va ancha aniq.
  • MediaPipe ning ustunligi boshqa joyda: kutubxona Apache-2.0 litsenziyasida, telefonlar uchun tayyor quvur beradi va yuz, qo'l, gavda nuqtalari uchun tayyor modellari bor. II qismda yuz va pozani aynan MediaPipe bilan qilamiz. Model fayllarining sharti hujjatda alohida ko'rsatilmagan — IV qismda tekshiramiz.

Eslatma: bu 5 000 emas, 500 rasm, shuning uchun mAP qiymatlari 2-bobdagi to'liq o'lchovdan farq qiladi. MediaPipe natijalari bitta rasmda 100 ta bilan cheklangan (max_results).

Qaysi birini qachon

Qayerda ishlaydi Format Izoh
O'qitish, tajriba PyTorch .pt eng qulay, lekin eng sekin ishlatish yo'li
NVIDIA GPU server yoki Jetson TensorRT .engine eng tez; engine faqat shu GPU va shu TensorRT versiyasi uchun
CPU server (GPU siz) ONNX yoki OpenVINO Python shart emas; ONNX Runtime ko'p tilda bor
Telefon, brauzer TFLite, CoreML, MediaPipe MediaPipe tayyor quvur beradi va Apache-2.0

Asosiy fikr

  • Video va kamera uchun stream=True. Ko'p kamerani bitta batch qilib berish bitta rasmga ketadigan vaqtni keskin kamaytiradi — lekin faqat GPU to'yinguncha (bizda batch 8); undan keyin tor joy CPU ga ko'chadi.
  • ONNX — hamma joyda ishlaydigan umumiy format; TensorRT FP16 — NVIDIA GPU da eng tez. Eksportdan keyin aniqlikni doim qayta o'lchang.
  • Qat'iy o'lchamli engine da letterbox chetdagi obyektlar ishonchini o'zgartiradi. Engine ni kameraning o'z nisbatida quring.

Mashqlar

  1. 1920 × 1080 kamera uchun letterbox o'lchamini qo'lda hisoblang (uzun tomon 640, qisqasi 32 ga karrali). Shu o'lchamda engine quring va bitta kadr uchun tezlikni 640 × 640 engine bilan solishtiring.
  2. yolo26n ni TensorRT FP16 ga eksport qiling. GPU da YOLO11n engine idan tezmi? Postprocess ustuniga alohida qarang.
  3. MediaPipe ning efficientdet_lite2 modelini (448 × 448) yuklab, jadvalga qo'shing. Aniqlik va tezlik qanday o'zgardi?

Bu bobni bepul o'qidingiz.

Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.

Telegramda yozish Narxlar