szakmai vélemények, ötletek és tanácsok, valamint hírek a vállalati pénzügyek világából szakembereknek, cégtulajdonosoknak és minden érdeklődőnek

vállalati pénzügyek - néhány percben, kávé mellé

tanuló algoritmusok a vállalati pénzügyekben - 3. rész

"hobbimodellezés" - fejlessz Te is AI algoritmust otthon

2018. december 01. - György Gábor

A sorozat korábbi bejegyzéseiben áttekintést adtunk a tanuló algoritmusokról, illetve azok pénzügyi hasznosításának lehetőségeiről. Először egy csődvalószínűség modellezési példán keresztül vizsgáltuk "gradient descent" (vagy gradiens) módszer és a genetikus algoritmusok működését. Az előző részben pedig a neurális hálózatok működését mutattuk be az említett példa segítségével.

Most ezt folytatjuk tovább a neurális hálózat kimeneti értékeinek meghatározásával és a hálózat tanításának összefoglalójával: egy R programon keresztül szemléltetjük a főbb lépéseket.

R kód – feedforward és training

A neurális hálózatok tanítására az R-ban használhatjuk a neuralnet könyvtárat. A jelen példában azonban nem ezt fogjuk használjuk, hanem betekintést adunk a “black box”-ba: ezért egy kifejezetten 2+1 rétegű neurális hálózatok optimalizálására szolgáló, a példa kedvéért megírt kódot mutatunk be (mivel ezen keresztül a jobban szemléltethető a neurális hálózatok tanítása)

Először is lássuk a neurális háló kimeneti értékét kiszámoló “feedforward” algoritmust, amely valójában néhány egyszerű mátrix szorzás.

[1] Első lépésben a Z1 értékeket, vagyis a rejtett réteg neuronjainak bemenetét számoljuk ki az X mátrixot szorozva a kapcsolati súlyokat tartalmazó W1 mátrixszal.

Az X mátrix 1-1 sora 1-1 mintát jelent a tanuló adathalmazban, vagyis egy adott cégre vonatkozóan tartalmazza az egyes pénzügyi mutatók értékeit  (és ennek a mátrix oszlopai jelentik a pénzügyi mutatókat illetve azok értékeit az egyes mintaelemek tekintetében). A lenti ábrán az algoritmus szempontjából az X mátrix 1-1 sorát a pénzügyi mutatókat tartalmazó bekeretezett rész jelenti.

A W1 mátrix soronként tartalmazza a súlyokat, amely egy adott pénzügyi mutató és a rejtett réteg neuronjai közötti kapcsolatot jellemzi, ld. az ábrán:

 

A súlymátrixban az oszlopok itt a rejtett réteg neuronjait jelölik -> mivel a példában 3 neuron van a rejtett rétegben, ezért a példában 3 oszlopa lesz a W1 mátrixnak (és annyi sora, ahány pénzügyi mutatót figyelmbe veszünk).

[2] A Z1 mátrix végeredményben mintaelemenként tartalmazza a rejtett réteg neuronjainak input értékét. Ebből a sigmoid() függvény alkalmazásával kiszámolhatók a rejtett neuronok aktivációs értékei (act_h). 

[3] Majd végül a kimeneti réteg aktivációját is meghatározzuk az 1-2. lépéshez hasonlóan! A Z2 értékeke itt is az act_h és a W2 mátrix szorzata, illetve ebből a neurális hálónk kimeneti neuronjának aktivációja (act_out) is a sigmoid függvény segítségével kerül kiszámításra.

feedforward_2Lyrs <- function(x, w1, w2) {

    z1 <- cbind(1,x) %*% w1

    act_h <- sigmoid(z1)

    z2 <- cbind(1, act_h) %*% w2

    act_out <- sigmoid(z2)

    list(output = act_out, act_h = act_h)

}

A feedforward_2Lyrs() függvény kiszámolja a kimeneti neuron aktivációs értékekét (output), illetve a rejtett réteg neuronjainak aktivációs értékét (act_h). A kódban látható sigmoid() függvény a korábban is említett aktivációs függvény leképzése R-ban:

sigmoid <- function(z) {

    1.0 / (1.0 + exp(-z))

}

 A következő kódrészlet a neurális hálózat optimalizálásának lényegét mutatja be: ez maga a hálózat tanítása - vagyis  a “helyes” súlyok kiszámítás - iteratív módon. A tanítást a train() függvény meghívásával végezzük.

