refactor: re-structure folder
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
"""
|
||||
Helper utilities and modules for Deep Learning experiments.
|
||||
"""
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user