top of page
Eren Özkan

Sıfırdan Uzun Kısa Süreli Bellek (LSTM)

Introduction

Uzun Kısa Süreli Bellek (LSTM), derin öğrenme alanında yaygın olarak kullanılan bir yapay sinir ağı türüdür. LSTM, RNN'in kaybolan/patlayan gradyan probleminden kaçınmak için geliştirilmiştir. Ancak, LSTM ağları hala patlayan gradyan probleminden muzdarip olabilir. Özel hafıza yeteneği sayesinde, LSTM genellikle zaman serisi tahmini için kullanılır. Bu makalede, LSTM mimarisinden ve bu mimariyi PyTorch ile inşa etmekten bahsetmek istiyorum.


 

Mimari


LSTM'de iki tür bellek vardır. Bunlardan biri, şekilde yeşil çizgi ile gösterilen uzun süreli bellek. Kırmızı çizgi ise kısa süreli belleği gösterir. Ayrıca, LSTM'de giriş, çıkış ve unutma kapısı bulunur.


 

Hesaplamalar


Son uzun süreli değerinin 2 (yeşil), kısa süreli değerinin 1 (kırmızı) ve girişin 1 (gri) olduğunu varsayıyoruz. Ayrıca, başlangıç ağırlıklarını ve biaslarını yazdım.


Şimdi çıktıyı hesaplayalım.


Unutma Kapısı (Forget Gate)


(1 x 2.2) + (1 x 2.7) = 4.9

4.9 + 2.3 = 7.2

sigmoid(7.2) = 1


Hatırlatma;

Unutma kapısı (forget gate) çıktımız 1'dir. Bunu 2 ile çarptığımızda, ilk uzun süreli bellek değerimiz 2 olur.


Giriş kapısı (Input Gate)


Yeşil Hücre

(1 x 1.1) + (1 x 0.8) = 1.9

1.9 + 0.8 = 2.7

sigmoid(2.7) = 0.937


Sarı Hücre

(1 x 0.4) + (1 x 1.2) = 1.6

1.6 + 0.9 = 2.5

tanh(2.5) = 0.987


Hatırlatma;

Bu iki hücreyi çarpıp uzun süreli belleğe ekleriz.

2 + 0.987 = 2.987


Çıkış Kapısı (Output Gate)


Gri hücre

(1 x 0.3) + (1 x 2.9) = 3.2

3.2 + 2.1 = 5.3

sigmoid(5.3) = 0.995


Pembe hücre

tanh(2.987) = 0.995

Bu değeri yeşil hücre çıktısıyla çarparız.

0.995 x 0.995 = 0.9899


Son olarak, yeni kısa bellek değerimiz 0.9899 olur. Bu hesaplama, yeni giriş değerleriyle devam eder. Ve tekrar tekrar aynı süreç işler.


Bu, ileri yayılmadır (forward propagation). Algoritma son çıktıyı hesapladığında, geri yayılım (back propagation) devreye girer. Geri yayılımın görevi, kaybı azaltmaktır.

 

Şimdi Sıra Kodlarda


Kütüphaneler

Öncelikle, gerekli kütüphaneleri içe aktarmamız gerekiyor. Lightning kütüphanesi, mimariyi oluşturmamıza yardımcı oluyor.

import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.optim import Adam
import lightning as L

Ağırlıklar ve biaslar

Şimdi ağırlıkları ve biasları yerleştirmemiz gerekiyor. Bundan önce, Lightning modülünü içeren bir sınıf tanımlıyorum.

class SimpleLSTM(L.LightningModule):
    def __init__(self):

        super().__init__()

        mean = torch.tensor(0.0)
        std = torch.tensor(1.0)

        # Blue cell weights and biases
        self.wbc1 =   	nn.Parameter(torch.normal(mean=mean,std=std),requires_grad=True)
        self.wbc2 = nn.Parameter(torch.normal(mean=mean,std=std),requires_grad=True)
        self.bbc1 = nn.Parameter(torch.tensor(0.),requires_grad=True)

        # Green cell weights and biases
        self.wgc1 = nn.Parameter(torch.normal(mean=mean,std=std),requires_grad=True)
        self.wgc2 = nn.Parameter(torch.normal(mean=mean,std=std),requires_grad=True)
        self.bgc1 = nn.Parameter(torch.tensor(0.),requires_grad=True)

        # Yellow cell weights and biases
        self.wyc1 = nn.Parameter(torch.normal(mean=mean,std=std),requires_grad=True)
        self.wyc2 = nn.Parameter(torch.normal(mean=mean,std=std),requires_grad=True)
        self.byc1 = nn.Parameter(torch.tensor(0.),requires_grad=True)

        # Gray cell weights and biases
        self.wpc1 = nn.Parameter(torch.normal(mean=mean,std=std),requires_grad=True)
        self.wpc2 = nn.Parameter(torch.normal(mean=mean,std=std),requires_grad=True)
        self.bpc1 = nn.Parameter(torch.tensor(0.),requires_grad=True)

