refactor: re-structure folder

This commit is contained in:
matthewflrnt 2026-09-21 09:04:44 +07:00
parent 7492704c8e
commit 5ac0a227c4
26 changed files with 911 additions and 944 deletions

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
# Python
__pycache__/
*.py[cod]
.venv/
venv/
# Environments & IDEs
.env
.vscode/
.idea/
.ipynb_checkpoints/
# OS
.DS_Store
Thumbs.db

View File

@ -1,4 +0,0 @@
venv/
__pycache__/
*.keras
.vscode/

View File

@ -1,3 +0,0 @@
{
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/Scripts/python.exe"
}

111
README.md Normal file
View File

@ -0,0 +1,111 @@
# Praktikum Deep Learning - Kelompok 3
Repository ini berisi implementasi tugas dan eksperimen Deep Learning, mencakup perbandingan arsitektur Multi-Layer Perceptron (MLP), teknik regularisasi (Batch Normalization & Dropout), studi kasus pemilihan model (*Model Selection*), serta implementasi Convolutional Neural Network (CNN) pada dataset MNIST.
---
## 📁 Struktur Folder Proyek
Struktur direktori telah dirapikan secara modular sebagai berikut:
```text
kelompok3-deeplearning/
├── .gitignore # Konfigurasi file & folder yang diabaikan git
├── requirements.txt # Daftar pustaka / dependensi Python
├── README.md # Dokumentasi utama proyek
├── docs/ # Dokumentasi dan analisis tambahan
│ └── model_selection.md # Analisis justifikasi pemilihan model (Tugas 3)
├── src/ # Modul reusable / fungsi pembantu
│ ├── __init__.py
│ ├── data_loader.py # Loader & preprocessor dataset MNIST (MLP & CNN)
│ ├── models.py # Definisi arsitektur model (MLP, Regularized MLP, CNN)
│ └── utils.py # Callback timer, manajemen folder, plotting helper
├── experiments/ # Skrip eksperimen & tugas utama
│ ├── 01_mlp_comparison.py # Tugas 1: Perbandingan 3 arsitektur MLP
│ ├── 02_regularization.py # Tugas 2: Eksperimen Regularisasi BatchNorm + Dropout
│ ├── 03_model_selection.py # Tugas 3: Implementasi contoh arsitektur model
│ └── 04_cnn_mnist.py # Tugas 4: Implementasi CNN MNIST & perbandingan vs MLP
└── results/ # Output dari eksperimen
├── figures/ # Plot visualisasi (akurasi, loss curve, bar chart)
│ ├── hasil_cnn.png
│ └── loss_regularization.png
└── models/ # Bobot model terlatih (.keras)
├── model_cnn_mnist.keras
└── model_c_regularized.keras
```
---
## 🚀 Panduan Instalasi & Menjalankan
### 1. Buat dan Aktifkan Virtual Environment
```bash
# Linux / macOS
python3 -m venv .venv
source .venv/bin/activate
# Windows (Command Prompt / PowerShell)
python -m venv .venv
.venv\Scripts\activate
```
### 2. Install Dependensi
```bash
pip install -r requirements.txt
```
### 3. Menjalankan Eksperimen
Semua skrip eksperimen berada di dalam folder `experiments/`:
- **Eksperimen 1: Perbandingan Arsitektur MLP**
```bash
python experiments/01_mlp_comparison.py
```
- **Eksperimen 2: Regularisasi (BatchNorm + Dropout)**
```bash
python experiments/02_regularization.py
```
- **Eksperimen 3: Contoh Model Selection (LSTM, CNN, NLP, XGBoost)**
```bash
python experiments/03_model_selection.py
```
- **Eksperimen 4: CNN MNIST vs MLP**
```bash
python experiments/04_cnn_mnist.py
```
---
## 📊 Ringkasan Hasil Eksperimen
### 1. Perbandingan Arsitektur MLP (Tugas 1)
- **Model A (1 Hidden Layer - 64)**: ~97.06% Akurasi, 50,890 Parameter
- **Model B (2 Hidden Layers - 128 → 64)**: ~97.24% Akurasi, 109,386 Parameter
- **Model C (3 Hidden Layers - 256 → 128 → 64)**: ~97.64% Akurasi, 242,762 Parameter
### 2. Regularisasi pada Model C (Tugas 2)
- Penambahan **Batch Normalization** dan **Dropout (0.3)** terbukti menstabilkan proses training dan menekan *generalization gap* / overfitting pada kurva validasi.
### 3. Keunggulan CNN vs MLP pada MNIST (Tugas 4)
| Metrik | MLP Terbaik (Model C) | CNN Sederhana | Perubahan |
| :--- | :--- | :--- | :--- |
| **Test Accuracy** | 97.64% | **99.03%** | **+1.39%** |
| **Error Rate** | 2.36% | **0.97%** | **-58.9% (relatif)** |
| **Jumlah Parameter** | 242,762 | **121,930** | **-49.8% (lebih efisien)** |
| **Salah Klasifikasi** | 236 / 10,000 | **97 / 10,000** | **139 gambar lebih sedikit** |
---
## 🛠️ Teknologi & Framework
- Python 3.10+
- TensorFlow / Keras
- NumPy & Pandas
- Matplotlib & Seaborn
- XGBoost & Scikit-Learn

136
docs/PRESENTATION.md Normal file
View File

