Membangun Model Neural Network dengan PyTorch

Membangun Model Neural Network dengan PyTorch

PyTorch adalah salah satu pustaka neural network khususnya deep learning yang sangat populer dan banyak digunakan saat ini. Salah satu alasan utama di balik popularitas PyTorch adalah kemudahannya dalam mengelola tensor, yang merupakan struktur data utama dalam jaringan neural. Selain itu, PyTorch juga dikenal dengan sifatnya yang lebih “pythonic”, yang membuat kode lebih mudah dibaca dan ditulis, serta lebih mudah di-debug dibandingkan dengan beberapa pustaka lainnya.

PyTorch menawarkan dua tingkat API untuk memenuhi berbagai kebutuhan pengembang. Pertama, API tingkat rendah (low-level API) yang memungkinkan pengguna untuk membangun dan melatih model neural network dari komponen-komponen dasar. Kedua, API tingkat tinggi berbasis objek yang dirancang untuk memudahkan pengembangan dan pemeliharaan model. Dengan API tingkat tinggi ini, pengembang dapat dengan cepat membuat prototipe dan mengimplementasikan model tanpa harus menulis banyak kode yang berulang. Kombinasi fleksibilitas dan kemudahan penggunaan ini menjadikan PyTorch pilihan favorit bagi banyak peneliti dan praktisi di bidang deep learning.

Dalam tutorial ini, kita akan membahas cara membangun, melatih, dan menyimpan model neural network menggunakan PyTorch. Langkah-langkahnya akan mencakup memuat dan memproses data, membangun arsitektur model, melatih model, menyimpan serta memuat kembali model yang telah dilatih. Selain itu, kita juga akan melihat bagaimana cara menggunakan model yang telah dilatih tersebut untuk memprediksi data baru. Tutorial ini diharapkan memberikan wawasan baru tentang bagaimana menggunakan PyTorch untuk pemodelan neural network.

Instalasi Pytroch

Untuk mulai menggunakan PyTorch, kita perlu menginstalnya terlebih dahulu menggunakan pip atau pake manager lainnya. Jika perangkat yang digunakan mendukung GPU maka dapat menginstal cudatoolkit (misal versi 11.8) dengan menambahkan --index-url https://download.pytorch.org/whl/cu118. Namun jika hanya menggunakan CPU bagian tersebut dapat dihilangkan.

pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

Selain menggunakan pip, terdapat beberapa pilihan untuk instalasi PyTorch yaitu dengan conda, LibTorch maupun langsung dari source code-nya. Tata cara instalasi dapat dilihat selengkapnya pada link berikut: https://pytorch.org/get-started/locally/

Untuk pembelajaran, dapat juga menggunakan layanan cloud gratis seperti Google Colab atau Kaggle. Pada kedua layanan tersebut, hampir setiap pustaka penting untuk deep learning sudah tersedia secara default sehingga langkah ini dapat dilewati. Selain itu kedua layanan juga mendukung penggunaan GPU secara gratis yang dapat mempercepat pelatihan model neural network secara signifikan.

Penyiapan Pustaka

Jika seluruhnya sudah terinstal, muat pustaka dan modul-modul yang diperlukan untuk membangun dan melatih model neural network menggunakan PyTorch. Dari modul torch, impor torch, torch.nn, dan torch.optim yang digunakan untuk membangun model, mendefinisikan layer, dan proses pelatihan model. torch.utils.data digunakan untuk membuat DataLoader, yang mempermudah iterasi melalui dataset selama pelatihan.

Pustaka lainnya yang juga diperlukan yaitu pandas untuk memuat dan memproses data, sklearn untuk membagi dataset, normalisasi data, encoding peubah respon dan menghitung nilai akurasi serta joblib untuk menyimpan objek python.

Pada bagian ini sekaligus kita menentukan device pengolahan tensor apakah menggunakan GPU atau CPU. Namun jika perangkat tidak mendukung GPU maka dapat diabaikan karena secara otomatis PyTorch akan menggunakan CPU.

