Keras és szekvenciális tanulás

a.k.a Mit tegyünk hogyan tanítsunk Keras modellt ha az adatok nem férnek a memóriánkba


A probléma

Ha Mesterséges Neurális Hálózatokkal dolgozunk el fog érkezni a pillanat amikor akkor adatmenyiséget szeretnénk feldolgozni amit nem tudunk egy lépésben beolvasni, és memóriában tárolni. Értelemszerűen ekkor kisebb adagokban kell az adatokat beolvasni és a modellünknek átadni.

Sajnos van egy probléma: Minden egyes adatot be kell olvasni mindegy egyes epoch-ba. Vagyis az nem működik, hogy beolvasom az első adagot lefuttatok rajta teszem azt 50 epoco-t majd beolvasom a másodikat és azon is megteszem ugyanezt. Miért? Ha így teszek akkor az lényegében mindig az egyes részekre optimalizálom a rendszert.

A megoldás

Ehoz, hogy a fenti problémát megoldjuk, valahogy tárolnunk kell, hogy mennyi adatot olvastunk már be, és jelezni a modellnek, ha már nincs több adat és új epoch-ot kezdhet. Ezek után gondolom nem túl meglepő, ha azt mondom, hogy ezt a feladatott egy osztály definiálásával oldhatjuk meg. Kell egy osztály ami megjegyzi, hol tart az adatok beolvasásban és van egy hívása ami segítségével mindig új részt tudunk beolvasni.

Ha Kerasban dolgozunk Sequence osztályt hozzunk létre. Ebben az osztályban három függvényt mindenféleképpen definiálni kell benne:

  • __init__ – ezt talán nem ragoznám 😉
  • __getitem__(self, idx) – ez a függvény hajtja végre az egyes adatrészek előállítását
  • __len__(self) – ez a függvény megmondja menyi részben fogjuk beolvasni az összes adatot. Vagyis, hogy hányszor kell a __getitem__-et hívni egy epochon belül.

A megvalósítás

Nézzünk egy egyszerű esetet: Van egy adatbázisunk és abból szeretnénk kiolvasni az adatokat amikkel a Keras modellünket tanítani szeretnénk. Sajnos, vagy szerencsére, annyi adatunk van, hogy nem vagyunk képesek egyszerre beolvasni az összeset, így eldöntöttük, hogy létrehozunk egy Sequence osztályt.

A bemeneti adatok mondjuk legyenek egy egyszerű PostgreSQL táblában tárolva, valami ilyesmiben:

ertek cimke
2.69558665826817 0
-0.204029061084586 0
-1.77239296600954 1
0.291882623301363 0
0.0749849084346058 1
-0.609192760524164 0
-2.65497836976503 0

Ahol az ertek a bemeneti X lesz, a cimke pedig a valós kimeneti osztály.

Az osztály így fog kinézni:

from tensorflow.keras.utils import Sequence
import math
import psycopg2

class SajatSzekvencialisOsztalyunk(Sequence):
    def __init__(self, sorokszama, batch_size = 360):
        # mennyi sorunk van az adatbázisban összesen
        self.sorokszama = sorokszama
        # mennyi sort olvasunk be egyszerre
        self.batch_size = batch_size
        self.on_epoch_end()
    def __len__(self):
        # mennyi körben tudjuk beolvasni az összes sort
        return math.ceil( len(self.sorokszama) / self.batch_size)
    def on_epoch_end(self):
        # mit csinálunk ez egyes epocok végén
        # ebben az esetben 0-uk az aktuális sort, 
        # ami mutatja nekünk hol tartunk éppen az adatolvasásban
        self.aktualissor = 0
    def __getitem__(self, idx):
        X = []
        y = []
        try:
            # adatok beolvasása az adatbázisból
            connection = psycopg2.connect()
            cursor = connection.cursor()
            postgreSQL_select_Query = "SELECT ertek, cimke FROM table LIMIT "+\
                                      str(self.batch_size) + \
                                      " OFFSET " + str(self.aktualissor )
            cursor.execute(postgreSQL_select_Query)
            adatok = cursor.fetchall() 
            # adatok beolvasása
            for row in adatok :
                X.append(row[0])
                y.append(row[1])
            # itt tartunk éppen
            self.aktualissor = self.aktualissor + self.batch_size
        except (Exception, psycopg2.Error) as error :
            print ("Adatolvasási hiba: ", error)
        finally:
            # kapcsolat zárása
            if(connection):
                cursor.close()
                connection.close()
        # formázzuk az adatokat a Kerasnak megfelelően
        #   ez modell függő
        ...

        return X, y
        

Most, hogy kész az osztályunk már csak inficiálni kell és a Keras tudtára adni, hogy azt használja a tanulás során. Ez roppan egyszerű:

# mennyi adatot olvasunk be egyszerre
batchsize = ...
# mennyi adat van összesen
osszesadat = ...

# inicializáljuk az osztályt
train_generator = SajatSzekvencialisOsztalyunk(sorokszama=osszesadat, 
                                               batch_size=batchsize)

# Létrehozzuk a modellünk
from keras.models import Sequential
classifier = Sequential()
# ITT definiálnunk kell magát a modellt, ezt én most kihagyom
...

# tanulás
classifier.fit(train_generator,  epochs=10)

Ezzel készen is vagyunk.

Irodalom

Vélemény, hozzászólás?

Adatok megadása vagy bejelentkezés valamelyik ikonnal:

WordPress.com Logo

Hozzászólhat a WordPress.com felhasználói fiók használatával. Kilépés /  Módosítás )

Google kép

Hozzászólhat a Google felhasználói fiók használatával. Kilépés /  Módosítás )

Twitter kép

Hozzászólhat a Twitter felhasználói fiók használatával. Kilépés /  Módosítás )

Facebook kép

Hozzászólhat a Facebook felhasználói fiók használatával. Kilépés /  Módosítás )

Kapcsolódás: %s