Siri Belajar AI : Mari Kita Kenal Jaringan Neural Berturut (Recurrent Neural Network) Bahagian 2
Maaf sebab dah lama tak buat sebarang hantaran. Rasanya macam sebulan juga tak buat sebarang tutorial mahupun artikel berkenaan AI. Ada urusan kerja dan urusan hidup yang perlu diselesaikan. Alhamdulillah, sekarang ada masa lapang dan sedikit ketenangan. Maka sangatlah sesuai untuk kita gunakan masa ini untuk menyambung siri belajar AI kita. Hari ini kita akan sambung mengenali jaringan neural berturut.
alam siri yang lepas, kita sudahpun mengenali apa itu jaringan neural berturut. Kita dah tahu kenapa perlu ada jaringan neural berturut, kita dah tahu apa kaitannya jaringan neurla berturut, dan juga mengenali matematik di sebaliknya. Dan kita juga berjaya membina satu jaringan neural berturut sendiri dari kosong, dengan hanya menggunakan python dan persamaan matematik yang kita telah pelajari. Kita gunakan jaringan neural berturut ini untuk meramalkan urutan nombor 3,6,9,12…dan memintanya untuk meramalkan nombor yang seterusnya. Namun begitu, ia gagal untuk melakukan perkara tersebut. Ini kerana, jaringan neural berturut belum lagi dilatih.
Seperti yang kita telah pelajari dalam asas jaringan neural, kita memerlukan algoritma backpropagation. Tetapi untuk jaringan neural berturut, kita ada algoritma backpropagation yang khusus. Ia dipanggil sebagai backpropagation through time.
Backpropagation Through Time (Penyebaran Melewati Langkah Masa)
Seperti yang dah dijelaskan dalam siri-siri yang lepas, kita mulakan algoritma backpropagation dengan fungsi kehilangan, ataupun loss function, seperti di bawah:
di mana Lt ialah kerugian pada langkah masa t.
Fungsi kehilangan di atas boleh digunakan untuk memperkemaskinikan nilai pemberat dan bias yang kita bentuk dalam siri yang lepas. Fungsi kehilangan ini akan melalui proses pembezaan (derivative) yang berterusan dengan objektif untuk mengurangkan nilai fungsi kehilangan tersebut. Jadi secara teori, dengan cara ini kita akan jumpa nilai pemberat dan bias yang sesuai untuk corak urutan yang kita latih tadi. Di bawah ini adalah fungsi perbezaan yang kita pakai untuk memperkemakinikan nilai pemberat dan bias dalam jaringan neural berturut.
Masalah pada RNN
Tapi para pembaca perlu ingat. Nilai ht yang kita letak dalam persamaan di atas bergantung kepada semua keadaan tersembunyi sebelumnya ,maka kerana itulah kita perlu mengira:
Disebabkan RNN menyimpan semua parameter yang datang dari langkah masa sebelumnya (termasuklah nilai gradient yang terhasil dari proses pembezaan (derivative)) maka ia boleh menghasilkan rantaian masalah yang besar. Rantaian masalah ini kita panggil sebagai vanishing and exploding gradient (gradient menghilang dan meletup)
Untuk memahami dengan lebih baik bagaimana vanishing dan exploding gradient boleh berlaku, mari kita cuba untuk demonstrasikan menggunakan kod.
Mari kita simulasikan bagaimana gradien menghilang dan meletup berlaku. kita mulakan dengan gradien menghilang dahulu
import matplotlib.pyplot as plt
# kita buat satu persamaan pembezaan yang mudah
def pembezaan_kecil(x):
return 0.5 * x # letakkan nilai pembezaan yang kecil (lebih kecil dari 1)
# kita letakkan nilai awal untuk nilai awal kita, dan bayangkan jaringan neural berturut kita ada 50 lapisan
gradient = 1.0 #nilai awal gradien
lapisan = 50 #jumlah lapisan jaringan neural kita
# kita kira dan kemaskini nilai gradien bagi setiap lapisan/langkah masa
gradients = []
for lapis in range(lapisan):
gradient = pembezaan_kecil(gradient)
gradients.append(gradient)
# mari kita plotkan di atas graf
plt.figure(figsize=(8, 6))
plt.plot(range(1, lapisan + 1), gradients, marker='o')
plt.title("Gradient Menghilang Melewati Langkah Masa", fontsize=14)
plt.xlabel("Jumlah Lapisan", fontsize=12)
plt.ylabel("Nilai Gradien", fontsize=12)
plt.grid(True)Mari kita tengok pula gradien meletup. apa yang kita perlu buat hanya tukar nilai dalam persamaan pembezaan kita tadi dari 0.5 ke 1.5.
import matplotlib.pyplot as plt
# kita buat satu persamaan pembezaan yang mudah
def pembezaan_besar(x):
return 1.5 * x # letakkan nilai pembezaan yang besar (lebih besar dari 1)
# kita letakkan nilai awal untuk nilai awal kita, dan bayangkan jaringan neural berturut kita ada 50 lapisan
gradient = 1.0 #nilai awal gradien
lapisan = 50 #jumlah lapisan jaringan neural kita
# kita kira dan kemaskini nilai gradien bagi setiap lapisan/langkah masa
gradients = []
for lapis in range(lapisan):
gradient = pembezaan_besar(gradient)
gradients.append(gradient)
# mari kita plotkan di atas graf
plt.figure(figsize=(8, 6))
plt.plot(range(1, lapisan + 1), gradients, marker='o')
plt.title("Gradient Meletup Melewati Langkah Masa", fontsize=14)
plt.xlabel("Jumlah Lapisan", fontsize=12)
plt.ylabel("Nilai Gradien", fontsize=12)
plt.grid(True)
plt.show()Dalam kedua-dua contoh di atas, kita boleh nampak kesannya apabila kita melakukan kiraan pembezaan secara berterusan, berturutan melewati langkah masa. Nilai gradien kita boleh menjadi terlalu kecil ataupun terlalu besar akan menjejaskan proses latihan kita sekaligus memberi kesan kepada prestasi model RNN yang kita ingin latih. Kemungkinan besar sekali, ia akan menyebabkan kita tak akan mampu menghasilkan model yang boleh memberi ramalan urutan yang tepat.
Masa untuk melatih, tapi dengan Pytorchlah
Kali ini kita dah bersedia untuk melatih jaringan neural berturut kita untuk melatih urutan nombor 3,6,9,12,15…. Tapi untuk kali ini, kita akan gunakan library untuk proses latihan kita. Bukan apa, saya dah cuba untuk melatih jaringan neural ini secara asas dengan matematik sahaja, tapi tak dapat untuk dilakukan barangkali kerana masalah vanishing dan exploding gradient yang muncul. Lagipun saya rasa, sudah tiba masanya untuk kita mempelajari library apa yang biasa digunakan untuk melatih jaringan neural. Jadi, mari saya perkenalkan kepada anda semua, Pytorch
PyTorch ialah sebuah library sumber terbuka (open-source) yang digunakan untuk membangunkan dan melatih model machine learning dan deep learning. PyTorch menawarkan pendekatan yang fleksibel dan intuitif dengan menggunakan graf pengiraan dinamik (dynamic computation graph), menjadikannya sangat popular dalam kalangan penyelidik dan jurutera. Ia dibangunkan oleh MetaAI sejak tahun 2016 dan kini digunakan secara meluas oleh ramai penyelidik dan saintis data. Nak install library ni senang je, kita run je kod di bawah dalam terminal
!pip install torch torchvision torchaudioJadi mari kita gunakan pytorch untuk melakukan latihan pada jaringan neural berturut.Ingat lagi tak objektif kita? Kita nak jaringan neural berturut kita mempelajari urutan nombor seperti di bawah 3,6,9,12….
dan kita mengharapkan RNN ini boleh meramalkan nombor seterusnya. Jadi langkah pertama kita adalah menyediakan data.
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
import matplotlib.animation as animation #untuk animasi sahaja
# kita buat satu urutan nombor dari 3 ke 333 dengan peningkatan sebanyak 3
urutan = np.array([i for i in range(3, 333, 3)])
# masukkan urutan kita ke dalam pembolehubah (variable) x dan y
saiz_tingkap = 5
X, y = [], []
for i in range(len(urutan) - saiz_tingkap):
X.append(urutan[i:i + saiz_tingkap])
y.append(urutan[i + saiz_tingkap])
X = np.array(X) #letakkan x dalam satu tatasusunan (array)
# kita tambah satu lagi fitur (features) dalam dataset kita, supaya RNN boleh belajar lebih baik. perbezaan antara urutan
perbezaan = np.diff(urutan, prepend=urutan[0])
X_features = []
for i in range(len(X)):
nilai_perbezaan = perbezaan[i:i + saiz_tingkap] #dapatkan nilai perbezaan antara urutan
gabungan = np.column_stack((X[i], nilai_perbezaan)) #gabungkan dengan nilai x secara stacking
X_features.append(gabungan)
X_features = np.array(X_features) #simpan dalam tatasusunan
y = np.array(y) #buat yang sama untuk y
# sebelum masuk dalam RNN, tensor itu perlu disusun seperti ini (samples, timesteps, features)
X_features = torch.tensor(X_features, dtype=torch.float32)
y = torch.tensor(y, dtype=torch.float32)Kemudian kita akan bina jaringan neural berturut kita menggunakan pytorch. Dalam class RNN yang kita bina di bawah, kita meletakkan 2 lapisan, satu lapisan jaringan neural berturut dengan 50 keadaan tersembunyi (50 langkah masa), diikuti oleh satu lapisan jaringan neural yang biasa. Lapisan neural berturut ini mengambil 2 input dan mengeluarkan satu output.
Untuk latihan kita akan menggunakan MAE (mean average error) sebagai fungsi kehilangan. Pada masa yang sama kita juga akan menggunakan optimizer (Adam) untuk memastikan proses latihan kita efisyen. Saya akan sentuh berkenaan optimizer ini nanti dalam siri akan datang. Latihan akan menggunakan kadar pembelajaran (learning rate, lr = 0.001)
# mari kita bina jaringan neural berturut kita
class SimpleRNN(nn.Module):
def __init__(self, input_size=2, hidden_size=50, output_size=1): #letak nilai lapisan tersembunyi pada 50
super(SimpleRNN, self).__init__()
self.rnn = nn.RNN(input_size, hidden_size, batch_first=True) #lapisan RNN kita
self.fc = nn.Linear(hidden_size, output_size) #lapisan jaringan neural yang biasa
def forward(self, x):
h0 = torch.zeros(1, x.size(0), 50) #ini lapisan tersempunyi yang pertama
out, _ = self.rnn(x, h0) #ia akan melalui jaringan neural berturut
out = self.fc(out[:, -1, :]) # sebelum di hantar ke lapisan neural yang biasa, lapisan yang terakhir
return out
#mari kita setkan model kita, apa kriteria untuk pembelajaran, dan perlu ada optimizer
model = SimpleRNN() #model
kriteria = nn.L1Loss() # kriteria pembelajaran, menggunakan MAE (mean average error)
optimizer = optim.Adam(model.parameters(), lr=0.001) #optimizer, menggunakan adam dengan kaedah pembelajaran 0.001Seterusnya kita akan melatih jaringan neural berturut kita sebanyak 12,000 epoch (kitaran). Anda boleh cuba dengan jumlah kitaran yang lain, tapi untuk jaringan neural yang mudah ini kita memang memerlukan sehingga 12,000 kitaran.
# kita akan latih dengan 12000 epoch
num_epochs = 12000
kehilangan = []
ramalan_ikut_epochs = []
for epoch in range(1, num_epochs + 1):
model.train()
optimizer.zero_grad()
outputs = model(X_features)
hilang = kriteria(outputs.view(-1), y)
hilang.backward()
optimizer.step()
kehilangan.append(hilang.item())
# Collect predictions every 50 epochs
if epoch % 50 == 0:
input_urutan = X_features[:1]
ramalan = []
for _ in range(10):
model.eval()
with torch.no_grad():
ramal= model(input_urutan)
ramalan.append(ramal.item())
# kemaskini input urutan
input_urutan = torch.cat((input_urutan[:, 1:, :], torch.tensor([[[ramal.item(), 3]]])), dim=1)
ramalan_ikut_epochs.append(ramalan)
print(f'Kehilangan selepas {epoch} epochs: {hilang.item()}')Jika semuanya berjalan lancar, kita akan mendapat nilai MAE seperti di bawah:
Nilai MAE 0.9 bermaksud yang model kita mempunyai nilai perbezaan dengan nilai sebenar yang kurang dari 1. Ini bermakna nilai kita sudah boleh meramalkan dengan baik urutan nombor 3,6,9,12,15… Maka jika kita gunakan model kita untuk meramalkan nombor seterusnya, maka ia akan menghasilkan nombor seperti
Macam mana? Hampir tepat bukan? Bolehlah untuk kali pertama. Ok, jumpa lagi dalam siri akan datang.










