Detect boshi: 6 300 katakdan 5 ta box gacha
Bu bobning kodi: kod/05_detect_bosh.py — kitob papkasidan ishga tushiring: python kod/05_detect_bosh.py
Bu bobda nima qilamiz
model.predict() bitta qator. Uning ichida esa beshta bosqich bor, va bu bobda hammasini qo'lda qaytadan yozamiz:
- Letterbox — rasmni tarmoqqa mos o'lchamga keltirish.
- DFL — har katak chegaragacha masofani taqsimot sifatida bashorat qiladi.
- Dekodlash — masofalardan piksel koordinatalarga.
- NMS — bitta obyektga chizilgan ko'p box dan bittasini qoldirish.
- Asl rasmga qaytarish — letterbox koordinatalaridan 810 × 1080 ga.
Oxirida natijani predict() bilan solishtiramiz: bir xil chiqishi kerak. Keyin YOLO26 NMS siz qanday ishlashini ko'ramiz.
Letterbox va xom chiqish
Tarmoq kirishi 32 ga karrali bo'lishi kerak (beshta qadam-2 li qatlam, 3-bob). predict() rasmni cho'zmaydi: nisbatni saqlab uzun tomonini 640 ga keltiradi, qisqa tomonini esa eng yaqin 32 ga karrali songacha kulrang (114) bilan to'ldiradi:
import cv2 import numpy as np import pandas as pd import torch import torchvision import matplotlib.pyplot as plt from ultralytics import YOLO from ultralytics.utils import ASSETS, LOGGER from ultralytics.data.augment import LetterBox LOGGER.setLevel("ERROR") asl = cv2.imread(str(ASSETS / "bus.jpg")) # (1080, 810, 3), BGR h0, w0 = asl.shape[:2] lb = LetterBox((640, 640), auto=True, stride=32)(image=asl) # predict() ishlatadigan aynan shu klass gain = min(640 / h0, 640 / w0) print("asl:", (h0, w0), "| letterbox:", lb.shape[:2], "| kichraytirish koeffitsiyenti:", round(gain, 4)) print("810 x gain =", w0 * gain, "-> 32 ga karrali, to'ldirish kerak emas") x = torch.from_numpy(lb[:, :, ::-1].copy()).permute(2, 0, 1)[None].float() / 255 # BGR -> RGB, NCHW, 0..1 tarmoq = YOLO("weights/yolo11n.pt").model.eval() # fuse qilinmagan nusxa: boshning ichi ko'rinadi with torch.no_grad(): y, ichki = tarmoq(x) # y: tayyor chiqish, ichki: boshning xom qismlari print("\ny (dekodlangan):", tuple(y.shape)) print("boxes (xom): ", tuple(ichki["boxes"].shape)) print("scores (xom): ", tuple(ichki["scores"].shape)) print("xaritalar: ", [tuple(f.shape) for f in ichki["feats"]])
asl: (1080, 810) | letterbox: (640, 480) | kichraytirish koeffitsiyenti: 0.5926 810 x gain = 480.0 -> 32 ga karrali, to'ldirish kerak emas y (dekodlangan): (1, 84, 6300) boxes (xom): (1, 64, 6300) scores (xom): (1, 80, 6300) xaritalar: [(1, 64, 80, 60), (1, 128, 40, 30), (1, 256, 20, 15)]
Bu rasm uchun 640 × 640 emas, 640 × 480 kirish yetarli bo'ldi. Kataklar ham kamaydi: 80 × 60 + 40 × 30 + 20 × 15 = 6 300 (2-bobdagi 8 400 kvadrat kirish uchun edi). Kamroq katak — tezroq ishlash.
Har katak uchun Detect boshi ikki narsa chiqaradi: boxes da 64 ta raqam (4 tomon × 16) va scores da 80 ta raqam (har sinf uchun bittadan). Ular ikki alohida tarmoqdan (branch) keladi:
bosh = tarmoq.model[-1] for nom, tarmoqcha in [("cv2 (box)", bosh.cv2[0]), ("cv3 (sinf)", bosh.cv3[0])]: print(f"{nom:11s}: {sum(p.numel() for p in tarmoqcha.parameters()):6,} parametr, oxirgi qatlam: {tarmoqcha[-1]}") print("reg_max:", bosh.reg_max, "| qadamlar:", bosh.stride.tolist())
cv2 (box) : 78,144 parametr, oxirgi qatlam: Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1)) cv3 (sinf) : 19,904 parametr, oxirgi qatlam: Conv2d(80, 80, kernel_size=(1, 1), stride=(1, 1)) reg_max: 16 | qadamlar: [8.0, 16.0, 32.0]
Anchor nuqtalar: har katakning markazi
Har bir katakning "o'z nuqtasi" bor — katak markazi. U katak birliklarida (x + 0.5, y + 0.5), pikselda esa qadamga ko'paytiriladi:
anchorlar, qadamlar = [], [] for f, s in zip(ichki["feats"], bosh.stride.tolist()): H, W = f.shape[2:] yy, xx = torch.meshgrid(torch.arange(H) + 0.5, torch.arange(W) + 0.5, indexing="ij") anchorlar.append(torch.stack([xx.flatten(), yy.flatten()])) # (2, H*W), katak birliklarida qadamlar.append(torch.full((H * W,), s)) A = torch.cat(anchorlar, 1) # (2, 6300) S = torch.cat(qadamlar) # (6300,) print("anchorlar:", tuple(A.shape), "| birinchi uchtasi (katak):", A[:, :3].T.tolist()) print("pikselda:", (A[:, :3] * S[:3]).T.tolist()) print("P3 / P4 / P5 oralig'i:", "0–4799 / 4800–5999 / 6000–6299")
anchorlar: (2, 6300) | birinchi uchtasi (katak): [[0.5, 0.5], [1.5, 0.5], [2.5, 0.5]] pikselda: [[4.0, 4.0], [12.0, 4.0], [20.0, 4.0]] P3 / P4 / P5 oralig'i: 0–4799 / 4800–5999 / 6000–6299
DFL: chegara — bu taqsimot
Oddiy regressiya "chap chegaragacha 6.4 katak" deb bitta son chiqarardi. YOLO11 boshqacha ishlaydi: har tomon uchun 16 ta ehtimol chiqaradi — "masofa 0 katak", "1 katak", ..., "15 katak". Keyin softmax va kutilgan qiymat (o'rtacha):
Bu DFL (Distribution Focal Loss) g'oyasi: model faqat javob emas, o'z ishonchsizligini ham ko'rsatadi. Keng taqsimot — "chegara aniq qayerda, bilmayman". Ultralytics da kutilgan qiymat qanday hisoblanishiga qarang: vaznlari 0, 1, ..., 15 bo'lgan va o'qitilmaydigan 1 × 1 konvolyutsiya.
print("DFL konvolyutsiyasi vaznlari:", bosh.dfl.conv.weight.flatten().tolist()) print("o'qitiladimi:", bosh.dfl.conv.weight.requires_grad) z = ichki["boxes"][0].view(4, 16, -1) # (4 tomon, 16 bin, 6300 katak) p = z.softmax(1) # har tomon bo'yicha ehtimollar d = (p * torch.arange(16).view(1, 16, 1)).sum(1) # kutilgan qiymat: (4, 6300), katak birliklarida print("\nqo'lda d vs bosh.dfl, eng katta farq:", float((d - bosh.dfl(ichki["boxes"])[0]).abs().max()))
DFL konvolyutsiyasi vaznlari: [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0] o'qitiladimi: False qo'lda d vs bosh.dfl, eng katta farq: 1.9073486328125e-06
Muhim cheklov: masofa 0 dan 15 gacha. Demak katak markazidan chegaragacha eng ko'pi bilan 15 katak, pikselda esa har to'rda har xil:
for nom, s in zip(["P3", "P4", "P5"], bosh.stride.tolist()): print(f"{nom}: qadam {s:4.0f} px -> markazdan chegaragacha ko'pi bilan 15 x {s:.0f} = {15 * s:5.0f} px, box ko'pi bilan ~{30 * s:.0f} px")
P3: qadam 8 px -> markazdan chegaragacha ko'pi bilan 15 x 8 = 120 px, box ko'pi bilan ~240 px P4: qadam 16 px -> markazdan chegaragacha ko'pi bilan 15 x 16 = 240 px, box ko'pi bilan ~480 px P5: qadam 32 px -> markazdan chegaragacha ko'pi bilan 15 x 32 = 480 px, box ko'pi bilan ~960 px
P3 katagi 240 pikseldan katta box ni umuman chiza olmaydi. Katta obyekt faqat P5 dan chiqishi mumkin. Arxitektura (3-4-boblar) va bosh bir-biriga shunday bog'langan.
Masofadan box ga
Katak markazi (a_x, a_y) va to'rtta masofa (chap l, yuqori t, o'ng r, past b) ma'lum bo'lsa, box:
Sinf ehtimoli — sigmoid. Softmax emas: har sinf mustaqil, "odam" ehtimoli "velosiped" ehtimoliga bog'liq emas.
Hammasini yig'ib, tarmoqning o'z chiqishi y bilan solishtiramiz:
x1, y1 = (A[0] - d[0]) * S, (A[1] - d[1]) * S x2, y2 = (A[0] + d[2]) * S, (A[1] + d[3]) * S xyxy = torch.stack([x1, y1, x2, y2], 1) # (6300, 4), letterbox pikselida ehtimol = ichki["scores"][0].sigmoid() # (80, 6300) bizniki = torch.cat([torch.stack([(x1 + x2) / 2, (y1 + y2) / 2, x2 - x1, y2 - y1]), ehtimol]) print("bizniki:", tuple(bizniki.shape), "| tarmoqniki:", tuple(y[0].shape)) print("eng katta farq:", float((bizniki - y[0]).abs().max()))
bizniki: (84, 6300) | tarmoqniki: (84, 6300) eng katta farq: 6.103515625e-05
6 300 dan 47 gacha: ishonch chegarasi
Har katak uchun eng ehtimolli sinf va uning ehtimoli. 0.25 dan pastlari tashlanadi:
ishonch, sinf = ehtimol.max(0) # har katak: eng yuqori ehtimol va uning sinfi nomzod = torch.nonzero(ishonch > 0.25).flatten() # katak raqamlari print("0.25 dan yuqori kataklar:", len(nomzod), "ta, 6 300 dan") print("to'rlar bo'yicha: P3", int((nomzod < 4800).sum()), "| P4", int(((nomzod >= 4800) & (nomzod < 6000)).sum()), "| P5", int((nomzod >= 6000).sum()))
0.25 dan yuqori kataklar: 47 ta, 6 300 dan to'rlar bo'yicha: P3 0 | P4 4 | P5 43
Rasmda odamlar katta (letterbox da ~270 px bo'yli), shuning uchun deyarli hamma nomzod P5 dan. 47 ta nomzod bor, obyekt esa 5 ta: har bir obyektni bir nechta qo'shni katak birdaniga "topgan".
NMS: takrorlarni o'chirish
Non-Maximum Suppression algoritmi oddiy:
- Box larni ishonch bo'yicha kamayish tartibida saralash.
- Eng ishonchlisini olib qoldirish.
- Qolganlar ichidan u bilan IoU si chegaradan (standart 0.7) katta bo'lganlarini o'chirish — ular o'sha obyektning takrori.
- Ro'yxat bo'shaguncha 2-qadamga qaytish.
Bitta nozik joy: turli sinfdagi box lar bir-birini o'chirmasligi kerak (odam avtobus oldida turibdi, ularning box lari ustma-ust). Ultralytics buni hiyla bilan qiladi: har box ni sinf × 7680 pikselga siljitadi. Turli sinflar hech qachon ustma-ust tushmaydi, bitta sinf ichida esa hech narsa o'zgarmaydi.
def iou_bitta(box, boxlar): """Bitta box va boxlar ro'yxati orasidagi IoU (1-bobdagi formula, torch da).""" ix1 = torch.maximum(box[0], boxlar[:, 0]); iy1 = torch.maximum(box[1], boxlar[:, 1]) ix2 = torch.minimum(box[2], boxlar[:, 2]); iy2 = torch.minimum(box[3], boxlar[:, 3]) kesishma = (ix2 - ix1).clamp(0) * (iy2 - iy1).clamp(0) yuza = lambda b: (b[..., 2] - b[..., 0]) * (b[..., 3] - b[..., 1]) return kesishma / (yuza(box) + yuza(boxlar) - kesishma) def nms(boxlar, ballar, chegara): """Ochko'z NMS: qoldirilgan box larning indekslari, ishonch bo'yicha tartibda.""" tartib = ballar.argsort(descending=True) qoldi = [] while tartib.numel() > 0: eng_yaxshi = tartib[0] qoldi.append(int(eng_yaxshi)) qolgan = tartib[1:] tartib = qolgan[iou_bitta(boxlar[eng_yaxshi], boxlar[qolgan]) <= chegara] # takrorlarni o'chiramiz return torch.tensor(qoldi) nb, ns, nc = xyxy[nomzod], ishonch[nomzod], sinf[nomzod] siljigan = nb + nc[:, None].float() * 7680 # sinflarni bir-biridan uzoqlashtirish bizniki = nms(siljigan, ns, 0.7) torchniki = torchvision.ops.nms(siljigan, ns, 0.7) print("bizning NMS: ", bizniki.tolist()) print("torchvision NMS: ", torchniki.tolist())
bizning NMS: [11, 46, 38, 32, 43] torchvision NMS: [11, 46, 38, 32, 43]
IoU chegarasini o'zgartirib ko'ramiz:
qatorlar = [{"IoU chegarasi": t, "qolgan box lar": len(nms(siljigan, ns, t))} for t in (0.3, 0.5, 0.7, 0.9, 1.0)] show(pd.DataFrame(qatorlar))
| IoU chegarasi | qolgan box lar |
|---|---|
| 0.3 | 5 |
| 0.5 | 5 |
| 0.7 | 5 |
| 0.9 | 6 |
| 1 | 47 |
Past chegara takrorlarni ishonchli o'chiradi, lekin olomonda xavfli: ikki odam bir-birini yarim to'sib turgan bo'lsa, ularning box lari IoU si katta bo'ladi va haqiqiy ikkinchi odam "takror" deb o'chiriladi. Baland chegara olomonga yaxshi, lekin takrorlar qoladi (0.9 da allaqachon bitta takror paydo bo'ldi). 1.0 da NMS hech narsani o'chirmaydi — 47 ta nomzodning hammasi qoladi.
Asl rasmga qaytarish va predict() bilan solishtirish
Letterbox koordinatalaridan asl rasmga: to'ldirishni ayirib, koeffitsiyentga bo'lamiz:
px, py = (lb.shape[1] - w0 * gain) / 2, (lb.shape[0] - h0 * gain) / 2 # chap va yuqoridagi to'ldirish yakuniy = (nb[bizniki] - torch.tensor([px, py, px, py])) / gain yakuniy[:, [0, 2]] = yakuniy[:, [0, 2]].clamp(0, w0) # rasm chegarasidan chiqmasin yakuniy[:, [1, 3]] = yakuniy[:, [1, 3]].clamp(0, h0) natija = YOLO("weights/yolo11n.pt").predict(ASSETS / "bus.jpg", device="cpu", verbose=False)[0] print("bizniki: ", [f"{natija.names[int(c)]} {s:.3f}" for c, s in zip(nc[bizniki], ns[bizniki])]) print("predict():", [f"{natija.names[int(c)]} {s:.3f}" for c, s in zip(natija.boxes.cls, natija.boxes.conf)]) print("box lar orasidagi eng katta farq, px:", float((yakuniy - natija.boxes.xyxy).abs().max())) toplar = ["P3" if i < 4800 else "P4" if i < 6000 else "P5" for i in nomzod[bizniki].tolist()] print("har yakuniy box qaysi to'rdan:", toplar)
bizniki: ['bus 0.940', 'person 0.888', 'person 0.878', 'person 0.856', 'person 0.622'] predict(): ['bus 0.940', 'person 0.888', 'person 0.878', 'person 0.856', 'person 0.622'] box lar orasidagi eng katta farq, px: 0.0001220703125 har yakuniy box qaysi to'rdan: ['P5', 'P5', 'P5', 'P5', 'P5']
Beshta bosqichni qo'lda yozdik va predict() natijasini piksel darajasida takrorladik. Endi rasmda: NMS dan oldin va keyin.
def asl_rasmga(b): return ((b - torch.tensor([px, py, px, py])) / gain).tolist() _, axes = plt.subplots(1, 2, figsize=(10, 6.8)) for ax, (sarlavha, boxlar) in zip(axes, [(f"NMS dan oldin: {len(nomzod)} ta", nb), (f"NMS dan keyin: {len(bizniki)} ta", nb[bizniki])]): ax.imshow(asl[:, :, ::-1]) for bx1, by1, bx2, by2 in asl_rasmga(boxlar): ax.add_patch(plt.Rectangle((bx1, by1), bx2 - bx1, by2 - by1, fill=False, color="yellow", lw=1.2)) ax.set_title(sarlavha) ax.axis("off") fig("nms_oldin_keyin.png", "Chapda 0.25 dan yuqori hamma nomzod: har obyekt atrofida bir nechta box. O'ngda NMS qoldirgan 5 tasi.")

