Ishlatish va eksport: tezlik qayerdan keladi
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:
predict()bilan ishlash: manbalar, sozlamalar, batch.- ONNX ga eksport, uni ultralytics siz ishga tushirish va YOLO26 ning "CPU da 43% gacha tez" da'vosini tekshirish.
- TensorRT: GPU dagi eng tez yo'l — va aniqlikni yashirincha o'zgartiradigan bitta tuzoq.
- Google MediaPipe bilan bir xil sharoitda solishtirish.
predict(): manbalar va natija
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])
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:
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))
| batch | preprocess | inference | postprocess | devor soati, ms/rasm | rasm / sekund |
|---|---|---|---|---|---|
| 1 | 0.63 | 4.85 | 0.73 | 8.67 | 115.3 |
| 8 | 0.59 | 0.78 | 0.47 | 1.88 | 532.33 |
| 32 | 1.04 | 0.87 | 0.4 | 2.32 | 431.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:
f = export_formats() show(pd.DataFrame({k: f[k] for k in ("Format", "Argument", "Suffix", "CPU", "GPU")}), 20)
| Format | Argument | Suffix | CPU | GPU |
|---|---|---|---|---|
| PyTorch | - | .pt | True | True |
| TorchScript | torchscript | .torchscript | True | True |
| ONNX | onnx | .onnx | True | True |
| OpenVINO | openvino | _openvino_model | True | False |
| TensorRT | engine | .engine | False | True |
| CoreML | coreml | .mlpackage | True | False |
| TensorFlow SavedModel | saved_model | _saved_model | True | True |
| TensorFlow GraphDef | pb | .pb | True | True |
| TensorFlow Lite | tflite | .tflite | True | False |
| TensorFlow Edge TPU | edgetpu | _edgetpu.tflite | True | False |
| TensorFlow.js | tfjs | _web_model | True | False |
| PaddlePaddle | paddle | _paddle_model | True | True |
| MNN | mnn | .mnn | True | True |
| NCNN | ncnn | _ncnn_model | True | True |
| IMX | imx | _imx_model | True | True |
| RKNN | rknn | _rknn_model | False | False |
| ExecuTorch | executorch | _executorch_model | True | False |
| Axelera | axelera | _axelera_model | False | False |
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:
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}")
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:
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()))
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:
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()}")
ONNX Runtime da YOLO26n YOLO11n dan 17% tez | protsessor iplari (WSL): 8
| model | PyTorch CPU, ms | ONNX Runtime CPU, ms |
|---|---|---|
| yolo11n | 27.5 | 21.63 |
| yolo26n | 30.65 | 17.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):
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))
| variant | preprocess | inference | postprocess | ishonchlar |
|---|---|---|---|---|
| PyTorch FP32, 640x480 (rect) | 0.87 | 4.4 | 0.67 | 0.94 0.89 0.88 0.86 0.62 |
| PyTorch FP32, 640x640 | 0.96 | 4.43 | 0.69 | 0.94 0.90 0.85 0.83 0.40 |
| PyTorch FP16, 640x640 | 1 | 4.5 | 0.71 | 0.94 0.90 0.85 0.83 0.40 |
| TensorRT FP16, 640x640 | 1.36 | 1.73 | 0.73 | 0.94 0.90 0.85 0.83 0.40 |
| TensorRT FP16, 640x480 | 0.8 | 1.54 | 0.67 | 0.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:
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))
| model | mAP50 | mAP50-95 |
|---|---|---|
| PyTorch FP32 (rect, standart) | 0.548 | 0.281 |
| PyTorch FP32 (640x640) | 0.543 | 0.279 |
| ONNX FP32 (640x640) | 0.543 | 0.279 |
| TensorRT FP16 (640x640) | 0.543 | 0.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.
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))
| model | mAP50 | mAP50-95 | CPU, ms/rasm | fayl, MB |
|---|---|---|---|---|
| YOLO11n, 640 | 0.574 | 0.421 | 23.07 | 5.614 |
| YOLO11n, 320 | 0.445 | 0.316 | 11.03 | 5.614 |
| MediaPipe EfficientDet-Lite0, 320 | 0.457 | 0.287 | 26.807 | 13.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
- 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.
yolo26nni TensorRT FP16 ga eksport qiling. GPU da YOLO11n engine idan tezmi? Postprocess ustuniga alohida qarang.- MediaPipe ning
efficientdet_lite2modelini (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.