Lab 6: Image Classification dengan CNN dan Transfer Learning
Klasifikasi Gambar CIFAR-10 menggunakan Convolutional Neural Networks
Author
Pembelajaran Mesin - Data Science for Cybersecurity
Published
December 15, 2025
17 Pendahuluan
17.1 Tujuan Pembelajaran
Setelah menyelesaikan lab ini, Anda diharapkan dapat:
Memahami arsitektur CNN untuk klasifikasi gambar
Membangun CNN dari awal dengan berbagai kompleksitas
Menerapkan data augmentation untuk meningkatkan generalisasi
Mengimplementasikan transfer learning dengan model pre-trained
Melakukan fine-tuning pada model pre-trained
Membandingkan berbagai pendekatan CNN dan transfer learning
Memvisualisasikan feature maps dan aktivasi CNN
Mengoptimasi performa model untuk akurasi tinggi
17.2 Gambaran Umum Lab
Pada lab ini, Anda akan bekerja dengan dataset CIFAR-10, yang merupakan dataset klasifikasi gambar berwarna berisi 60,000 gambar berukuran 32×32 piksel dalam 10 kelas berbeda.
17.2.1 Dataset CIFAR-10
CIFAR-10 (Canadian Institute For Advanced Research) adalah dataset yang sangat populer dalam computer vision:
Ukuran total: 60,000 gambar berwarna (RGB)
Resolusi: 32 × 32 piksel
Jumlah kelas: 10 kategori
Training set: 50,000 gambar
Test set: 10,000 gambar
Distribusi: Seimbang (6,000 gambar per kelas)
10 Kelas dalam CIFAR-10:
✈️ Airplane (pesawat)
🚗 Automobile (mobil)
🐦 Bird (burung)
🐱 Cat (kucing)
🦌 Deer (rusa)
🐕 Dog (anjing)
🐸 Frog (katak)
🐴 Horse (kuda)
🚢 Ship (kapal)
🚚 Truck (truk)
17.2.2 Pendekatan yang Akan Dipelajari
Dalam lab ini, kita akan mengeksplorasi berbagai pendekatan:
graph TD A[CIFAR-10 Dataset] --> B[Part 1: Data Exploration] B --> C[Part 2: CNN from Scratch] B --> D[Part 3: Transfer Learning] C --> C1[Simple CNN] C --> C2[VGG-style CNN] C --> C3[Data Augmentation] D --> D1[Feature Extraction] D --> D2[Fine-tuning] D1 --> E[Part 4: Advanced Techniques] D2 --> E E --> E1[ResNet50] E --> E2[Model Ensemble] E --> E3[Grad-CAM] E1 --> F[Final Comparison] E2 --> F E3 --> F
graph TD
A[CIFAR-10 Dataset] --> B[Part 1: Data Exploration]
B --> C[Part 2: CNN from Scratch]
B --> D[Part 3: Transfer Learning]
C --> C1[Simple CNN]
C --> C2[VGG-style CNN]
C --> C3[Data Augmentation]
D --> D1[Feature Extraction]
D --> D2[Fine-tuning]
D1 --> E[Part 4: Advanced Techniques]
D2 --> E
E --> E1[ResNet50]
E --> E2[Model Ensemble]
E --> E3[Grad-CAM]
E1 --> F[Final Comparison]
E2 --> F
E3 --> F
17.3 Persiapan Environment
17.3.1 Import Libraries
# Import library dasarimport numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport seaborn as snsfrom pathlib import Pathimport warningswarnings.filterwarnings('ignore')# Import TensorFlow/Kerasimport tensorflow as tffrom tensorflow import kerasfrom tensorflow.keras import layers, models, optimizersfrom tensorflow.keras.preprocessing.image import ImageDataGeneratorfrom tensorflow.keras.applications import VGG16, ResNet50from tensorflow.keras.callbacks import ( ModelCheckpoint, EarlyStopping, ReduceLROnPlateau, TensorBoard)# Import scikit-learnfrom sklearn.model_selection import train_test_splitfrom sklearn.metrics import ( classification_report, confusion_matrix, accuracy_score, precision_recall_fscore_support)# Import untuk visualisasiimport cv2from PIL import Image# Set random seed untuk reproducibilitynp.random.seed(42)tf.random.set_seed(42)print(f"TensorFlow version: {tf.__version__}")print(f"Keras version: {keras.__version__}")print(f"GPU available: {tf.config.list_physical_devices('GPU')}")
17.3.2 Konfigurasi GPU (Opsional)
# Cek dan konfigurasi GPU jika tersediadef setup_gpu():"""Setup GPU untuk training yang lebih efisien""" gpus = tf.config.list_physical_devices('GPU')if gpus:try:# Set memory growth untuk menghindari OOMfor gpu in gpus: tf.config.experimental.set_memory_growth(gpu, True)print(f"✓ {len(gpus)} GPU ditemukan dan dikonfigurasi")print(f" GPU devices: {[gpu.name for gpu in gpus]}")# Set mixed precision untuk training lebih cepat policy = tf.keras.mixed_precision.Policy('mixed_float16') tf.keras.mixed_precision.set_global_policy(policy)print(f"✓ Mixed precision enabled: {policy.name}")exceptRuntimeErroras e:print(f"✗ GPU configuration error: {e}")else:print("⚠ No GPU found. Training will use CPU (slower)")setup_gpu()
17.3.3 Setup Direktori
# Buat direktori untuk menyimpan model dan hasildirs = {'models': Path('models'),'checkpoints': Path('checkpoints'),'figures': Path('figures'),'logs': Path('logs'),'predictions': Path('predictions')}for name, path in dirs.items(): path.mkdir(exist_ok=True, parents=True)print(f"✓ Directory created: {path}")
17.3.4 Konstanta Global
# Konstanta untuk CIFAR-10IMG_HEIGHT =32IMG_WIDTH =32IMG_CHANNELS =3NUM_CLASSES =10BATCH_SIZE =128EPOCHS =50# Nama kelas CIFAR-10CLASS_NAMES = ['airplane', 'automobile', 'bird', 'cat', 'deer','dog', 'frog', 'horse', 'ship', 'truck']# Nama kelas dalam Bahasa IndonesiaCLASS_NAMES_ID = ['Pesawat', 'Mobil', 'Burung', 'Kucing', 'Rusa','Anjing', 'Katak', 'Kuda', 'Kapal', 'Truk']print("Konfigurasi Dataset:")print(f" Image size: {IMG_HEIGHT}×{IMG_WIDTH}×{IMG_CHANNELS}")print(f" Number of classes: {NUM_CLASSES}")print(f" Batch size: {BATCH_SIZE}")print(f" Training epochs: {EPOCHS}")
18 Part 1: Data Loading dan Exploration
18.1 Load Dataset CIFAR-10
CIFAR-10 tersedia langsung dari Keras datasets, sehingga mudah untuk diload.
def display_dataset_info(X_train, y_train, X_test, y_test):"""Tampilkan informasi lengkap tentang dataset"""print("="*70)print("CIFAR-10 DATASET INFORMATION")print("="*70)# Basic infoprint(f"\n1. DIMENSI DATA:")print(f" Training images: {X_train.shape}")print(f" Training labels: {y_train.shape}")print(f" Test images: {X_test.shape}")print(f" Test labels: {y_test.shape}")# Memory usage train_size_mb = X_train.nbytes / (1024**2) test_size_mb = X_test.nbytes / (1024**2)print(f"\n2. MEMORY USAGE:")print(f" Training data: {train_size_mb:.2f} MB")print(f" Test data: {test_size_mb:.2f} MB")print(f" Total: {train_size_mb + test_size_mb:.2f} MB")# Data type and rangeprint(f"\n3. DATA TYPE:")print(f" Image dtype: {X_train.dtype}")print(f" Label dtype: {y_train.dtype}")print(f" Pixel value range: [{X_train.min()}, {X_train.max()}]")# Class distributionprint(f"\n4. CLASS DISTRIBUTION:") unique, counts = np.unique(y_train, return_counts=True)for class_id, count inzip(unique, counts): class_name = CLASS_NAMES[class_id[0]] percentage = (count /len(y_train)) *100print(f" {class_id[0]}: {class_name:12s} - {count:5,} images ({percentage:.2f}%)")print("="*70)display_dataset_info(X_train_raw, y_train_raw, X_test_raw, y_test_raw)
18.2.2 Visualisasi Distribusi Kelas
def plot_class_distribution(y_train, y_test, save_path=None):"""Plot distribusi kelas untuk training dan test set""" fig, axes = plt.subplots(1, 2, figsize=(15, 5))# Training set distribution unique_train, counts_train = np.unique(y_train, return_counts=True) axes[0].bar(unique_train.flatten(), counts_train, color='steelblue', alpha=0.8) axes[0].set_xlabel('Class ID', fontsize=12, fontweight='bold') axes[0].set_ylabel('Number of Images', fontsize=12, fontweight='bold') axes[0].set_title('Training Set - Class Distribution', fontsize=14, fontweight='bold') axes[0].set_xticks(range(NUM_CLASSES)) axes[0].set_xticklabels(CLASS_NAMES, rotation=45, ha='right') axes[0].grid(axis='y', alpha=0.3)# Add count labelsfor i, count inenumerate(counts_train): axes[0].text(i, count +100, str(count), ha='center', va='bottom', fontweight='bold')# Test set distribution unique_test, counts_test = np.unique(y_test, return_counts=True) axes[1].bar(unique_test.flatten(), counts_test, color='coral', alpha=0.8) axes[1].set_xlabel('Class ID', fontsize=12, fontweight='bold') axes[1].set_ylabel('Number of Images', fontsize=12, fontweight='bold') axes[1].set_title('Test Set - Class Distribution', fontsize=14, fontweight='bold') axes[1].set_xticks(range(NUM_CLASSES)) axes[1].set_xticklabels(CLASS_NAMES, rotation=45, ha='right') axes[1].grid(axis='y', alpha=0.3)# Add count labelsfor i, count inenumerate(counts_test): axes[1].text(i, count +20, str(count), ha='center', va='bottom', fontweight='bold') plt.tight_layout()if save_path: plt.savefig(save_path, dpi=300, bbox_inches='tight')print(f"✓ Figure saved to: {save_path}") plt.show()plot_class_distribution(y_train_raw, y_test_raw, save_path=dirs['figures'] /'class_distribution.png')
18.2.3 Visualisasi Sample Images
def plot_sample_images(X, y, num_samples=20, save_path=None):""" Plot sample images dari setiap kelas Parameters: X: array gambar y: array label num_samples: jumlah sample per kelas save_path: path untuk menyimpan figure """ samples_per_class = num_samples // NUM_CLASSES fig, axes = plt.subplots(NUM_CLASSES, samples_per_class, figsize=(15, 18)) fig.suptitle('CIFAR-10 Sample Images per Class', fontsize=16, fontweight='bold', y=0.995)for class_id inrange(NUM_CLASSES):# Ambil indices untuk kelas ini class_indices = np.where(y.flatten() == class_id)[0]# Random sample sample_indices = np.random.choice(class_indices, samples_per_class, replace=False)for i, idx inenumerate(sample_indices): ax = axes[class_id, i] ax.imshow(X[idx]) ax.axis('off')if i ==0:# Tambahkan label kelas di kolom pertama ax.set_ylabel(f'{CLASS_NAMES[class_id]}\n({CLASS_NAMES_ID[class_id]})', fontsize=10, fontweight='bold', rotation=0, ha='right', va='center') plt.tight_layout()if save_path: plt.savefig(save_path, dpi=300, bbox_inches='tight')print(f"✓ Figure saved to: {save_path}") plt.show()plot_sample_images(X_train_raw, y_train_raw, num_samples=20, save_path=dirs['figures'] /'sample_images.png')
# Plot model architecturedef plot_model_architecture(model, save_path=None):"""Plot arsitektur model""" keras.utils.plot_model( model, to_file=save_path if save_path else'model_architecture.png', show_shapes=True, show_layer_names=True, rankdir='TB', # Top to Bottom expand_nested=True, dpi=150 )if save_path:print(f"✓ Model architecture saved to: {save_path}")plot_model_architecture(simple_cnn, save_path=dirs['figures'] /'simple_cnn_architecture.png')
19.1.3 Compile Model
def compile_model(model, learning_rate=0.001):""" Compile model dengan optimizer, loss, dan metrics Parameters: model: Keras model learning_rate: learning rate untuk optimizer """ optimizer = optimizers.Adam(learning_rate=learning_rate) model.compile( optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy', keras.metrics.TopKCategoricalAccuracy(k=3, name='top3_acc')] )print(f"✓ Model compiled with:")print(f" Optimizer: Adam (lr={learning_rate})")print(f" Loss: categorical_crossentropy")print(f" Metrics: accuracy, top-3 accuracy")compile_model(simple_cnn, learning_rate=0.001)
19.1.4 Setup Callbacks
def create_callbacks(model_name, monitor='val_accuracy', patience=10):""" Create callbacks untuk training Parameters: model_name: nama model untuk checkpoint monitor: metric yang dimonitor patience: patience untuk early stopping Returns: list of callbacks """ callbacks = [# ModelCheckpoint: simpan best model ModelCheckpoint( filepath=dirs['checkpoints'] /f'{model_name}_best.h5', monitor=monitor, mode='max', save_best_only=True, verbose=1 ),# EarlyStopping: stop training jika tidak ada improvement EarlyStopping( monitor=monitor, mode='max', patience=patience, restore_best_weights=True, verbose=1 ),# ReduceLROnPlateau: reduce learning rate jika plateau ReduceLROnPlateau( monitor=monitor, mode='max', factor=0.5, patience=5, min_lr=1e-7, verbose=1 ),# TensorBoard: logging untuk visualisasi TensorBoard( log_dir=dirs['logs'] / model_name, histogram_freq=1, write_graph=True, write_images=True ) ]print(f"✓ Created {len(callbacks)} callbacks for training")return callbackscallbacks_simple = create_callbacks('simple_cnn', patience=15)
19.1.5 Train Simple CNN
def train_model(model, X_train, y_train, X_val, y_val, callbacks, epochs=50, batch_size=128):""" Train model Parameters: model: Keras model X_train, y_train: training data X_val, y_val: validation data callbacks: list of callbacks epochs: jumlah epochs batch_size: batch size Returns: history: training history """print(f"\nTraining {model.name}...")print(f" Epochs: {epochs}")print(f" Batch size: {batch_size}")print(f" Training samples: {len(X_train):,}")print(f" Validation samples: {len(X_val):,}")print("="*70) history = model.fit( X_train, y_train, batch_size=batch_size, epochs=epochs, validation_data=(X_val, y_val), callbacks=callbacks, verbose=1 )print("\n✓ Training complete!")return history# Train simple CNNhistory_simple = train_model( simple_cnn, X_train, y_train, X_val, y_val, callbacks_simple, epochs=EPOCHS, batch_size=BATCH_SIZE)
def evaluate_model(model, X_test, y_test, model_name='Model'):""" Evaluate model pada test set Parameters: model: trained model X_test: test images y_test: test labels (one-hot) model_name: nama model Returns: test_loss, test_accuracy """print(f"\nEvaluating {model_name} on test set...")print("="*70)# Evaluate results = model.evaluate(X_test, y_test, verbose=1)print(f"\n{model_name} Test Results:")print(f" Test Loss: {results[0]:.4f}")print(f" Test Accuracy: {results[1]:.4f}")print(f" Top-3 Accuracy: {results[2]:.4f}")return results# Evaluate simple CNNresults_simple = evaluate_model(simple_cnn, X_test_norm, y_test_encoded,'Simple CNN')
19.2 VGG-Style CNN
Sekarang kita build CNN yang lebih dalam dengan arsitektur mirip VGG.
Transfer learning memanfaatkan model yang sudah di-train pada dataset besar (ImageNet) untuk task kita.
20.1 Load Pre-trained VGG16
20.1.1 Setup VGG16 Base
def load_pretrained_vgg16(input_shape=(32, 32, 3), trainable=False):""" Load VGG16 pre-trained pada ImageNet Parameters: input_shape: shape input gambar trainable: freeze atau unfreeze base layers Returns: base_model: VGG16 base model """print("Loading VGG16 pre-trained model...")# Load VGG16 tanpa top layers (classifier) base_model = VGG16( include_top=False, weights='imagenet', input_shape=input_shape )# Freeze base model layers base_model.trainable = trainableprint(f"✓ VGG16 loaded!")print(f" Total layers: {len(base_model.layers)}")print(f" Trainable: {trainable}")print(f" Input shape: {input_shape}")print(f" Output shape: {base_model.output_shape}")return base_model# Load VGG16 base (frozen)vgg16_base = load_pretrained_vgg16(trainable=False)vgg16_base.summary()
20.1.2 Build Transfer Learning Model
def build_transfer_learning_model(base_model, num_classes=10, model_name='TransferLearning'):""" Build model dengan pre-trained base dan custom classifier Parameters: base_model: pre-trained base model num_classes: jumlah kelas output model_name: nama model Returns: model: complete model """print(f"\nBuilding {model_name} model...")# Create Sequential model model = models.Sequential(name=model_name)# Add pre-trained base model.add(base_model)# Add custom classifier model.add(layers.Flatten(name='flatten')) model.add(layers.Dense(512, activation='relu', name='fc1')) model.add(layers.BatchNormalization(name='bn1')) model.add(layers.Dropout(0.5, name='dropout1')) model.add(layers.Dense(256, activation='relu', name='fc2')) model.add(layers.BatchNormalization(name='bn2')) model.add(layers.Dropout(0.5, name='dropout2')) model.add(layers.Dense(num_classes, activation='softmax', name='output'))print(f"✓ {model_name} model built!")print(f" Total layers: {len(model.layers)}")return model# Build transfer learning model dengan VGG16vgg16_tl = build_transfer_learning_model(vgg16_base, model_name='VGG16_FeatureExtraction')vgg16_tl.summary()
20.1.3 Count Trainable Parameters
def print_trainable_parameters(model):"""Print jumlah trainable dan non-trainable parameters""" trainable_count = np.sum([keras.backend.count_params(w) for w in model.trainable_weights]) non_trainable_count = np.sum([keras.backend.count_params(w) for w in model.non_trainable_weights])print("\n"+"="*70)print("MODEL PARAMETERS")print("="*70)print(f"Trainable parameters: {trainable_count:,}")print(f"Non-trainable parameters: {non_trainable_count:,}")print(f"Total parameters: {trainable_count + non_trainable_count:,}")print(f"Trainable ratio: {trainable_count/(trainable_count + non_trainable_count)*100:.2f}%")print("="*70)print_trainable_parameters(vgg16_tl)
Fine-tuning melibatkan unfreezing beberapa top layers dari base model dan melatihnya dengan learning rate rendah.
21.1 VGG16 Fine-tuning
21.1.1 Unfreeze Top Layers
def unfreeze_top_layers(model, base_model, num_layers_to_unfreeze=4):""" Unfreeze top N layers dari base model Parameters: model: complete model base_model: base model inside complete model num_layers_to_unfreeze: jumlah top layers yang di-unfreeze Returns: model: model dengan unfrozen layers """print(f"\nUnfreezing top {num_layers_to_unfreeze} layers...")# Freeze semua layers dulu base_model.trainable =True# Freeze semua kecuali top N layers total_layers =len(base_model.layers) freeze_until = total_layers - num_layers_to_unfreezefor layer in base_model.layers[:freeze_until]: layer.trainable =Falsefor layer in base_model.layers[freeze_until:]: layer.trainable =Trueprint(f"✓ Layers configuration:")print(f" Total base layers: {total_layers}")print(f" Frozen layers: {freeze_until}")print(f" Trainable layers: {num_layers_to_unfreeze}")# Print trainable layersprint(f"\n Trainable layers:")for i, layer inenumerate(base_model.layers[freeze_until:]):print(f" {freeze_until + i}: {layer.name}")return model# Load best VGG16 feature extraction modelvgg16_ft = keras.models.load_model(dirs['checkpoints'] /'vgg16_feature_extraction_best.h5')# Unfreeze top 4 layersvgg16_ft = unfreeze_top_layers(vgg16_ft, vgg16_ft.layers[0], num_layers_to_unfreeze=4)# Print parameters after unfreezingprint_trainable_parameters(vgg16_ft)
Grad-CAM (Gradient-weighted Class Activation Mapping) memvisualisasikan bagian mana dari gambar yang penting untuk prediksi.
def make_gradcam_heatmap(img_array, model, last_conv_layer_name, pred_index=None):""" Generate Grad-CAM heatmap Parameters: img_array: input image (preprocessed) model: trained model last_conv_layer_name: nama last convolutional layer pred_index: class index untuk visualisasi (None = predicted class) Returns: heatmap: Grad-CAM heatmap """# Create model that maps input to last conv layer dan predictions grad_model = keras.models.Model( [model.inputs], [model.get_layer(last_conv_layer_name).output, model.output] )# Compute gradientwith tf.GradientTape() as tape: conv_outputs, predictions = grad_model(img_array)if pred_index isNone: pred_index = tf.argmax(predictions[0]) class_channel = predictions[:, pred_index]# Gradient dari predicted class terhadap output feature map grads = tape.gradient(class_channel, conv_outputs)# Pooled gradients pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2))# Weighted combination conv_outputs = conv_outputs[0] heatmap = conv_outputs @ pooled_grads[..., tf.newaxis] heatmap = tf.squeeze(heatmap)# Normalize heatmap heatmap = tf.maximum(heatmap, 0) / tf.math.reduce_max(heatmap)return heatmap.numpy()def plot_gradcam(img, heatmap, alpha=0.4):""" Overlay Grad-CAM heatmap pada gambar original Parameters: img: original image heatmap: Grad-CAM heatmap alpha: transparency level Returns: superimposed_img: image dengan heatmap overlay """# Resize heatmap ke ukuran gambar heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))# Convert heatmap ke RGB heatmap = np.uint8(255* heatmap) heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)# Convert BGR to RGB heatmap = cv2.cvtColor(heatmap, cv2.COLOR_BGR2RGB)# Superimpose superimposed_img = heatmap * alpha + img *255 superimposed_img = np.clip(superimposed_img, 0, 255).astype('uint8')return superimposed_img# Visualisasi Grad-CAM untuk beberapa sampledef visualize_gradcam_samples(model, X_test, y_test, num_samples=6, last_conv_layer_name='conv5_block3_out', save_path=None):"""Visualisasi Grad-CAM untuk multiple samples"""# Random samples indices = np.random.choice(len(X_test), num_samples, replace=False) fig, axes = plt.subplots(num_samples, 3, figsize=(12, num_samples*3)) fig.suptitle('Grad-CAM Visualization', fontsize=16, fontweight='bold')for i, idx inenumerate(indices): img = X_test[idx] true_label = np.argmax(y_test[idx])# Get prediction img_array = np.expand_dims(img, axis=0) preds = model.predict(img_array, verbose=0) pred_label = np.argmax(preds[0]) pred_prob = preds[0][pred_label]# Generate Grad-CAMtry: heatmap = make_gradcam_heatmap(img_array, model, last_conv_layer_name) gradcam_img = plot_gradcam(img, heatmap)except:print(f"⚠ Grad-CAM failed for sample {i}, using placeholder") gradcam_img = img# Plot original axes[i, 0].imshow(img) axes[i, 0].set_title(f'Original\nTrue: {CLASS_NAMES[true_label]}', fontsize=10) axes[i, 0].axis('off')# Plot heatmap axes[i, 1].imshow(heatmap, cmap='jet') axes[i, 1].set_title(f'Heatmap', fontsize=10) axes[i, 1].axis('off')# Plot Grad-CAM overlay axes[i, 2].imshow(gradcam_img) axes[i, 2].set_title(f'Grad-CAM\nPred: {CLASS_NAMES[pred_label]} ({pred_prob:.2f})', fontsize=10) axes[i, 2].axis('off') plt.tight_layout()if save_path: plt.savefig(save_path, dpi=300, bbox_inches='tight')print(f"✓ Figure saved to: {save_path}") plt.show()# Visualize Grad-CAM untuk ResNet50 (ResNet has specific layer names)try:# Cari last conv layer name conv_layers = [layer.name for layer in resnet50_ft.layers[0].layersif'conv'in layer.name.lower()] last_conv_layer = conv_layers[-1] if conv_layers else'conv5_block3_out'print(f"Using last conv layer: {last_conv_layer}") visualize_gradcam_samples(resnet50_ft, X_test_norm, y_test_encoded, num_samples=6, last_conv_layer_name=last_conv_layer, save_path=dirs['figures'] /'gradcam_visualization.png')exceptExceptionas e:print(f"⚠ Grad-CAM visualization failed: {e}")print(" Skipping Grad-CAM visualization")
22.4 Feature Map Visualization
def visualize_feature_maps(model, img, layer_names, save_path=None):""" Visualisasi feature maps dari convolutional layers Parameters: model: trained model img: input image layer_names: list of layer names untuk visualisasi save_path: path untuk save figure """# Create model untuk extract feature maps layer_outputs = [model.get_layer(name).output for name in layer_names] activation_model = keras.models.Model(inputs=model.input, outputs=layer_outputs)# Get activations img_array = np.expand_dims(img, axis=0) activations = activation_model.predict(img_array, verbose=0)# Plot feature maps num_layers =len(layer_names) fig, axes = plt.subplots(num_layers +1, 8, figsize=(20, 2.5*(num_layers +1))) fig.suptitle('Feature Maps Visualization', fontsize=16, fontweight='bold')# Plot original imagefor j inrange(8): axes[0, j].imshow(img)if j ==0: axes[0, j].set_ylabel('Original', fontsize=10, fontweight='bold') axes[0, j].axis('off')# Plot feature maps untuk setiap layerfor i, (layer_name, activation) inenumerate(zip(layer_names, activations), 1): num_features =min(8, activation.shape[-1])for j inrange(8):if j < num_features: feature_map = activation[0, :, :, j] axes[i, j].imshow(feature_map, cmap='viridis')else: axes[i, j].axis('off')if j ==0: axes[i, j].set_ylabel(layer_name, fontsize=8, fontweight='bold') axes[i, j].set_xticks([]) axes[i, j].set_yticks([]) plt.tight_layout()if save_path: plt.savefig(save_path, dpi=300, bbox_inches='tight')print(f"✓ Figure saved to: {save_path}") plt.show()# Visualize feature maps dari Simple CNNtry: sample_idx = np.random.randint(0, len(X_test_norm)) sample_img = X_test_norm[sample_idx]# Select beberapa conv layers conv_layer_names = ['conv1', 'conv2', 'conv3'] visualize_feature_maps(simple_cnn, sample_img, conv_layer_names, save_path=dirs['figures'] /'feature_maps.png')exceptExceptionas e:print(f"⚠ Feature map visualization failed: {e}")
22.5 Final Model Comparison
# Compile all resultsall_models_comparison = {'Simple CNN': results_simple,'VGG-Style CNN': results_vgg,'VGG-Style (Aug)': results_vgg_aug,'VGG16 Feature Ext': results_vgg16_tl,'ResNet50 Feature Ext': results_resnet50_tl,'VGG16 Fine-tuned': results_vgg16_ft,'ResNet50 Fine-tuned': results_resnet50_ft,'VGG16 Progressive': results_vgg16_prog}# Add ensemble resultsall_models_comparison['Ensemble'] = [0.0, # Loss not directly available ensemble_accuracy,0.0# Top-3 not calculated]# Compare all modelscompare_models(all_models_comparison)
23 Kesimpulan
23.1 Ringkasan Pembelajaran
Pada lab ini, Anda telah mempelajari:
CNN Architecture: Membangun CNN dari scratch dengan berbagai kompleksitas
Data Augmentation: Meningkatkan generalisasi dengan augmentasi data
Transfer Learning: Memanfaatkan pre-trained models (VGG16, ResNet50)
Fine-tuning: Mengoptimalkan pre-trained models untuk task spesifik
Advanced Techniques: Ensemble, Grad-CAM, dan visualisasi
Model Comparison: Membandingkan berbagai pendekatan
23.2 Key Takeaways
print("="*70)print("KEY TAKEAWAYS - CIFAR-10 IMAGE CLASSIFICATION")print("="*70)print("""1. CNN ARCHITECTURE: - Simple CNN bisa achieve ~70-75% accuracy - Deeper networks (VGG-style) improve ke ~78-82% - Batch normalization dan dropout penting untuk regularization2. DATA AUGMENTATION: - Meningkatkan accuracy ~3-5% - Membantu model generalize better - Essential untuk dataset kecil-medium3. TRANSFER LEARNING: - Feature extraction: ~80-85% accuracy dengan training minimal - Pre-trained models sudah punya feature detectors yang bagus - Jauh lebih cepat daripada training from scratch4. FINE-TUNING: - Meningkatkan accuracy ~2-5% dari feature extraction - Butuh learning rate yang lebih kecil - Progressive unfreezing lebih stable5. ENSEMBLE: - Combining models bisa boost accuracy 1-3% - Trade-off: lebih akurat tapi lebih lambat - Best untuk production systems6. BEST PRACTICES: - Start simple, iterate gradually - Always use validation set - Monitor overfitting - Save best models - Visualize to understand""")print("="*70)
23.3 Saran Eksperimen Lanjutan
Beberapa eksperimen yang bisa Anda coba:
Architecture Variations:
Coba EfficientNet, DenseNet, atau MobileNet
Experiment dengan different layer configurations
Try different activation functions (Swish, GELU)
Regularization Techniques:
L1/L2 regularization
Different dropout rates
Cutout/Mixup augmentation
Optimization:
Different optimizers (SGD with momentum, AdamW)
Learning rate schedules (cosine annealing)
Batch size effects
Advanced Transfer Learning:
Multi-stage fine-tuning
Knowledge distillation
Meta-learning approaches
23.4 Referensi
Krizhevsky, A. (2009). Learning Multiple Layers of Features from Tiny Images
Simonyan, K., & Zisserman, A. (2014). Very Deep Convolutional Networks (VGG)
He, K., et al. (2016). Deep Residual Learning for Image Recognition (ResNet)
Selvaraju, R. R., et al. (2017). Grad-CAM: Visual Explanations from Deep Networks
24 Submission Guidelines
24.1 Deliverables
Kumpulkan file-file berikut:
Notebook (.ipynb atau .qmd)
Trained Models (best checkpoints)
Figures (semua visualisasi)
Report (PDF, maksimal 10 halaman) berisi:
Ringkasan eksperimen
Hasil setiap model
Analisis perbandingan
Insights dan kesimpulan
24.2 Grading Rubric
Lihat file rubric.md untuk detail penilaian.
Total Points: 100 + 10 Bonus
Part 1: Data Exploration (15 points)
Part 2: CNN from Scratch (25 points)
Part 3: Transfer Learning - Feature Extraction (25 points)