@ -0,0 +1,136 @@
# 📊 Presentasi Praktikum Deep Learning
**Kelompok 3**
---
## 1. INTRODUKSI
### 📌 Latar Belakang
Praktikum ini bertujuan untuk mengeksplorasi berbagai arsitektur jaringan saraf tiruan (Neural Network) dan teknik pelatihan, mulai dari Multi-Layer Perceptron (MLP), mitigasi overfitting melalui regularisasi, analisis pemilihan model (*Model Selection*), hingga Convolutional Neural Network (CNN) pada dataset MNIST dan domain data lainnya.
### 📦 Dataset Utama: MNIST Handwritten Digits
* **Ukuran Dataset:** 60.000 citra training & 10.000 citra testing.
* **Format Data:** Citra grayscale berukuran $28 \times 28$ piksel.
* **Jumlah Kelas:** 10 kelas target (digit angka 0 sampai 9).
* **Preprocessing:**
* Normalisasi nilai piksel dari $[0, 255]$ menjadi rentang $[0.0, 1.0]$.
* Penyesuaian bentuk data (vektor 784 untuk MLP, tensor $28 \times 28 \times 1$ untuk CNN).
---
## 2. PENJELASAN TUGAS 1: Eksperimen Arsitektur & Kedalaman MLP
### 🎯 Tujuan
Menguji pengaruh kedalaman layer dan jumlah neuron terhadap akurasi model serta waktu pelatihan pada dataset MNIST.
### 🏗️ Konfigurasi 3 Model MLP
* **Model A (1 Hidden Layer):** Input (784) $\rightarrow$ `Dense(64, ReLU)` $\rightarrow$ `Dense(10, Softmax)`
* **Model B (2 Hidden Layer):** Input (784) $\rightarrow$ `Dense(128, ReLU)` $\rightarrow$ `Dense(64, ReLU)` $\rightarrow$ `Dense(10, Softmax)`
* **Model C (3 Hidden Layer):** Input (784) $\rightarrow$ `Dense(256, ReLU)` $\rightarrow$ `Dense(128, ReLU)` $\rightarrow$ `Dense(64, ReLU)` $\rightarrow$ `Dense(10, Softmax)`
### 📈 Hasil Eksperimen
| Model | Arsitektur Hidden Layer | Jumlah Parameter | Test Accuracy | Waktu Training / Epoch |
| :--- | :--- | :---: | :---: | :---: |
| **Model A** | `[64]` | 50.890 | 97,06% | 1,22 detik |
| **Model B** | `[128, 64]` | 109.386 | 97,24% | 1,29 detik |
| **Model C (Terbaik)** | `[256, 128, 64]` | 242.762 | **97,64%** | 2,50 detik |
### 💡 Kesimpulan Tugas 1
* **Model C** menghasilkan akurasi tertinggi (**97,64%**) karena mampu mempelajari representasi fitur yang lebih kompleks.
* Semakin dalam layer, jumlah parameter dan waktu komputasi per epoch meningkat secara signifikan.
---
## 3. PENJELASAN TUGAS 2: Eksperimen Regularisasi pada Deep MLP
### 🎯 Tujuan
Mengatasi permasalahan *overfitting* yang muncul pada Model C saat dilatih dalam durasi yang lebih panjang (20 epoch).
### 🔍 Permasalahan pada Baseline (Tanpa Regularisasi)
* *Training loss* terus menurun mendekati 0, namun *validation loss* mulai naik dan berfluktuasi setelah epoch ke-7.
* Terjadi pelebaran *generalization gap* (model menghafal data training, bukan mempelajari pola umum).
### 🛡️ Solusi: Penerapan Batch Normalization & Dropout
* **Batch Normalization:** Menormalkan input di setiap layer, menstabilkan distribusi gradien, dan mempercepat konvergensi.
* **Dropout (rate = 0.3):** Mematikan 30% koneksi neuron secara acak selama training untuk mencegah *co-adaptation*.
```text
Arsitektur Regularized:
Input (784) ──> Dense(256) ──> BatchNorm ──> ReLU ──> Dropout(0.3)
──> Dense(128) ──> BatchNorm ──> ReLU ──> Dropout(0.3)
──> Dense(64) ──> BatchNorm ──> ReLU ──> Dropout(0.3)
──> Dense(10, Softmax)
```
### 💡 Kesimpulan Tugas 2
* Penambahan BatchNorm dan Dropout berhasil menjaga kurva *validation loss* tetap stabil dan sejajar dengan *training loss*.
* Daya generalisasi model meningkat dan risiko overfitting berhasil ditekan secara efektif.
---
## 4. PENJELASAN TUGAS 3: Analisis & Justifikasi Pemilihan Model (*Model Selection*)
### 🎯 Tujuan
Menentukan dan menjustifikasi arsitektur model yang paling optimal berdasarkan karakteristik data input dan kebutuhan komputasi.
### 📋 Hasil Pemilihan Model untuk 4 Skenario:
#### (a) Prediksi Stok Barang dari 12 Bulan Historis Penjualan
* **Tipe Data:** Deret Waktu (*Time-Series*).
* **Arsitektur Terpilih:** **LSTM (Long Short-Term Memory)** *(Alternatif: XGBoost / SARIMA)*.
* **Justifikasi:** Data memiliki dependensi urutan waktu dan tren musiman. LSTM mampu mempertahankan memori jangka panjang melalui *cell state* dan mekanisme *gates* tanpa terkena *vanishing gradient*.
#### (b) Klasifikasi Foto Produk Rusak vs Normal di Lini Produksi
* **Tipe Data:** Citra 2D (*Computer Vision*).
* **Arsitektur Terpilih:** **CNN (Convolutional Neural Network)**.
* **Justifikasi:** Pola kerusakan (goresan/retakan) terikat pada korelasi spasial piksel. CNN mengekstrak hierarki fitur visual secara bertingkat dan memiliki sifat *translation invariance* (tahan pergeseran).
#### (c) Analisis Sentimen Review Google Play Store
* **Tipe Data:** Teks Bebas Bahasa Alami (*NLP / Sequential Text*).
* **Arsitektur Terpilih:** **LSTM dengan Word Embedding** *(Alternatif: Transformer / IndoBERT)*.
* **Justifikasi:** Ulasan teks adalah sekuens kata di mana arti kalimat sangat bergantung pada urutan. Embedding memetakan makna semantik kata, dan LSTM memahami konteks kalimat dari awal hingga akhir.
#### (d) Prediksi Churn Pelanggan dari 15 Kolom Tabular
* **Tipe Data:** Tabular Terstruktur (*Structured Tabular Data*).
* **Arsitektur Terpilih:** **ML Klasik (XGBoost / LightGBM)**.
* **Justifikasi:** Pada data tabular dimensi kecil (15 fitur), model *gradient boosted trees* secara konsisten mengungguli deep learning dalam performa generalisasi, kecepatan latih, dan interpretasi fitur (*feature importance*).
---
## 5. PENJELASAN TUGAS 4: Implementasi CNN pada MNIST vs MLP
### 🎯 Tujuan
Membangun model CNN 2D sederhana dan membandingkan performanya secara kuantitatif dengan model MLP terbaik dari Tugas 1 (Model C).
### 🏗️ Arsitektur Model CNN
```text
Input (28, 28, 1)
↓
Conv2D (32 filter, 3×3, ReLU) ──> Output: (26, 26, 32)
MaxPooling2D (2×2) ──> Output: (13, 13, 32)
↓
Conv2D (64 filter, 3×3, ReLU) ──> Output: (11, 11, 64)
MaxPooling2D (2×2) ──> Output: (5, 5, 64)
↓
Flatten ──> Output: 1600
Dense (64, ReLU) + Dropout (0.3)
↓
Dense (10, Softmax) ──> Output: Probabilitas 10 Kelas
```
### 📊 Tabel Perbandingan Kuantitatif: CNN vs MLP Terbaik
| Metrik Evaluasi | MLP Terbaik (Model C) | Model CNN Sederhana | Analisis / Improvement |
| :--- | :---: | :---: | :--- |
| **Test Accuracy** | 97,64% | **99,03%** | **+1,39 poin persentase** |
| **Test Loss** | 0,0933 | **0,0297** | **Turun signifikan (-68,2%)** |
| **Error Rate** | 2,36% | **0,97%** | **Pengurangan error 58,9% (relatif)** |
| **Salah Klasifikasi** | 236 dari 10.000 | **97 dari 10.000** | **139 gambar lebih sedikit salah** |
| **Jumlah Parameter** | 242.762 | **121.930** | **Hemat 49,8% parameter (separuh bobot)** |
| **Waktu / Epoch (CPU)** | **2,50 detik** | 16,56 detik | Konvolusi membutuhkan komputasi lebih di CPU |
### 💡 Mengapa CNN Lebih Unggul untuk Data Citra?
1. **Preservasi Struktur Spasial:** Memproses citra dalam format 2D asli sehingga korelasi antarpiksel tetangga tetap terjaga (tidak hilang seperti pada *flattening* MLP).
2. **Parameter Sharing:** Filter konvolusi yang sama digeser ke seluruh permukaan citra untuk mendeteksi pola yang sama di berbagai posisi.
3. **Hierarki Fitur Otomatis:** Layer awal mengekstrak garis tepi/sudut, sedangkan layer lanjutan menggabungkannya menjadi bentuk kurva dan pola angka utuh.
4. **Translation Invariance:** Fitur `MaxPooling2D` membuat prediksi model tetap konsisten meskipun posisi tulisan tangan sedikit bergeser.

