Memahami Apa yang Dipelajari oleh Lapisan Konvolusi

Dalam dunia deep learning, memahami apa yang dipelajari oleh model konvolusi (ConvNet) sangat penting untuk memastikan model tidak hanya akurat tetapi juga dapat diinterpretasikan. Dua teknik yang sering digunakan untuk tujuan ini adalah visualisasi intermediate activation dan Grad-CAM (Gradient-weighted Class Activation Mapping). Dalam artikel ini, kita akan membahas kedua teknik tersebut dan menerapkannya pada model ResNet-101 yang telah dilatih sebelumnya. Gambar yang akan kita gunakan untuk visualisasi adalah gambar lubang jalan.

Pendahuluan

Model konvolusi seperti ResNet-101 telah mencapai hasil yang luar biasa dalam berbagai tugas pengenalan gambar. Namun, model ini sering dianggap sebagai "kotak hitam" karena kompleksitasnya yang tinggi. Untuk mengatasi masalah ini, kita dapat menggunakan teknik visualisasi seperti intermediate activation dan Grad-CAM untuk memahami bagaimana model memproses gambar dan bagian mana dari gambar yang paling mempengaruhi prediksi model.

Intermediate Activation

Intermediate activation adalah teknik yang digunakan untuk mengekstrak dan memvisualisasikan keluaran dari lapisan-lapisan tertentu di dalam jaringan konvolusi. Teknik ini membantu kita memahami bagaimana gambar diproses pada berbagai tahap dalam jaringan.

Mengapa Intermediate Activation Penting?

  1. Memahami Fitur yang Dipelajari: Dengan melihat bagaimana gambar diproses oleh setiap lapisan, kita bisa memahami jenis fitur apa yang dipelajari oleh model pada tiap tahap.

  2. Debugging Model: Jika model tidak bekerja sebagaimana mestinya, visualisasi ini dapat membantu dalam mengidentifikasi di mana masalahnya terjadi.

  3. Transparansi Model: Ini memberikan wawasan tentang bagaimana model membuat keputusan, yang sangat penting untuk aplikasi-aplikasi yang memerlukan tingkat transparansi tinggi seperti bidang medis dan otomotif.

Implementasi Intermediate Activation

Berikut adalah langkah-langkah untuk mengimplementasikan visualisasi intermediate activation pada model ResNet-101 menggunakan PyTorch.

import torch
import torchvision.models as models
import torchvision.transforms as transforms
from PIL import Image
import matplotlib.pyplot as plt

# Memuat model ResNet-101 yang telah dilatih sebelumnya
model = models.resnet101(pretrained=True)
model.eval()  # Mengatur model ke mode evaluasi

# Mendefinisikan transformasi untuk mengubah gambar menjadi tensor dan menormalkannya
transform = transforms.Compose([
    transforms.Resize((224, 224)),  # Mengubah ukuran gambar menjadi 224x224 piksel
    transforms.ToTensor(),  # Mengubah gambar menjadi tensor
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])  # Menormalkan tensor
])

# Memuat gambar contoh dan menerapkan transformasi
img = Image.open("/path/to/your/image.jpg")
img_t = transform(img)  # Menerapkan transformasi pada gambar
img_t = img_t.unsqueeze(0)  # Menambahkan dimensi batch

# Fungsi untuk mendapatkan aktivasi intermediate
def get_activations(layer, x):
    """
    Mengambil aktivasi intermediate dari lapisan tertentu.

    Args:
        layer (torch.nn.Module): Lapisan dari mana aktivasi akan diambil.
        x (torch.Tensor): Tensor input.

    Returns:
        torch.Tensor: Aktivasi dari lapisan tersebut.
    """
    activations = []  # List untuk menyimpan aktivasi
    def hook_fn(module, input, output):
        activations.append(output)  # Menambahkan output (aktivasi) ke list
    handle = layer.register_forward_hook(hook_fn)  # Mendaftarkan hook untuk mendapatkan aktivasi
    model(x)
    handle.remove()  # Menghapus hook setelah mendapatkan aktivasi
    return activations[0]

