IlmHamroh
Data Science va sun'iy intellekt/Kompyuter korish2/14-dars29 daqiqa
Mundarija (21)

22.2-dars: Konvolyutsiya

22-QISM — KOMPYUTER KO'RISH · 2-dars


1. Kirish va motivatsiya

22.1-darsda ko'rdik: rasmni flatten qilib piksellarni belgi sifatida ishlatsak, shakl joyi o'zgarishi bilan model adashadi. Sintetik shakllarda logistik regressiya shakl markazda bo'lganda xatosiz ishladi, tasodifiy joyda esa 0.7 atrofida qoldi. Bizga joyga bog'liq bo'lmagan belgi kerak: "bu yerda vertikal chegara bor", "bu yerda burchak bor" — rasmning qayerida bo'lishidan qat'i nazar.

Konvolyutsiya aynan shuni qiladi. Kichik sonlar matritsasi — yadro (kernel, filtr) — rasm ustida sirpanadi va har joyda bitta skalyar ko'paytma hisoblaydi. Natija — yangi "rasm", u har joyda yadroga o'xshash naqsh qanchalik kuchli ekanini ko'rsatadi. Yadro bitta, joylar ko'p — shu sabab "chegara detektori" rasmning hamma joyida bir xil ishlaydi.

Konvolyutsiya kompyuter ko'rishga neyron tarmoqlardan ancha oldin kirgan: xiralashtirish, keskinlashtirish, Sobel chegara detektori — hammasi qo'lda tanlangan yadrolar. CNN ning g'oyasi oddiy: yadrolarni qo'lda tanlash o'rniga ularni o'rgatamiz. Lekin buning uchun avval amalning o'zini ichidan tushunish kerak — padding, stride, chiqish o'lchami va torch aslida nimani hisoblashini.

Real vaziyat. Bir muhandis tibbiy rasmlar uchun CNN yozdi va har qatlamdan keyin o'lchamni qo'lda hisobladi. Uchinchi qatlamda stride=2 va toq o'lcham tufayli bir piksel yo'qoldi, Linear qatlamiga kiruvchi o'lcham mos kelmay, RuntimeError: mat1 and mat2 shapes cannot be multiplied chiqdi. Formulani bilganida bu xatoni kod yozishdan oldin ko'rgan bo'lardi.

Bu darsda konvolyutsiyani qo'lda yozamiz va torch bilan aynan solishtiramiz.

Bu darsda:

  • Sirpanuvchi oyna: konvolyutsiya qadam-baqadam
  • Klassik yadrolar: xiralashtirish, chegara, Sobel
  • Padding va stride
  • Chiqish o'lchami formulasi
  • Cross-correlation va konvolyutsiya
  • Chiziqlilik va im2col
  • Tuzoqlar

ℹ Misollar real torch/numpy bilan (Python 3.14, torch 2.14 CPU).


2. Nazariya — chuqur tushuntirish

2.1. Sirpanuvchi oyna

text
KIRISH x: (H, W),  YADRO k: (kh, kw)

chiqish[i, j] = SUM_{a, b} x[i + a, j + b] * k[a, b]
                a = 0..kh-1, b = 0..kw-1

QADAMLAR:
  1. yadroni chap-yuqori burchakka qo'yish
  2. ostidagi oyna bilan elementma-element ko'paytirish
  3. yig'indini chiqishga yozish
  4. bir qadam o'ngga siljish; qator tugasa - pastga

