Konvolusi dasar dari chapter sebelumnya menggeser jendela satu piksel per langkah dan berhenti saat jendela menabrak tepi gambar. Tiga parameter opsional melonggarkan aturan tersebut: stride mengatur seberapa jauh jendela melompat, padding menambahkan baris nol di pinggir input, dan dilation merenggangkan posisi bobot di dalam kernel. Ketiganya menentukan ukuran feature map yang dihasilkan — dan kesalahan menghitung ukuran adalah salah satu sumber bug paling sering pada kode CNN. Pada chapter ini kita menguji keenam kombinasi parameter pada input yang sama dan mencocokkan setiap hasilnya dengan rumus.

Stride: Jendela Melompat #

Stride S membuat jendela bergeser S piksel sekali, bukan satu. Stride 2 pada input 7x7 dengan kernel 3x3 hanya memuat tiga posisi menempel per sumbu, sehingga keluaran turun dari 5x5 menjadi 3x3 — resolusi setengahnya. Stride besar dipakai sebagai downsampling murah: menggantikan sebagian tugas pooling dengan lompatan jendela, sekaligus menghemat komputasi karena jumlah posisi yang dihitung berkurang.

Padding: Valid versus Same #

Tanpa padding (valid), setiap langkah convolution menggerus tepi: kernel 3x3 memangkas 2 piksel dari tiap sisi. Same padding menambahkan P baris dan kolom nol mengelilingi input agar keluaran berukuran sama dengan masukan — untuk kernel 3x3 stride 1 cukup P = 1. Angka nol pada padding juga netral bagi banyak kernel: jendela yang menabrak tepi tidak serta-merta menghasilkan respons palsu. Perhatikan bahwa pada stride 2 hasil “same” tidak lagi persis sama ukurannya — pembulatan ke bawah pada rumus membuat keluaran 4x4 dari input 7x7, seperti terlihat pada eksperimen di bawah.

Dilation: Jendela Renggang #

Dilation D menyisipkan celah D-1 piksel antar bobot kernel, sehingga kernel 3x3 dengan dilation 2 mengamati area 5x5 dan dilation 3 mengamati area 7x7 — tanpa satu pun bobot tambahan. Jangkauan (receptive field) meningkat tajam sambil biaya komputasi tetap 9 perkalian per posisi. Teknik ini dipopulerkan arsitektur DeepLab untuk segmentasi semantik karena konteks luas dibutuhkan tanpa parameter yang menumpuk.

Eksperimen: Satu Input, Enam Kombinasi #

Berkas stride_padding_dilation.py menjalankan input 7x7 yang sama melalui enam kombinasi parameter, mencetak ukuran keluaran nyata dari F.conv2d, dan memverifikasi setiap angkanya terhadap rumus:

python
"""Efek stride, padding, dan dilation terhadap ukuran keluaran konvolusi."""

import torch
import torch.nn.functional as F

torch.manual_seed(42)

# Input yang sama untuk semua kombinasi: 1 batch, 1 channel, 7x7
x = torch.arange(1, 50, dtype=torch.float32).reshape(1, 1, 7, 7)
kernel = torch.ones(1, 1, 3, 3)

def rumus_ukuran(W_in, K, P, S, D):
    """Rumus ukuran keluaran konvolusi: (W + 2P - D(K-1) - 1)/S + 1, dibulatkan ke bawah."""
    return (W_in + 2 * P - D * (K - 1) - 1) // S + 1

kombinasi = [
    # (stride, padding, dilation, keterangan)
    (1, 0, 1, "valid: jendela menempel pinggir"),
    (2, 0, 1, "stride 2: jendela melompat 2 piksel"),
    (1, 1, 1, "same: padding 1 menjaga ukuran 7x7"),
    (2, 1, 1, "stride 2 + same padding"),
    (1, 0, 2, "dilation 2: jendela renggang 5x5 efektif"),
    (1, 0, 3, "dilation 3: jendela renggang 7x7 efektif"),
]

