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:

python data/generate_data.py — pola kelas kucing
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 kanvas

Tiga 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:

JitterRentangDampak pada tugas
Geseran dx, dy-2 sampai +2 pikselposisi hewan berpindah di kanvas
Skala0.85-1.15ukuran hewan bervariasi
Intensitas0.75-0.95terang bentuk bervariasi
Derau Gaussiansigma 0.06 + latar 0.06tekstur mengganggu yang harus diabaikan

Merakit Dataset #

Seluruh kelas dirakit dalam satu fungsi yang juga menuliskan berkas .npz:

python data/generate_data.py — perakitan dataset dengan jitter
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 #

bash
python3 data/generate_data.py

Output yang Dihasilkan:

text
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.