Chapda 0.25 dan yuqori hamma nomzod: har obyekt atrofida bir nechta box. O'ngda NMS qoldirgan 5 tasi.
DFL taqsimotlari: model qanchalik ishonadi
Yakuniy ikki box ning to'rt tomoni uchun 16 lik taqsimotlarni chizamiz: chap chetdagi yarim ko'ringan odam (ishonchi 0.62) va eng aniq odam (0.89):
tanlangan = {"aniq odam (0.89)": int(nomzod[bizniki][1]), "yarim ko'ringan odam (0.62)": int(nomzod[bizniki][4])} tomonlar = ["chap (l)", "yuqori (t)", "o'ng (r)", "past (b)"] _, axes = plt.subplots(2, 4, figsize=(11, 4.6), sharey=True) qatorlar = [] for qator, (nom, k) in zip(axes, tanlangan.items()): for j, ax in enumerate(qator): pj = p[j, :, k].numpy() ax.bar(range(16), pj, color="#2563eb") ax.set_title(f"{tomonlar[j]}", fontsize=9) ax.set_xticks([0, 5, 10, 15]) orta = float((pj * np.arange(16)).sum()) qatorlar.append({"box": nom, "tomon": tomonlar[j], "kutilgan d, katak": round(orta, 2), "standart og'ish": round(float(np.sqrt((pj * (np.arange(16) - orta) ** 2).sum())), 2), "eng katta p": round(float(pj.max()), 2)}) qator[0].set_ylabel(nom, fontsize=9) fig("dfl.png", "Har tomon uchun 16 ta ehtimol. Tor cho'qqi — model chegara joyiga ishonadi; keng — ishonmaydi.") show(pd.DataFrame(qatorlar), 8)
| box | tomon | kutilgan d, katak | standart og'ish | eng katta p |
|---|---|---|---|---|
| aniq odam (0.89) | chap (l) | 2.07 | 0.29 | 0.91 |
| aniq odam (0.89) | yuqori (t) | 7.19 | 0.55 | 0.74 |
| aniq odam (0.89) | o'ng (r) | 0.5 | 0.5 | 0.5 |
| aniq odam (0.89) | past (b) | 1.77 | 0.47 | 0.76 |
| yarim ko'ringan odam (0.62) | chap (l) | 0.5 | 0.51 | 0.5 |
| yarim ko'ringan odam (0.62) | yuqori (t) | 4.2 | 0.72 | 0.71 |
| yarim ko'ringan odam (0.62) | o'ng (r) | 0.78 | 0.48 | 0.75 |
| yarim ko'ringan odam (0.62) | past (b) | 1.65 | 0.62 | 0.6 |