Python

import torch
import torch.nn as nn
import torch.optim as optim
import pandas as pd
import joblib
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler, LabelEncoder
from sklearn.metrics import accuracy_score, confusion_matrix
from torch.utils.data import DataLoader, TensorDataset

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

print(f'Using device: {device}')
# OUTPUT

Using device: cuda

Penyiapan Data

Dataset yang digunakan untuk tutorial ini adalah Wine Quality Multiclass. Dataset terdiri dari 1.143 observasi dengan 11 fitur yang keseluruhannya bertipe numerik. Kelas respon pada dataset adalah quality yang terdiri dari 3 kategori yaitu (LOW, STANDARD dan HIGH).

Setelah data dimuat, data dibagi menjadi data latih dan data uji. Pembagian data dilakukan dengan fungsi train_test_split dari modul sklearn.model_selection, dengan komposisi data latih sebesar 80% dan data uji 20%. Berikutnya, lakukan normalisasi data numerik menggunakan fungsi MinMaxScaler. Dalam penggunaan fungsi ini, praktik yang baik adalah melakukan proses normalisasi berdasarkan nilai-nilai data latih saja. Adapun transformasi data uji dilakukan menggunakan objek scaler hasil data latih tersebut. Teknik ini dilakukan untuk menghindari terjadinya data leakage dalam proses pelatihan model nantinya.

Kita juga perlu mentransformasi label kelas respon menjadi numerik, dikarenakan nilainya pada dataset masih berupa kategorik (LOW, STANDARD dan HIGH. Proses transformasi dapat dilakukan dengan fungsi LabelEncoder dengan cara yang sama seperti saat melakukan normalisasi fitur.

Agar dapat diproses menggunakan PyTorch, seluruh data perlu dikonversi menjadi tensor dengan tipe data yang sesuai, yaitu torch.float32 untuk data fitur (X) dan torch.long untuk data label (y). Selanjutnya, gunakan DataLoader untuk membagi data menjadi batch-batch yang lebih kecil, sehingga iterasi melalui dataset menjadi lebih efisien selama pelatihan dan pengujian model. Pembagian ini berguna khususnya ketika data yang digunakan sangat besar seperti gambar atau video. Selain itu, pada data pelatihan kita dapat mengacak urutan data (shuffle=True) untuk memastikan bahwa model tidak belajar urutan tertentu dalam data, yang dapat membantu meningkatkan kemampuan generalisasi model.

Python

# Membaca dataset
url = "https://raw.githubusercontent.com/sainsdataid/dataset/main/wine-quality-multiclass.csv"
data = pd.read_csv(url)

# Pisahkan fitur dan label
X = data.drop("quality", axis=1).values
y = data["quality"].values

# Pisahkan data menjadi train dan test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Normalisasi fitur
scaler = MinMaxScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

# Encode label menjadi numerik
label_encoder = LabelEncoder()
y_train = label_encoder.fit_transform(y_train)
y_test =  label_encoder.transform(y_test)

# Konversi data ke tensor PyTorch
X_train = torch.tensor(X_train, dtype=torch.float32)
X_test = torch.tensor(X_test, dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.long)
y_test = torch.tensor(y_test, dtype=torch.long)

# Buat DataLoader
train_dataset = TensorDataset(X_train, y_train)
test_dataset = TensorDataset(X_test, y_test)

train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)

Arsitektur Model

Pada tahapan ini, buat kelas turunan dari kelas nn.Module misalnya dengan nama WineQualityModel. Terdapat setidaknya 2 metode yang perlu didefinisikan yaitu __init__ dan forward.

Metode __init__ mendefinisikan arsitektur model neural network. Model yang kita buat terdiri dari tiga fully connected layer. Layer pertama (self.fc1) menerima 11 fitur input dan menghasilkan 128 neuron output. Layer kedua (self.fc2) menerima 128 input dari layer sebelumnya dan menghasilkan 64 neuron output. Terakhir yaitu layer ketiga (self.fc3) sebagai output layer, menerima 64 input dan menghasilkan 3 output yang sesuai dengan jumlah kelas dalam tugas klasifikasi ini.

