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
+4
View File
@@ -0,0 +1,4 @@
"""
Helper utilities and modules for Deep Learning experiments.
"""
+46
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
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
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()