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!