"requires_grad = True" özelliği, geri yayılım sırasında değerlerin kayba göre değişeceğini belirtir. Ağırlıkları ve biasları, örnekte yaptığımız gibi yerleştirdim.

class SimpleLSTM(L.LightningModule):
    def __init__(self):

        super().__init__()

        self.wbc1 = 2.7
        self.wbc2 = 2.2
        self.bbc1 = 2.3

        self.wgc1 = 1.1
        self.wgc2 = 0.8
        self.bgc1 = 0.8

        self.wyc1 = 0.4
        self.wyc2 = 1.2
        self.byc1 = 0.9

        self.wgrc1 = 0.3
        self.wgrc2 = 2.9
        self.bgrc1 = 2.1

Hücreler

Giriş değeri, uzun süreli bellek ve kısa süreli belleği tanımladım. Ardından, tüm hücreleri şekildeki gibi birbirine bağladım.

def lstm_cells(self, input_value, long_memory, short_memory):

        
        blue_cell = torch.sigmoid((short_memory * self.wbc1) + 
                                              (input_value * self.wbc2) + 
                                              self.bbc1)

        green_cell = torch.sigmoid((short_memory * self.wgc1) +
                                                   (input_value * self.wgc2)+ 
                                                   self.bbc1)

        yellow_cell= torch.tanh((short_memory * self.wyc1) + 
                                      (input_value * self.wyc2) + self.byc1)
        
        updated_long_memory = ((long_memory * blue_cell) + 
                               (green_cell * yellow_cell))

        gray_cell= torch.sigmoid((short_memory * self.wgrc) + 
                                       (input_value * self.wgrc2) + self.bgrc1)
        
        updated_short_memory = torch.tanh(updated_long_memory) * gray_cell

        return ([updated_long_memory,updated_short_memory])

İleri yayılım (Forward Propagation)

Uzun süreli bellek değerlerini 2, kısa süreli belleği ise 1 olarak seçtim.

def forward(self, input):
        long_memory = 2
        short_memory = 1

        value = input[0]

        long_memory, short_memory = self.lstm_cells(value, long_memory, short_memory)

        return short_memory

Tahmin

Modeli tanımladım ve değeri tahmin ettim.

class SimpleLSTM(L.LightningModule):
    def __init__(self):

        super().__init__()
        self.wlr1 = 2.7
        self.wlr2 = 2.2
        self.blr1 = 2.3

        self.wpr1 = 1.1
        self.wpr2 = 0.8
        self.bpr1 = 0.8

        self.wp1 = 0.4
        self.wp2 = 1.2
        self.bp1 = 0.9

        self.wo1 = 0.3
        self.wo2 = 2.9
        self.bo1 = 2.1

    def lstm_cells(self, input_value, long_memory, short_memory):

        
        blue_cell = torch.sigmoid((short_memory * self.wbc1) + 
                                              (input_value * self.wbc2) + 
                                              self.bbc1)

        green_cell = torch.sigmoid((short_memory * self.wgc1) +
                                                   (input_value * self.wgc2)+ 
                                                   self.bbc1)

        yellow_cell= torch.tanh((short_memory * self.wyc1) + 
                                      (input_value * self.wyc2) + self.byc1)
        
        updated_long_memory = ((long_memory * blue_cell) + 
                               (green_cell * yellow_cell))

        gray_cell= torch.sigmoid((short_memory * self.wgrc) + 
                                       (input_value * self.wgrc2) + self.bgrc1)
        
        updated_short_memory = torch.tanh(updated_long_memory) * gray_cell

        return ([updated_long_memory,updated_short_memory])
    
    def forward(self, input):
        long_memory = 2
        short_memory = 1

        value = input[0]

        long_memory, short_memory = self.lstm_cells(value, long_memory, short_memory)

        return short_memory