Metode forward mendefinisikan aliran data melalui jaringan neural. Input x pertama-tama melewati layer pertama (fc1) dan diaktifkan menggunakan fungsi ReLU (torch.relu). Hasil ini kemudian diteruskan ke layer kedua (fc2) dan diaktifkan kembali dengan ReLU. Terakhir, output dari layer kedua diteruskan ke layer ketiga (fc3) yang menghasilkan prediksi akhir tanpa aktivasi tambahan karena nantinya kita akan menggunakan loss function Cross Entropy (nn.CrossEntropyLoss). Loss function ini secara otomatis akan menghasilkan nilai probabilitas untuk masing-masing kelas.

Kita dapat menambahkan lebih banyak hidden layer lainnya jika diperlukan. Namun, perlu diperhatikan bahwa jumlah neuron input pada suatu layer harus sama dengan jumlah neuron output dari layer sebelumnya.

Python

class WineQualityModel(nn.Module):
    def __init__(self):
        super(WineQualityModel, self).__init__()
        self.fc1 = nn.Linear(11, 128)  # Input layer dengan 11 fitur, output 128 neuron
        self.fc2 = nn.Linear(128, 64)  # Hidden layer dengan 128 input dan 64 output neuron
        self.fc3 = nn.Linear(64, 3)    # Output layer dengan 64 input dan 3 output neuron (3 kelas)

    def forward(self, x):
        x = torch.relu(self.fc1(x))  # Aktivasi ReLU setelah lapisan pertama
        x = torch.relu(self.fc2(x))  # Aktivasi ReLU setelah lapisan kedua
        x = self.fc3(x)              # Output layer (tanpa aktivasi)
        return x

Pelatihan Model

Setelah kelas model didefinisikan, buat objek model menggunakan kelas tersebut. Kita juga perlu menginisiasi loss function dan optimizer yang akan digunakan. Untuk model klasifikasi multikelas dengan PyTorch,loss function yang digunakan adalah nn.CrossEntropyLoss. Fungsi ini menggabungkan nn.LogSoftmax dan nn.NLLLoss (Negative Log Likelihood Loss) dalam satu langkah untuk menghitung loss antara prediksi model dan kelas aslinya.

Optimizer yang akan kita gunakan pada contoh ini adalah Adam. Optimizer adam adalah salah satu optimizer yang paling populer dan banyak digunakan dalam pembelajaran mesin dan deep learning saat ini. Selain Adam terdapat berbagai algoritma optimasi yang dapat digunakan seperti SGD, RMSProp dan sebagainya. Silahkan mengeksplorasi berbagai optimizer tersebut untuk membandingkan hasilnya.

Langkah selanjutnya adalah melakukan pelatihan model. Pelatihan model neural network dilakukan sebanyak iterasi tertentu yang disebut epoch. Satu epoch berarti satu kali iterasi penuh melalui seluruh dataset pelatihan. Selama satu epoch, model melakukan forward pass dan backward pass untuk setiap sampel dalam dataset. Jika dataset sangat besar, sering kali tidak praktis untuk memproses seluruh dataset sekaligus, sehingga dataset dibagi menjadi batch-batch yang lebih kecil. Dalam konteks ini 1 epoch menunjukkan proses pelatihan lengkap pada keseluruhan batch tersebut.

Python

model = WineQualityModel()                            # inisiasi Model

print(model, "\n")

criterion = nn.CrossEntropyLoss()                     # inisiasi loss function
optimizer = optim.Adam(model.parameters(), lr=0.003)  # inisiasi optimizer (adam)

n_epochs = 100                             # jumlah epoch

