Memahami Forward dan Backward pada Pytorch
Membuat model NN menggunakan pytorch sebenarnya sangat mudah sekali karena kita tidak lagi dipusingkan dengan operasi backward yang merupakan teknik gradient descent. Adapun untuk operasi forward merupakan perkalian dot matrik yang biasa kita temui.
Operasi forward secara umum menggunakan persamaan target=xw+b atau disebut dengan Linear. Misalkan kita punya x berupa tensor dengan ukuran sebagai berikut
x Out[6]: tensor([[1., 1.], [1., 0.], [0., 1.], [0., 0.]])
dan y sebagai target dengan ukuran sebagai berikut
target Out[7]: tensor([[1.], [1.], [1.], [0.]])
Perhatikan bahwa ukuran x akan diringkas dari ukuran 4 record x 2 feature menjadi 4 record x 1 feature. Sehingga bobot dan bias sebagai berikut
w1 Out[9]: Parameter containing: tensor([[3.2761], [3.4772]], requires_grad=True)
dan bias sebagai berikut
b1 Out[10]: Parameter containing: tensor([-1.3895], requires_grad=True)
Operasi Forward
Contents
Perhatikan operasi linear /forward berikut ini
y = x.matmul(w1)+b1
menghasilkan output y sebagai berikut
y Out[13]: tensor([[ 5.3637], [ 1.8865], [ 2.0877], [-1.3895]], grad_fn=<AddBackward0>)
kemudian ouput tersebut akan dimasukan fungsi aktifasi sigmoid()
prediksi = sigmoid(y)
akan menghasilkan berikut
prediksi Out[15]: tensor([[0.9953], [0.8684], [0.8897], [0.1995]], grad_fn=<SigmoidBackward0>)
perhatikan output target yang akan mendekati nilai prediksi
Loss Function
Fungsi loss yang digunakan berupa MSE untuk menghitung selisih antar target dan prediksi.
loss = loss_function(prediksi,target)
hasilnya bisa kita lihat
loss.item() Out[17]: 0.017359605059027672
Nilai tersebut harus semakin kecil! Sehingga butuh operasi gradient descent pada operasi backward()
Operasi backward
Operasi backward merupakan operasi yang cukup kompleks yaitu pada matematika kalkulus untuk menghitung fungsi derivatif sehingga dihasilkan global minimum. Namun teknik analitik tidak bisa kita gunakan begitu saja oleh sebab itu butuh teknik numerik berupa gradient descent. Kalian bisa baca Apa itu Gradient Descent-Machine Learning?
Nah yang di masukan ke gradient descent berupa bobot dan bias yang akan diubah pada proses looping, oleh sebab itu kita masukan saja kedalam operasi gradient berikut dengan learning rate 0.01
optimizer = torch.optim.Adam([w1,b1],lr=0.01)
Yuk kita lakukan operasi backward() bersamaan dengan gradient descent
loss.backward() #propagation optimizer.step()
Ketiga operasi diatas dilakukan berkali-kali dalam prosess looping. Kode lengkapnya bisa kalian pelajari sebagai berikut
import numpy as np import torch import torch.nn as nn x = torch.tensor([[1,1],[1,0],[0,1],[0,0]],dtype=torch.float) target = torch.tensor([[1],[1],[1],[0]],dtype=torch.float) #init bobot dan bias secara random w1 = np.random.uniform(-1,1,(x.shape[1],1)) b1 = np.random.uniform(-1,1,(1)) sigmoid = nn.Sigmoid() #buat sebagai paramater w1 = torch.nn.Parameter(torch.tensor(w1,dtype=torch.float)) b1 = torch.nn.Parameter(torch.tensor(b1,dtype=torch.float)) optimizer = torch.optim.Adam([w1,b1],lr=0.01) loss_function = nn.MSELoss() loss_epoch = list() for i in range(0,1000): optimizer.zero_grad() #operasi forward y = x.matmul(w1)+b1 prediksi = sigmoid(y) loss = loss_function(prediksi,target) #backward loss.backward() #propagation optimizer.step() loss_epoch.append(loss.item()) print("epoch ",i," ",loss.item()) print(prediksi)
Jika dilakukan dalam 1000 epoch, maka hasilnya prediksi akan mendekati target. Misalkan akan menghasilkan berikut
tensor([[0.9984], [0.8874], [0.9310], [0.1434]],
Bila dibulatkan akan mendekati angka [1,1,1,0] yang merupakan target dari output logika boolean AND.
Menggunakan Class NN.Module
Bila sebelumnya kita bisa secara manual membuat operasi forward dan backward maka di Pytorch bisa kita manfaatkan class Module seperti berikut dengan Linear sebagai operasi target=xw+b
#menggunakan class module x = torch.tensor([[1,1],[1,0],[0,1],[0,0]],dtype=torch.float) target = torch.tensor([[1],[1],[1],[0]],dtype=torch.float) class Model(nn.Module): def __init__(self): super().__init__() self.layer1 = nn.Linear(2,1) self.sigmoid = nn.Sigmoid() def forward(self,x): x = self.layer1(x) x = self.sigmoid(x) return x model = Model() optimizer = torch.optim.Adam(model.parameters(),lr=0.01) loss_function = nn.MSELoss() loss_epoch = list() for i in range(0,1000): optimizer.zero_grad() prediksi = model(x) loss = loss_function(prediksi,target) loss.backward() optimizer.step() loss_epoch.append(loss.item()) print("epoch ",i," ",loss.item())
Untuk mendapatkan Bobot dan Bias pada Linear, kalian bisa memanggil dengan cara berikut yang merupakan class yang terbuild/init secara random.
layer1 = nn.Linear(2,1) layer1.weight layer1.bias
nn.Linear() merupakan class turunan dari Paramaters. Akan tetapi perkalian nya agak sedikit berbeda harus di transpose terlebih dahulu. Kalian bisa baca Pytorch Apa itu Operasi Linear, Bobot, dan Bias pada Algoritma CNN
x.matmul(layer1.weight.t())+layer1.bias
Operasi Backward untuk menghitung derivatif/turunan
Agar lebih memahami cara kerja backward, bisa kalian pelajari Apa itu Gradient Descent-Machine Learning? atau Linear Regression dengan Konsep Gradient Descent. Atau contohnya sebagai berikut . Perhatikan persamaan berikut
akan diturunkan menjadi
Sehingga apabila akan menghasilkan turunan
x = torch.tensor(4.0,requires_grad=True) y = x**2+x*5+1 y.backward() print(x.grad)
Coba kalian bisa hitung turunan dari
Yuk biar nggak puyeng, kita nggak usah pakai teknik rumus njlimet tapi dikalian saja dulu satu persatu.
kemudian
kalau sudah seperti diatas, kita turunkan saja
sehingga apabila akan dihasilkan nilai 48, mari kita coba dengan tensor saja
x = torch.tensor(1.0,requires_grad=True) y = (2*x+10)**2 y.backward() print(x.grad)
Tentu perhitungan analitik cukup menguras pikiran karena kalau banyak melibatkan persamaan akan semakin rumit seperti perhitungan MSE yang melibatkan aturan turunan .
Global Minimum
Persamaan akan mencapai global minimum jika x = -5, yuk kita ingat aturan turunan yang akan digunakan sebagai cara mencari global minimum pada sebuah persamaan. Dari persamaan tersebut bila kita turunkan akan menjadi
sehingga jika akan didapatkan nilai , Mari kita uji dengan plot grafik seperti berikut
x = np.arange(-10,5,1) y = (2*x+10)**2 from matplotlib import pyplot as plt plt.figure() plt.plot(x,y) plt.show()
Untuk mencari global minimum, sebenarnya kita bisa menggunakan teknik iterasi seperti di gradient descent. Kalian bisa baca paragraf terakhir.
a = np.array([1],dtype=np.float32) #tebakan awal x= 1 for i in range(0,1000): x = torch.tensor(a,requires_grad=True) y = (2*x+10)**2 y.backward() optim = torch.optim.SGD([x],lr=0.15) optim.step() print(x) #akan menuju -5 a = x.detach().numpy()
hasilnya
tensor([-5.], requires_grad=True) tensor([-5.], requires_grad=True) tensor([-5.], requires_grad=True) tensor([-5.], requires_grad=True) tensor([-5.], requires_grad=True) tensor([-5.], requires_grad=True)
Itulah asalan mengapa pemilihan loss function mempunyai aturan harus bisa diturunkan/derivatif.