MISOL (3x3 yadro, 5x5 kirish, padding yo'q):
  chiqish 3x3 - yadro faqat 3 x 3 = 9 joyga to'liq sig'adi

BITTA CHIQISH = oyna va yadroning SKALYAR KO'PAYTMASI
  -> oyna yadroga "o'xshasa", javob katta
  -> yadro - naqsh shabloni

Konvolyutsiya — har joyda bir xil yadro bilan skalyar ko'paytma; natija — naqsh qayerda kuchli ekanining xaritasi.

2.2. Klassik yadrolar

text
XIRALASHTIRISH (yig'indi = 1, yorqinlik saqlanadi):
  o'rtacha 3x3:  1/9 * [[1,1,1],[1,1,1],[1,1,1]]
  Gauss 3x3:     1/16 * [[1,2,1],[2,4,2],[1,2,1]]
  -> shovqin kamayadi, chegaralar yumshaydi

KESKINLASHTIRISH (yig'indi = 1):
  [[0,-1,0],[-1,5,-1],[0,-1,0]]  = aynan + (aynan - xira)

CHEGARA (yig'indi = 0, tekis joyda javob 0):
  Laplas:   [[0,1,0],[1,-4,1],[0,1,0]]          - hamma yo'nalish
  Sobel x:  [[-1,0,1],[-2,0,2],[-1,0,1]]        - vertikal chegara
  Sobel y:  [[-1,-2,-1],[0,0,0],[1,2,1]]        - gorizontal chegara
  kattalik: sqrt(gx^2 + gy^2)

YIG'INDI QOIDASI:
  yig'indi 1 -> tekis joy o'zgarmaydi
  yig'indi 0 -> tekis joy 0 ga aylanadi, faqat O'ZGARISH qoladi

SHOVQIN: chegara yadrolari shovqinni kuchaytiradi
  -> avval xiralashtirish, keyin chegara (Canny g'oyasi)

Yadro yig'indisi uning vazifasini aytadi: 1 — silliqlash, 0 — o'zgarishni topish.

2.3. Padding

text
MUAMMO: padding siz har qatlamda rasm kichrayadi
  28 -> 26 -> 24 -> ...   (3x3 yadro)
  va chekka piksellar kamroq "ko'riladi"

PADDING p: chetga p qator/ustun qo'shish
  p = (k - 1) / 2  (toq k) -> o'lcham saqlanadi ("same")
  k=3 -> p=1, k=5 -> p=2, k=7 -> p=3

TURLARI (F.pad mode=...):
  constant (0)  - eng keng tarqalgan, chegara qorayadi
  reflect       - ko'zgu: [3 2 | 1 2 3 | 2 1]
  replicate     - chetini takrorlash: [1 1 | 1 2 3 | 3 3]
  circular      - aylanma: [2 3 | 1 2 3 | 1 2]

nn.Conv2d(..., padding=1, padding_mode="zeros"/"reflect"/...)
padding="same" - faqat stride=1 da

p = (k - 1) / 2 o'lchamni saqlaydi; nol padding chegara piksellarini qoraytiradi.

2.4. Stride va chiqish o'lchami formulasi

text
STRIDE s: oyna har safar s piksel siljiydi
  s = 2 -> chiqish taxminan 2 barobar kichik (har o'qda)

FORMULA (har o'q uchun alohida):
  H_chiq = floor((H + 2p - k) / s) + 1

MISOLLAR:
  H=28, k=3, p=1, s=1 -> 28          (same)
  H=28, k=3, p=1, s=2 -> 14
  H=27, k=3, p=1, s=2 -> 14
  H=8,  k=3, p=0, s=2 -> 3           (floor(2.5) + 1)

FLOOR NIMANI ANGLATADI:
  kasr chiqsa, oxirgi to'liq sig'maydigan oyna TASHLANADI
  -> oxirgi qator/ustun hech qachon ko'rilmasligi mumkin

DILATION d: yadro elementlari orasida d-1 bo'shliq
  samarali yadro: k_eff = d * (k - 1) + 1
  formulada k o'rniga k_eff

floor((H + 2p - k) / s) + 1 — CNN yozishda eng ko'p ishlatiladigan formula.

2.5. Cross-correlation va konvolyutsiya

text
MATEMATIK KONVOLYUTSIYA:
  (x * k)[i, j] = SUM x[i - a, j - b] * k[a, b]
  -> yadro 180 gradusga BURILADI

CROSS-CORRELATION:
  (x . k)[i, j] = SUM x[i + a, j + b] * k[a, b]
  -> yadro burilmaydi

torch.nn.functional.conv2d, nn.Conv2d  -> CROSS-CORRELATION
scipy.signal.correlate2d               -> cross-correlation
scipy.signal.convolve2d                -> haqiqiy konvolyutsiya

conv(x, k) = corr(x, flip(k))

NEGA FARQ MUHIM EMAS (tarmoqda):
  yadro o'rgatiladi -> tarmoq kerak bo'lsa burilgan yadroni o'rganadi
  simmetrik yadroda (Gauss) ikkalasi bir xil

QACHON MUHIM:
  qo'lda yozilgan yadroni kutubxonalar orasida ko'chirganda
  signal ishlashda (scipy) va tarmoqda (torch) natija taqqoslanganda

Chuqur o'rganishdagi "konvolyutsiya" — aslida cross-correlation; o'rgatiladigan yadroda bu farq yo'qoladi.

2.6. Chiziqlilik va im2col

text
CHIZIQLILIK:
  conv(a*x + b*y, k) = a*conv(x, k) + b*conv(y, k)
  conv(x, k1) + conv(x, k2) = conv(x, k1 + k2)

KETMA-KET:
  conv(conv(x, k1), k2) = conv(x, conv(k1, k2))    (katta yadro)
  -> nochiziqliksiz ikki qatlam = bitta qatlam
  -> shuning uchun qatlamlar orasida ReLU (20-qism)

im2col (unfold):
  har oynani ustun qilib yoyish: (N, C*k*k, L)   L - joylar soni
  og'irlik: (out, C*k*k)
  chiqish = W @ ustunlar -> (N, out, L) -> (N, out, H_chiq, W_chiq)

  -> konvolyutsiya = MATRITSA KO'PAYTMASI
  -> GPU/BLAS da tez, lekin xotira k*k marta ko'p

Konvolyutsiya — chiziqli amal; ichida u oynalar ustida matritsa ko'paytmasi.

2.7. Tuzoqlar

Asosiy tuzoqlar: chiqish o'lchamini formulasiz "taxmin qilish"; floor tufayli oxirgi qator/ustun tashlanishini sezmaslik; padding="same" ni stride=2 bilan ishlatish; nol padding chegara piksellarini qoraytirishini unutish; torch va scipy.signal.convolve2d natijasini to'g'ridan-to'g'ri taqqoslash (biri yadroni buradi); chegara yadrosini shovqinli rasmga xiralashtirmasdan qo'llash; F.conv2d ga (H, W) yoki (C, H, W) ni (N, C, H, W) o'rniga berish; qatlamlar orasida nochiziqlik qo'ymaslik.


3. Tez ma'lumotnoma

python
import numpy as np
import torch
import torch.nn.functional as F


def chiqish_olchami(h, k, p=0, s=1, d=1):
    return (h + 2 * p - d * (k - 1) - 1) // s + 1


def conv2d_qolda(x, k, padding=0, stride=1):
    """(H, W) x (kh, kw) - cross-correlation, torch kabi."""
    x = np.pad(x, padding)
    kh, kw = k.shape
    h = (x.shape[0] - kh) // stride + 1
    w = (x.shape[1] - kw) // stride + 1
    return np.array([[np.sum(x[i * stride:i * stride + kh,
                                j * stride:j * stride + kw] * k)
                      for j in range(w)] for i in range(h)])


SOBEL_X = torch.tensor([[-1., 0, 1], [-2, 0, 2], [-1, 0, 1]])
GAUSS = torch.tensor([[1., 2, 1], [2, 4, 2], [1, 2, 1]]) / 16

x = torch.rand(1, 1, 28, 28)                           # (N, C, H, W)
gx = F.conv2d(x, SOBEL_X.view(1, 1, 3, 3), padding=1)  # (1, 1, 28, 28)

Konvolyutsiya xulosasi

chiqish[i, j] = sum(oyna * yadro)    - cross-correlation (torch)
H_chiq = floor((H + 2p - k) / s) + 1
same: p = (k - 1) / 2, faqat stride=1
yig'indi 1 -> silliqlash, yig'indi 0 -> chegara
conv = corr(flip(k)); o'rgatishda farq yo'q
conv - chiziqli: qatlamlar orasida ReLU shart

4. Batafsil misollar

Misollar real torch/numpy bilan (Python 3.14, torch 2.14 CPU).

Misol 1 — Konvolyutsiya qo'lda va torch bilan

python
"""Konvolyutsiya qo'lda (sirpanuvchi oyna) va torch bilan aynan solishtirish."""

import numpy as np
import torch
import torch.nn.functional as F


def conv2d_qolda(x, k, padding=0, stride=1):
    """x: (H, W), k: (kh, kw). Aslida cross-correlation - torch kabi."""
    if padding:
        x = np.pad(x, padding)
    kh, kw = k.shape
    h_ch = (x.shape[0] - kh) // stride + 1
    w_ch = (x.shape[1] - kw) // stride + 1
    chiqish = np.zeros((h_ch, w_ch), dtype=np.float64)
    for i in range(h_ch):
        for j in range(w_ch):
            oyna = x[i * stride:i * stride + kh, j * stride:j * stride + kw]
            chiqish[i, j] = np.sum(oyna * k)
    return chiqish


def jadval(m, fmt="{:>5.0f}"):
    for qator in m:
        print("    " + " ".join(fmt.format(v + 0.0) for v in qator))


def main() -> None:
    x = np.array([[1, 2, 0, 3, 1],
                  [0, 1, 3, 1, 2],
                  [2, 1, 0, 2, 0],
                  [1, 3, 2, 1, 1],
                  [0, 2, 1, 0, 3]], dtype=np.float64)
    k = np.array([[1, 0, -1],
                  [2, 0, -2],
                  [1, 0, -1]], dtype=np.float64)

    print("=== 1. Kirish (5x5) va yadro (3x3) ===")
    jadval(x)
    print("  yadro:")
    jadval(k)

    print("\n=== 2. Bitta oyna qadam-baqadam (chiqish[0, 0]) ===")
    oyna = x[0:3, 0:3]
    kopaytma = oyna * k
    print("  oyna * yadro (elementma-element):")
    jadval(kopaytma)
    print(f"  yig'indi: {kopaytma.sum():.0f}")

    print("\n=== 3. To'liq chiqish (padding=0, stride=1) ===")
    y = conv2d_qolda(x, k)
    print(f"  shakl: {y.shape}  (5 - 3 + 1 = 3)")
    jadval(y)

    print("\n=== 4. torch.nn.functional.conv2d bilan solishtirish ===")
    xt = torch.tensor(x).view(1, 1, 5, 5)
    kt = torch.tensor(k).view(1, 1, 3, 3)
    print(f"  F.conv2d kirish (N,C,H,W): {tuple(xt.shape)}, "
          f"og'irlik (out,in,kh,kw): {tuple(kt.shape)}")
    for p, s in [(0, 1), (1, 1), (1, 2), (2, 3)]:
        qolda = conv2d_qolda(x, k, padding=p, stride=s)
        tt = F.conv2d(xt, kt, padding=p, stride=s)[0, 0].numpy()
        print(f"  padding={p}, stride={s}: shakl {qolda.shape}, "
              f"aynan teng: {np.array_equal(qolda, tt)}, "
              f"maks farq {np.abs(qolda - tt).max():.1e}")

    print("\n=== 5. float32 da ===")
    rng = np.random.default_rng(0)
    katta = rng.normal(0, 1, (32, 32))
    yadro = rng.normal(0, 1, (5, 5))
    q = conv2d_qolda(katta, yadro, padding=2)
    t32 = F.conv2d(torch.tensor(katta, dtype=torch.float32).view(1, 1, 32, 32),
                   torch.tensor(yadro, dtype=torch.float32).view(1, 1, 5, 5),
                   padding=2)[0, 0].numpy()
    farq = np.abs(q - t32).max()
    print(f"  32x32, yadro 5x5: maks farq {farq:.1e}")
    print(f"  np.allclose(atol=1e-5): {np.allclose(q, t32, atol=1e-5)}")
    print("  float32 yaxlitlash - farq faqat oxirgi raqamlarda")

    print("\n=== 6. Hisob hajmi ===")
    h, w, kk = 224, 224, 3
    amallar = h * w * kk * kk
    print(f"  224x224 rasm, 3x3 yadro, padding=1: {amallar:,} ko'paytirish")
    print(f"  64 kirish va 64 chiqish kanal bilan: "
          f"{amallar * 64 * 64:,}")
    print("  ⭐ Konvolyutsiya = har joyda bir xil yadro bilan skalyar ko'paytma")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Kirish (5x5) va yadro (3x3) ===
        1     2     0     3     1
        0     1     3     1     2
        2     1     0     2     0
        1     3     2     1     1
        0     2     1     0     3
  yadro:
        1     0    -1
        2     0    -2
        1     0    -1

=== 2. Bitta oyna qadam-baqadam (chiqish[0, 0]) ===
  oyna * yadro (elementma-element):
        1     0     0
        0     0    -6
        2     0     0
  yig'indi: -3

=== 3. To'liq chiqish (padding=0, stride=1) ===
  shakl: (3, 3)  (5 - 3 + 1 = 3)
       -3    -2     1
        0     0     2
       -1     5     0

=== 4. torch.nn.functional.conv2d bilan solishtirish ===
  F.conv2d kirish (N,C,H,W): (1, 1, 5, 5), og'irlik (out,in,kh,kw): (1, 1, 3, 3)
  padding=0, stride=1: shakl (3, 3), aynan teng: True, maks farq 0.0e+00
  padding=1, stride=1: shakl (5, 5), aynan teng: True, maks farq 0.0e+00
  padding=1, stride=2: shakl (3, 3), aynan teng: True, maks farq 0.0e+00
  padding=2, stride=3: shakl (3, 3), aynan teng: True, maks farq 0.0e+00

=== 5. float32 da ===
  32x32, yadro 5x5: maks farq 1.8e-06
  np.allclose(atol=1e-5): True
  float32 yaxlitlash - farq faqat oxirgi raqamlarda

=== 6. Hisob hajmi ===
  224x224 rasm, 3x3 yadro, padding=1: 451,584 ko'paytirish
  64 kirish va 64 chiqish kanal bilan: 1,849,688,064
  ⭐ Konvolyutsiya = har joyda bir xil yadro bilan skalyar ko'paytma

Nima ko'rsatdi: 2.1, 2.4-bo'limlar.

Misol 2 — Klassik yadrolar

python
"""Klassik yadrolar: xiralashtirish, chegara, Sobel (real torch)."""

import numpy as np
import torch
import torch.nn.functional as F
from sklearn.datasets import load_digits

YADROLAR = {
    "aynan": [[0, 0, 0], [0, 1, 0], [0, 0, 0]],
    "o'rtacha 3x3": [[1 / 9] * 3] * 3,
    "Gauss 3x3": [[1 / 16, 2 / 16, 1 / 16], [2 / 16, 4 / 16, 2 / 16],
                  [1 / 16, 2 / 16, 1 / 16]],
    "keskinlash": [[0, -1, 0], [-1, 5, -1], [0, -1, 0]],
    "Laplas": [[0, 1, 0], [1, -4, 1], [0, 1, 0]],
    "Sobel x": [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]],
    "Sobel y": [[-1, -2, -1], [0, 0, 0], [1, 2, 1]],
}


def qolla(rasm, yadro):
    x = rasm.view(1, 1, *rasm.shape)
    k = torch.tensor(yadro, dtype=torch.float32).view(1, 1, 3, 3)
    return F.conv2d(x, k, padding=1)[0, 0]


def ascii_chiz(m):
    for qator in m:
        s = ""
        for v in qator:
            s += " +" if v > 0.5 else (" -" if v < -0.5 else " .")
        print("   " + s)


def main() -> None:
    rng = np.random.default_rng(0)
    toza = torch.zeros(14, 14)
    toza[5:10, 4:11] = 1.0
    shovqin = torch.tensor(rng.normal(0, 0.2, (14, 14)), dtype=torch.float32)
    rasm = toza + shovqin
    tekis = (slice(1, 4), slice(1, 13))      # kvadratdan uzoq fon

    print("=== 1. Yadro yig'indisi nimani anglatadi ===")
    print(f"  {'yadro':<14} {'yig_indi':>9} {'tekis fonda':>12} "
          f"{'kvadrat ichida':>15}")
    for nom, k in YADROLAR.items():
        y = qolla(toza, k)
        print(f"  {nom:<14} {np.sum(k):>9.2f} {y[tekis].abs().mean():>12.3f} "
              f"{y[6:9, 6:9].mean():>15.3f}")
    print("  yig'indi 1 - yorqinlik saqlanadi; yig'indi 0 - tekis joyda 0")

    print("\n=== 2. Xiralashtirish shovqinni kamaytiradi ===")
    print(f"  shovqinli rasmda fon std: {rasm[tekis].std():.3f}")
    for nom in ["o'rtacha 3x3", "Gauss 3x3"]:
        y = qolla(rasm, YADROLAR[nom])
        print(f"  {nom:<13} dan keyin fon std: {y[tekis].std():.3f}")
    print(f"  nazariy (o'rtacha 3x3, mustaqil shovqin): 0.2 / 3 = "
          f"{0.2 / 3:.3f}")

    print("\n=== 3. Sobel x - vertikal chegaralar (toza kvadrat) ===")
    gx = qolla(toza, YADROLAR["Sobel x"])
    ascii_chiz(gx.numpy())
    print("  + : chapdan o'ngga yorqinlashadi, - : qorayadi")

    print("\n=== 4. Sobel y - gorizontal chegaralar ===")
    gy = qolla(toza, YADROLAR["Sobel y"])
    ascii_chiz(gy.numpy())
    print("  + : yuqoridan pastga yorqinlashadi, - : qorayadi")

    print("\n=== 5. Gradient kattaligi va shovqin ===")
    mag = torch.sqrt(gx ** 2 + gy ** 2)
    chegara = mag > 1.0
    print(f"  toza rasm: chegara piksellari {int(chegara.sum())}, "
          f"maks kattalik {mag.max():.2f}")
    for nom, kirish in [("shovqinli", rasm),
                        ("avval Gauss", qolla(rasm, YADROLAR["Gauss 3x3"]))]:
        m = torch.sqrt(qolla(kirish, YADROLAR["Sobel x"]) ** 2
                       + qolla(kirish, YADROLAR["Sobel y"]) ** 2)
        topildi = m > 1.0
        togri = int((topildi & chegara).sum())
        yolgon = int((topildi & ~chegara).sum())
        print(f"  {nom:<12} to'g'ri topilgan {togri:>3}, "
              f"yolg'on chegara {yolgon:>3}")

    print("\n=== 6. Raqam rasmida (load_digits) ===")
    raqam = torch.tensor(load_digits().images[0], dtype=torch.float32) / 16
    for nom in ["Sobel x", "Laplas"]:
        y = qolla(raqam, YADROLAR[nom])
        print(f"  {nom:<8}: min {y.min():.2f}, max {y.max():.2f}, "
              f"|y| > 0.5 bo'lgan piksellar {int((y.abs() > 0.5).sum())}/64")
    print("  ⭐ Yadro - naqsh detektori: yadroga o'xshash joyda javob katta")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Yadro yig'indisi nimani anglatadi ===
  yadro           yig_indi  tekis fonda  kvadrat ichida
  aynan               1.00        0.000           1.000
  o'rtacha 3x3        1.00        0.000           1.000
  Gauss 3x3           1.00        0.000           1.000
  keskinlash          1.00        0.000           1.000
  Laplas              0.00        0.000           0.000
  Sobel x             0.00        0.000           0.000
  Sobel y             0.00        0.000           0.000
  yig'indi 1 - yorqinlik saqlanadi; yig'indi 0 - tekis joyda 0

=== 2. Xiralashtirish shovqinni kamaytiradi ===
  shovqinli rasmda fon std: 0.174
  o'rtacha 3x3  dan keyin fon std: 0.068
  Gauss 3x3     dan keyin fon std: 0.080
  nazariy (o'rtacha 3x3, mustaqil shovqin): 0.2 / 3 = 0.067

=== 3. Sobel x - vertikal chegaralar (toza kvadrat) ===
    . . . . . . . . . . . . . .
    . . . . . . . . . . . . . .
    . . . . . . . . . . . . . .
    . . . . . . . . . . . . . .
    . . . + + . . . . . - - . .
    . . . + + . . . . . - - . .
    . . . + + . . . . . - - . .
    . . . + + . . . . . - - . .
    . . . + + . . . . . - - . .
    . . . + + . . . . . - - . .
    . . . + + . . . . . - - . .
    . . . . . . . . . . . . . .
    . . . . . . . . . . . . . .
    . . . . . . . . . . . . . .
  + : chapdan o'ngga yorqinlashadi, - : qorayadi

=== 4. Sobel y - gorizontal chegaralar ===
    . . . . . . . . . . . . . .
    . . . . . . . . . . . . . .
    . . . . . . . . . . . . . .
    . . . . . . . . . . . . . .
    . . . + + + + + + + + + . .
    . . . + + + + + + + + + . .
    . . . . . . . . . . . . . .
    . . . . . . . . . . . . . .
    . . . . . . . . . . . . . .
    . . . - - - - - - - - - . .
    . . . - - - - - - - - - . .
    . . . . . . . . . . . . . .
    . . . . . . . . . . . . . .
    . . . . . . . . . . . . . .
  + : yuqoridan pastga yorqinlashadi, - : qorayadi

=== 5. Gradient kattaligi va shovqin ===
  toza rasm: chegara piksellari 48, maks kattalik 4.24
  shovqinli    to'g'ri topilgan  47, yolg'on chegara  45
  avval Gauss  to'g'ri topilgan  48, yolg'on chegara  21

=== 6. Raqam rasmida (load_digits) ===
  Sobel x : min -2.94, max 3.44, |y| > 0.5 bo'lgan piksellar 54/64
  Laplas  : min -2.06, max 1.44, |y| > 0.5 bo'lgan piksellar 27/64
  ⭐ Yadro - naqsh detektori: yadroga o'xshash joyda javob katta

Nima ko'rsatdi: 2.2-bo'lim.

Misol 3 — Padding, stride va o'lcham formulasi

python
"""Padding, stride va chiqish o'lchami formulasi (real torch)."""

import torch
import torch.nn.functional as F


def formula(h, k, p, s, d=1):
    k_eff = d * (k - 1) + 1
    return (h + 2 * p - k_eff) // s + 1


def main() -> None:
    torch.manual_seed(0)

    print("=== 1. Formula va haqiqiy shakl ===")
    print(f"  {'H':>4} {'k':>3} {'p':>3} {'s':>3} {'(H+2p-k)/s+1':>14} "
          f"{'formula':>8} {'torch':>6}")
    holatlar = [(28, 3, 0, 1), (28, 3, 1, 1), (28, 5, 2, 1), (28, 3, 1, 2),
                (27, 3, 1, 2), (32, 7, 3, 2), (8, 3, 0, 2), (224, 11, 2, 4)]
    hammasi = True
    for h, k, p, s in holatlar:
        x = torch.zeros(1, 1, h, h)
        w = torch.zeros(1, 1, k, k)
        haqiqiy = F.conv2d(x, w, padding=p, stride=s).shape[-1]
        kasr = (h + 2 * p - k) / s + 1
        f = formula(h, k, p, s)
        hammasi &= f == haqiqiy
        print(f"  {h:>4} {k:>3} {p:>3} {s:>3} {kasr:>14.2f} {f:>8} "
              f"{haqiqiy:>6}")
    print(f"  formula (pastga yaxlitlab) hamma holatda to'g'ri: {hammasi}")

    print("\n=== 2. 'same' padding ===")
    for k in [3, 5, 7]:
        p = (k - 1) // 2
        print(f"  k={k}: p=(k-1)/2={p} -> 32 dan {formula(32, k, p, 1)}")
    y = F.conv2d(torch.zeros(1, 1, 32, 32), torch.zeros(1, 1, 5, 5),
                 padding="same")
    print(f"  padding='same', k=5: {tuple(y.shape)}")
    try:
        F.conv2d(torch.zeros(1, 1, 32, 32), torch.zeros(1, 1, 3, 3),
                 padding="same", stride=2)
        print("  'same' + stride=2 ishladi (kutilmagan)")
    except (RuntimeError, ValueError) as xato:
        print(f"  'same' + stride=2: {type(xato).__name__} - "
              f"{str(xato)[:43]}")

    print("\n=== 3. Yaxlitlash: qaysi piksellar e'tiborsiz qoladi ===")
    for h, k, p, s in [(8, 3, 0, 2), (9, 3, 0, 2), (8, 3, 1, 2)]:
        x = torch.ones(1, 1, h, h, requires_grad=True)
        w = torch.ones(1, 1, k, k)
        F.conv2d(x, w, padding=p, stride=s).sum().backward()
        g = x.grad[0, 0]
        korilmagan = int((g == 0).sum())
        qatorlar = (g == 0).all(dim=1).nonzero().flatten().tolist()
        ustunlar = (g == 0).all(dim=0).nonzero().flatten().tolist()
        print(f"  H={h}, k={k}, p={p}, s={s}: chiqish {formula(h, k, p, s)}, "
              f"ko'rilmagan piksellar {korilmagan}, qatorlar {qatorlar}, "
              f"ustunlar {ustunlar}")

    print("\n=== 4. Padding turi: chegaradagi qiymat ===")
    x = torch.ones(1, 1, 6, 6)
    k = torch.full((1, 1, 3, 3), 1 / 9)
    print("  kirish hammasi 1, yadro - o'rtacha 3x3")
    print(f"  {'rejim':<10} {'burchak':>8} {'chekka':>7} {'markaz':>7}")
    for rejim in ["constant", "reflect", "replicate", "circular"]:
        xp = F.pad(x, (1, 1, 1, 1), mode=rejim)
        y = F.conv2d(xp, k)[0, 0]
        print(f"  {rejim:<10} {y[0, 0]:>8.3f} {y[0, 3]:>7.3f} "
              f"{y[3, 3]:>7.3f}")
    print("  nol padding chegarani qoraytiradi (burchak 4/9, chekka 6/9)")

    print("\n=== 5. Dilation - kengaytirilgan yadro ===")
    for d in [1, 2, 3]:
        y = F.conv2d(torch.zeros(1, 1, 32, 32), torch.zeros(1, 1, 3, 3),
                     dilation=d)
        print(f"  k=3, dilation={d}: samarali yadro {d * 2 + 1}x{d * 2 + 1}, "
              f"chiqish {y.shape[-1]} (formula {formula(32, 3, 0, 1, d)})")

    print("\n=== 6. O'lchamlar zanjiri ===")
    x = torch.zeros(1, 3, 64, 64)
    print(f"  kirish: {tuple(x.shape)}")
    for i, (k, p, s) in enumerate([(3, 1, 1), (3, 1, 2), (3, 1, 2),
                                   (3, 0, 1), (3, 1, 2)], 1):
        x = F.conv2d(x, torch.zeros(3, 3, k, k), padding=p, stride=s)
        print(f"  {i}-qadam k={k}, p={p}, s={s}: {tuple(x.shape)}")
    print("  ⭐ Chiqish = floor((H + 2p - k) / s) + 1")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Formula va haqiqiy shakl ===
     H   k   p   s   (H+2p-k)/s+1  formula  torch
    28   3   0   1          26.00       26     26
    28   3   1   1          28.00       28     28
    28   5   2   1          28.00       28     28
    28   3   1   2          14.50       14     14
    27   3   1   2          14.00       14     14
    32   7   3   2          16.50       16     16
     8   3   0   2           3.50        3      3
   224  11   2   4          55.25       55     55
  formula (pastga yaxlitlab) hamma holatda to'g'ri: True

=== 2. 'same' padding ===
  k=3: p=(k-1)/2=1 -> 32 dan 32
  k=5: p=(k-1)/2=2 -> 32 dan 32
  k=7: p=(k-1)/2=3 -> 32 dan 32
  padding='same', k=5: (1, 1, 32, 32)
  'same' + stride=2: RuntimeError - padding='same' is not supported for strided

=== 3. Yaxlitlash: qaysi piksellar e'tiborsiz qoladi ===
  H=8, k=3, p=0, s=2: chiqish 3, ko'rilmagan piksellar 15, qatorlar [7], ustunlar [7]
  H=9, k=3, p=0, s=2: chiqish 4, ko'rilmagan piksellar 0, qatorlar [], ustunlar []
  H=8, k=3, p=1, s=2: chiqish 4, ko'rilmagan piksellar 0, qatorlar [], ustunlar []

=== 4. Padding turi: chegaradagi qiymat ===
  kirish hammasi 1, yadro - o'rtacha 3x3
  rejim       burchak  chekka  markaz
  constant      0.444   0.667   1.000
  reflect       1.000   1.000   1.000
  replicate     1.000   1.000   1.000
  circular      1.000   1.000   1.000
  nol padding chegarani qoraytiradi (burchak 4/9, chekka 6/9)

=== 5. Dilation - kengaytirilgan yadro ===
  k=3, dilation=1: samarali yadro 3x3, chiqish 30 (formula 30)
  k=3, dilation=2: samarali yadro 5x5, chiqish 28 (formula 28)
  k=3, dilation=3: samarali yadro 7x7, chiqish 26 (formula 26)

=== 6. O'lchamlar zanjiri ===
  kirish: (1, 3, 64, 64)
  1-qadam k=3, p=1, s=1: (1, 3, 64, 64)
  2-qadam k=3, p=1, s=2: (1, 3, 32, 32)
  3-qadam k=3, p=1, s=2: (1, 3, 16, 16)
  4-qadam k=3, p=0, s=1: (1, 3, 14, 14)
  5-qadam k=3, p=1, s=2: (1, 3, 7, 7)
  ⭐ Chiqish = floor((H + 2p - k) / s) + 1

Nima ko'rsatdi: 2.3, 2.4-bo'limlar.

Misol 4 — Cross-correlation, chiziqlilik va im2col

python
"""Cross-correlation va konvolyutsiya, chiziqlilik, im2col (real torch/scipy)."""

import numpy as np
import torch
import torch.nn.functional as F
from scipy import signal


def main() -> None:
    rng = np.random.default_rng(0)
    x = rng.integers(0, 5, (6, 6)).astype(np.float64)
    k = np.array([[1, 2, 0],
                  [0, 1, 0],
                  [0, 0, -1]], dtype=np.float64)   # nosimmetrik
    xt = torch.tensor(x).view(1, 1, 6, 6)

    def torch_conv(yadro):
        return F.conv2d(xt, torch.tensor(yadro).view(1, 1, 3, 3))[0, 0].numpy()

    print("=== 1. torch nimani hisoblaydi ===")
    tt = torch_conv(k)
    korr = signal.correlate2d(x, k, mode="valid")
    konv = signal.convolve2d(x, k, mode="valid")
    print(f"  F.conv2d == scipy correlate2d: {np.array_equal(tt, korr)}")
    print(f"  F.conv2d == scipy convolve2d:  {np.array_equal(tt, konv)}")
    print("  torch 'conv2d' aslida CROSS-CORRELATION hisoblaydi")

    print("\n=== 2. Farq - yadroni 180 gradusga burish ===")
    burilgan = np.flip(k)
    print("  burilgan yadro:")
    for qator in burilgan:
        print("    " + " ".join(f"{v:>4.0f}" for v in qator))
    print(f"  convolve2d(x, k) == correlate2d(x, flip(k)): "
          f"{np.array_equal(konv, signal.correlate2d(x, burilgan, 'valid'))}")
    print(f"  F.conv2d(x, flip(k)) == convolve2d(x, k): "
          f"{np.array_equal(torch_conv(burilgan.copy()), konv)}")

    print("\n=== 3. Simmetrik yadroda farq yo'q ===")
    gauss = np.array([[1, 2, 1], [2, 4, 2], [1, 2, 1]]) / 16
    print(f"  Gauss: correlate == convolve: "
          f"{np.allclose(signal.correlate2d(x, gauss, 'valid'), signal.convolve2d(x, gauss, 'valid'))}")
    sobel = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], dtype=float)
    a = signal.correlate2d(x, sobel, "valid")
    b = signal.convolve2d(x, sobel, "valid")
    print(f"  Sobel x: convolve == -correlate: {np.array_equal(b, -a)}")
    print("  o'rgatiladigan yadroda farq muhim emas - tarmoq burilgan")
    print("  versiyani o'rganadi")

    print("\n=== 4. Chiziqlilik ===")
    x2 = rng.normal(0, 1, (6, 6))
    chap = signal.correlate2d(2 * x + 3 * x2, k, "valid")
    ong = (2 * signal.correlate2d(x, k, "valid")
           + 3 * signal.correlate2d(x2, k, "valid"))
    print(f"  conv(2a + 3b) == 2 conv(a) + 3 conv(b): {np.allclose(chap, ong)}")
    ikki = (signal.correlate2d(x, k, "valid")
            + signal.correlate2d(x, sobel, "valid"))
    birga = signal.correlate2d(x, k + sobel, "valid")
    print(f"  conv(x, k1) + conv(x, k2) == conv(x, k1 + k2): "
          f"{np.allclose(ikki, birga)}")

    print("\n=== 5. Ketma-ket ikki yadro = bitta katta yadro ===")
    katta = rng.normal(0, 1, (12, 12))
    ketma = signal.convolve2d(signal.convolve2d(katta, gauss, "valid"),
                              sobel, "valid")
    birlashgan = signal.convolve2d(gauss, sobel)          # 5x5
    bir_marta = signal.convolve2d(katta, birlashgan, "valid")
    print(f"  birlashgan yadro shakli: {birlashgan.shape}")
    print(f"  Gauss keyin Sobel == bitta 5x5 yadro: "
          f"{np.allclose(ketma, bir_marta)}")
    print("  nochiziqlik (ReLU) bo'lmasa, qatlamlar bitta qatlamga qisqaradi")

    print("\n=== 6. im2col: konvolyutsiya = matritsa ko'paytmasi ===")
    torch.manual_seed(0)
    xb = torch.randn(2, 3, 8, 8)
    w = torch.randn(4, 3, 3, 3)
    ustunlar = F.unfold(xb, kernel_size=3, padding=1)      # (N, C*k*k, L)
    print(f"  unfold shakli: {tuple(ustunlar.shape)}  "
          f"(N, C*k*k = {3 * 9}, joylar L = {8 * 8})")
    y_mat = (w.view(4, -1) @ ustunlar).view(2, 4, 8, 8)
    y_conv = F.conv2d(xb, w, padding=1)
    print(f"  matmul natijasi shakli: {tuple(y_mat.shape)}")
    print(f"  F.conv2d bilan maks farq: {(y_mat - y_conv).abs().max():.1e}")
    print(f"  allclose: {torch.allclose(y_mat, y_conv, atol=1e-5)}")
    print("  ⭐ Konvolyutsiya - og'irligi baham ko'rilgan chiziqli amal")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. torch nimani hisoblaydi ===
  F.conv2d == scipy correlate2d: True
  F.conv2d == scipy convolve2d:  False
  torch 'conv2d' aslida CROSS-CORRELATION hisoblaydi

=== 2. Farq - yadroni 180 gradusga burish ===
  burilgan yadro:
      -1    0    0
       0    1    0
       0    2    1
  convolve2d(x, k) == correlate2d(x, flip(k)): True
  F.conv2d(x, flip(k)) == convolve2d(x, k): True

=== 3. Simmetrik yadroda farq yo'q ===
  Gauss: correlate == convolve: True
  Sobel x: convolve == -correlate: True
  o'rgatiladigan yadroda farq muhim emas - tarmoq burilgan
  versiyani o'rganadi

=== 4. Chiziqlilik ===
  conv(2a + 3b) == 2 conv(a) + 3 conv(b): True
  conv(x, k1) + conv(x, k2) == conv(x, k1 + k2): True

=== 5. Ketma-ket ikki yadro = bitta katta yadro ===
  birlashgan yadro shakli: (5, 5)
  Gauss keyin Sobel == bitta 5x5 yadro: True
  nochiziqlik (ReLU) bo'lmasa, qatlamlar bitta qatlamga qisqaradi

=== 6. im2col: konvolyutsiya = matritsa ko'paytmasi ===
  unfold shakli: (2, 27, 64)  (N, C*k*k = 27, joylar L = 64)
  matmul natijasi shakli: (2, 4, 8, 8)
  F.conv2d bilan maks farq: 3.8e-06
  allclose: True
  ⭐ Konvolyutsiya - og'irligi baham ko'rilgan chiziqli amal

Nima ko'rsatdi: 2.5, 2.6-bo'limlar.


5. To'g'ri va noto'g'ri tushunishlar

Noto'g'ri fikr To'g'risi
"nn.Conv2d matematik konvolyutsiya hisoblaydi" Cross-correlation — yadro burilmaydi
"Chiqish o'lchami = kirish o'lchami" Faqat p = (k - 1) / 2 va s = 1 da
"stride=2 o'lchamni aniq ikkiga bo'ladi" floor — toq o'lchamda yaxlitlanadi
"Padding faqat o'lcham uchun" Chegara piksellari qiymatiga ham ta'sir qiladi
"Chegara yadrosi shovqinga chidamli" Shovqinni kuchaytiradi — avval xiralashtiring
"Ko'p konvolyutsiya qatlami — murakkab funksiya" Nochiziqliksiz bitta konvolyutsiyaga teng
"Yadro o'lchami — faqat tezlik masalasi" Qancha qo'shnini ko'rishni belgilaydi
"Konvolyutsiya — maxsus sehrli amal" Oynalar ustida matritsa ko'paytmasi

6. Keng tarqalgan xatolar va yechimlari

1. Kirish shaklida N va C yo'q

python
F.conv2d(torch.rand(28, 28), w)                         # ⚠️
F.conv2d(torch.rand(28, 28).view(1, 1, 28, 28), w)      # ✅ (N, C, H, W)

2. O'lchamni taxmin qilish

python
nn.Linear(32 * 13 * 13, 10)    # "27 // 2 = 13" deb taxmin      # ⚠️
chiqish_olchami(27, 3, 1, 2)   # -> 14, keyin Linear(32*14*14)  # ✅

3. same + stride

python
F.conv2d(x, w, padding="same", stride=2)                # ⚠️ RuntimeError
F.conv2d(x, w, padding=1, stride=2)                     # ✅

4. Juft yadro va same

python
nn.Conv2d(1, 8, kernel_size=4, padding=2)   # 28 -> 29   # ⚠️
nn.Conv2d(1, 8, kernel_size=3, padding=1)   # 28 -> 28   # ✅

5. scipy va torch natijasini to'g'ridan-to'g'ri taqqoslash

python
signal.convolve2d(x, k, "valid") == F.conv2d(...)       # ⚠️ yadro burilgan
signal.correlate2d(x, k, "valid") == F.conv2d(...)      # ✅

6. Shovqinli rasmga to'g'ridan-to'g'ri Sobel

python
g = F.conv2d(x, SOBEL_X, padding=1)                     # ⚠️
g = F.conv2d(F.conv2d(x, GAUSS, padding=1), SOBEL_X, padding=1)  # ✅

7. Qatlamlar orasida nochiziqlik yo'q

python
nn.Sequential(nn.Conv2d(1, 8, 3), nn.Conv2d(8, 8, 3))               # ⚠️
nn.Sequential(nn.Conv2d(1, 8, 3), nn.ReLU(), nn.Conv2d(8, 8, 3))    # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 10-qism (o'tilgan): Skalyar ko'paytma va matritsa ko'paytmasi
  • 20-qism (o'tilgan): Nochiziqlik nima uchun kerak
  • 22.1-dars (o'tilgan): (N, C, H, W) shakli
  • Keyingi dars: nn.Conv2d — ko'p kanalli va o'rgatiladigan yadrolar
  • CNN arxitekturalari mavzusida: Stride va padding bilan o'lcham boshqaruvi
  • Vaqt qatorlari va NLP qismlarida: Bir o'lchamli konvolyutsiya (Conv1d) — xuddi shu g'oya

8. Eng yaxshi amaliyotlar

  1. Har qatlamdan keyin o'lchamni formula bilan hisoblang.

  2. O'lchamni saqlash uchun toq yadro va p = (k - 1) / 2.

  3. O'lchamni kamaytirish uchun stride=2 — toq o'lchamlarga e'tibor bering.

  4. Yangi yadroni avval kichik qo'lda misolda tekshiring.

  5. scipy bilan solishtirishda correlate2d dan foydalaning.

  6. Chegara topishdan oldin xiralashtiring.

  7. Chegara piksellari muhim bo'lsa, reflect padding ni sinab ko'ring.

  8. Konvolyutsiyalar orasida doim nochiziqlik.


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

python
1.  # 5x5 kirish, 3x3 yadro, p=0, s=1 - chiqish?
2.  # 28x28, k=5, p=2, s=1 - chiqish?
3.  # 32x32, k=3, p=1, s=2 - chiqish?
4.  # 27x27, k=3, p=0, s=2 - chiqish?
5.  # o'rtacha 3x3 yadroning yig'indisi?
6.  # Sobel x qanday chegarani topadi?
7.  # yig'indisi 0 yadro tekis joyda nima beradi?
8.  # nn.Conv2d konvolyutsiyami yoki cross-correlation?
9.  # k=7 uchun "same" padding?
10. # k=3, dilation=2 samarali yadro o'lchami?
11. # nol padding bilan hammasi 1 rasmni o'rtacha 3x3 bilan - burchak qiymati?
12. # unfold (N, C, 8, 8), k=3, p=1 shakli (C=3)?
Javoblar
  1. 3×3
  2. 28×28
  3. 16×16
  4. 13×13 (floor(24 / 2) + 1)
  5. 1
  6. Vertikal (chapdan o'ngga o'zgarish)
  7. 0
  8. Cross-correlation
  9. 3
  10. 5×5
  11. 4/9 ≈ 0.444
  12. (N, 27, 64)

Vazifa 2: Xatolarni tuzating

python
1.  F.conv2d(torch.rand(28, 28), w)

2.  F.conv2d(x, w, padding="same", stride=2)

3.  nn.Conv2d(1, 8, kernel_size=4, padding=2)   # o'lcham saqlansin

4.  assert np.allclose(signal.convolve2d(x, k, "valid"), F.conv2d(xt, kt)[0, 0])

5.  nn.Sequential(nn.Conv2d(1, 8, 3), nn.Conv2d(8, 8, 3))
Javoblar
python
1.  F.conv2d(torch.rand(28, 28).view(1, 1, 28, 28), w)

2.  F.conv2d(x, w, padding=1, stride=2)

3.  nn.Conv2d(1, 8, kernel_size=3, padding=1)

4.  assert np.allclose(signal.correlate2d(x, k, "valid"), F.conv2d(xt, kt)[0, 0])

5.  nn.Sequential(nn.Conv2d(1, 8, 3), nn.ReLU(), nn.Conv2d(8, 8, 3))

Vazifa 3: Qo'lda

Modellang:

  1. Bitta oyna
  2. To'liq chiqish
  3. F.conv2d bilan tenglik
  4. float32 farqi

Vazifa 4: Yadrolar

Modellang:

  1. Yig'indi qoidasi
  2. Xiralashtirish va shovqin
  3. Sobel x va y
  4. Gauss + Sobel

Vazifa 5: O'lchamlar

Modellang:

  1. Formula jadvali
  2. Same padding
  3. Ko'rilmagan piksellar
  4. Padding turlari

Vazifa 6: Nazariya tekshiruvi

Modellang:

  1. Correlate va convolve
  2. Yadroni burish
  3. Chiziqlilik
  4. im2col

Vazifa 7: O'ylash

Hamkasbingiz so'radi: "Sobel, Gauss kabi yadrolar o'nlab yillar ishlatilgan va yaxshi ishlaydi. Nega CNN da yadrolarni tasodifiy boshlab o'rgatamiz? Yaxshi yadrolarni qo'lda qo'ysak, tezroq o'rganmaydimi?" Nima deysiz?

Javob

Qisqa javob: qo'lda qo'yilgan yadrolar faqat birinchi qatlamdagi oddiy naqshlarni qamraydi. Vazifaga kerak bo'lgan murakkab naqshlarni (ko'z, g'ildirak, o'sma chegarasi) hech kim qo'lda yoza olmaydi — ularni ma'lumotdan o'rganish kerak.

Qo'lda yadrolar nimaga yaxshi:

  • Chegara, silliqlash, gradient — umumiy, ko'p vazifada foydali
  • 2-misolda Gauss + Sobel shovqinli rasmda yolg'on chegaralarni 45 tadan 21 taga kamaytirdi — qo'lda ham ancha narsa qilish mumkin

Nega baribir o'rgatiladi:

  1. Ko'p qatlamlilik. Ikkinchi, uchinchi qatlam yadrolari birinchi qatlam chiqishlari ustida ishlaydi. "Sobel javoblarining qanday birikmasi mushuk qulog'ini bildiradi?" — bunga qo'lda javob yo'q.

  2. Vazifaga moslik. Rentgen rasmida muhim chegaralar va avtomobil suratidagi muhim chegaralar boshqa-boshqa. O'rgatish yadrolarni aynan shu vazifaga moslaydi.

  3. O'rgatilgan birinchi qatlam baribir shunga o'xshaydi. Katta to'plamlarda o'rgatilgan CNN larning birinchi qatlam yadrolari chizib ko'rilsa, ular ko'pincha chegara detektorlari va rang dog'lariga o'xshaydi — ya'ni tarmoq Sobel ga o'xshash narsani o'zi topadi.

  4. Qo'lda boshlash — kichik yutuq. Tasodifiy boshlangan birinchi qatlam bir necha davrda chegara detektorlariga aylanadi. Asosiy o'rgatish vaqti chuqur qatlamlarga ketadi.

Qachon qo'lda yadro foydali:

Holat Nima qilish
Ma'lumot juda kam Qo'lda belgilar (Sobel, histogram) + klassik model
Oldindan ishlov berish Shovqinni Gauss bilan kamaytirish
Tushuntirish kerak "Chegara zichligi" kabi tushunarli belgilar
Ko'p ma'lumot O'rgatiladigan yadrolar, yaxshisi oldindan o'rgatilgan model

Hamkasbga javob:

"Qo'lda yadrolar birinchi qatlam uchun yaxshi, lekin CNN ning kuchi chuqur qatlamlarda — u yerdagi naqshlarni qo'lda yozib bo'lmaydi. O'rgatilgan birinchi qatlam baribir chegara detektorlariga o'xshab qoladi. Ma'lumot kam bo'lsa, qo'lda yadrolardan emas, oldindan o'rgatilgan tarmoqdan boshlagan ma'qul — bu transfer learning mavzusida keladi."

Nimani mustahkamlaydi: 2.2, 2.6-bo'limlar.


Xulosa

Bu darsda konvolyutsiyani ichidan ko'rdik.

Eng muhim uch fikr:

  1. Konvolyutsiya — sirpanuvchi skalyar ko'paytma. 1-misolda qo'lda yozilgan sirpanuvchi oyna F.conv2d bilan to'rtta padding/stride kombinatsiyasida aynan teng chiqdi (float64 da farq 0), float32 da esa farq faqat 1.8e-06. 2-misolda yig'indisi 1 bo'lgan yadrolar tekis joyni o'zgartirmadi, yig'indisi 0 bo'lganlar esa tekis joyda 0 berdi. O'rtacha 3×3 yadro fon shovqinining std sini 0.174 dan 0.068 ga tushirdi, Gauss dan keyin Sobel yolg'on chegaralarni 45 tadan 21 taga kamaytirdi.

  2. Chiqish o'lchami = floor((H + 2p - k) / s) + 1. 3-misolda formula sakkizta holatning hammasida torch bilan mos keldi. floor ning narxi ham ko'rindi: H=8, k=3, p=0, s=2 da oxirgi qator va ustun (15 piksel) hech qachon ko'rilmadi, p=1 qo'yilganda esa hammasi qamrab olindi. Nol padding hammasi 1 bo'lgan rasmda burchakni 0.444 ga, chekkani 0.667 ga tushirdi; reflect, replicate va circular 1.000 ni saqladi.

  3. Torch "konvolyutsiyasi" — cross-correlation va chiziqli amal. 4-misolda F.conv2d scipy.signal.correlate2d bilan teng, convolve2d bilan esa faqat yadro 180 gradusga burilganda teng chiqdi. Gauss dan keyin Sobel bitta 5×5 yadroga teng — nochiziqliksiz qatlamlar bittaga qisqaradi. unfold + matritsa ko'paytmasi F.conv2d natijasini 3.8e-06 aniqlikda takrorladi.

Keyingi darsda nn.Conv2d qatlami: ko'p kanalli konvolyutsiya, parametrlar soni formulasi, retseptiv maydon va og'irlik baham ko'rish siljishga qanday ekvivariantlik berishi.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
22.2-dars: Konvolyutsiya — IlmHamroh