for epoch in range(num_epochs):
    model.train()                          # Set model ke mode pelatihan
    running_loss = 0.0                     # Inisialisasi running loss untuk akumulasi loss setiap epoch
    
    for inputs, labels in train_loader: 
        optimizer.zero_grad()              # Reset gradient optimizer
        outputs = model(inputs)            # Forward pass: hitung prediksi model
        loss = criterion(outputs, labels)  # Hitung loss antara prediksi dan label sebenarnya
        
        loss.backward()                    # Backward pass: hitung gradient loss terhadap parameter model
        optimizer.step()                   # Update parameter model menggunakan gradient
        
        running_loss += loss.item()        # Akumulasi nilai loss

    
    # Cetak nilai rata-rata loss (misal setiap 10 epoch)
    if (epoch + 1) % 10 == 0:    
        print(f"Epoch {epoch+1}/{n_epochs}, Loss: {running_loss/len(train_loader)}")
# OUTPUT

WineQualityModel(
  (fc1): Linear(in_features=11, out_features=128, bias=True)
  (fc2): Linear(in_features=128, out_features=64, bias=True)
  (fc3): Linear(in_features=64, out_features=3, bias=True)
)

Epoch 10/100,  Loss: 0.7406906403344253
Epoch 20/100,  Loss: 0.6883006136992882
Epoch 30/100,  Loss: 0.6507052142044594
Epoch 40/100,  Loss: 0.6076385563817518
Epoch 50/100,  Loss: 0.5549306951720139
Epoch 60/100,  Loss: 0.5403578425275868
Epoch 70/100,  Loss: 0.4850634418684861
Epoch 80/100,  Loss: 0.4302411721698169
Epoch 90/100,  Loss: 0.38807110745331336
Epoch 100/100, Loss: 0.3351901502444826

Evaluasi Model

Evaluasi model dilakukan dengan menilai kinerja model dalam memprediksi data uji misalkan menggunakan metrik akurasi. Untuk memprediksi data uji, pertama kita atur model ke dalam mode evaluasi menggunakan metode eval dari objek model tersebut. Berikutnya, kita gunakan torch.no_grad() untuk menonaktifkan penghitungan gradien selama evaluasi. Hal ini mengurangi penggunaan memori serta meningkatkan kecepatan komputasi karena kita tidak perlu menyimpan informasi gradien.

Untuk memudahkan penghitungan kinerja model, kita dapat menggunakan fungsi accuracy_score dari modul sklearn.metrics. Dari modul yang sama, terdapat berbagai metrik lainnya seperti precision, recall, f1-score dan lainnya jika diperlukan. Di sini, kita juga akan menampilkan confusion matrix menggunakan fungsi confusion_matrix.

Python

model.eval()                                     # set model ke dalam mode evaluasi

true_labels, preds = [], []

with torch.no_grad():                             # nonaktifkan penghitungan gradient
    for inputs, labels in test_loader:            # iterasi data uji
        outputs = model(inputs)                   # Forward pass: hitung prediksi model
        _, predicted = torch.max(outputs, 1)      # tentukan prediksi kelas (probabilitas tertinggi)
        true_labels.extend(labels.cpu().numpy())  # simpan label sebenarnya
        preds.extend(predicted.cpu().numpy())     # Simpan prediksi

        
accuracy = accuracy_score(true_labels, preds)     # menghitung akurasi
print(f"Accuracy: {accuracy}")

cm = confusion_matrix(true_labels, preds)         # menghitung confusion matrix
print(f"\nConfusion Matrix:\n {cm}")
# OUTPUT

Accuracy: 0.6681222707423581

Confusion Matrix:
 [[18  3  7]
  [ 1 88 13]
  [10 42 47]]

Persistensi Model

Setelah pelatihan selesai, kita dapat menyimpan model menggunakan torch.save untuk menyimpan state dictionary dari model. Model yang sudah disimpan selanjutnya dapat kita gunakan lagi untuk melakukan prediksi data baru tanpa perlu melakukan pelatihan ulang. Namun demikian, tidak menutup kemungkinan model tersebut dilatih dilatih kembali, misal dengan penambahan epoch ataupun penambahan data pelatihan baru. Namun tentunya pelatihan tidak perlu dilakukan dari awal, karena pada model tersebut tersimpan informasi berbagai informasi terakhir dari model.

