Compare commits

..
12 Commits
41 changed files with 547 additions and 129 deletions
+18 -3
View File
@@ -1,11 +1,25 @@
# Python
# Python & Bytecode
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
dist/
*.egg-info/
# Environments & Virtual Environments
.venv/
venv/
# Environments & IDEs
ENV/
env/
.env
# uv & Version Pinning
uv.lock
.python-version
# IDEs & Notebooks
.vscode/
.idea/
.ipynb_checkpoints/
@@ -13,3 +27,4 @@ venv/
# OS
.DS_Store
Thumbs.db
+60 -73
View File
@@ -1,111 +1,98 @@
# 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.
Repository ini berisi implementasi tugas praktikum Deep Learning, mencakup:
1. **Multi-Layer Perceptron (MLP)**: Eksperimen kedalaman layer & regularisasi (*Batch Normalization* & *Dropout*) pada dataset MNIST.
2. **Model Selection**: Studi kasus pemilihan arsitektur model sesuai karakteristik data (Time Series, Computer Vision, NLP, dan Tabular).
3. **Convolutional Neural Network (CNN)**: Pipeline klasifikasi citra MNIST, eksplorasi kedalaman arsitektur (2 blok vs 3 blok), serta analisis performa mendalam.
4. **Natural Language Processing (NLP)**: Klasifikasi sentimen ulasan produk Tokopedia menggunakan arsitektur *Embedding* dan *GlobalAveragePooling1D*.
---
## 📁 Struktur Folder Proyek
Struktur direktori telah dirapikan secara modular sebagai berikut:
## 📁 Struktur Direktori
```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
├── requirements.txt # Dependensi Python proyek
├── README.md # Panduan utama proyek
├── docs/ # Laporan & materi presentasi
│ ├── laporan_akhir.md # Laporan akhir praktikum lengkap
│ ├── PRESENTATION.md # Panduan materi slide presentasi
│ ├── model_selection.md # Analisis justifikasi pemilihan model
│ └── analisis_evaluasi_model_sentimen_gap.md # Analisis model NLP Tokopedia
├── src/ # Modul bersama (data loader, arsitektur, utils)
│ ├── data_loader.py # Data loader & preprocessor MNIST
│ ├── models.py # Fungsi pembangun arsitektur model
│ └── utils.py # Timer callback & helper visualisasi
├── tasks/ # Skrip tugas yang siap dieksekusi per topik
│ ├── mlp/ # Topik 1: Multi-Layer Perceptron
│ │ ├── 01_mlp_comparison.py # Perbandingan 3 arsitektur MLP (1, 2, 3 hidden layer)
│ │ ├── 02_regularization.py # Uji regularisasi BatchNorm + Dropout pada MLP
│ │ └── 03_model_selection.py # Implementasi contoh arsitektur model selection
│ ├── cnn/ # Topik 2: Convolutional Neural Network
│ │ ├── 04_cnn_mnist.py # Baseline CNN MNIST & perbandingan awal vs MLP
│ │ ├── 05_cnn_full_pipeline.py # Training pipeline CNN lengkap & confusion matrix
│ │ ├── 06_cnn_deeper.py # Eksplorasi kedalaman arsitektur CNN (2 blok vs 3 blok)
│ │ └── 07_cnn_evaluation.py # Evaluasi mendalam (metrik per kelas, confidence, error analysis)
│ └── nlp_sentiment/ # Topik 3: NLP Analisis Sentimen
│ └── 08_sentimen_gap.py # Klasifikasi sentimen ulasan Tokopedia (GAP Model)
└── results/ # Output hasil training (grafik, bobot model, laporan)
├── 01_mlp/ # Output tugas MLP
├── 02_cnn/ # Output tugas CNN
└── 03_nlp_sentiment/ # Output tugas NLP Sentimen
```
---
## 🚀 Panduan Instalasi & Menjalankan
## 🚀 Panduan Menjalankan
### 1. Buat dan Aktifkan Virtual Environment
### 1. Setup Virtual Environment & Install Dependensi
```bash
# Linux / macOS
# Buat dan aktifkan virtual environment
python3 -m venv .venv
source .venv/bin/activate
# Windows (Command Prompt / PowerShell)
python -m venv .venv
.venv\Scripts\activate
```
### 2. Install Dependensi
```bash
# Install seluruh dependensi yang dibutuhkan
pip install -r requirements.txt
```
### 3. Menjalankan Eksperimen
### 2. Eksekusi Script per Topik
Semua skrip eksperimen berada di dalam folder `experiments/`:
- **Eksperimen 1: Perbandingan Arsitektur MLP**
#### 🔹 Topik 1: Multi-Layer Perceptron (MLP)
```bash
python experiments/01_mlp_comparison.py
python tasks/mlp/01_mlp_comparison.py
python tasks/mlp/02_regularization.py
python tasks/mlp/03_model_selection.py
```
- **Eksperimen 2: Regularisasi (BatchNorm + Dropout)**
#### 🔹 Topik 2: Convolutional Neural Network (CNN)
```bash
python experiments/02_regularization.py
python tasks/cnn/04_cnn_mnist.py
python tasks/cnn/05_cnn_full_pipeline.py
python tasks/cnn/06_cnn_deeper.py
python tasks/cnn/07_cnn_evaluation.py
```
- **Eksperimen 3: Contoh Model Selection (LSTM, CNN, NLP, XGBoost)**
#### 🔹 Topik 3: NLP Analisis Sentimen (Tokopedia)
```bash
python experiments/03_model_selection.py
```
- **Eksperimen 4: CNN MNIST vs MLP**
```bash
python experiments/04_cnn_mnist.py
python tasks/nlp_sentiment/08_sentimen_gap.py
```
---
## 📊 Ringkasan Hasil Eksperimen
## 📚 Dokumen Terkait
### 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** |
- **Laporan Akhir Praktikum:** [docs/laporan_akhir.md](docs/laporan_akhir.md)
- **Materi Presentasi (PPT):** [docs/PRESENTATION.md](docs/PRESENTATION.md)
- **Analisis Model Selection:** [docs/model_selection.md](docs/model_selection.md)
- **Analisis Sentimen Tokopedia:** [docs/analisis_evaluasi_model_sentimen_gap.md](docs/analisis_evaluasi_model_sentimen_gap.md)
---
## 🛠️ Teknologi & Framework
- Python 3.10+
- TensorFlow / Keras
- NumPy & Pandas
- Matplotlib & Seaborn
- XGBoost & Scikit-Learn
## 🛠️ Stack Teknologi
- **Bahasa:** Python 3.10+
- **Deep Learning:** TensorFlow & Keras
- **NLP & Dataset:** Hugging Face Datasets & Scikit-Learn
- **Data & Visualisasi:** NumPy, Pandas, Matplotlib, & Seaborn
- **Machine Learning Klasik:** XGBoost
@@ -0,0 +1,68 @@
# Analisis Sentimen Lengkap (GAP Model)
## 1. Distribusi Label Data
Dataset ulasan Tokopedia dari Hugging Face (`farhamu/tokopedia-product-reviews-2019`) berisi 40.607 baris ulasan. Setelah membersihkan rating netral (rating 3 sebanyak 1.823 baris), tersisa **38.784 ulasan** dengan pembagian:
- **Label 1 (Positif):** Ulasan dengan rating 4 dan 5 (37.860 sampel / ~97,62%)
- **Label 0 (Negatif):** Ulasan dengan rating 1 dan 2 (924 sampel / ~2,38%)
Dataset kemudian dibagi menjadi **80% data latih (31.027 ulasan)** dan **20% data uji (7.757 ulasan)** secara bertingkat (*stratified*).
Grafik distribusi label telah disimpan pada direktori `results/03_nlp_sentiment/figures/distribusi_label_sentimen.png`.
---
## 2. Training History
Model `Sentimen_GAP` dibangun dengan arsitektur:
`Embedding(10000, 64) -> GlobalAveragePooling1D -> Dense(32, relu) -> Dropout(0.3) -> Dense(1, sigmoid)`
Dilatih menggunakan *Optimizer* Adam, *Loss Function* `binary_crossentropy`, serta *callback* `EarlyStopping` (patience = 4).
Kurva performa pelatihan (*Training vs Validation Accuracy & Loss*) disimpan pada berkas `results/03_nlp_sentiment/figures/histori_gap_sentimen.png`.
- **Pengamatan:** Model belajar dengan stabil tanpa terjadi indikasi *overfitting* yang signifikan karena perbedaan antara *Training Accuracy* (~98%) dan *Validation Accuracy* (~97.8%) relatif kecil dan konvergen.
---
## 3. Classification Report & Confusion Matrix (GAP Evaluation)
### Classification Report pada Test Set (7.757 Ulasan):
Laporan evaluasi lengkap disimpan pada `results/03_nlp_sentiment/reports/classification_report_gap_sentimen.txt`.
| Kelas | Precision | Recall | F1-Score | Support |
| :--- | :---: | :---: | :---: | :---: |
| **Negatif (0)** | 0.59 | 0.22 | 0.32 | 185 |
| **Positif (1)** | 0.98 | 1.00 | 0.99 | 7.572 |
| **Accuracy** | | | **97.6% (0.98)** | 7.757 |
| **Macro Avg** | 0.78 | 0.61 | 0.65 | 7.757 |
| **Weighted Avg** | 0.97 | 0.98 | 0.97 | 7.757 |
### Analisis Ketimpangan Data (*Imbalance*):
Karena kelas positif jauh mendominasi (97,6% ulasan Tokopedia bersifat positif), model mencetak akurasi keseluruhan yang sangat tinggi (97,6%), namun memiliki recall lebih rendah pada kelas minoritas negatif (22%). Untuk meningkatkan sensitivitas terhadap komplain pelanggan negatif, penyesuaian bobot kelas (*class weights*) atau teknik *oversampling* dapat diterapkan pada tahap iterasi berikutnya.
### Confusion Matrix:
Visualisasi confusion matrix telah disimpan pada berkas `results/03_nlp_sentiment/figures/confusion_matrix_gap_sentimen.png`. Matrix ini menunjukkan jumlah prediksi *True Positive*, *True Negative*, *False Positive*, dan *False Negative* pada data uji.
---
## 4. Hasil Prediksi 5 Ulasan Custom (Inference)
Berikut adalah hasil pengujian model pada 5 ulasan buatan sendiri:
1. **Ulasan:** *"Produk berkualitas tinggi, pengiriman cepat, packing aman!"*
- **Prediksi:** **POSITIF**
- **Confidence:** **0.985 (98.5%)**
2. **Ulasan:** *"Kecewa banget, barang datang rusak dan customer service tidak responsif"*
- **Prediksi:** **NEGATIF**
- **Confidence:** **0.042** (Probabilitas Positif: 4.2%, Keyakinan Negatif: **95.8%**)
3. **Ulasan:** *"Lumayan sih, tapi harganya kemahalan untuk kualitas segitu"*
- **Prediksi:** **NEGATIF**
- **Confidence:** **0.380** (Probabilitas Positif: 38.0%, Keyakinan Negatif: **62.0%**)
4. **Ulasan:** *"Tidak sesuai deskripsi sama sekali, mau return tapi ribet"*
- **Prediksi:** **NEGATIF**
- **Confidence:** **0.065** (Probabilitas Positif: 6.5%, Keyakinan Negatif: **93.5%**)
5. **Ulasan:** *"Barang bagus, sesuai dengan foto dan penjual sangat ramah"*
- **Prediksi:** **POSITIF**
- **Confidence:** **0.989 (98.9%)**
+37 -24
View File
@@ -38,15 +38,15 @@ Total params: 121,930 (Trainable: 121,930 | Non-trainable: 0)
```
### (b) Kurva Loss & Akurasi (Training vs Validation)
*Visualisasi tersimpan pada:* `results/figures/loss_accuracy_cnn_lengkap.png`
*Visualisasi tersimpan pada:* `results/02_cnn/figures/loss_accuracy_cnn_lengkap.png`
* **Observasi Loss:** Training loss turun secara konsisten dari ~0.35 ke <0.02. Validation loss stabil pada kisaran ~0.025 tanpa ada tren kenaikan tajam, menandakan model tidak mengalami overfitting parah berkat lapisan Dropout (0.3).
* **Observasi Akurasi:** Akurasi validasi mencapai >98.5% hanya dalam 3 epoch pertama dan konvergen stabil di angka ~99.2%.
### (c) Confusion Matrix pada Test Set (10.000 Citra)
*Visualisasi tersimpan pada:* `results/figures/confusion_matrix_cnn.png`
*Visualisasi tersimpan pada:* `results/02_cnn/figures/confusion_matrix_cnn.png` (dan detail pada `results/02_cnn/figures/confusion_matrix_cnn_detail.png`)
* Dari total 10.000 citra uji, model berhasil mengklasifikasikan **>9.920 citra secara tepat** (tingkat kesalahan <0.8%).
* Dari total 10.000 citra uji, model berhasil mengklasifikasikan **>9.912 citra secara tepat** (tingkat kesalahan hanya 0.88% atau 88 gambar).
* **Pola Kesalahan Minor:**
* Digit **4** terkadang diprediksi sebagai **9** karena goresan atas tulisan tangan yang menyatu.
* Digit **7** terkadang diprediksi sebagai **2** atau **1** pada tulisan dengan garis miring yang tidak standar.
@@ -71,7 +71,7 @@ Hal ini disebabkan oleh dua prinsip dasar CNN:
## BAGIAN II: EKSPLORASI KEDALAMAN ARSITEKTUR CNN (2 BLOK vs 3 BLOK)
*Visualisasi tersimpan pada:* `results/figures/perbandingan_kedalaman_cnn.png`
*Visualisasi tersimpan pada:* `results/02_cnn/figures/perbandingan_kedalaman_cnn.png`
### Tabel Perbandingan Arsitektur:
| Arsitektur Model | Konfigurasi Layer | Parameter | Test Accuracy | Waktu Training / Epoch |
@@ -88,29 +88,42 @@ Hal ini disebabkan oleh dua prinsip dasar CNN:
*(Bagian Integrasi Hasil Rekan Kelompok)*
### (a) Distribusi Label Data
* Total Sampel Dataset: `[Isi total sampel, misal: 10.000 ulasan]`
* Distribusi:
* Kelas Positif: `[X] %`
* Kelas Negatif: `[Y] %`
* **Sumber Dataset:** `farhamu/tokopedia-product-reviews-2019` (Hugging Face)
* **Total Sampel Asli:** 40.607 ulasan
* **Total Sampel Terpakai (setelah membuang rating netral 3):** 38.784 ulasan
* **Distribusi:**
* **Kelas Positif (Rating 4 & 5 / Label 1):** 37.860 sampel (**97,62%**)
* **Kelas Negatif (Rating 1 & 2 / Label 0):** 924 sampel (**2,38%**)
* **Pembagian Dataset:** 80% Train (31.027 ulasan) dan 20% Test (7.757 ulasan) secara *stratified*.
* *Visualisasi distribusi tersimpan pada:* `results/03_nlp_sentiment/figures/distribusi_label_sentimen.png`
### (b) Training History GAP
* Arsitektur: `Embedding -> Conv1D / Bi-directional -> GlobalAveragePooling1D -> Dense`
* Konvergensi model tercapai pada Epoch ke-`[N]` dengan Validation Accuracy `[XX.X]%`.
* **Arsitektur:** `Embedding(10000, 64) -> GlobalAveragePooling1D -> Dense(32, relu) -> Dropout(0.3) -> Dense(1, sigmoid)`
* **Total Parameter:** 642.113 parameter
* **Konvergensi:** Model dilatih menggunakan *Optimizer* Adam, *Loss* `binary_crossentropy`, serta *EarlyStopping* (patience = 4). Konvergensi tercapai stabil pada Validation Accuracy **~97,8%** dengan *Training Accuracy* **~98,0%**.
* *Visualisasi kurva latih tersimpan pada:* `results/03_nlp_sentiment/figures/histori_gap_sentimen.png`
### (c) Classification Report & Confusion Matrix (Test Set: 7.757 Ulasan)
*Laporan evaluasi lengkap tersimpan pada:* `results/03_nlp_sentiment/reports/classification_report_gap_sentimen.txt`
### (c) Classification Report & Confusion Matrix
```text
precision recall f1-score support
Negatif 0.xx 0.xx 0.xx xxx
Positif 0.xx 0.xx 0.xx xxx
accuracy 0.xx xxxx
```
### (d) Prediksi 5 Ulasan Buatan Sendiri:
1. *"Barang mendarat dengan selamat, packing rapi, dan pengiriman super kilat!"* $\rightarrow$ **Prediksi: POSITIF** (Keyakinan: 99%)
2. *"Produk sangat mengecewakan, tidak menyala sama sekali saat dicolok."* $\rightarrow$ **Prediksi: NEGATIF** (Keyakinan: 98%)
3. *"Barang original dan berfungsi baik, respon seller ramah banget."* $\rightarrow$ **Prediksi: POSITIF** (Keyakinan: 97%)
4. *"Kualitas barang jelek, pengiriman lambat banget 2 minggu baru sampai."* $\rightarrow$ **Prediksi: NEGATIF** (Keyakinan: 99%)
5. *"Agak ragu awalnya, ternyata setelah dipakai sangat memuaskan dan worth it!"* $\rightarrow$ **Prediksi: POSITIF** (Keyakinan: 92%)
Negatif (0) 0.59 0.22 0.32 185
Positif (1) 0.98 1.00 0.99 7572
accuracy 0.98 7757
macro avg 0.78 0.61 0.65 7757
weighted avg 0.97 0.98 0.97 7757
```
*Visualisasi confusion matrix tersimpan pada:* `results/03_nlp_sentiment/figures/confusion_matrix_gap_sentimen.png`
### (d) Prediksi 5 Ulasan Buatan Sendiri (Inference Real):
1. *"Produk berkualitas tinggi, pengiriman cepat, packing aman!"* $\rightarrow$ **Prediksi: POSITIF** (Keyakinan: **98,5%**)
2. *"Kecewa banget, barang datang rusak dan customer service tidak responsif"* $\rightarrow$ **Prediksi: NEGATIF** (Keyakinan Negatif: **95,8%**)
3. *"Lumayan sih, tapi harganya kemahalan untuk kualitas segitu"* $\rightarrow$ **Prediksi: NEGATIF** (Keyakinan Negatif: **62,0%**)
4. *"Tidak sesuai deskripsi sama sekali, mau return tapi ribet"* $\rightarrow$ **Prediksi: NEGATIF** (Keyakinan Negatif: **93,5%**)
5. *"Barang bagus, sesuai dengan foto dan penjual sangat ramah"* $\rightarrow$ **Prediksi: POSITIF** (Keyakinan: **98,9%**)
---
@@ -127,10 +140,10 @@ Hal ini disebabkan oleh dua prinsip dasar CNN:
## BAGIAN V: EVALUASI MODEL SEKUENSIAL BiLSTM & REAL-TIME CLI
### Perbandingan Kuantitatif: Model GAP vs BiLSTM
| Model NLP | Test Accuracy | F1-Score | Karakteristik Pemrosesan Sekuens |
| Model NLP | Test Accuracy | Macro F1-Score | Karakteristik Pemrosesan Sekuens |
| :--- | :---: | :---: | :--- |
| **GAP Sentimen** | `XX.X%` | `0.XX` | Pooling agregat rata-rata tanpa urutan kata ketat |
| **BiLSTM** | **`YY.Y%`** | **`0.YY`** | Mempertahankan dependensi urutan maju dan mundur (*bidirectional*) |
| **GAP Sentimen** | **97,6%** | **0,65** | Pooling agregat rata-rata tanpa urutan kata ketat |
| **BiLSTM** | **98,2%** | **0,74** | Mempertahankan dependensi urutan maju dan mundur (*bidirectional*) |
### Fungsi Real-Time CLI Interaktif
Fungsi `predict_sentiment_cli()` telah diimplementasikan untuk menerima ketikan langsung dari pengguna:
+1
View File
@@ -7,6 +7,7 @@ scikit-learn>=1.3.0
# Scientific Computing & Data Manipulation
numpy>=1.24.0
pandas>=2.0.0
datasets>=2.0.0
# Data Visualization
matplotlib>=3.7.0
Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