# Memilih beberapa lapisan untuk divisualisasikan
layers = [model.layer1[0].conv1, model.layer2[0].conv1, model.layer3[0].conv1, model.layer4[0].conv1]
activations = [get_activations(layer, img_t) for layer in layers]  # Mendapatkan aktivasi dari lapisan-lapisan tersebut

# Memvisualisasikan aktivasi
fig, axes = plt.subplots(len(layers), 1, figsize=(12, 24))
for i, activation in enumerate(activations):
    activation = activation.squeeze(0).detach().numpy()  # Menghilangkan dimensi batch dan mengubah ke numpy array
    ax = axes[i]
    ax.imshow(activation.mean(axis=0), cmap='viridis')  # Menampilkan rata-rata aktivasi dengan colormap 'viridis'
    ax.axis('off')  # Menonaktifkan sumbu
    ax.set_title(f'Layer {i+1} Activation')  # Menambahkan judul pada plot
plt.show()  # Menampilkan plot

Berikut adalah hasil visualisasi intermediate activation pada lapisan-lapisan yang berbeda di ResNet-101:

Grad-CAM

Grad-CAM adalah teknik yang digunakan untuk menghasilkan peta panas (heatmap) yang menunjukkan area-area dalam gambar yang paling mempengaruhi prediksi akhir dari model. Grad-CAM bekerja dengan menghitung gradien dari kelas target terhadap keluaran dari lapisan konvolusi terakhir. Gradien ini kemudian digunakan untuk membobot aktivasi lapisan tersebut, menghasilkan peta aktivasi yang terfokus pada fitur-fitur penting.

Mengapa Grad-CAM Penting?

  1. Interprestabilitas Model: Grad-CAM membantu dalam mengidentifikasi bagian mana dari gambar yang dianggap penting oleh model untuk membuat prediksi tertentu, meningkatkan kepercayaan pengguna terhadap model.

  2. Diagnostik Model: Dengan mengetahui bagian mana dari gambar yang paling mempengaruhi prediksi, kita dapat mengidentifikasi apakah model benar-benar melihat fitur yang relevan atau hanya fitur-fitur spurious yang tidak penting.

  3. Pengawasan dan Validasi: Dalam banyak aplikasi kritis, seperti diagnosis medis, penting untuk memverifikasi bahwa model membuat keputusan berdasarkan fitur yang tepat, bukan artefak yang tidak relevan.

Implementasi Grad-CAM

Berikut adalah langkah-langkah untuk mengimplementasikan Grad-CAM pada model ResNet-101 menggunakan PyTorch.

import torch.nn.functional as F
import cv2
import numpy as np

# Fungsi untuk mendapatkan peta aktivasi kelas (CAM)
def get_cam(model, img_tensor, target_class):
    """
    Menghasilkan peta aktivasi kelas (CAM) untuk kelas target yang ditentukan.

    Args:
        model (torch.nn.Module): Model yang digunakan untuk inferensi.
        img_tensor (torch.Tensor): Tensor gambar input.
        target_class (int): Indeks kelas target untuk menghasilkan CAM.

    Returns:
        np.ndarray: Peta aktivasi kelas (heatmap).
    """
    final_conv_layer = model.layer4[2].conv3  # Mendapatkan lapisan konvolusi terakhir
    activations = get_activations(final_conv_layer, img_tensor)  # Mendapatkan aktivasi dari lapisan tersebut

    output = model(img_tensor)  # Melakukan forward pass pada model dengan gambar input
    model.zero_grad()  # Mengatur gradien menjadi nol
    target = torch.zeros(output.shape)  # Membuat tensor target dengan bentuk yang sama dengan output model
    target[0][target_class] = 1  # Menentukan target untuk kelas spesifik
    output.backward(gradient=target)  # Melakukan backward pass untuk menghitung gradien

    gradients = final_conv_layer.weight.grad  # Mendapatkan gradien dari lapisan konvolusi terakhir
    pooled_gradients = torch.mean(gradients, dim=[0, 2, 3])  # Mengambil rata-rata gradien
    activations = activations.squeeze(0).detach()  # Menghilangkan dimensi batch dan detach dari komputasi graf

    for i in range(512):  # Mengalikan setiap aktivasi dengan gradien yang dipool
        activations[i, :, :] *= pooled_gradients[i]

    heatmap = torch.mean(activations, dim=0).cpu()  # Mengambil rata-rata dari semua aktivasi untuk membuat heatmap
    heatmap = np.maximum(heatmap, 0)  # Menerapkan ReLU pada heatmap
    heatmap /= torch.max(heatmap)  # Menormalkan heatmap
    return heatmap  # Mengembalikan heatmap