32
docs/model_selection.md Normal file
View File

@ -0,0 +1,32 @@
# Analisis Pemilihan Model (Model Selection)
## (a) Prediksi stok barang dari 12 bulan historis penjualan
**Arsitektur:** LSTM (atau ML Klasik seperti XGBoost / SARIMA sebagai alternatif kuat).
**Justifikasi:** Data penjualan historis merupakan deret waktu (time-series) yang memiliki dependensi temporal, tren, dan pola musiman antar-bulan. LSTM dirancang khusus untuk memproses data sekuensial dengan mempertahankan informasi masa lalu melalui mekanisme cell state dan gates, sehingga mampu menangkap dinamika tren penjualan tanpa kehilangan memori jangka panjang.
---
## (b) Klasifikasi foto produk rusak vs normal di lini produksi
**Arsitektur:** CNN (Convolutional Neural Network).
**Justifikasi:** Data citra memerlukan ekstraksi pola visual lokal seperti goresan, retakan, atau perbedaan warna yang terikat pada korelasi spasial antarpiksel. Operasi konvolusi pada CNN mampu mengekstraksi hierarki fitur visual (dari garis tepi hingga tekstur utuh) serta memiliki sifat translation invariance, sehingga cacat produk tetap terdeteksi meskipun posisinya bergeser.
---
## (c) Analisis sentimen review Google Play Store
**Arsitektur:** LSTM (atau variannya seperti Bi-LSTM / model berbasis Transformer).
**Justifikasi:** Ulasan teks adalah data sekuensial linguistik di mana arti suatu kalimat sangat bergantung pada urutan dan konteks kata di sekitarnya. LSTM secara efektif menangani panjang kalimat yang bervariasi dan mampu mempertahankan konteks makna dari awal hingga akhir ulasan untuk menentukan polaritas sentimen positif atau negatif secara akurat.
---
## (d) Prediksi churn pelanggan dari 15 kolom tabular
**Arsitektur:** ML Klasik (seperti XGBoost, LightGBM, atau Random Forest).
**Justifikasi:** Pada data tabular berdimensi kecil (15 fitur), model gradient boosted decision trees secara konsisten mengungguli deep learning dalam hal performa generalisasi, kecepatan latih, dan interpretasi fitur (feature importance). Jaringan saraf seperti ANN cenderung membutuhkan volume sampel yang jauh lebih besar dan rentan overfitting pada batas keputusan data tabular yang tidak terstruktur secara spasial.
3. **Gunakan Model ML Klasik Berbasis Pohon (XGBoost / LightGBM)** saat bekerja dengan data tabular berstruktur tetap karena akurasi lebih unggul, waktu latih cepat, dan memiliki interpretabilitas fitur yang tinggi.