Sebagai tambahan, karena data yang digunakan sebelum pelatihan telah dilakukan preprocessing berupa normalisasi data. Ada baiknya kita juga menyimpan objek scaler yang digunakan untuk normalisasi tersebut, agar nantinya dapat digunakan kembali ketika memprediksi data baru. Untuk menyimpan objek seperti ini, kita dapat menggunakan fungsi dump dari pustaka joblib.

Python

preprocs = (scaler, label_encoder)

# menyimpan scaler dan label encoder
joblib.dump(preprocs, "preprocs.pkl")

# menyimpan model
torch.save(model, "wine_quality_model.pth")   


# memuat scaler dan label encoder
scaler, label_encoder = joblib.load("preprocs.pkl")

# memuat model
my_model = torch.load("wine_quality_model.pth")

print(my_model)
WineQualityModel(
  (fc1): Linear(in_features=11, out_features=256, bias=True)
  (fc2): Linear(in_features=256, out_features=128, bias=True)
  (fc3): Linear(in_features=128, out_features=3, bias=True)
)

Prediksi Data Baru

Misalkan kita memiliki data baru sebagai berikut:

Python

# contoh data baru
new_data = pd.DataFrame(
    {
        "fixed acidity": [8.1, 7.94],
        "volatile acidity": [0.46, 0.48],
        "citric acid": [0.32, 0.28],
        "residual sugar": [3.4, 2.6],
        "chlorides": [0.065, 0.081],
        "free sulfur dioxide": [15.7, 14.7],
        "total sulfur dioxide": [52.24, 38.85],
        "density": [0.99, 0.98],
        "pH": [3.2, 3.4],
        "sulphates": [0.82, 0.70],
        "alcohol": [8.4, 11.0],
    }
)

print(new_data.transpose())
# OUTPUT

                           0       1
fixed acidity          8.100   7.940
volatile acidity       0.460   0.480
citric acid            0.320   0.280
residual sugar         3.400   2.600
chlorides              0.065   0.081
free sulfur dioxide   15.700  14.700
total sulfur dioxide  52.240  38.850
density                0.990   0.980
pH                     3.200   3.400
sulphates              0.820   0.700
alcohol                8.400  11.000

Untuk dapat memprediksi kualitas wine dari data tersebut lakukan langkah-langkah pada kode di bawah ini. Pertama muat model dan file untuk tahapan preprocessing data. Setelah itu, lakukan tahapan preprocessing (normalisasi) pada data dan konversi hasilnya data ke dalam bentuk tensor. Jika menggunakan GPU, maka kita dapat juga memindahkan data agar diproses pada GPU. Selanjutnya atur model ke dalam mode evaluasi dan lakukan prediksi.

Python

# memuat scaler dan label encoder
scaler, label_encoder = joblib.load("preprocs.pkl")

# memuat model
my_model = torch.load("wine_quality_model.pth")

# Terapkan scaler pada data baru
new_data_scaled = scaler.transform(new_data.to_numpy())

# Konversi data baru ke tensor
new_data_tensor = torch.tensor(new_data_scaled, dtype=torch.float32)

# Pindahkan tensor ke perangkat yang sesuai jika menggunakan GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

new_data_tensor = new_data_tensor.to(device)

my_model.to(device)

my_model.eval()

with torch.no_grad():
    output = my_model(new_data_tensor)            # Forward pass: hitung prediksi model
    _, predicted_class = torch.max(output, 1)     # tentukan prediksi kelas (probabilitas tertinggi)

predicted_class = predicted_class.cpu().numpy()                    # output dalam bentuk numerik
predicted_label = label_encoder.inverse_transform(predicted_class) # mendapatkan label kelas

print(f"Prediksi: {predicted_label}")
# OUTPUT

Predisi: ['LOW' 'STANDARD']

Selamat mencoba!

Tulisan Lainnya

You may also like...

Daftar Isi