Har tomon uchun 16 ta ehtimol. Tor cho'qqi — model chegara joyiga ishonadi; keng — ishonmaydi.
Ehtimol ko'pincha ikkita qo'shni bin ga bo'linadi. Aniq odamning o'ng tomonida 0 va 1 ga teng yarimdan — kutilgan qiymat aynan 0.5 katak. DFL butun sonlar orasidagi masofani shunday ifodalaydi: 16 ta bin bilan 0 dan 15 gacha istalgan kasr son. Yarim ko'ringan odamda yuqori va past tomonlarning standart og'ishi aniq odamnikidan kattaroq (0.72 va 0.62, 0.55 va 0.47 ga qarshi): model uning bo'yi qayerda boshlanib, qayerda tugashiga kamroq ishonadi.
YOLO26: NMS siz bosh
YOLO26 ning Detect boshida ikki juft tarmoqcha bor: one2many (YOLO11 dagi kabi, bitta obyektga ko'p katak javob beradi) va one2one (bitta obyektga bitta katak). O'qitishda ikkalasi ham o'rganadi, ishlatishda esa faqat one2one ishlaydi. reg_max = 1, ya'ni DFL yo'q: har tomon uchun 16 ta ehtimol emas, bitta son.
tarmoq26 = YOLO("weights/yolo26n.pt").model.eval() with torch.no_grad(): y26, ichki26 = tarmoq26(x) # o'sha letterbox rasm print("tayyor chiqish:", tuple(y26.shape), "-> 300 ta qator: x1, y1, x2, y2, ishonch, sinf") qatorlar = [] for nom in ("one2many", "one2one"): eh = ichki26[nom]["scores"][0].sigmoid().max(0).values qatorlar.append({"bosh": nom, "box kanallari": ichki26[nom]["boxes"].shape[1], "ishonch > 0.25": int((eh > 0.25).sum()), "> 0.1": int((eh > 0.1).sum()), "> 0.05": int((eh > 0.05).sum())}) show(pd.DataFrame(qatorlar)) top = y26[0][y26[0][:, 4] > 0.05] print("one2one chiqishi, ishonch > 0.05:") for r in top.tolist(): print(f" {tarmoq26.names[int(r[5])]:7s} {r[4]:.2f} ({r[0]:6.1f}, {r[1]:6.1f}) -> ({r[2]:6.1f}, {r[3]:6.1f})") kuchli = top[top[:, 4] > 0.25] print("0.25 dan yuqorilarga NMS qo'llasak, nechtasi qoladi:", len(torchvision.ops.nms(kuchli[:, :4] + kuchli[:, 5:6] * 7680, kuchli[:, 4], 0.7)), "/", len(kuchli))
tayyor chiqish: (1, 300, 6) -> 300 ta qator: x1, y1, x2, y2, ishonch, sinf one2one chiqishi, ishonch > 0.05: bus 0.92 ( -1.4, 135.9) -> ( 477.7, 448.6) person 0.91 ( 131.8, 240.0) -> ( 204.7, 510.6) person 0.91 ( 28.3, 236.6) -> ( 141.8, 535.1) person 0.87 ( 397.4, 232.0) -> ( 479.9, 520.9) person 0.53 ( 0.1, 329.9) -> ( 35.6, 515.6) person 0.15 ( 0.2, 328.3) -> ( 38.2, 516.8) stop sign 0.12 ( -0.2, 150.2) -> ( 20.4, 192.8) stop sign 0.07 ( 0.0, 149.2) -> ( 21.3, 193.0) handbag 0.06 ( 25.7, 435.0) -> ( 46.2, 480.9) handbag 0.06 ( 134.2, 377.5) -> ( 173.2, 417.1) 0.25 dan yuqorilarga NMS qo'llasak, nechtasi qoladi: 5 / 5
| bosh | box kanallari | ishonch > 0.25 | > 0.1 | > 0.05 |
|---|---|---|---|---|
| one2many | 4 | 51 | 57 | 71 |
| one2one | 4 | 5 | 7 | 10 |
one2many boshda 0.25 dan yuqori kataklar o'nlab, one2one boshda esa obyektlar soniga teng. NMS qo'llasak ham hech narsa o'chirilmaydi — takrorlar yo'q. Lekin diqqat bilan qarang: one2one ham chap chetdagi yarim ko'ringan odamga ikkinchi box chiqargan, faqat past ishonch bilan. Chegara 0.25 bo'lsa, u o'tmaydi. Bosh takrorni butunlay yo'qotishni emas, unga past ball berishni o'rgangan.
Bu qanday o'rgatiladi? O'qitishda har bir haqiqiy obyekt one2many boshga bir nechta katak bilan, one2one boshga esa aynan bitta katak bilan bog'lanadi. Birinchisi boy gradient beradi, ikkinchisi "faqat bir marta javob ber" ni o'rgatadi (YOLOv10 dagi "consistent dual assignments"). Bog'lash qoidalari va loss funksiyalari — 6-bobda. Narxini 2-bobda o'lchagan edik: NMS siz rejim COCO da 0.7–0.8 mAP past, lekin postprocess deyarli uch barobar qisqa.
Asosiy fikr
- Detect boshi har katak uchun 4 × 16 masofa taqsimoti (DFL) va 80 ta sigmoid ehtimol chiqaradi. Kutilgan qiymat d = Σ i · pᵢ, keyin (a ∓ d) · s — piksel koordinata.
- DFL da masofa 15 katakdan oshmaydi: P3 240 pikseldan katta box chiza olmaydi. Katta obyektlar P5 dan keladi.
- NMS takrorlarni IoU bo'yicha o'chiradi. Chegara past — olomonda haqiqiy odamlar yo'qoladi, baland — takrorlar qoladi. YOLO26 ning
one2oneboshi takrorlarga o'zi past ball beradi va NMS ga ehtiyoj qolmaydi.
Mashqlar
zidane.jpguchun letterbox o'lchamini oldindan qo'lda hisoblang (rasm 1280 × 720), keyin kod bilan tekshiring. Qancha to'ldirish qo'shildi va kataklar soni qancha?nms()funksiyasini sinflarni siljitmasdan (7680 hiylasisiz) ishga tushiring. bus.jpg da natija o'zgaradimi? Qanday rasmda albatta o'zgaradi?- Kataklarning 0.25 dan yuqori nomzodlarini to'rlar bo'yicha
zidane.jpguchun sanang. Odamlar kattami yoki kichikmi — P3, P4, P5 taqsimoti bunga mos keladimi?
Bu bobni bepul o'qidingiz.
Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.