train <- function(X, Y, hidden = 3, learn_rate = 0.005, iterations = 1000) {

    ### 1) neuronok közötti kapcsolatokat reprezentáló súlyok inicializálása

    d <- ncol(X)

    w1 <- matrix(rnorm(d * hidden), d, hidden)

    w2 <- as.matrix(rnorm(hidden))

    bias1 <- matrix(rnorm(hidden),1,hidden)

    bias2 <- matrix(rnorm(ncol(Y)),1,ncol(Y))

    w1 <- rbind(bias1, w1)

    w2 <- rbind(bias2, w2)

    ### 2) súlyok újraszámolása – alapesetben 1000 iterációs lépés

    for (i in 1:iterations) {

        ### 2/A) aktuális súlyok mellett a neurális háló neuronjainak – kimeneti és rejtett is! –  aktivációs értékeit is kiszámoljuk

        ffRes <- feedforward_2Lyrs(X, w1, w2)

        ### 2/B) backpropagation algoritmussal újraszámoljuk a w1 és w2 súly mátrixok értékeit

        bp <- backPropNN_2Lyrs(X, Y,

                        Yhat = ffRes$output,

                        w1, w2,

                        sigm_h = ffRes$act_h,

                        lRate = learn_rate)

        w1 <- bp$w1

        w2 <- bp$w2

    }

    list(output = ffRes$output, w1 = w1, w2 = w2)

}

 

A hálózat tanításának lépései röviden összefoglalva:

  1. lépés – kezdeti súlyok inicializálása
  • Véletlenszerű értékekkel inicializáljuk a W1 és W2 súlymátrixokat, illetve mindegyikhez hozzáillesztünk egy ún. eltolás (bias) értéket/vektort az rbind() függvény segítségével – ezek az aktiváció függvény kimenetét tolják el bizonyos mértékben jobbra vagy balra (bővebben a bias szerepéről itt).
  • A W1 mátrix esetében az eltolás értékek 3 elemű vektorként kerülnek hozzáadásra egy új sorként, hiszen mindhárom rejtett neuronnak a bemeneti értékét képezik (vagyis az 5 bemenő pénzügyi mutatót kiegészítjük mindhárom neuron esetében plusz egy-egy eltolás értékkel)

 

  1. lépés – iteráció, vagyis a súlyok újraszámolása
  • Után a paraméterként megadott számú iterációt hajtunk végre (az iterációk számának default értéke 1000) a neurális hálózat súlyainak optimalizálása céljából.
  • Az iterációk során feedforward_2Lyrs() függvény segítségével először kiszámoljuk a neurális hálózat kimeneti értékeit illetve a rejtett réteg neuronjainak aktivációs értékeit.
  • A backprop_2Lyr() függvény meghívásával újraszámoljuk W1 és W2 súlyokat: a tanulási ráta alap esetben 0.005 – vagyis az egyes neuronok „hibájának” (pontosabb az output neuron hibájához való „hozzájárulását”) 0.5%-val módosítjuk a súlyokat. A függvény további bemenetei az eredeti minta független változói (X) és tényleges kimentek (Y), valamint az aktuális súlyokkal számolt kimenet (Yhat), illetve az 1. és 2. réteg aktuális súlyai (w1,w2).
  • A backprop_2Lyr() függvény kimenetként megkapott újraszámolt súlyokat eltároljuk az eredeti W1/W2 mátrixokban és újra indul a következő iterációs kör.

 

 

A neruális hálózat súlyainak meghatározása:

library(readxl)

setwd("C:/InputDat/")

dfNNTrain <- read_excel("defaultData_NN.xlsx", col_names = TRUE, sheet = 'train')

X <- as.matrix(dfNNTrain[,2:6])

Y <- as.matrix(dfNNTrain$csod)

bbResult <- train(X, Y, 3, 0.005, 1000)

dfNNTest <- read_excel("defaultData_NN.xlsx", col_names = TRUE, sheet = 'test')

Xt <- as.matrix(dfNNTest[,2:6])

Yt <- as.matrix(dfNNTest$csod)

ffTest <- feedforward_2Lyrs(Xt,bbResult$w1,bbResult$w2)

ffTest$csod <- Yt

ffTest$csod_pr <- round(ffTest$output, digits = 0)

mean(abs(ffTest$csod - ffTest$csod_pr))

 

Továbblépési lehetőségek, a neurális háló előrejelző képességének javítása

  • További pénzügyi mutatók figyelembe vétele.
  • A pénzügyi mutatók tendenciájának felhasználása inputként: míg pl. a likviditási mutatók alacsony értéke sokszor egy hosszabb folyamat következménye és a csődöt közvetlenül megelőző időkben romlik le, addig bizonyos hatékonysági mutatók tartósan alacsony értéke illetve azok negatív tendenciája hosszabb távon vezethet csődhöz
  • Nem csak pénzügyi, hanem piaci vagy egyéb mutatók, attribútumok figyelembe vétele a neurális hálózat bemenetei között: pl. iparág szerinti differenciálás, piaci részesedés, cég életkora vagy tulajdonosi kör tőkeereje.

 

A bejegyzés trackback címe:

https://vallalatipenzugyek.blog.hu/api/trackback/id/tr4314405490