View File

@ -0,0 +1,99 @@
import sys
import os
import time
# Tambahkan root directory ke path agar dapat import dari src
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from src.data_loader import load_mnist_for_mlp
from src.models import create_mlp_model
def main():
print("=" * 60)
print("TUGAS 1: MEMUAT DATASET MNIST & EKSPERIMEN MLP")
print("=" * 60)
# 1. Load Data
(x_train, y_train), (x_test, y_test) = load_mnist_for_mlp()
print(f"Data training : {x_train.shape}")
print(f"Data testing : {x_test.shape}")
# 2. Konfigurasi 3 Model MLP
models_config = {
"Model A - 1 Hidden Layer": [64],
"Model B - 2 Hidden Layer": [128, 64],
"Model C - 3 Hidden Layer": [256, 128, 64]
}
results = []
EPOCHS = 10
BATCH_SIZE = 128
# 3. Training & Evaluasi
for model_name, architecture in models_config.items():
print("\n" + "=" * 60)
print(model_name)
print("=" * 60)
model = create_mlp_model(architecture)
model.summary()
print("\nMemulai training...")
start_time = time.time()
model.fit(
x_train,
y_train,
epochs=EPOCHS,
batch_size=BATCH_SIZE,
validation_split=0.1,
verbose=1
)
total_time = time.time() - start_time
average_time = total_time / EPOCHS
test_loss, test_accuracy = model.evaluate(x_test, y_test, verbose=0)
total_parameters = model.count_params()
results.append({
"model": model_name,
"parameters": total_parameters,
"accuracy": test_accuracy * 100,
"time_per_epoch": average_time
})
print("\nHasil:")
print(f"Test Accuracy : {test_accuracy * 100:.2f}%")
print(f"Jumlah Parameter : {total_parameters:,}")
print(f"Waktu/Epoch : {average_time:.2f} detik")
# 4. Ringkasan Perbandingan
print("\n\n" + "=" * 80)
print("HASIL PERBANDINGAN 3 MODEL MLP")
print("=" * 80)
print(f"{'Model':<30}{'Parameter':>15}{'Accuracy':>15}{'Time/Epoch':>15}")
print("-" * 80)
for res in results:
print(
f"{res['model']:<30}"
f"{res['parameters']:>15,}"
f"{res['accuracy']:>14.2f}%"
f"{res['time_per_epoch']:>14.2f}s"
)
best_model = max(results, key=lambda x: x["accuracy"])
print("\n" + "=" * 60)
print("MODEL DENGAN TEST ACCURACY TERTINGGI")
print("=" * 60)
print(f"Model : {best_model['model']}")
print(f"Test Accuracy : {best_model['accuracy']:.2f}%")
print(f"Jumlah Parameter : {best_model['parameters']:,}")
print(f"Waktu Training/Epoch: {best_model['time_per_epoch']:.2f} detik")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,93 @@
import sys
import os
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
# Tambahkan root directory ke path agar dapat import dari src
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from src.data_loader import load_mnist_for_mlp
from src.models import create_mlp_model, create_regularized_mlp_model
from src.utils import ensure_dir
def main():
print("=" * 60)
print("TUGAS 2: EKSPERIMEN REGULARISASI (BASELINE vs BATCHNORM + DROPOUT)")
print("=" * 60)
# 1. Load Data
(x_train, y_train), (x_test, y_test) = load_mnist_for_mlp()
EPOCHS = 20
BATCH_SIZE = 128
# 2. Baseline Model (Without Regularization)
print("\n" + "=" * 60)
print("TRAINING BASELINE MODEL (WITHOUT REGULARIZATION)")
print("=" * 60)
model_base = create_mlp_model([256, 128, 64])
history_base = model_base.fit(
x_train, y_train,
epochs=EPOCHS,
batch_size=BATCH_SIZE,
validation_split=0.1,
verbose=1
)
# 3. Regularized Model (BatchNorm + Dropout 0.3)
print("\n" + "=" * 60)
print("TRAINING REGULARIZED MODEL (WITH BATCHNORM + DROPOUT)")
print("=" * 60)
model_reg = create_regularized_mlp_model(hidden_layers=[256, 128, 64], dropout_rate=0.3)
history_reg = model_reg.fit(
x_train, y_train,
epochs=EPOCHS,
batch_size=BATCH_SIZE,
validation_split=0.1,
verbose=1
)
# 4. Save Model Artifact
results_model_dir = os.path.join("results", "models")
ensure_dir(results_model_dir)
model_reg_path = os.path.join(results_model_dir, "model_c_regularized.keras")
model_reg.save(model_reg_path)
print(f"\n[INFO] Model teregularisasi disimpan di: {model_reg_path}")
# 5. Plot Comparison Curves
results_fig_dir = os.path.join("results", "figures")
ensure_dir(results_fig_dir)
fig_path = os.path.join(results_fig_dir, "loss_regularization.png")
plt.figure(figsize=(14, 5))
# Subplot 1: Baseline
plt.subplot(1, 2, 1)
plt.plot(history_base.history['loss'], label='Training Loss', color='blue')
plt.plot(history_base.history['val_loss'], label='Validation Loss', color='orange', linestyle='--')
plt.title('Model C Without Regularization')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.grid(True, alpha=0.3)
# Subplot 2: Regularized
plt.subplot(1, 2, 2)
plt.plot(history_reg.history['loss'], label='Training Loss', color='blue')
plt.plot(history_reg.history['val_loss'], label='Validation Loss', color='green', linestyle='--')
plt.title('Model C With BatchNorm + Dropout(0.3)')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig(fig_path, dpi=130)
print(f"[INFO] Grafik perbandingan loss disimpan di: {fig_path}")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,67 @@
"""
Tugas 3: Contoh Implementasi Berbagai Arsitektur Model Sesuai Karakteristik Data
"""
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.layers import Conv2D, Dense, Embedding, Flatten, LSTM, MaxPooling2D
from tensorflow.keras.models import Sequential
from xgboost import XGBClassifier
def build_models():
print("=" * 60)
print("TUGAS 3: CONTOH ARSITEKTUR MODEL SELECTION")
print("=" * 60)
# (a) Prediksi Stok Barang dari Deret Waktu (LSTM)
# Input shape: (samples, time_steps=12, features=1)
model_a = Sequential([
LSTM(32, input_shape=(12, 1)),
Dense(1)
], name="LSTM_Stock_Forecasting")
model_a.compile(optimizer='adam', loss='mse')
print("\n[Case A] Model LSTM untuk Prediksi Stok Barang (Time Series):")
model_a.summary()
# (b) Klasifikasi Foto Produk Rusak vs Normal (CNN)
# Input shape contoh citra RGB 128x128
model_b = Sequential([
Conv2D(32, (3, 3), activation='relu', input_shape=(128, 128, 3)),
MaxPooling2D((2, 2)),
Flatten(),
Dense(64, activation='relu'),
Dense(1, activation='sigmoid') # binary: rusak vs normal
], name="CNN_Defect_Classification")
model_b.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
print("\n[Case B] Model CNN untuk Klasifikasi Foto Produk (Computer Vision):")
model_b.summary()
# (c) Analisis Sentimen Ulasan Play Store (LSTM + Embedding)
vocab_size = 5000
max_length = 100
model_c = Sequential([
Embedding(input_dim=vocab_size, output_dim=64, input_length=max_length),
LSTM(64),
Dense(32, activation='relu'),
Dense(1, activation='sigmoid') # binary: positif vs negatif
], name="LSTM_Sentiment_Analysis")
model_c.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
print("\n[Case C] Model LSTM + Embedding untuk Analisis Sentimen (NLP):")
model_c.summary()
# (d) Prediksi Churn Pelanggan Tabular (ML Klasik - XGBoost)
# X_train memiliki dimensi (n_samples, 15)
model_d = XGBClassifier(
n_estimators=100,
max_depth=4,
learning_rate=0.1,
random_state=42
)
print("\n[Case D] Model XGBoost untuk Prediksi Churn (Tabular 15 fitur):")
print(model_d)
if __name__ == "__main__":
build_models()