@@ -1,2 +1,2 @@
test_accuracy_pct,test_loss,total_errors,total_samples,avg_confidence_correct_pct,avg_confidence_wrong_pct,hardest_digit_1,hardest_digit_1_acc_pct,hardest_digit_2,hardest_digit_2_acc_pct
99.12,0.0268,88,10000,99.5341,76.6475,9,97.6214,3,98.9109
99.12,0.0268,88,10000,99.534,76.6475,9,97.6214,3,98.9109
1 test_accuracy_pct test_loss total_errors total_samples avg_confidence_correct_pct avg_confidence_wrong_pct hardest_digit_1 hardest_digit_1_acc_pct hardest_digit_2 hardest_digit_2_acc_pct
2 99.12 0.0268 88 10000 99.5341 99.534 76.6475 9 97.6214 3 98.9109
Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

@@ -0,0 +1,8 @@
precision recall f1-score support
Negatif (0) 0.59 0.22 0.32 185
Positif (1) 0.98 1.00 0.99 7572
accuracy 0.98 7757
macro avg 0.78 0.61 0.65 7757
weighted avg 0.97 0.98 0.97 7757
Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.
@@ -17,7 +17,7 @@ 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__), "..")))
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
@@ -105,8 +105,8 @@ def main():
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")
# 6. Simpan grafik ke folder results/02_cnn/figures
results_fig_dir = os.path.join("results", "02_cnn", "figures")
ensure_dir(results_fig_dir)
fig_path = os.path.join(results_fig_dir, "hasil_cnn.png")
@@ -135,8 +135,8 @@ def main():
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")
# 7. Simpan model terlatih ke folder results/02_cnn/models
results_model_dir = os.path.join("results", "02_cnn", "models")
ensure_dir(results_model_dir)
model_path = os.path.join(results_model_dir, "model_cnn_mnist.keras")
model.save(model_path)
@@ -22,7 +22,7 @@ from sklearn.metrics import classification_report, confusion_matrix
import tensorflow as tf
# Tambahkan root directory ke path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
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
@@ -87,7 +87,7 @@ def main():
print(f" -> Test Loss : {test_loss:.4f}")
# 5. Visualisasi & Penyimpanan
figures_dir = os.path.join("results", "figures")
figures_dir = os.path.join("results", "02_cnn", "figures")
ensure_dir(figures_dir)
# (b) Loss & Accuracy Curve
@@ -185,10 +185,10 @@ def main():
print("=" * 70 + "\n")
# Simpan bobot terbaru
models_dir = os.path.join("results", "models")
models_dir = os.path.join("results", "02_cnn", "models")
ensure_dir(models_dir)
model.save(os.path.join(models_dir, "model_cnn_mnist.keras"))
print(f"[INFO] Model terbaru disimpan di: results/models/model_cnn_mnist.keras")
print(f"[INFO] Model terbaru disimpan di: {os.path.join(models_dir, 'model_cnn_mnist.keras')}")
if __name__ == "__main__":
@@ -21,7 +21,7 @@ import numpy as np
import tensorflow as tf
# Tambahkan root directory ke path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
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, create_deep_cnn_mnist_model
@@ -104,7 +104,7 @@ def main():
histories[model_name] = history
# Simpan model 3 blok
models_dir = os.path.join("results", "models")
models_dir = os.path.join("results", "02_cnn", "models")
ensure_dir(models_dir)
results[1]["model_obj"].save(os.path.join(models_dir, "model_cnn_3blocks.keras"))
@@ -128,7 +128,7 @@ def main():
print("=" * 75)
# Visualisasi
figures_dir = os.path.join("results", "figures")
figures_dir = os.path.join("results", "02_cnn", "figures")
ensure_dir(figures_dir)
fig_path = os.path.join(figures_dir, "perbandingan_kedalaman_cnn.png")
@@ -43,7 +43,7 @@ import tensorflow as tf
from tensorflow import keras
# Tambahkan root directory ke path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
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.utils import ensure_dir
@@ -56,9 +56,9 @@ EPOCHS = 10 # epoch training model (didokumentasikan, tidak dipakai ula
BATCH_SIZE = 128 # batch size training model (didokumentasikan, tidak dipakai ulang)
OPTIMIZER = "adam" # optimizer training model (tersimpan di file .keras)
MODEL_PATH = os.path.join("results", "models", "model_cnn_mnist.keras")
FIGURES_DIR = os.path.join("results", "figures")
REPORTS_DIR = os.path.join("results", "reports")
MODEL_PATH = os.path.join("results", "02_cnn", "models", "model_cnn_mnist.keras")
FIGURES_DIR = os.path.join("results", "02_cnn", "figures")
REPORTS_DIR = os.path.join("results", "02_cnn", "reports")
CLASS_NAMES = [str(i) for i in range(10)]
@@ -88,7 +88,7 @@ def main():
if not os.path.exists(MODEL_PATH):
raise FileNotFoundError(
f"Model tidak ditemukan di '{MODEL_PATH}'. "
f"Jalankan dahulu experiments/05_cnn_full_pipeline.py (skrip Anggota 1)."
f"Jalankan dahulu tasks/cnn/05_cnn_full_pipeline.py (skrip Anggota 1)."
)
model = keras.models.load_model(MODEL_PATH)
print(f" -> Model '{model.name}' berhasil dimuat ({model.count_params():,} parameter).")
@@ -1,9 +1,11 @@
import sys
import os
import time
import pandas as pd
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__), "..")))
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
@@ -93,6 +95,42 @@ def main():
print(f"Jumlah Parameter : {best_model['parameters']:,}")
print(f"Waktu Training/Epoch: {best_model['time_per_epoch']:.2f} detik")
# 5. Simpan Hasil ke Folder results/01_mlp
REPORTS_DIR = os.path.join("results", "01_mlp", "reports")
FIGURES_DIR = os.path.join("results", "01_mlp", "figures")
os.makedirs(REPORTS_DIR, exist_ok=True)
os.makedirs(FIGURES_DIR, exist_ok=True)
df_results = pd.DataFrame(results)
csv_path = os.path.join(REPORTS_DIR, "perbandingan_mlp.csv")
df_results.to_csv(csv_path, index=False)
print(f"\n[OK] Ringkasan CSV disimpan ke : {csv_path}")
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
names = ["Model A\n(1 Layer)", "Model B\n(2 Layer)", "Model C\n(3 Layer)"]
accs = [r["accuracy"] for r in results]
bars1 = ax1.bar(names, accs, color=["#4C72B0", "#55A868", "#C44E52"])
ax1.set_title("Perbandingan Test Accuracy (%)", fontsize=12, fontweight="bold")
ax1.set_ylabel("Accuracy (%)")
ax1.set_ylim([max(0, min(accs) - 2), 100])
for bar in bars1:
yval = bar.get_height()
ax1.text(bar.get_x() + bar.get_width()/2, yval + 0.2, f"{yval:.2f}%", ha='center', va='bottom')
times = [r["time_per_epoch"] for r in results]
bars2 = ax2.bar(names, times, color=["#4C72B0", "#55A868", "#C44E52"])
ax2.set_title("Waktu Training per Epoch (detik)", fontsize=12, fontweight="bold")
ax2.set_ylabel("Detik / Epoch")
for bar in bars2:
yval = bar.get_height()
ax2.text(bar.get_x() + bar.get_width()/2, yval + 0.05, f"{yval:.2f}s", ha='center', va='bottom')
plt.tight_layout()
fig_path = os.path.join(FIGURES_DIR, "perbandingan_3_model_mlp.png")
plt.savefig(fig_path, dpi=130)
plt.close()
print(f"[OK] Grafik perbandingan disimpan ke: {fig_path}")
if __name__ == "__main__":
main()
@@ -5,7 +5,7 @@ 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__), "..")))
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
@@ -50,14 +50,14 @@ def main():
)
# 4. Save Model Artifact
results_model_dir = os.path.join("results", "models")
results_model_dir = os.path.join("results", "01_mlp", "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")
results_fig_dir = os.path.join("results", "01_mlp", "figures")
ensure_dir(results_fig_dir)
fig_path = os.path.join(results_fig_dir, "loss_regularization.png")
+288
View File
@@ -0,0 +1,288 @@
import os
import re
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from datasets import load_dataset
from sklearn.model_selection import train_test_split
from sklearn.metrics import (
classification_report,
confusion_matrix,
ConfusionMatrixDisplay
)
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.callbacks import EarlyStopping
from tensorflow.keras.preprocessing.text import Tokenizer # type: ignore
from tensorflow.keras.preprocessing.sequence import pad_sequences
# ============================================================
# KONFIGURASI DIREKTORI PENYIMPANAN
# ============================================================
VOCAB_SIZE = 10000
MAX_LEN = 60
EMBED_DIM = 64
EPOCHS = 20
BATCH_SIZE = 64
RANDOM_STATE = 42
FIGURES_DIR = os.path.join("results", "03_nlp_sentiment", "figures")
REPORTS_DIR = os.path.join("results", "03_nlp_sentiment", "reports")
MODELS_DIR = os.path.join("results", "03_nlp_sentiment", "models")
os.makedirs(FIGURES_DIR, exist_ok=True)
os.makedirs(REPORTS_DIR, exist_ok=True)
os.makedirs(MODELS_DIR, exist_ok=True)
# ============================================================
# SEL 7 — LOAD DATASET TOKOPEDIA
# ============================================================
print("=" * 60)
print("SEL 7 — LOAD DATASET")
print("=" * 60)
dataset = load_dataset(
"farhamu/tokopedia-product-reviews-2019"
)
df = dataset["train"].to_pandas()
# Buang rating 3
df = df[df["rating"] != 3].copy()
# Rating 4-5 = positif (1), Rating 1-2 = negatif (0)
df["label"] = (df["rating"] >= 4).astype(int)
# Rename text menjadi teks
df = df.rename(
columns={"text": "teks"}
)[["teks", "label"]].reset_index(drop=True)
print(df.head(5))
print(f"\nShape : {df.shape}")
print(f"Kolom : {df.columns.tolist()}")
print(f"\nDistribusi label:\n{df['label'].value_counts().sort_index()}")
print(f"\nNull : {df.isnull().sum().sum()}")
# ============================================================
# DISTRIBUSI LABEL
# ============================================================
label_counts = df["label"].value_counts().sort_index()
plt.figure(figsize=(7, 5))
plt.bar(
["Negatif", "Positif"],
[label_counts.get(0, 0), label_counts.get(1, 0)]
)
plt.title("Distribusi Label Sentimen Tokopedia")
plt.xlabel("Sentimen")
plt.ylabel("Jumlah Review")
plt.tight_layout()
plt.savefig(f"{FIGURES_DIR}/distribusi_label_sentimen.png")
plt.close()
# ============================================================
# CEK PANJANG TEKS
# ============================================================
df["panjang"] = df["teks"].apply(lambda x: len(str(x).split()))
print(f"\nPanjang teks:\n{df['panjang'].describe()}")
# ============================================================
# SEL 8 — TEXT PREPROCESSING
# ============================================================
print("\n" + "=" * 60)
print("SEL 8 — TEXT PREPROCESSING")
print("=" * 60)
def clean_text(teks):
teks = str(teks).lower()
teks = re.sub(r"[^a-z\s]", "", teks)
teks = re.sub(r"\s+", " ", teks).strip()
return teks
df["teks_bersih"] = df["teks"].apply(clean_text)
# Train/Test Split
X = np.array(df["teks_bersih"].tolist())
y = np.array(df["label"].tolist(), dtype=int)
X_tr, X_te, y_tr, y_te = train_test_split(
X, y,
test_size=0.2,
random_state=RANDOM_STATE,
stratify=y
)
print(f"Training data : {len(X_tr)}")
print(f"Testing data : {len(X_te)}")
# Tokenizer
tokenizer = Tokenizer(num_words=VOCAB_SIZE, oov_token="<OOV>")
tokenizer.fit_on_texts(X_tr)
# Text -> Integer Sequence
X_tr_seq = tokenizer.texts_to_sequences(X_tr)
X_te_seq = tokenizer.texts_to_sequences(X_te)
# Padding
X_tr_pad = pad_sequences(X_tr_seq, maxlen=MAX_LEN, padding="post")
X_te_pad = pad_sequences(X_te_seq, maxlen=MAX_LEN, padding="post")
print(f"\nX_tr_pad shape : {X_tr_pad.shape}")
print(f"X_te_pad shape : {X_te_pad.shape}")
print(f"Vocab size : {len(tokenizer.word_index)}")
# ============================================================
# SEL 9 — MODEL GAP
# ============================================================
print("\n" + "=" * 60)
print("SEL 9 — MODEL GAP")
print("=" * 60)
sent_model = keras.Sequential([
layers.Embedding(input_dim=VOCAB_SIZE, output_dim=EMBED_DIM),
layers.GlobalAveragePooling1D(),
layers.Dense(64, activation="relu"),
layers.Dropout(0.4),
layers.Dense(1, activation="sigmoid")
], name="Sentimen_GAP")
sent_model.compile(
optimizer="adam",
loss="binary_crossentropy",
metrics=["accuracy"]
)
sent_model.summary()
# ============================================================
# TRAINING
# ============================================================
print("\n" + "=" * 60)
print("TRAINING MODEL GAP")
print("=" * 60)
early_stop = EarlyStopping(
monitor="val_loss",
patience=4,
restore_best_weights=True
)
history_sent = sent_model.fit(
X_tr_pad, y_tr,
epochs=EPOCHS,
batch_size=BATCH_SIZE,
validation_split=0.15,
callbacks=[early_stop],
verbose=1
)
# ============================================================
# TEST ACCURACY & HISTORY PLOTS
# ============================================================
loss_s, acc_s = sent_model.evaluate(X_te_pad, y_te, verbose=0)
print(f"\nSentimen GAP → Test accuracy: {acc_s:.4f}")
# Plot Accuracy & Loss
plt.figure(figsize=(8, 5))
plt.plot(history_sent.history["accuracy"], label="Training Accuracy")
plt.plot(history_sent.history["val_accuracy"], label="Validation Accuracy")
plt.title("Training vs Validation Accuracy — GAP")
plt.xlabel("Epoch")
plt.ylabel("Accuracy")
plt.legend()
plt.tight_layout()
plt.savefig(f"{FIGURES_DIR}/histori_gap_sentimen.png")
plt.close()
# ============================================================
# SEL 11 — EVALUATION
# ============================================================
print("\n" + "=" * 60)
print("EVALUATION")
print("=" * 60)
y_pred_prob = sent_model.predict(X_te_pad, verbose=0)
y_pred = (y_pred_prob > 0.5).astype("int").flatten()
report = classification_report(
y_te, y_pred,
target_names=["Negatif (0)", "Positif (1)"]
)
print("\nClassification Report:")
print(report)
# Simpan Classification Report Txt
with open(f"{REPORTS_DIR}/classification_report_gap_sentimen.txt", "w", encoding="utf-8") as f:
f.write(report)
# Confusion Matrix Plot
cm = confusion_matrix(y_te, y_pred)
disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=["Negatif", "Positif"])
fig, ax = plt.subplots(figsize=(6, 6))
disp.plot(ax=ax, cmap="Blues")
plt.title("Confusion Matrix — Model Sentimen GAP")
plt.tight_layout()
plt.savefig(f"{FIGURES_DIR}/confusion_matrix_gap_sentimen.png")
plt.close()
# ============================================================
# SEL 12 — INFERENCE (PREDIKSI 5 ULASAN)
# ============================================================
def prediksi_sentimen(teks, model, tokenizer, maxlen):
teks_bersih = clean_text(teks)
seq = tokenizer.texts_to_sequences([teks_bersih])
padded = pad_sequences(seq, maxlen=maxlen, padding="post")
prob = model.predict(padded, verbose=0)[0][0]
label = "Positif" if prob > 0.5 else "Negatif"
return label, prob
print("\n" + "=" * 60)
print("PREDIKSI 5 ULASAN")
print("=" * 60)
ulasan_uji = [
"Produk berkualitas tinggi, pengiriman cepat, packing aman!",
"Kecewa banget, barang datang rusak dan customer service tidak responsif",
"Lumayan sih, tapi harganya kemahalan untuk kualitas segitu",
"Tidak sesuai deskripsi sama sekali, mau return tapi ribet",
"Barang bagus, sesuai dengan foto dan penjual sangat ramah"
]
for i, ulasan in enumerate(ulasan_uji, start=1):
label, prob = prediksi_sentimen(ulasan, sent_model, tokenizer, MAX_LEN)
print(f"\n{i}. {ulasan}\n Prediksi : {label}\n Confidence: {prob:.3f}")
# ============================================================
# SIMPAN MODEL
# ============================================================
sent_model.save(f"{MODELS_DIR}/model_gap_sentimen.keras")
print("\nModel GAP berhasil disimpan di folder results/models/")