print("input: (1, 1, 7, 7), kernel 3x3")
print()
print(f"{'stride':>6} {'pad':>4} {'dil':>4} {'output':>16} {'rumus':>28}")
for S, P, D, ket in kombinasi:
    out = F.conv2d(x, kernel, stride=S, padding=P, dilation=D)
    ukuran_rumus = rumus_ukuran(7, 3, P, S, D)
    assert out.shape[-1] == ukuran_rumus, "rumus tidak cocok"
    bagian = f"(7 + {2*P} - {D}*2 - 1)//{S} + 1 = {ukuran_rumus}"
    print(f"{S:>6} {P:>4} {D:>4} {str(tuple(out.shape)):>16} {bagian:>28}")

print()
for D in (1, 2, 3):
    efektif = 3 + (3 - 1) * (D - 1)
    print(f"dilation {D}: ukuran kernel efektif = {efektif}x{efektif}")

Output yang Dihasilkan:

text
input: (1, 1, 7, 7), kernel 3x3

stride  pad  dil           output                        rumus
     1    0    1     (1, 1, 5, 5) (7 + 0 - 1*2 - 1)//1 + 1 = 5
     2    0    1     (1, 1, 3, 3) (7 + 0 - 1*2 - 1)//2 + 1 = 3
     1    1    1     (1, 1, 7, 7) (7 + 2 - 1*2 - 1)//1 + 1 = 7
     2    1    1     (1, 1, 4, 4) (7 + 2 - 1*2 - 1)//2 + 1 = 4
     1    0    2     (1, 1, 3, 3) (7 + 0 - 2*2 - 1)//1 + 1 = 3
     1    0    3     (1, 1, 1, 1) (7 + 0 - 3*2 - 1)//1 + 1 = 1

dilation 1: ukuran kernel efektif = 3x3
dilation 2: ukuran kernel efektif = 5x5
dilation 3: ukuran kernel efektif = 7x7

Mari kita telaah kode di atas baris per baris:

  1. Baris 9-10: input (1, 1, 7, 7) diisi arange dan kernel 3x3 berisi satu — nilai tidak berpengaruh pada ukuran, yang diuji murni dimensinya.
  2. Baris 12-14 (rumus_ukuran): rumus umum (W + 2P - D(K-1) - 1)/S + 1 dengan pembagian bulat ke bawah; bentuk sederhana (W - F + 2P)/S + 1 dari chapter sebelumnya adalah kasus khusus D = 1.
  3. Baris 16-24 (kombinasi): enam konfigurasi (S, P, D) mencakup valid, same, stride 2, dan dilation 2-3.
  4. Baris 29-34: setiap konfigurasi dieksekusi F.conv2d, ukuran keluaran dibandingkan dengan rumus lewat assert — seluruh enam baris lolos, bukti rumus dan perilaku framework selaras.
  5. Baris 37-39: ukuran kernel efektif K + (K-1)(D-1) dihitung untuk D = 1, 2, 3 — 3x3, 5x5, 7x7 — menjelaskan mengapa dilation 3 pada input 7x7 hanya menghasilkan keluaran 1x1.

Rangkuman hasil aktual di atas dalam satu tabel:

stridepaddingdilationKeluaran (input 7x7)Efek utama
1015x5valid: tepi tergerus 2
2013x3resolusi turun setengah
1117x7same: ukuran terjaga
2114x4setengah resolusi, tergerus sedikit
1023x3jangkauan 5x5, bobot tetap 9
1031x1jangkauan 7x7 menyapu seluruh input

Ketiga knob ini mengatur di mana jendela berjalan, tetapi downsampling paling klasik pada CNN justru dilakukan layer terpisah yang tidak punya parameter sama sekali — MaxPool2d dan kawan-kawannya dibedah pada chapter Pooling Layer . Daftar lengkap argumen stride, padding, dan dilation terdokumentasi resmi di docs.pytorch.org/docs/stable/generated/torch.nn.Conv2d.html .