148
experiments/04_cnn_mnist.py Normal file
View File

@ -0,0 +1,148 @@
"""
Tugas No. 4 - Implementasi CNN sederhana untuk MNIST
dan perbandingannya dengan MLP dari Tugas No. 1.
"""
import os
import sys
import time
# Sembunyikan log informasi TensorFlow
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
import matplotlib
matplotlib.use("Agg") # simpan plot sebagai file
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
# Tambahkan root directory ke path agar dapat import dari src
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from src.data_loader import load_mnist_for_cnn
from src.models import create_cnn_mnist_model
from src.utils import EpochTimerCallback, ensure_dir
def main():
# 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)
MLP_ACCURACY = 0.9764
MLP_PARAMS = 242_762
MLP_EPOCH_TIME = 2.50
# 1. Load dan preprocessing data
print("Memuat dataset MNIST untuk CNN...")
(x_train, y_train), (x_test, y_test) = load_mnist_for_cnn()
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 (channel={x_train.shape[3]})\n")
# 2. Bangun model CNN
model = create_cnn_mnist_model()
model.summary()
# 3. Training dengan pencatatan waktu per epoch
timer_cb = EpochTimerCallback()
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=[timer_cb],
)
# 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(timer_cb.epoch_times)) if timer_cb.epoch_times else 0.0
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 ke folder results/figures
results_fig_dir = os.path.join("results", "figures")
ensure_dir(results_fig_dir)
fig_path = os.path.join(results_fig_dir, "hasil_cnn.png")
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(fig_path, dpi=130)
print(f"\n[INFO] Grafik disimpan di: {fig_path}")
# 7. Simpan model terlatih ke folder results/models
results_model_dir = os.path.join("results", "models")
ensure_dir(results_model_dir)
model_path = os.path.join(results_model_dir, "model_cnn_mnist.keras")
model.save(model_path)
print(f"[INFO] Model disimpan di: {model_path}")
if __name__ == "__main__":
main()

13
requirements.txt Normal file
View File

@ -0,0 +1,13 @@
# Core Deep Learning & Machine Learning Frameworks
tensorflow>=2.16.0
keras>=3.0.0
xgboost>=2.0.0
scikit-learn>=1.3.0
# Scientific Computing & Data Manipulation
numpy>=1.24.0
pandas>=2.0.0
# Data Visualization
matplotlib>=3.7.0
seaborn>=0.12.0

View File

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

View File

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 87 KiB

4
src/__init__.py Normal file
View File

@ -0,0 +1,4 @@
"""
Helper utilities and modules for Deep Learning experiments.
"""

46
src/data_loader.py Normal file
View File

