feat: add task 4 cnn mnist
This commit is contained in:
parent
c9f8a02573
commit
4cf0e4732a
4
.gitignore/Plaintext
Normal file
4
.gitignore/Plaintext
Normal file
@ -0,0 +1,4 @@
|
||||
venv/
|
||||
__pycache__/
|
||||
*.keras
|
||||
.vscode/
|
||||
333
README_No4_MNIST_CNN .md
Normal file
333
README_No4_MNIST_CNN .md
Normal file
@ -0,0 +1,333 @@
|
||||
# Implementasi CNN pada MNIST dan Perbandingannya dengan MLP
|
||||
|
||||
## 1. Deskripsi
|
||||
|
||||
Program ini dibuat untuk menyelesaikan **Tugas No. 4: Implementasi CNN** menggunakan dataset **MNIST** dan framework **TensorFlow/Keras**.
|
||||
|
||||
Eksperimen bertujuan untuk:
|
||||
|
||||
- Membangun model **Convolutional Neural Network (CNN)** sederhana menggunakan `Conv2D` dan `MaxPooling2D` sebelum Dense layers.
|
||||
- Membandingkan performanya dengan model **MLP terbaik** dari Tugas No. 1 (Model C — 3 hidden layer 256 → 128 → 64).
|
||||
- Mengukur besar peningkatan (improvement) akurasi yang diperoleh.
|
||||
- Menjelaskan mengapa CNN lebih efektif untuk data gambar dibandingkan MLP.
|
||||
|
||||
## 2. Dataset
|
||||
|
||||
Dataset yang digunakan sama dengan Tugas No. 1, yaitu **MNIST**, dataset gambar angka tulisan tangan 0 sampai 9.
|
||||
|
||||
Dataset dimuat menggunakan fungsi bawaan Keras:
|
||||
|
||||
``` python
|
||||
keras.datasets.mnist.load_data()
|
||||
```
|
||||
|
||||
Karakteristik dataset:
|
||||
|
||||
- 60.000 data training
|
||||
- 10.000 data testing
|
||||
- Ukuran gambar: 28 × 28 piksel
|
||||
- Jumlah kelas: 10
|
||||
- Kelas: angka 0 sampai 9
|
||||
|
||||
## 3. Preprocessing
|
||||
|
||||
Perbedaan utama preprocessing CNN dibandingkan MLP terletak pada **bentuk input**.
|
||||
|
||||
| Aspek | MLP (Tugas 1) | CNN (Tugas 4) |
|
||||
|---|---|---|
|
||||
| Bentuk input | `(N, 784)` — diratakan (flatten) | `(N, 28, 28, 1)` — tetap 2D + channel |
|
||||
| Normalisasi | 0–255 → 0–1 | 0–255 → 0–1 |
|
||||
| Struktur spasial | Hilang | Dipertahankan |
|
||||
|
||||
MLP meratakan gambar menjadi vektor 784 angka sehingga informasi posisi antar piksel hilang. CNN tetap memproses gambar dalam bentuk 2D aslinya dan hanya menambahkan dimensi channel (grayscale = 1).
|
||||
|
||||
``` python
|
||||
x_train = x_train.astype("float32") / 255.0
|
||||
x_test = x_test.astype("float32") / 255.0
|
||||
|
||||
# CNN membutuhkan dimensi channel
|
||||
x_train = x_train.reshape(-1, 28, 28, 1)
|
||||
x_test = x_test.reshape(-1, 28, 28, 1)
|
||||
```
|
||||
|
||||
## 4. Arsitektur Model CNN
|
||||
|
||||
``` text
|
||||
Input (28, 28, 1)
|
||||
↓
|
||||
Conv2D (32 filter, 3×3, ReLU) → (26, 26, 32)
|
||||
↓
|
||||
MaxPooling2D (2×2) → (13, 13, 32)
|
||||
↓
|
||||
Conv2D (64 filter, 3×3, ReLU) → (11, 11, 64)
|
||||
↓
|
||||
MaxPooling2D (2×2) → (5, 5, 64)
|
||||
↓
|
||||
Flatten → (1600)
|
||||
↓
|
||||
Dense (64, ReLU)
|
||||
↓
|
||||
Dropout (0.3)
|
||||
↓
|
||||
Output (10, Softmax)
|
||||
```
|
||||
|
||||
Kode model:
|
||||
|
||||
``` python
|
||||
model = keras.Sequential([
|
||||
layers.Input(shape=(28, 28, 1)),
|
||||
layers.Conv2D(32, (3, 3), activation="relu"),
|
||||
layers.MaxPooling2D((2, 2)),
|
||||
layers.Conv2D(64, (3, 3), activation="relu"),
|
||||
layers.MaxPooling2D((2, 2)),
|
||||
layers.Flatten(),
|
||||
layers.Dense(64, activation="relu"),
|
||||
layers.Dropout(0.3),
|
||||
layers.Dense(10, activation="softmax"),
|
||||
])
|
||||
|
||||
model.compile(
|
||||
optimizer="adam",
|
||||
loss="sparse_categorical_crossentropy",
|
||||
metrics=["accuracy"],
|
||||
)
|
||||
```
|
||||
|
||||
### Rincian Jumlah Parameter
|
||||
|
||||
| Layer | Output Shape | Parameter |
|
||||
|---|---|---|
|
||||
| Conv2D (32) | (26, 26, 32) | 320 |
|
||||
| MaxPooling2D | (13, 13, 32) | 0 |
|
||||
| Conv2D (64) | (11, 11, 64) | 18.496 |
|
||||
| MaxPooling2D | (5, 5, 64) | 0 |
|
||||
| Flatten | (1600) | 0 |
|
||||
| Dense (64) | (64) | 102.464 |
|
||||
| Dropout (0.3) | (64) | 0 |
|
||||
| Dense (10) | (10) | 650 |
|
||||
| **Total** | | **121.930** |
|
||||
|
||||
Perhatikan bahwa dua layer konvolusi hanya menggunakan **18.816 parameter** untuk seluruh ekstraksi fitur, sedangkan satu Dense layer saja sudah menghabiskan 102.464 parameter. Ini menunjukkan efisiensi *parameter sharing* pada konvolusi.
|
||||
|
||||
## 5. Konfigurasi Training
|
||||
|
||||
Konfigurasi dibuat identik dengan Tugas No. 1 agar perbandingan adil.
|
||||
|
||||
| Parameter | Nilai |
|
||||
|---|---|
|
||||
| Optimizer | Adam |
|
||||
| Loss Function | Sparse Categorical Crossentropy |
|
||||
| Epochs | 10 |
|
||||
| Batch Size | 128 |
|
||||
| Validation Split | 10% |
|
||||
| Hidden Activation | ReLU |
|
||||
| Output Activation | Softmax |
|
||||
| Regularisasi | Dropout (0.3) sebelum output layer |
|
||||
|
||||
## 6. Hasil Eksperimen
|
||||
|
||||
### 6.1 Progres Training CNN per Epoch
|
||||
|
||||
| Epoch | Train Accuracy | Validation Accuracy |
|
||||
|---|---|---|
|
||||
| 1 | 90,04% | 98,18% |
|
||||
| 2 | 96,80% | 98,50% |
|
||||
| 3 | 97,55% | 98,87% |
|
||||
| 4 | 98,07% | 98,83% |
|
||||
| 5 | 98,42% | 99,02% |
|
||||
| 6 | 98,59% | 98,80% |
|
||||
| 7 | 98,72% | 98,93% |
|
||||
| 8 | 98,93% | 99,05% |
|
||||
| 9 | 98,96% | 99,05% |
|
||||
| 10 | 99,07% | 99,02% |
|
||||
|
||||
Validation accuracy sudah melampaui 98% sejak **epoch pertama** — sesuatu yang tidak pernah dicapai MLP bahkan setelah 10 epoch.
|
||||
|
||||
### 6.2 Perbandingan CNN vs MLP
|
||||
|
||||
| Model | Arsitektur | Jumlah Parameter | Test Accuracy | Waktu Training/Epoch |
|
||||
|---|---|---|---|---|
|
||||
| Model A (MLP) | 64 | 50.890 | 97,06% | 1,22 detik |
|
||||
| Model B (MLP) | 128 → 64 | 109.386 | 97,24% | 1,29 detik |
|
||||
| **Model C (MLP terbaik)** | 256 → 128 → 64 | 242.762 | **97,64%** | 2,50 detik |
|
||||
| **Model CNN** | Conv32 → Pool → Conv64 → Pool → Dense64 | **121.930** | **99,03%** | 16,56 detik |
|
||||
|
||||
### 6.3 Besar Improvement
|
||||
|
||||
| Metrik | MLP Terbaik | CNN | Perubahan |
|
||||
|---|---|---|---|
|
||||
| Test Accuracy | 97,64% | 99,03% | **+1,39 poin persentase** |
|
||||
| Test Loss | 0,0933 | 0,0297 | **−68,2%** |
|
||||
| Error Rate | 2,36% | 0,97% | **−58,9% (relatif)** |
|
||||
| Salah klasifikasi | 236 dari 10.000 | **97 dari 10.000** | 139 gambar lebih sedikit |
|
||||
| Jumlah Parameter | 242.762 | 121.930 | **−49,8% (separuh lebih sedikit)** |
|
||||
| Waktu/Epoch | 2,50 detik | 16,56 detik | +562% (lebih lambat) |
|
||||
|
||||
**Catatan penting mengenai interpretasi improvement:**
|
||||
|
||||
Kenaikan 1,39 poin persentase terlihat kecil, tetapi cara yang lebih tepat membacanya adalah lewat **error rate**. CNN memangkas hampir **59% kesalahan** yang masih dilakukan MLP. Pada skala industri, misalnya sistem pembacaan kode pos otomatis yang memproses 1 juta surat, perbedaan ini berarti sekitar **13.900 surat lebih sedikit yang salah baca**.
|
||||
|
||||
## 7. Analisis: Mengapa CNN Lebih Efektif untuk Data Gambar?
|
||||
|
||||
### 7.1 Mempertahankan Struktur Spasial
|
||||
|
||||
MLP meratakan gambar 28 × 28 menjadi vektor 784 angka. Setelah diratakan, piksel yang secara visual bersebelahan (misalnya piksel baris 1 kolom 28 dan baris 2 kolom 1) menjadi berjauhan, sementara model tidak punya cara mengetahui bahwa keduanya sebenarnya bertetangga. Informasi geometris gambar hilang sebelum training dimulai. CNN memproses gambar dalam bentuk 2D aslinya, sehingga pola lokal seperti tepi, sudut, dan lengkungan angka tetap utuh.
|
||||
|
||||
### 7.2 Local Receptive Field dan Parameter Sharing
|
||||
|
||||
Setiap filter konvolusi berukuran 3 × 3 hanya melihat area kecil gambar, lalu **digeser ke seluruh permukaan gambar dengan bobot yang sama**. Artinya, satu filter yang belajar mendeteksi garis diagonal dapat menemukan garis diagonal di mana pun posisinya.
|
||||
|
||||
Pada MLP, setiap posisi piksel punya bobotnya sendiri-sendiri, sehingga model harus mempelajari pola yang sama berulang kali untuk setiap posisi. Inilah alasan CNN mencapai akurasi lebih tinggi meskipun jumlah parameternya **separuh lebih sedikit** dari MLP terbaik.
|
||||
|
||||
### 7.3 Hierarki Fitur Otomatis
|
||||
|
||||
CNN membangun pemahaman secara bertingkat, mirip cara kerja sistem visual manusia:
|
||||
|
||||
``` text
|
||||
Conv layer 1 → fitur sederhana: tepi, garis, gradien terang-gelap
|
||||
↓
|
||||
Conv layer 2 → kombinasi fitur: lengkungan, sudut, lingkaran kecil
|
||||
↓
|
||||
Dense layer → konsep utuh: "ini bentuk angka 8"
|
||||
```
|
||||
|
||||
MLP tidak memiliki hierarki semacam ini karena semua piksel langsung dihubungkan ke semua neuron tanpa tahapan abstraksi spasial.
|
||||
|
||||
### 7.4 Translation Invariance melalui MaxPooling
|
||||
|
||||
`MaxPooling2D` mengambil nilai maksimum dari setiap area 2 × 2, sehingga pergeseran kecil posisi angka dalam gambar tidak banyak mengubah output. Model menjadi tahan terhadap variasi penulisan, misalnya angka yang ditulis sedikit lebih ke kiri atau lebih ke kanan. Pada MLP, pergeseran satu piksel saja mengubah seluruh vektor input dan dapat mengubah hasil prediksi.
|
||||
|
||||
### 7.5 Trade-off yang Perlu Dicatat
|
||||
|
||||
CNN unggul dalam akurasi dan efisiensi parameter, tetapi **waktu training per epoch jauh lebih lama** (16,56 detik vs 2,50 detik). Operasi konvolusi secara komputasi lebih mahal dibanding perkalian matriks pada Dense layer, karena filter harus digeser ke setiap posisi gambar. Perlu diingat bahwa pengukuran ini dilakukan pada CPU; pada GPU, selisih waktu ini mengecil drastis karena konvolusi sangat mudah diparalelkan.
|
||||
|
||||
## 8. Kesimpulan
|
||||
|
||||
1. Model CNN sederhana dengan dua blok `Conv2D` + `MaxPooling2D` berhasil mencapai **test accuracy 99,03%** pada MNIST.
|
||||
2. Dibandingkan MLP terbaik dari Tugas No. 1 (97,64%), CNN memberikan improvement **+1,39 poin persentase**, atau setara dengan **pengurangan error rate sebesar 58,9%**.
|
||||
3. CNN mencapai hasil tersebut dengan **jumlah parameter hampir separuh lebih sedikit**, membuktikan bahwa keunggulannya berasal dari *inductive bias* yang sesuai dengan sifat data gambar, bukan sekadar dari kapasitas model yang lebih besar.
|
||||
4. Keunggulan CNN untuk data gambar berakar pada empat hal: preservasi struktur spasial, parameter sharing, hierarki fitur otomatis, dan translation invariance.
|
||||
5. Konsekuensinya adalah waktu training per epoch yang lebih lama, sehingga pemilihan arsitektur tetap perlu mempertimbangkan ketersediaan sumber daya komputasi.
|
||||
|
||||
## 9. Teknologi
|
||||
|
||||
- Python 3.10 – 3.12
|
||||
- TensorFlow 2.x
|
||||
- Keras
|
||||
- NumPy
|
||||
- Matplotlib (untuk plot learning curve)
|
||||
- MNIST
|
||||
- **Visual Studio Code** (editor & runtime lokal)
|
||||
|
||||
## 10. Struktur Folder
|
||||
|
||||
```text
|
||||
tugas-mnist/
|
||||
├── .venv/ # virtual environment (tidak perlu di-commit)
|
||||
├── task4_cnn.py # program utama CNN
|
||||
├── README_No4_MNIST_CNN.md # dokumentasi ini
|
||||
└── requirements.txt
|
||||
```
|
||||
|
||||
Isi `requirements.txt`:
|
||||
|
||||
```text
|
||||
tensorflow>=2.16
|
||||
numpy
|
||||
matplotlib
|
||||
```
|
||||
|
||||
## 11. Cara Menjalankan di VS Code
|
||||
|
||||
### 11.1 Persiapan Awal (sekali saja)
|
||||
|
||||
**1. Install ekstensi yang dibutuhkan**
|
||||
|
||||
Buka panel Extensions di VS Code (`Ctrl+Shift+X`), lalu install:
|
||||
|
||||
- **Python** (Microsoft)
|
||||
- **Pylance** (Microsoft)
|
||||
- **Jupyter** (opsional, jika ingin menjalankan per-cell)
|
||||
|
||||
**2. Buka folder proyek**
|
||||
|
||||
`File → Open Folder…` lalu pilih folder `tugas-mnist`.
|
||||
|
||||
**3. Buat virtual environment**
|
||||
|
||||
Buka terminal terintegrasi dengan `` Ctrl+` `` lalu jalankan:
|
||||
|
||||
```bash
|
||||
# Windows
|
||||
python -m venv .venv
|
||||
.venv\Scripts\activate
|
||||
|
||||
# macOS / Linux
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
```
|
||||
|
||||
**4. Pilih interpreter di VS Code**
|
||||
|
||||
Tekan `Ctrl+Shift+P` → ketik **Python: Select Interpreter** → pilih interpreter yang berada di dalam folder `.venv`. Langkah ini penting agar VS Code menjalankan kode memakai environment yang benar, bukan Python sistem.
|
||||
|
||||
**5. Install dependensi**
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
Catatan: jika pemasangan TensorFlow terasa berat atau tidak memiliki GPU, gunakan versi CPU yang ukurannya lebih ringan:
|
||||
|
||||
```bash
|
||||
pip install tensorflow-cpu numpy matplotlib
|
||||
```
|
||||
|
||||
### 11.2 Menjalankan Program
|
||||
|
||||
Ada tiga cara, pilih salah satu:
|
||||
|
||||
| Cara | Langkah |
|
||||
|---|---|
|
||||
| Tombol Run | Buka `task4_cnn.py`, klik tombol **▶ Run Python File** di kanan atas |
|
||||
| Terminal | Jalankan `python task4_cnn.py` |
|
||||
| Debug | Tekan `F5`, pilih konfigurasi **Python File** |
|
||||
|
||||
### 11.3 Hal yang Perlu Diperhatikan
|
||||
|
||||
**Dataset akan diunduh otomatis pada eksekusi pertama.** `keras.datasets.mnist.load_data()` mengunduh berkas `mnist.npz` (± 11 MB) dan menyimpannya di:
|
||||
|
||||
```text
|
||||
Windows : C:\Users\<nama-user>\.keras\datasets\
|
||||
macOS/Linux : ~/.keras/datasets/
|
||||
```
|
||||
|
||||
Eksekusi berikutnya akan memakai cache tersebut, jadi tidak perlu koneksi internet lagi. Pastikan koneksi aktif saat menjalankan pertama kali.
|
||||
|
||||
**Waktu training di CPU.** Model CNN membutuhkan sekitar **15–20 detik per epoch** di CPU, sehingga total training 10 epoch memakan waktu sekitar **3 menit**. Ini wajar; jangan dikira program macet. Gunakan `verbose=2` agar progres tercetak rapi per epoch di terminal VS Code.
|
||||
|
||||
**Peringatan oneDNN/CUDA di awal output.** TensorFlow biasanya mencetak pesan seperti `Could not find cuda drivers` atau `oneDNN custom operations are on`. Pesan ini **normal dan bukan error** — artinya TensorFlow berjalan memakai CPU. Program tetap berjalan dengan benar. Jika ingin menyembunyikannya, tambahkan di baris paling atas program, sebelum `import tensorflow`:
|
||||
|
||||
```python
|
||||
import os
|
||||
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
|
||||
```
|
||||
|
||||
**Plot Matplotlib.** Saat dijalankan sebagai file `.py`, jendela plot akan terbuka terpisah dan program berhenti sampai jendela ditutup. Agar plot langsung tersimpan sebagai gambar tanpa mengganggu alur program, gunakan `plt.savefig("nama.png")` alih-alih `plt.show()`.
|
||||
|
||||
### 11.4 Langkah Pengerjaan Tugas
|
||||
|
||||
1. Jalankan program hingga selesai 10 epoch.
|
||||
2. Catat **test accuracy**, **jumlah parameter** (dari `model.summary()`), dan **waktu training per epoch**.
|
||||
3. Bandingkan hasilnya dengan tabel hasil MLP dari Tugas No. 1.
|
||||
4. Hitung improvement, baik dalam poin persentase maupun pengurangan error rate.
|
||||
5. Isi tabel pada bagian **Hasil Eksperimen** dengan angka aktual yang Anda peroleh.
|
||||
|
||||
Nilai akurasi yang Anda dapatkan mungkin berbeda tipis dari dokumen ini (biasanya di kisaran 98,9% – 99,2%) karena inisialisasi bobot bersifat acak. Untuk hasil yang dapat direproduksi, atur seed di awal program:
|
||||
|
||||
```python
|
||||
import numpy as np, tensorflow as tf
|
||||
tf.random.set_seed(42)
|
||||
np.random.seed(42)
|
||||
```
|
||||
BIN
hasil_cnn.png
Normal file
BIN
hasil_cnn.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 56 KiB |
3
requirements.txt
Normal file
3
requirements.txt
Normal file
@ -0,0 +1,3 @@
|
||||
tensorflow>=2.16
|
||||
numpy
|
||||
matplotlib
|
||||
184
task4_cnn.py
Normal file
184
task4_cnn.py
Normal file
@ -0,0 +1,184 @@
|
||||
"""
|
||||
Tugas No. 4 - Implementasi CNN sederhana untuk MNIST
|
||||
dan perbandingannya dengan MLP dari Tugas No. 1.
|
||||
|
||||
Cara menjalankan di VS Code:
|
||||
1. Aktifkan virtual environment
|
||||
2. pip install tensorflow numpy matplotlib
|
||||
3. Klik tombol Run, atau jalankan: python task4_cnn.py
|
||||
|
||||
Dataset akan diunduh otomatis saat pertama kali dijalankan
|
||||
dan disimpan di ~/.keras/datasets/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
# Sembunyikan log informasi TensorFlow (harus sebelum import tensorflow)
|
||||
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
|
||||
|
||||
import time
|
||||
|
||||
import matplotlib
|
||||
matplotlib.use("Agg") # simpan plot sebagai file, tidak membuka jendela
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import tensorflow as tf
|
||||
import keras
|
||||
from keras import layers
|
||||
|
||||
#Konfigurasi
|
||||
SEED = 42
|
||||
EPOCHS = 10
|
||||
BATCH_SIZE = 128
|
||||
VAL_SPLIT = 0.1
|
||||
|
||||
tf.random.set_seed(SEED)
|
||||
np.random.seed(SEED)
|
||||
|
||||
# Hasil MLP terbaik dari Tugas No. 1 (Model C: 256-128-64).
|
||||
# Ganti angka di bawah ini dengan hasil eksperimen Anda sendiri.
|
||||
MLP_ACCURACY = 0.9764
|
||||
MLP_PARAMS = 242_762
|
||||
MLP_EPOCH_TIME = 2.50
|
||||
|
||||
#1. Load dan preprocessing data
|
||||
print("Memuat dataset MNIST...")
|
||||
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
|
||||
|
||||
print(f"Data training : {x_train.shape[0]:,} gambar")
|
||||
print(f"Data testing : {x_test.shape[0]:,} gambar")
|
||||
print(f"Ukuran gambar : {x_train.shape[1]} x {x_train.shape[2]} piksel\n")
|
||||
|
||||
# ormalisasi nilai piksel dari 0-255 menjadi 0-1
|
||||
x_train = x_train.astype("float32") / 255.0
|
||||
x_test = x_test.astype("float32") / 255.0
|
||||
|
||||
#CNN membutuhkan dimensi channel: (N, 28, 28) -> (N, 28, 28, 1)
|
||||
#Berbeda dengan MLP yang meratakan gambar menjadi (N, 784)
|
||||
x_train = x_train.reshape(-1, 28, 28, 1)
|
||||
x_test = x_test.reshape(-1, 28, 28, 1)
|
||||
|
||||
#2. Bangun model CNN
|
||||
|
||||
model = keras.Sequential(
|
||||
name="cnn_mnist",
|
||||
layers=[
|
||||
layers.Input(shape=(28, 28, 1)),
|
||||
|
||||
# Blok konvolusi 1: deteksi fitur sederhana (tepi, garis)
|
||||
layers.Conv2D(32, (3, 3), activation="relu"),
|
||||
layers.MaxPooling2D((2, 2)),
|
||||
|
||||
# Blok konvolusi 2: gabungkan menjadi fitur lebih kompleks
|
||||
layers.Conv2D(64, (3, 3), activation="relu"),
|
||||
layers.MaxPooling2D((2, 2)),
|
||||
|
||||
# Klasifikasi
|
||||
layers.Flatten(),
|
||||
layers.Dense(64, activation="relu"),
|
||||
layers.Dropout(0.3),
|
||||
layers.Dense(10, activation="softmax"),
|
||||
],
|
||||
)
|
||||
|
||||
model.compile(
|
||||
optimizer="adam",
|
||||
loss="sparse_categorical_crossentropy",
|
||||
metrics=["accuracy"],
|
||||
)
|
||||
|
||||
model.summary()
|
||||
|
||||
# 3. Training dengan pencatatan waktu per epoch
|
||||
epoch_times = []
|
||||
|
||||
class TimeCallback(keras.callbacks.Callback):
|
||||
"""Mencatat durasi setiap epoch."""
|
||||
|
||||
def on_epoch_begin(self, epoch, logs=None):
|
||||
self._start = time.time()
|
||||
|
||||
def on_epoch_end(self, epoch, logs=None):
|
||||
epoch_times.append(time.time() - self._start)
|
||||
|
||||
|
||||
print("\nMemulai training CNN...")
|
||||
print("Perkiraan waktu: 15-20 detik per epoch di CPU (total sekitar 3 menit).\n")
|
||||
|
||||
history = model.fit(
|
||||
x_train,
|
||||
y_train,
|
||||
validation_split=VAL_SPLIT,
|
||||
epochs=EPOCHS,
|
||||
batch_size=BATCH_SIZE,
|
||||
verbose=2,
|
||||
callbacks=[TimeCallback()],
|
||||
)
|
||||
# 4. Evaluasi
|
||||
test_loss, test_acc = model.evaluate(x_test, y_test, verbose=0)
|
||||
n_params = model.count_params()
|
||||
avg_epoch_time = float(np.mean(epoch_times))
|
||||
|
||||
predictions = np.argmax(model.predict(x_test, verbose=0), axis=1)
|
||||
n_wrong = int(np.sum(predictions != y_test))
|
||||
|
||||
# 5. Perbandingan CNN vs MLP
|
||||
error_mlp = (1 - MLP_ACCURACY) * 100
|
||||
error_cnn = (1 - test_acc) * 100
|
||||
gain_point = (test_acc - MLP_ACCURACY) * 100
|
||||
error_reduction = (1 - error_cnn / error_mlp) * 100
|
||||
|
||||
print("\n" + "=" * 62)
|
||||
print("HASIL EKSPERIMEN CNN")
|
||||
print("=" * 62)
|
||||
print(f"Test accuracy : {test_acc * 100:.2f}%")
|
||||
print(f"Test loss : {test_loss:.4f}")
|
||||
print(f"Jumlah parameter : {n_params:,}")
|
||||
print(f"Waktu training/epoch : {avg_epoch_time:.2f} detik")
|
||||
print(f"Salah klasifikasi : {n_wrong} dari {len(y_test):,} gambar")
|
||||
|
||||
print("\n" + "=" * 62)
|
||||
print("PERBANDINGAN CNN vs MLP")
|
||||
print("=" * 62)
|
||||
print(f"{'Metrik':<24}{'MLP':>14}{'CNN':>14}")
|
||||
print("-" * 62)
|
||||
print(f"{'Test accuracy':<24}{MLP_ACCURACY * 100:>13.2f}%{test_acc * 100:>13.2f}%")
|
||||
print(f"{'Error rate':<24}{error_mlp:>13.2f}%{error_cnn:>13.2f}%")
|
||||
print(f"{'Jumlah parameter':<24}{MLP_PARAMS:>14,}{n_params:>14,}")
|
||||
print(f"{'Waktu/epoch (detik)':<24}{MLP_EPOCH_TIME:>14.2f}{avg_epoch_time:>14.2f}")
|
||||
print("-" * 62)
|
||||
print(f"Improvement akurasi : +{gain_point:.2f} poin persentase")
|
||||
print(f"Pengurangan error rate : {error_reduction:.1f}% (relatif)")
|
||||
print(f"Selisih parameter : {n_params - MLP_PARAMS:+,}")
|
||||
print("=" * 62)
|
||||
|
||||
# 6. Simpan grafik
|
||||
fig, axes = plt.subplots(1, 2, figsize=(12, 4.5))
|
||||
|
||||
epochs_range = range(1, EPOCHS + 1)
|
||||
axes[0].plot(epochs_range, history.history["accuracy"], label="Train accuracy")
|
||||
axes[0].plot(epochs_range, history.history["val_accuracy"], label="Validation accuracy")
|
||||
axes[0].set_title("Learning Curve CNN")
|
||||
axes[0].set_xlabel("Epoch")
|
||||
axes[0].set_ylabel("Accuracy")
|
||||
axes[0].legend()
|
||||
axes[0].grid(alpha=0.3)
|
||||
|
||||
axes[1].bar(
|
||||
["MLP terbaik", "CNN"],
|
||||
[MLP_ACCURACY * 100, test_acc * 100],
|
||||
color=["#55A868", "#C44E52"],
|
||||
)
|
||||
axes[1].set_ylim(96, 100)
|
||||
axes[1].set_ylabel("Test Accuracy (%)")
|
||||
axes[1].set_title("Perbandingan MLP vs CNN")
|
||||
for i, value in enumerate([MLP_ACCURACY * 100, test_acc * 100]):
|
||||
axes[1].text(i, value + 0.05, f"{value:.2f}%", ha="center")
|
||||
|
||||
plt.tight_layout()
|
||||
plt.savefig("hasil_cnn.png", dpi=130)
|
||||
print("\nGrafik disimpan sebagai: hasil_cnn.png")
|
||||
|
||||
# Simpan model terlatih agar tidak perlu training ulang
|
||||
model.save("model_cnn_mnist.keras")
|
||||
print("Model disimpan sebagai: model_cnn_mnist.keras")
|
||||
Loading…
x
Reference in New Issue
Block a user