# Mendapatkan kelas yang diprediksi
output = model(img_t)  # Melakukan forward pass pada model dengan gambar input
_, pred = torch.max(output, 1)  # Mendapatkan indeks kelas dengan probabilitas tertinggi

# Mendapatkan peta aktivasi kelas (CAM)
heatmap = get_cam(model, img_t, pred.item())  # Menghasilkan heatmap untuk kelas yang diprediksi

# Menumpangkan heatmap pada gambar asli
heatmap = heatmap.numpy()  # Mengubah heatmap menjadi numpy array
heatmap = cv2.resize(heatmap, (img.size[0], img.size[1]))  # Mengubah ukuran heatmap agar sesuai dengan gambar asli
heatmap = np.uint8(255 * heatmap)  # Mengubah heatmap ke uint8
heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)  # Menerapkan colormap JET pada heatmap

img = cv2.imread("/path/to/your/image.jpg")  # Membaca gambar asli
superimposed_img = heatmap * 0.4 + img

  # Menumpangkan heatmap pada gambar asli dengan bobot 0.4
cv2.imwrite('cam.jpg', superimposed_img)  # Menyimpan gambar hasil tumpangan
# Menampilkan gambar hasil tumpangan
cv2_imshow(superimposed_img)  # Menampilkan gambar di Google Colab

Berikut adalah hasil visualisasi Grad-CAM yang menunjukkan area penting pada gambar yang mempengaruhi prediksi model:

Visualisasi Filter Konvolusi

Selain intermediate activation dan Grad-CAM, penting juga untuk melihat filter yang dipelajari oleh lapisan pertama dari model konvolusi. Filter ini menangkap fitur-fitur dasar seperti tepi dan tekstur.

Implementasi Visualisasi Filter

# Mendapatkan bobot dari lapisan konvolusi pertama
filters = model.conv1.weight.data
filters = filters - filters.min()  # Menormalkan filter ke rentang [0, 1]
filters = filters / filters.max()

# Memvisualisasikan filter
fig, axes = plt.subplots(8, 8, figsize=(12, 12))  # Membuat grid plot 8x8
for i, ax in enumerate(axes.flat):
    if i < filters.size(0):  # Memastikan indeks tidak melebihi jumlah filter
        ax.imshow(filters[i].permute(1, 2, 0))  # Memutar dimensi filter untuk plotting
    ax.axis('off')  # Menonaktifkan sumbu
plt.show()  # Menampilkan plot

Berikut adalah hasil visualisasi filter konvolusi dari lapisan pertama model:

Kesimpulan

Visualisasi intermediate activation, Grad-CAM, dan filter konvolusi adalah alat yang sangat berguna untuk memahami apa yang dipelajari oleh model konvolusi seperti ResNet-101. Dengan menggunakan teknik-teknik ini, kita dapat memastikan model bekerja sebagaimana mestinya dan membuat keputusan berdasarkan fitur yang relevan. Ini sangat penting dalam aplikasi-aplikasi yang memerlukan transparansi dan interpretabilitas tinggi, seperti diagnosis medis dan pengenalan gambar otonom.

Dengan alat-alat ini, kita dapat lebih percaya diri dalam menggunakan model deep learning untuk berbagai tugas kompleks dan memastikan model tidak hanya akurat tetapi juga dapat diinterpretasikan dengan baik.