Model CNN membutuhkan gambar, dan pilihan dataset menentukan seluruh alur proyek. Dataset foto hewan nyata seperti Dogs vs. Cats di Kaggle memuat 25.000 berkas yang harus diunduh dan diproses lama di CPU — terlalu mahal untuk belajar alur kerja. Karena itu proyek ini membangkitkan dataset sendiri: 96 gambar 16x16 grayscale dari pola geometris yang berbeda per kelas, dilengkapi jitter agar tidak ada dua gambar yang identik. Pada bagian ini kita menulis generatornya, memeriksa hasilnya secara visual, dan mencatat keputusan desainnya.
Pola Geometris Tiap Kelas #
Tiga kelas dibangun dari bentuk dasar yang mudah dibedakan: kucing berupa kepala bulat dengan dua telinga segitiga, ikan berupa elips memanjang dengan ekor segitiga, dan burung berupa badan bulat dengan paruh serta ekor. Fungsi satu kelas tampak seperti ini:
def gambar_kucing(rng):
"""Kepala bulat besar + dua telinga segitiga di bagian atas."""
kanvas = np.zeros((UKURAN, UKURAN), dtype=np.float32)
dx, dy = rng.integers(-2, 3, size=2)
skala = rng.uniform(0.85, 1.15)
nilai = rng.uniform(0.75, 0.95)
lingkaran(kanvas, 8 + dx, 9.2 + dy, 4.3 * skala, nilai)
segitiga(kanvas, (4.5 + dx, 6.5 + dy), (3.5 + dx, 2.5 + dy), (7.0 + dx, 5.5 + dy), nilai)
segitiga(kanvas, (11.5 + dx, 6.5 + dy), (12.5 + dx, 2.5 + dy), (9.0 + dx, 5.5 + dy), nilai)
return kanvasTiga fungsi bentuk dasar — lingkaran, elips, dan segitiga — mengisi kanvas NumPy lewat uji keanggotaan per piksel; segitiga memakai koordinat barycentric untuk menguji apakah sebuah piksel berada di dalam segitiga. Variasi antar gambar datang dari empat sumber jitter yang ditarik dari rng:
| Jitter | Rentang | Dampak pada tugas |
|---|---|---|
Geseran dx, dy | -2 sampai +2 piksel | posisi hewan berpindah di kanvas |
| Skala | 0.85-1.15 | ukuran hewan bervariasi |
| Intensitas | 0.75-0.95 | terang bentuk bervariasi |
| Derau Gaussian | sigma 0.06 + latar 0.06 | tekstur mengganggu yang harus diabaikan |
Merakit Dataset #
Seluruh kelas dirakit dalam satu fungsi yang juga menuliskan berkas .npz:
def buat_dataset(seed=42, jumlah_per_kelas=32):
"""Kembalikan (gambar (N,16,16) float32 [0,1], label (N,) int)."""
rng = np.random.default_rng(seed)
fungsi_per_kelas = [gambar_kucing, gambar_ikan, gambar_burung]
daftar_gambar, daftar_label = [], []
for kelas, fungsi in enumerate(fungsi_per_kelas):
for _ in range(jumlah_per_kelas):
kanvas = fungsi(rng)
kanvas = kanvas + 0.06 + rng.normal(0, 0.06, size=kanvas.shape)
daftar_gambar.append(np.clip(kanvas, 0.0, 1.0).astype(np.float32))
daftar_label.append(kelas)
return np.stack(daftar_gambar), np.array(daftar_label)Argumen seed=42 pada default_rng menjamin urutan jitter yang sama setiap eksekusi — menjalankan ulang generator menimpa berkas dengan isi identik. Nilai piksel dikunci ke rentang [0, 1] lewat np.clip setelah derau ditambahkan, sehingga normalisasi di loader cukup memastikan rentang tanpa menghitung ulang statistik.
Menjalankan dan Memeriksa #
python3 data/generate_data.pyOutput yang Dihasilkan:
dataset : 96 gambar 16x16 grayscale
per kelas : {'kucing': 32, 'ikan': 32, 'burung': 32}
nilai : min 0.00 maks 1.00
tersimpan : hewan_sintetis.npz (80511 byte)
contoh kucing (gambar #0):
................
................
................
................
..#.......#.....
..##.....##.....
...##.#.##......
...#######......
...#######......
..#########.....
..#########.....
..#########.....
...#######......
...#######......
.....###........
................
contoh ikan (gambar #32):
................
................
................
................
................
...#######...#..
.#############..
.#############..
.#############..
...#######...#..
................
................
................
................
................
................
contoh burung (gambar #64):
................
................
.#..............
..#.............
...##...........
....#.##........
.....####.......
....######..##..
....######..##..
.....####.......
......##........
................
................
................
................
................Peta karakter #, +, dan . memetakan nilai piksel ke tiga tingkat sehingga bentuk terbaca langsung di terminal. Ketiga kelas tampak jelas berbeda bagi mata manusia: telinga kucing menjulang di atas kepala bulat, badan ikan memanjang horizontal dengan ekor di kanan, dan burung punya paruh kecil plus ekor di kiri atas.
Dataset tersimpan sebagai data/hewan_sintetis.npz (sekitar 78 KB) dan siap dimuat. Rincian asal-usul data serta langkah menggantinya dengan dataset nyata dari Kaggle terdokumentasi di data/README.md. Bagian berikutnya merancang CNN yang membaca gambar-gambar ini tanpa meratakan strukturnya terlebih dahulu.