@ -0,0 +1,46 @@
import numpy as np
from tensorflow import keras
from typing import Tuple
def load_mnist_for_mlp() -> Tuple[Tuple[np.ndarray, np.ndarray], Tuple[np.ndarray, np.ndarray]]:
"""
Memuat dataset MNIST dan melakukan normalisasi serta perataan (flatten)
menjadi 784 fitur untuk arsitektur MLP.
Returns:
(x_train, y_train), (x_test, y_test)
"""
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
# Normalisasi nilai pixel dari 0-255 menjadi 0.0-1.0
x_train = x_train.astype("float32") / 255.0
x_test = x_test.astype("float32") / 255.0
# Flatten 28x28 menjadi 784
x_train = x_train.reshape(-1, 784)
x_test = x_test.reshape(-1, 784)
return (x_train, y_train), (x_test, y_test)
def load_mnist_for_cnn() -> Tuple[Tuple[np.ndarray, np.ndarray], Tuple[np.ndarray, np.ndarray]]:
"""
Memuat dataset MNIST dan melakukan normalisasi serta penambahan dimensi channel
(28, 28, 1) untuk arsitektur CNN.
Returns:
(x_train, y_train), (x_test, y_test)
"""
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
# Normalisasi nilai pixel dari 0-255 menjadi 0.0-1.0
x_train = x_train.astype("float32") / 255.0
x_test = x_test.astype("float32") / 255.0
# Reshape ke format (N, 28, 28, 1)
x_train = x_train.reshape(-1, 28, 28, 1)
x_test = x_test.reshape(-1, 28, 28, 1)
return (x_train, y_train), (x_test, y_test)

82
src/models.py Normal file
View File

@ -0,0 +1,82 @@
from typing import List
from tensorflow import keras
from tensorflow.keras import layers
def create_mlp_model(hidden_layers: List[int], input_dim: int = 784, num_classes: int = 10) -> keras.Model:
"""
Membangun model MLP sederhana sesuai daftar neuron per hidden layer.
"""
model = keras.Sequential(name="mlp_model")
model.add(layers.Input(shape=(input_dim,)))
for neurons in hidden_layers:
model.add(layers.Dense(neurons, activation="relu"))
model.add(layers.Dense(num_classes, activation="softmax"))
model.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"]
)
return model
def create_regularized_mlp_model(
hidden_layers: List[int] = [256, 128, 64],
dropout_rate: float = 0.3,
input_dim: int = 784,
num_classes: int = 10
) -> keras.Model:
"""
Membangun model MLP dengan Batch Normalization dan Dropout.
"""
model = keras.Sequential(name="mlp_regularized")
model.add(layers.Input(shape=(input_dim,)))
for neurons in hidden_layers:
model.add(layers.Dense(neurons))
model.add(layers.BatchNormalization())
model.add(layers.Activation("relu"))
model.add(layers.Dropout(dropout_rate))
model.add(layers.Dense(num_classes, activation="softmax"))
model.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"]
)
return model
def create_cnn_mnist_model(input_shape: tuple = (28, 28, 1), num_classes: int = 10) -> keras.Model:
"""
Membangun model Convolutional Neural Network (CNN) untuk MNIST.
"""
model = keras.Sequential(
name="cnn_mnist",
layers=[
layers.Input(shape=input_shape),
# Block 1
layers.Conv2D(32, (3, 3), activation="relu"),
layers.MaxPooling2D((2, 2)),
# Block 2
layers.Conv2D(64, (3, 3), activation="relu"),
layers.MaxPooling2D((2, 2)),
# Classifier
layers.Flatten(),
layers.Dense(64, activation="relu"),
layers.Dropout(0.3),
layers.Dense(num_classes, activation="softmax"),
]
)
model.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"]
)
return model

65
src/utils.py Normal file
View File

@ -0,0 +1,65 @@
import os
import time
from typing import Dict, List
import matplotlib.pyplot as plt
from tensorflow import keras
class EpochTimerCallback(keras.callbacks.Callback):
"""
Keras callback untuk mencatat durasi waktu setiap epoch.
"""
def __init__(self):
super().__init__()
self.epoch_times: List[float] = []
self._start: float = 0.0
def on_epoch_begin(self, epoch, logs=None):
self._start = time.time()
def on_epoch_end(self, epoch, logs=None):
self.epoch_times.append(time.time() - self._start)
def ensure_dir(dir_path: str):
"""Membuat direktori jika belum ada."""
os.makedirs(dir_path, exist_ok=True)
def plot_training_history(
history,
title: str = "Training History",
save_path: str = None
):
"""
Membuat plot loss dan akurasi dari training history Keras.
"""
fig, axes = plt.subplots(1, 2, figsize=(12, 4.5))
# Loss plot
axes[0].plot(history.history.get("loss", []), label="Train Loss")
if "val_loss" in history.history:
axes[0].plot(history.history["val_loss"], label="Val Loss", linestyle="--")
axes[0].set_title(f"{title} - Loss")
axes[0].set_xlabel("Epoch")
axes[0].set_ylabel("Loss")
axes[0].legend()
axes[0].grid(True, alpha=0.3)
# Accuracy plot
axes[1].plot(history.history.get("accuracy", []), label="Train Accuracy")
if "val_accuracy" in history.history:
axes[1].plot(history.history["val_accuracy"], label="Val Accuracy", linestyle="--")
axes[1].set_title(f"{title} - Accuracy")
axes[1].set_xlabel("Epoch")
axes[1].set_ylabel("Accuracy")
axes[1].legend()
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
if save_path:
ensure_dir(os.path.dirname(save_path))
plt.savefig(save_path, dpi=130)
print(f"[INFO] Plot disimpan di: {save_path}")
plt.close()

View File

