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:
"""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:
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 = 7x7Mari kita telaah kode di atas baris per baris:
- Baris 9-10: input
(1, 1, 7, 7)diisiarangedan kernel 3x3 berisi satu — nilai tidak berpengaruh pada ukuran, yang diuji murni dimensinya. - Baris 12-14 (
rumus_ukuran): rumus umum(W + 2P - D(K-1) - 1)/S + 1dengan pembagian bulat ke bawah; bentuk sederhana(W - F + 2P)/S + 1dari chapter sebelumnya adalah kasus khususD = 1. - Baris 16-24 (
kombinasi): enam konfigurasi(S, P, D)mencakup valid, same, stride 2, dan dilation 2-3. - Baris 29-34: setiap konfigurasi dieksekusi
F.conv2d, ukuran keluaran dibandingkan dengan rumus lewatassert— seluruh enam baris lolos, bukti rumus dan perilaku framework selaras. - Baris 37-39: ukuran kernel efektif
K + (K-1)(D-1)dihitung untukD = 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:
| stride | padding | dilation | Keluaran (input 7x7) | Efek utama |
|---|---|---|---|---|
| 1 | 0 | 1 | 5x5 | valid: tepi tergerus 2 |
| 2 | 0 | 1 | 3x3 | resolusi turun setengah |
| 1 | 1 | 1 | 7x7 | same: ukuran terjaga |
| 2 | 1 | 1 | 4x4 | setengah resolusi, tergerus sedikit |
| 1 | 0 | 2 | 3x3 | jangkauan 5x5, bobot tetap 9 |
| 1 | 0 | 3 | 1x1 | jangkauan 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
.