input = 1.
model = SimpleLSTM()
model(torch.tensor([input]).detach())

-OUTPUT-

Predict is 
tensor(0.9893)

Sonucun, yukarıdaki yaptığımız örnekle aynı olduğu görünüyor.



Geri yayılım (backpropagation)


Geri yayılım kullanıldığında, model bu şekilde görünür.


Adam'ı optimizasyon algoritması olarak tanımladık.


Model, optimum kayba ulaşana kadar ağırlıkları ve biasları güncellemeye devam eder.

class SimpleLSTM(L.LightningModule):
    def __init__(self):

        super().__init__()

        mean = torch.tensor(0.0)
        std = torch.tensor(1.0)
        zero = torch.tensor(0.)

        # Blue cell weights and biases
        self.wbc1 = nn.Parameter(torch.normal(mean=mean,std=std),requires_grad=True)
        self.wbc2 = nn.Parameter(torch.normal(mean=mean,std=std),requires_grad=True)
        self.bbc1 = nn.Parameter(zero,requires_grad=True)

        # Green cell weights and biases
        self.wgc1 = nn.Parameter(torch.normal(mean=mean,std=std),requires_grad=True)
        self.wgc2 = nn.Parameter(torch.normal(mean=mean,std=std),requires_grad=True)
        self.bgc1 = nn.Parameter(zero,requires_grad=True)

        # Yellow cell weights and biases
        self.wyc1 = nn.Parameter(torch.normal(mean=mean,std=std),requires_grad=True)
        self.wyc2 = nn.Parameter(torch.normal(mean=mean,std=std),requires_grad=True)
        self.byc1 = nn.Parameter(zero,requires_grad=True)

        # Gray cell weights and biases
        self.wpc1 = nn.Parameter(torch.normal(mean=mean,std=std),requires_grad=True)
        self.wpc2 = nn.Parameter(torch.normal(mean=mean,std=std),requires_grad=True)
        self.bpc1 = nn.Parameter(zero,requires_grad=True)

    def lstm_cells(self, input_value, long_memory, short_memory):

        
        blue_cell = torch.sigmoid((short_memory * self.wbc1) + 
                                              (input_value * self.wbc2) + 
                                              self.bbc1)

        green_cell = torch.sigmoid((short_memory * self.wgc1) +
                                                   (input_value * self.wgc2)+ 
                                                   self.bbc1)

        yellow_cell= torch.tanh((short_memory * self.wyc1) + 
                                      (input_value * self.wyc2) + self.byc1)
        
        updated_long_memory = ((long_memory * blue_cell) + 
                               (green_cell * yellow_cell))

        gray_cell= torch.sigmoid((short_memory * self.wgrc) + 
                                       (input_value * self.wgrc2) + self.bgrc1)
        
        updated_short_memory = torch.tanh(updated_long_memory) * gray_cell

        return ([updated_long_memory,updated_short_memory])
    
    def forward(self, input):
        long_memory = 0
        short_memory = 0

        value1 = input[0]
        value2 = input[1]
        value3 = input[2]
        value4 = input[3]

        long_memory, short_memory = self.lstm_cells(value1, long_memory, short_memory)
        long_memory, short_memory = self.lstm_cells(value2, long_memory, short_memory)  
        long_memory, short_memory = self.lstm_cells(value3, long_memory, short_memory)
        long_memory, short_memory = self.lstm_cells(value4, long_memory, short_memory)
  
        return short_memory

    def configure_optimizers(self):
        return (Adam(self.parameters()))
    
    def training_step(self, batch, batch_idx):

        input_i, label_i = batch
        output_i = self.forward(input_i[0])
        loss = (output_i - label_i)**2
        self.log("train_loss",loss)

        if (label_i  == 0):
            self.log("out_0",output_i)
        else:
            self.log("out_1",output_i)
        return loss

LSTM mimarisinden ve bunu PyTorch kullanarak nasıl inşa edileceğinden bahsettik. Umarım yazdıklarım anlaşılır olmuştur. Okuduğunuz için teşekkürler.

0 görüntüleme0 yorum

Son Yazılar

Hepsini Gör

Comments


bottom of page