@ -1,123 +0,0 @@
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import matplotlib.pyplot as plt
# 1. LOAD & PREPROCESS MNIST DATASET
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train = x_train.astype("float32") / 255.0
x_test = x_test.astype("float32") / 255.0
x_train = x_train.reshape(-1, 784)
x_test = x_test.reshape(-1, 784)
# Model C Architecture from Task 1
BEST_ARCHITECTURE = [256, 128, 64]
EPOCHS = 20 # 20 epochs gives enough room to observe overfitting
BATCH_SIZE = 128
# ============================================================
# MODEL 1: WITHOUT REGULARIZATION (Baseline Model C from Task 1)
# ============================================================
model_base = keras.Sequential([
layers.Input(shape=(784,)),
layers.Dense(256, activation="relu"),
layers.Dense(128, activation="relu"),
layers.Dense(64, activation="relu"),
layers.Dense(10, activation="softmax")
])
model_base.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"]
)
print("=" * 60)
print("TRAINING BASELINE MODEL (WITHOUT REGULARIZATION)")
print("=" * 60)
history_base = model_base.fit(
x_train, y_train,
epochs=EPOCHS,
batch_size=BATCH_SIZE,
validation_split=0.1,
verbose=1
)
# ============================================================
# MODEL 2: WITH REGULARIZATION (Batch Normalization + Dropout 0.3)
# ============================================================
model_reg = keras.Sequential([
layers.Input(shape=(784,)),
layers.Dense(256),
layers.BatchNormalization(),
layers.Activation("relu"),
layers.Dropout(0.3),
layers.Dense(128),
layers.BatchNormalization(),
layers.Activation("relu"),
layers.Dropout(0.3),
layers.Dense(64),
layers.BatchNormalization(),
layers.Activation("relu"),
layers.Dropout(0.3),
layers.Dense(10, activation="softmax")
])
model_reg.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"]
)
print("\n" + "=" * 60)
print("TRAINING REGULARIZED MODEL (WITH BATCHNORM + DROPOUT)")
print("=" * 60)
history_reg = model_reg.fit(
x_train, y_train,
epochs=EPOCHS,
batch_size=BATCH_SIZE,
validation_split=0.1,
verbose=1
)
# Optional: Save the trained regularized model to disk
model_reg.save("model_c_regularized.keras")
print("\n[INFO] Regularized model saved as 'model_c_regularized.keras' in your project directory.")
# ============================================================
# PLOTTING LOSS CURVES FOR COMPARISON
# ============================================================
plt.figure(figsize=(14, 5))
# Plot 1: Baseline (Without Regularization)
plt.subplot(1, 2, 1)
plt.plot(history_base.history['loss'], label='Training Loss', color='blue')
plt.plot(history_base.history['val_loss'], label='Validation Loss', color='orange', linestyle='--')
plt.title('Model C Without Regularization')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.grid(True)
# Plot 2: Regularized (With BatchNorm + Dropout)
plt.subplot(1, 2, 2)
plt.plot(history_reg.history['loss'], label='Training Loss', color='blue')
plt.plot(history_reg.history['val_loss'], label='Validation Loss', color='green', linestyle='--')
plt.title('Model C With BatchNorm + Dropout(0.3)')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()

View File

@ -1,224 +0,0 @@
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import time
# ============================================================
# 1. LOAD DATASET MNIST
# ============================================================
print("=" * 60)
print("MEMUAT DATASET MNIST")
print("=" * 60)
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
print(f"Data training : {x_train.shape}")
print(f"Data testing : {x_test.shape}")
# ============================================================
# 2. PREPROCESSING
# ============================================================
# Normalisasi nilai pixel dari 0-255 menjadi 0-1
x_train = x_train.astype("float32") / 255.0
x_test = x_test.astype("float32") / 255.0
# Mengubah gambar 28x28 menjadi 784 fitur
x_train = x_train.reshape(-1, 784)
x_test = x_test.reshape(-1, 784)
print(f"Training setelah preprocessing: {x_train.shape}")
print(f"Testing setelah preprocessing : {x_test.shape}")
# ============================================================
# 3. FUNGSI MEMBUAT MODEL
# ============================================================
def create_model(hidden_layers):
model = keras.Sequential()
# Input layer
model.add(layers.Input(shape=(784,)))
# Hidden layers
for neurons in hidden_layers:
model.add(
layers.Dense(
neurons,
activation="relu"
)
)
# Output layer
model.add(
layers.Dense(
10,
activation="softmax"
)
)
model.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"]
)
return model
# ============================================================
# 4. KONFIGURASI 3 MODEL
# ============================================================
models_config = {
"Model A - 1 Hidden Layer": [64],
"Model B - 2 Hidden Layer": [128, 64],
"Model C - 3 Hidden Layer": [256, 128, 64]
}
# ============================================================
# 5. TRAINING DAN EVALUASI
# ============================================================
results = []
EPOCHS = 10
BATCH_SIZE = 128
for model_name, architecture in models_config.items():
print("\n")
print("=" * 60)
print(model_name)
print("=" * 60)
# Membuat model
model = create_model(architecture)
# Menampilkan arsitektur
model.summary()
# Training
print("\nMemulai training...")
start_time = time.time()
history = model.fit(
x_train,
y_train,
epochs=EPOCHS,
batch_size=BATCH_SIZE,
validation_split=0.1,
verbose=1
)
end_time = time.time()
# Total waktu training
total_time = end_time - start_time
# Rata-rata waktu per epoch
average_time = total_time / EPOCHS
# Evaluasi menggunakan test data
test_loss, test_accuracy = model.evaluate(
x_test,
y_test,
verbose=0
)
# Jumlah parameter
total_parameters = model.count_params()
# Menyimpan hasil
results.append({
"model": model_name,
"parameters": total_parameters,
"accuracy": test_accuracy * 100,
"time_per_epoch": average_time
})
print("\nHasil:")
print(f"Test Accuracy : {test_accuracy * 100:.2f}%")
print(f"Jumlah Parameter : {total_parameters:,}")
print(f"Waktu/Epoch : {average_time:.2f} detik")
# ============================================================
# 6. HASIL PERBANDINGAN
# ============================================================
print("\n\n")
print("=" * 80)
print("HASIL PERBANDINGAN 3 MODEL MLP")
print("=" * 80)
print(
f"{'Model':<30}"
f"{'Parameter':>15}"
f"{'Accuracy':>15}"
f"{'Time/Epoch':>15}"
)
print("-" * 80)
for result in results:
print(
f"{result['model']:<30}"
f"{result['parameters']:>15,}"
f"{result['accuracy']:>14.2f}%"
f"{result['time_per_epoch']:>14.2f}s"
)
# ============================================================
# 7. MENENTUKAN MODEL DENGAN ACCURACY TERTINGGI
# ============================================================
best_model = max(
results,
key=lambda x: x["accuracy"]
)
print("\n")
print("=" * 60)
print("MODEL DENGAN TEST ACCURACY TERTINGGI")
print("=" * 60)
print(f"Model : {best_model['model']}")
print(f"Test Accuracy : {best_model['accuracy']:.2f}%")
print(f"Jumlah Parameter : {best_model['parameters']:,}")
print(f"Waktu Training/Epoch: {best_model['time_per_epoch']:.2f} detik")
# ============================================================
# 8. KESIMPULAN SINGKAT
# ============================================================
print("\n")
print("=" * 60)
print("KESIMPULAN")
print("=" * 60)
print(
"Model yang lebih dalam memiliki jumlah parameter "
"yang lebih banyak dan umumnya membutuhkan waktu "
"training yang lebih besar."
)
print(
"Namun, model yang lebih dalam tidak selalu menghasilkan "
"peningkatan test accuracy yang signifikan."
)
print(
"Pemilihan arsitektur sebaiknya mempertimbangkan "
"accuracy, jumlah parameter, dan waktu training."
)

