×

Memahami Forward dan Backward pada Pytorch

Memahami Forward dan Backward pada Pytorch

558 Views

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

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?

See also  Penjelasan Algoritma RNN dan Contoh Kasus

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

See also  Memilih Tensorflow atau Pytorch untuk Framework Deep Learning

    \[ y(x) = x^2+x5+1 \]

akan diturunkan menjadi

    \[ \frac{dy}{dx}=2x+5 \]

Sehingga apabila x=4 akan menghasilkan turunan \frac{dy}{dx}=13

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 y=(2x+10)^2

Yuk biar nggak puyeng, kita nggak usah pakai teknik rumus njlimet f(x)=h(g(x)) tapi dikalian saja dulu satu persatu.

    \[ y=(2x+10) (2x+10) \]

kemudian

    \[ y=4x^2+20x + 20x+100 \]

kalau sudah seperti diatas, kita turunkan saja

    \[ y=8x+20 + 20 \]

sehingga apabila x=1 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 f(x)=h(g(x)).

Global Minimum

Persamaan y=(2x+10) (2x+10) 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

    \[ y=8x+20 + 20 \]

sehingga jika y=0 akan didapatkan nilai x=-5, 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.

 

 

You May Have Missed