View File

@ -1,23 +0,0 @@
(a) Prediksi stok barang dari 12 bulan historis penjualan
Arsitektur: LSTM (atau ML Klasik seperti XGBoost / SARIMA sebagai alternatif kuat).
Justifikasi: Data penjualan historis merupakan deret waktu (time-series) yang memiliki dependensi temporal, tren, dan pola musiman antar-bulan. LSTM dirancang khusus untuk memproses data sekuensial dengan mempertahankan informasi masa lalu melalui mekanisme cell state dan gates, sehingga mampu menangkap dinamika tren penjualan tanpa kehilangan memori jangka panjang.
(b) Klasifikasi foto produk rusak vs normal di lini produksi
Arsitektur: CNN (Convolutional Neural Network).
Justifikasi: Data citra memerlukan ekstraksi pola visual lokal seperti goresan, retakan, atau perbedaan warna yang terikat pada korelasi spasial antarpiksel. Operasi konvolusi pada CNN mampu mengekstraksi hierarki fitur visual (dari garis tepi hingga tekstur utuh) serta memiliki sifat translation invariance, sehingga cacat produk tetap terdeteksi meskipun posisinya bergeser.
(c) Analisis sentimen review Google Play Store
Arsitektur: LSTM (atau variannya seperti Bi-LSTM / model berbasis Transformer).
Justifikasi: Ulasan teks adalah data sekuensial linguistik di mana arti suatu kalimat sangat bergantung pada urutan dan konteks kata di sekitarnya. LSTM secara efektif menangani panjang kalimat yang bervariasi dan mampu mempertahankan konteks makna dari awal hingga akhir ulasan untuk menentukan polaritas sentimen positif atau negatif secara akurat.
(d) Prediksi churn pelanggan dari 15 kolom tabular
Arsitektur: ML Klasik (seperti XGBoost, LightGBM, atau Random Forest).
Justifikasi: Pada data tabular berdimensi kecil (15 fitur), model gradient boosted decision trees secara konsisten mengungguli deep learning dalam hal performa generalisasi, kecepatan latih, dan interpretasi fitur (feature importance). Jaringan saraf seperti ANN cenderung membutuhkan volume sampel yang jauh lebih besar dan rentan overfitting pada batas keputusan data tabular yang tidak terstruktur secara spasial.

View File

@ -1,47 +0,0 @@
import numpy as np
import tensorflow as tf
from tensorflow import keras
from keras.layers import Conv2D, Dense, Embedding, Flatten, LSTM, MaxPooling2D
from keras.models import Sequential
from xgboost import XGBClassifier
# (a) Prediksi Stok Barang (LSTM)
# Input shape: (samples, time_steps=12, features=1)
model_a = Sequential([
LSTM(32, input_shape=(12, 1)),
Dense(1)
])
model_a.compile(optimizer='adam', loss='mse')
# (b) Klasifikasi Foto Produk Rusak vs Normal (CNN)
# Input shape contoh citra RGB 128x128
model_b = Sequential([
Conv2D(32, (3, 3), activation='relu', input_shape=(128, 128, 3)),
MaxPooling2D((2, 2)),
Flatten(),
Dense(64, activation='relu'),
Dense(1, activation='sigmoid') # binary: rusak vs normal
])
model_b.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
# (c) Analisis Sentimen Ulasan Play Store (LSTM + Embedding)
vocab_size = 5000
max_length = 100
model_c = Sequential([
Embedding(input_dim=vocab_size, output_dim=64, input_length=max_length),
LSTM(64),
Dense(32, activation='relu'),
Dense(1, activation='sigmoid') # binary: positif vs negatif
])
model_c.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
# (d) Prediksi Churn Pelanggan Tabular (ML Klasik - XGBoost)
# X_train memiliki dimensi (n_samples, 15)
model_d = XGBClassifier(
n_estimators=100,
max_depth=4,
learning_rate=0.1,
random_state=42
)
# model_d.fit(X_train, y_train)

View File

@ -1,333 +0,0 @@
# 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)
```

View File

@ -1,3 +0,0 @@
tensorflow>=2.16
numpy
matplotlib

View File

@ -1,184 +0,0 @@
"""
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")