Hogyan használjunk matematikai kifejezéseket a blog.hu-n

2021/01/13. - írta: sajozsattila

A blog.hu a legnagyobb magyar nyelvű blog platform. Ha valakinek sikerül kikerülni a címlapra a szolgáltatónál szinte biztosan jó olvasottságot tud elérni a bejegyzése számára. Viszont a blogmotornak megvannak a maga hiányosságai. Ezek egyike a matematikai kifejezések támogatásának hiánya. Ebben a bejegyzésben megnézünk egy egyszerű módszert arra, hogy ne kelljen ezeket képként beszúrni.


 

In medias rex, a dolgok közepébe vágva: Létezik egy olyan nyelv, a Markdown. Ezt, ezt fogjuk használni a probléma megoldására.

Egy kis bevezetés annak, aki még nem hallott erről a nyelvről: A Markdown olyan egyszerű szintaxisú szövegszerkesztésre használt nyelv, amit kifejezetten arra dolgoztak ki, hogy növeljék a produktivitást. A lényeg: soha sem kell felemelnünk a kezünket a billentyűzetről, lényegében minden egyes szövegszerkesztési feladatot elvégezhetünk gépelés közben. Online publikáció írásakor a Markdown napjainkban az egyik legnépszerűbb megoldás. Több szerkesztő elérhető az interneten Markdown szövegek szedésére. Én most ezek közül a μr² megoldását fogom használni.

Térjünk a lényegre és nézzünk egy példát.

Ez egy görög betű a szövegben: \sigma. Ez pedig egy matematikai kifejezés blokkban:


P_{\omega}=\hbar\omega\,\frac{1+R}{1-v^2}\int\limits_{-1}^{1}dx\,(x-v)|x-v|

Ami Markdownban egyszerű LaTeX bevitelt jelent $$ jelek között:

Ez egy görög betű a szövegben:$$\sigma$$. 
Ez pedig egy matematikai kifejezés blokkban:

$$
P_{\omega}=\hbar\omega\,\frac{1+R}{1-v^2}\int\limits_{-1}^{1}dx\,(x-v)|x-v|
$$

Ha megírtuk Markdown-ban a bejegyzésünket, akkor a következő módon tudjuk importálni a blog.hu-ba:

Először nyissuk meg a μr² szerkesztő oldalsó menüjét, a jobb felső sarokban lévő ikonra kattintva. Valami ilyesmit fogunk látni:

μr² oldalsó menüje

Majd állítsuk HTML-re az előnézetet, az oldalsó menü HTML pontjára kattintva. Ekkor a szerkesztő bal oldalán a bejegyzésünk nyers HTML kódját fogjuk látni. Ezt el is menthetjük, de ha nem túl hosszú, akkor csak jelöljük ki és másoljuk be egy blog.hu bejegyzés HTML részébe:

Blog.hu szerkesztő menüje

Készen is vagyunk.

Matematikai képletek mellett a Markdownt több olyan dologra is tudjuk használni ami talán egy kicsit nehézkes a blog.hu-ban. Mire gondolok? Például lábjegyzet[1], formázott táblázat vagy irodalomjegyzék. Akit érdekelnek a részletek vessen egy pillantást a μr² felhasználói kézikönyvére.

Végjegyzetek

  1. Mint ez. ↩︎

1 komment

Mesterséges Neurális Hálózat alapjai – 2. rész

2020/07/07. - írta: sajozsattila

 

Az előző részben átnéztük, a Neurális Hálózat részeit és a lejátszási szakaszt. Most folytassuk a Hibaszámítással és a Visszajátszással!

Hibaszámítás

Az előző részben, a lejátszás végén kaptunk egy előrejelzést a bemeneti adatok alapján. A konkrét példánk esetében ez így alakult:

 o = \begin{bmatrix} 0.81152104 \\1.77152357 \end{bmatrix}

Mivel felügyelettel végrehajtott tanulást végzünk ismerjük a bemeneti adatok tényleges eredményét. Semmi akadálya tehát, hogy összevessük ezt az eredményt az MNH előrejelzésével. Nem meglepő, hogy a kettő különbsége lesz az előrejelzés hibája. Több módon számíthatjuk ezt az értéket, az egyetlen megkötés, hogy részekben deriválható legyen. A legegyszerűbb, és amit itt mi is alkalmazunk, a négyzetes hiba:

 E = \frac{(y-o)^2}{2}

Ahol:

  • E — a Hiba
  • y — a valós eredmény

Számítsuk is ki a korábbi példán, legyen mondjuk a tényleges eredmény:

  y = \begin{bmatrix} 0 \\1 \end{bmatrix}

Ennek megfelelően a Hiba:

y = np.array([0,1])
 
e = 0.5*(y-o)**2
print("Teljes hiba: ", sum(e))

Aminek az eredménye:

 E = \begin{bmatrix} 0.3292832 \\0.29762431 \end{bmatrix}

Ezzel a lépéssel készek is vagyunk. Most már csak tanulnunk kell a tévedésből, ez lesz a Visszajátszás.

Visszajátszás

Ebben a lépésben frissítjük a Hálózat beállításait annak megfelelően, hogy mekkora részben járultak hozzá az előző lépésben számított Hibához. Ezt a frissítést most visszafelé haladva hajtjuk végre a rendszeren. Vagyis az adatáramlás így alakul:

Visszajátszás

Hogy miért visszafelé tesszük ezt? Ennek számítástechnikai oka van, amit majd lentebb bemutatok.

De mit is frissítünk konkrétan? Ha valaki odafigyelt, akkor nyilvánvaló a számára, hogy az MNH-nak csupán egyetlen része nem fixen meghatározott: a súlyok. A visszajátszás során ezeket állítjuk. Ugye, így szabályozzuk, hogy az előző rétegben az egyes tulajdonságoknak mekkora szerepük legyen az adott neuron kimeneti értékében.

Most nézzük magát a konkrét számítást! Ez egy minimalizációs probléma: azt szeretnénk, hogy a Hiba minél kisebb legyen. És a Hiba ott a legkisebb, ahol a deriváltja nulla. Legalábbis elméletileg. A gyakorlatban lehetségesek olyan lokális minimumok, amelyek kielégítik ezt a feltételt, és mégsem a legjobb megoldások. Amint azt a nevük is mutatja, csak lokálisan a legjobbak. Ezt mindig tartsuk az észben! A MNH csupán azt garantálja, hogy a lokális minimumot megtaláljuk, de azt nem, hogy ez valóban a legjobb megoldás a lehetséges megoldások végtelenjében.

A kimeneti réteg súlyainak hibája

Térjünk vissza a számításra! Az első lépésben azt nézzük meg, hogy a Kimeneti réteg egyes súlyainak mekkora szerepük volt a Hibában. Ezt az értéket fogjuk gradiensnek nevezni. Hogy ezt kiszámoljuk, deriválnunk kell a Hibát az egyes súlyokra. Nézzünk egy konkrét példát, a v_{11} súlyt:

 \frac{\partial E_{o_1}}{\partial v_{11}}

Vegyük észre, hogy a v_{11} csak egyetlen egy hibához, a o_1 hibájához járul hozzá. Az o_2 teljesen független tőle. Ugye, a négyzetes hibában nem szerepel a v, tehát ez a parciális deriválás nem lesz egy lépésben elvégezhető művelet. A láncszabályt használva vissza kell fejtenünk az egyenletet a keresett súlyig. Először is írjuk fel a Hibát, úgy, hogy lássuk a keresett elemet:

 E = 0.5 \cdot (y-f_k(v_p o_r))^2

Most már látjuk a v súlyokat. Úgyhogy felírhatjuk a parciális deriváltak sorát. Először deriváljuk a o_1-t az o_1-hez tartozó hibából:

 \frac{ \partial E_{o_p} }{ \partial o_p} = o_p-y_p

Lépjünk egyel visszább, most az f_k-ból a u_p-t. Ez egy kicsit trükkösebb, mivel a ReLU nem deriválható egy az egyben, csak két részben: külön eset ha u kisebb, mint 0 és külön eset, ha nagyobb.

 \frac{ \partial f_k(u_p)}{ \partial u_p} = \begin{cases} 1 & \text{ha } u_p > 1 \\ 0 & \text{ha } u_p <=0 \end{cases}

És a következőben már meg is érkeztünk a v-hoz. Vegyük észre, hogy itt a deriváltnál szintén két lehetőség van: 1 ha az eltolásra deriválunk, és 1 ha bármelyik másra:

 \frac{ \partial u_p}{ \partial v_{mp}} = \begin{cases} o_r & \text{ha } p >0 \\ 1 & \text{ha } p = 0 \end{cases}

A fentieknek megfelelően a Hiba v_{11}-ra számolt részderiváltja:

 \frac{\partial E_ {o_1} }{\partial v_{11}} = \frac{\partial E_{o_1}}{\partial o_{1}} \cdot \frac{\partial f_k(u_1)}{\partial u_{1}} \cdot \frac{\partial u_1}{\partial v_{11}}

Ami behelyettesítve:

 \frac{\partial E_{o_1}}{\partial v_{11}} = (o_1-y_1 ) \cdot 1 \cdot o_r = 0,1582235

Ez azt fejezi ki, hogy mekkora részben felelős a v_{11} a Hibáért. Mivel csökkenteni akarjuk a hibát, ezért az így kapott eredményt ki kell vonnunk a jelenleg beállított súlyból, hogy a következő alkalommal jobb eredményt kapjunk. Ennek megfelelően a frissített súly így alakul:

 v_{11} = v_{11} - \eta \frac{\partial E_{o_1}}{\partial v_{11}}

Ahol:

  • \eta — a tanulási ráta. Erre most nem térek ki, maradjunk annyiban, hogy gradient descent tanulást alkalmazunk.

Gondolom, már mindenki rájött, hogy a lejátszáshoz hasonlóan, ezt se kell egyesével számolni a neuronokra. Rétegenként is elvégezhetjük egyszerű lineáris algebrával:

v_gradient = np.insert(o_r,0,1,axis=0) * ((o-y)*f_k.derivate(u)  ).reshape(1,-1).T

Ami ebben a példában:

 \frac{\partial E}{\partial v_{mp}} = \begin{bmatrix} 0,81152104 & 0,1582235 & 0,40160394 & 0,57630714 \\0,77152357 & 0,15042513 & 0,38181007 & 0,54790266 \end{bmatrix}

Most már csak frissíteni kell ezzel az értékkel a kimeneti réteg súlyait az elözöeknek megfelelően. De mielőtt ez megtennénk számoljuk ki a Rejtett réteg súlyainak gradienseit. Ajánlott előszőr minden gradienst kiszámolni és csak utána frissíteni az összes súlyt. Miért? Mindjárt kiderül.

A Rejtett réteg súlyainak hibája

Az alapvető eljárás ugyanaz lesz itt is mint a Kimeneti réteg esetében, azzal az eltéréssel, hogy itt még visszább kell fejteni a láncszabály segítségével. Ami még megbonyolítja az életünket, az az, hogy a Rejtett rétegben nem csak 1 irányból érkezik az adat, hanem a Kimeneti rétegben lévő minden neurontól. Nézzük például a w_{11} súlyt:

A Rejtett réteg súlyainak hibája

A fenti ábrán pirossal jelöltem, honnan származnak az információk, amelyeket ennek a súlynak a frissítésére használunk. Egyértelmű a különbség a Kimeneti réteghez képest. Ott a neuronokra csak egy irányból érkezett információ, ezzel szemben a Rejtett rétegben az előző rétegben lévő minden neuron befolyásolja, hogy milyen módon frissítjük a súlyt. Ennek megfelelően a w_{11} -nak megfelelő parciális derivált a következő lesz:

 \frac{\partial E}{\partial w_{11}} = \frac{\partial E}{\partial o_{r1}} \cdot \frac{\partial f_r(z_1) }{\partial z_1} \cdot \frac{\partial z_1}{\partial w_{11}}

Ahol:

  •  o_{r1} — a Rejtett réteg 1. neuronjának kimenete

Vegyük észre, hogy menyire hasonlít ez a Kimeneti réteg egyenletére. Számítása is hasonló lesz, csak az első részderivált okozhat némi problémát. Ez a rész arra válaszol, hogy összességében mekkora hibát generált ez a súly a következő rétegen. Vagyis:

\frac{\partial E}{\partial o_r} = \frac{\partial E_{o_1}}{\partial o_{r1}} + \frac{\partial E_{o_2}}{\partial o_{r1}}

Hogyan valósítsuk meg ezt a gyakorlati életben? Úgy, hogy a Visszajátszás során minden előző rétegben kiszámoljuk, ezt az értéket, és csak ezt passzoljuk vissza az előző rétegnek. Ez a magyarázata annak, amiért nem frissítjük a súlyokat egyből, amint kiszámoljuk a hibájukat. Ha így tennénk az összeadás elemei megváltoznának.

Az összeadásban szereplő elemeket meg így általánosíthatjuk:

 \frac{\partial E_{o_p}}{\partial o_{rm}} = \frac{\partial E_{o_p}}{\partial o_p} \cdot \frac{ \partial f_r(u_p)}{ \partial u_p} \cdot \frac{ \partial u_p}{ \partial v_{mp}}

Pythonban:

elozo_retek_hiba = np.sum(v*((o-y)*f_k.derivate(u)).reshape(1,-1).T, axis=0)

A Kimeneti rétegben megismert módon számíthatjuk ennek a rétegnek a hibáit is:

w_gradient = np.insert(x,0,1,axis=0) * ( elozo_retek_hiba * f_r.derivate(z) ).reshape(1,-1).T

A konkrét számtani példánál maradva az eredmény pedig a következő:

 \frac{\partial E}{\partial w_{mp}} = \begin{bmatrix} 0,75373805 & 0,0376869 & 0,07537381 \\0,71116975 &  0,03555849 &0,07111697 \\0,54531045 & 0,02726552 & 0,05453104 \end{bmatrix}

A Súlyok frissítése

Most már, hogy ismerjük az össze súly hibáját, nyugodtan frissíthetjük őket:

eta = 0.002
v = v-eta*v_gradient[:,1:] 
v0 =  (v0.T - eta*v_gradient[:,0]).T 
w = w-eta*w_gradient[:,1:]
w0 = (w0.T - eta*w_gradient[:,0]).T 

Aminek megfelelően az új súlyok a következők lesznek:

 w = \begin{bmatrix} 0,14849252 & 0,24992463 & 0,34984925 \\0,44857766 & 0,54992888 & 0,64985777 \\ 0,74890938 &0,84994547 & 0,94989094 \end{bmatrix}

v = \begin{bmatrix} 0,19837696 & 0,29968355 & 0,39919679 & 0,49884739 \\ 0,59845695 &0,69969915 & 0,79923638 & 0,89890419 \end

Befejezés

Ezzel készen is vagyunk. Átnéztük a MNH alapvető lépéseit és elemeit. Napjainkban már persze egy rakás szoftver könyvtár elérhető MNH megvalósítására, és általában azokat használjuk a gyakorlati életben. Viszont, ha anélkül használunk valamit, hogy valóban értenénk a működését, fennáll a veszélye annak, hogy az „mágiává” válik. Sokszor mint valami Delphoi orákulumot kezelik a Neurális Hálózatokat. Ami sajnos magával hozza a rossz felhasználásokat is. Ez a lehetőség maga is megérne egy újabb bejegyzést, de nem részletezem, hanem végszó gyanánt álljon itt két fontos megjegyzés:

  • Minden MNH annyit ér, amennyit az adat, amivel tanítjuk.
  • Csak a lokális legjobb válasz megtalálása garantált.
Szólj hozzá!

A Mesterséges Neurális Hálózat alapjai – 1. rész

2020/06/16. - írta: sajozsattila

 

 

Napjaink igen felkapott elnevezéseinek egyike minden bizonnyal a Mesterséges Neurális Hálózat (MNH), avagy Artificial Neural Networks (ANN). Ami jórészt annak köszönhető, hogy e technológiának a mindennapi életben való alkalmazásai az emberek egy jelentős részét lenyűgözi. Az MNH az alapja sok arcfelismerő, képfeldolgozó megoldásnak, a Google-fordítónak vagy a Facebook-hirdetés optimalizációjának, hogy csak néhányat említsek. Mai posztomban a legegyszerűbb MNH-t, az un. Feedforward-típust törekszem egy kicsit részletesében bemutatni.


In medias res, kezdjük a neurális hálózat részeivel! Ehhez rajzoltam egy diagramot:

1. ábra
Neurális hálózat részei

Elsőre talán bonyolultnak látszik, de valójában nagyon egyszerű. Ha jól megnézzük a fenti ábrát, láthatjuk, hogy csupán két fajta objektumból épül fel:

  • a körök — az úgynevezett neuronok. Ezek végzik a számítást.
  • a nyilak — a neuronok közötti kapcsolatokat jelölik. A fenti ábrán minden neuron kapcsolódik minden neuronhoz a következő rétegben. Ezt az elrendezést „teljesen csatolt” rendszernek nevezzük. (Van olyan eset is, amikor ez nem így van. Ilyenkor „részlegesen csatolt” a rendszer, de a mi példánk nem ilyen.)

Az alapelemek nem véletlenszerűen helyezkednek el a térben, hanem rétegekbe rendezve. Három rétegtípusról beszélhetünk:

  • Bemeneti réteg — gondolom, senkit nem lepek meg, ha azt mondom, hogy a megfigyelt adatok itt érkeznek a hálózatba. Ebből a rétegből jobbára csak egy van (a kivételekkel most nem foglalkozunk). A rétegben elhelyezkedő neuronok mind egy-egy tulajdonságot, megfigyelési dimenziót jelölnek.
  • Rejtett réteg — a számítások helye. Ennek a rétegnek a célja modellezni a bemeneti rétegben feltüntetett tulajdonságok kapcsolatát. (A fenti példában egy rejtett réteg van, de voltaképpen akármennyi követheti egymást, akár elhagyhatjuk is ezt a réteget.).
  • Kimeneti réteg — beszédes neve szerint ez az utolsó réteg, az MNH eredményének helye.

Most nézzük a többi kifejezést az ábrán:

  • xn — az n tulajdonság megfigyelt értéke
  • w0m — a rejtett réteg neuronjára jellemző eltolás
  • wnm — a bemeneti és a rejtett réteg közötti kapcsolatokhoz rendelt súlyok. Az indexek a rétegeknek megfelelő neuronokat jelölik. Pl: w12 a bementi réteg 1. neuronját köti össze a rejtett réteg 2. neuronjával.
  • fr — a rejtett réteg aktivációs függvénye. Erről később lesz szó. Most csak azt vegyük észre, hogy a réteg összes neuronján megegyezik.
  • zm — az aktivációs függvény – az előző réteg kimenetéből és a súlyokból számolt – bemenete.
  • v0p — a kimeneti réteg neuronjára jellemző eltolás.
  • vmp — a rejtett és a kimeneti réteg közötti kapcsolatok súlyai. Az indexelés ugyanazon az elven működik, mint a wnm -nél.
  • fk — a kimeneti réteg aktivációs függvénye, hasonlóan a rejtett réteghez, a rétegen belül minden neuronon ugyanaz.
  • up — a kimeneti réteg aktivációs függvényének bemenete.
  • op — a hálózat végső eredménye.

Most, hogy ismerjük a MNH részeit, nézzük, hogyan mozog az adat a rendszeren belül. Ehhez idézzük fel, hogy minden felügyelettel végrehajtott tanulás lényegében három részből áll:

  1. Alkalmazzuk a már meglévő ismereteinket egy megfigyelésen, azaz az eddigi ismereteink alapján kiszámoljuk, hogy mi lehet a megfigyelés eredménye.
  2. Összevetjük az előző lépésben kiszámított eredményt a tényleges eredménnyel. Ha a kettő nem egyezik meg, akkor kalkuláljuk az eltérés mennyiségét és irányát. Lényegében Loss kalkulációt végzünk.
  3. Korrigáljuk az ismereteinket, annak megfelelően, hogy mekkora és milyen az előző pontban kiszámított hiba.

A Feedforward-típusú MNH első lépését nevezzük Lejátszásnak (Forward propagation), a másodikat a Hibaszámításnak, míg az utolsót a Visszajátszásnak (Back propagation). Gondolom, senkit se lepek meg, ha elárulom, hogy a lejátszás során az adatok a Bemeneti réteg felől a Kimeneti réteg felé haladnak. Az első ábrám ezt a lépést szemlélteti. Ezzel szemben a Visszajátszás során az ellenkező irányba haladunk:

2. ábra
Visszajátszás

Most, hogy ismerjük a hálózat alapvető felépítését, nézzük meg, mi a konkrét kivitelezése az egyes lépéseknek.

Lejátszás — Előrejelzés

Mint fentebb említettem, az összes számítás a neuronokban történik. De mit is csinál egy neuron? Lényegében hipersíkokat állít elő. Magát a konkrét számítást, amit végez, így lehetne megjeleníteni:

3. ábra
Mit csinál egy neuron

A fenti ábra a j rejtett rétegbeli neuron működését szemlélteti, de minden, nem a Bemeneti rétegben elhelyezkedő neuron ugyanígy működik. Első lépésben összeadja a bemeneti adatok súlyozott értekét. Ez lesz a zj . Vegyük észre, hogy van egy bemeneti érték, ami mindig 1, ez az eltolás. Vagyis:

 z_j = w_{0j} + \sum_{i=1}^n x_i w_{ij}

Majd ezen a zj-én alkalmazza a fr aktivációs függvényt. És ezzel kész is van. A függvény kimeneti értéke már megy is a neuron kimenetére. Miért kell az aktivációs függvény? Azért használjuk, hogy a lineárisan nem elválasztható feladatokat is meg tudjunk oldani.

Hogy ne csak elméletben legyünk képesek megoldani ezt a feladatot, számszerűsítsük a fenti modellt, valahogy így:

Mivel elég kusza lett volna, ha minden számot feltűntetek a fenti ábrán, csak néhány értéket ábrázoltam. A teljes kezdeti állapot legyen a következő:

x = \begin{bmatrix} 0,05 \\ 0,1 \end{bmatrix}

w = \begin{bmatrix} 0,15 & 0,25 & 0,35 \\ 0,45 & 0,55 & 0,65 \\ 0,75 & 0,85 & 0,95 \end{bmatrix}

v = \begin{bmatrix} 0,2 & 0,3 & 0,4 & 0,5 \\ 0,6 & 0,7 & 0,8 & 0,9 \end{bmatrix}

Nézzük az első neuront a Rejtett rétegben. Ennek a z1 értéke az (1) alapján:

z_1 = 1\cdot 0,35+0,05 \cdot 0,25 + 0,1 \cdot 0,35 = 0,1975

Aki egy kicsit járatos a lineáris algebrában, az már biztosan rájött, hogy nem kell minden neuront külön-külön kiszámítanunk, hanem a számítást rétegenként egyszerre elvégezhetjük:

	
import numpy as np # megfigyelés
x = np.array([.05, .1])

# rejtet réteg súlyai
w = np.array([[.25,.35],[.55, .65],[.85, .95]])

# rejtett réteg eltolás
w0 = np.array([[.15],[.45],[.75]])

# rejtett rétek z érték
z = (np.concatenate((w0, w), axis=1))@np.insert(x,0,1,axis=0)

Aminek az eredménye:

 z = \begin{bmatrix} 0.1975 \\ 0.5425 \\ 0.8875 \end{bmatrix}

A következő lépésben át kell engednünk ezt az eredményt a rejtett réteg aktivációs függvényén. Ez a 3. ábra szerint, egy tanh függvény. Vagyis:

 f_r(z) = 1-\frac{2}{e^{2z}+1}

Ugye, ez az első neuron esetén:

 f_r(z_1) = 1-\frac{2}{e^{2z_1}+1} \approx 0.194972

A teljes rejtett rétegre:

	
class Tanh(): def run(self, x): return 1-(2/(np.exp(2*x)+1))
def derivate(self, x): return 4*np.exp(2*x)/(np.exp(2*x)+1)**2
# rejtett réteg aktivációs függvény f_r = Tanh()

# rejtett réteg kimenet
o_r = f_r.run(z)

Az eredmény pedig:

o_r = \begin{bmatrix} 0.19497153 \\ 0.49487804 \\ 0.71015674 \end{bmatrix}

A Rejtett réteget be is fejeztük. Most ismételjük meg ugyanezeket a lépéseket a Kimeneti rétegben. A lépések ugyanezek, az egyetlen különbség, hogy az aktivációs függvény ReLU lesz:

f_k(u) = max(0,u)

Ne is húzzuk az időt, nézzük mi a Kimeneti réteg eredménye:

	
class ReLU(): def run(self, x): return np.maximum(0,x)
def derivate(self, x): x[x0] = 1 return x
# kimeneti réteg súlyai v = np.array([[0.3,0.4,0.5],[0.7,0.8,0.9]])
# kimeneti rétek eltolása
v0 = np.array([[.2],[.6]])

# kimeneti réteg
u = (np.concatenate((v0, v), axis=1))@np.insert(o_r,0,1,axis=0)
f_k = ReLU()
o = f_k.run(u)

Aminek az eredményei:

 u = \begin{bmatrix} 0.81152104 \\1.77152357 \end{bmatrix}

Mind a két szám pozitív, így nem meglepő módon a ReLU aktivációs függvény nem változtat rajtuk:

o = \begin{bmatrix} 0.81152104 \\1.77152357 \end{bmatrix}

Végére is értünk a Lejátszási szakasznak.

A következő lépésben meg kell néznünk, hogy mekkora hibát követtünk el, és a beállításokat ennek megfelelően kell frissítenünk. Ezt fogjuk a következő blogbejegyzésben megtárgyalni.

Irodalom

Szólj hozzá!

Nem egyenlő végtelenség

2020/06/06. - írta: sajozsattila

 

a.k.a Miért megszámolható a Racionális számok halmaza és miért nem a Valósoké?Valószínűleg a lustaságom az oka annak, hogy reggel azon gondolkodtam: miért duplázzuk meg a valószínűségszámítást azzal, hogy ugyanazt a számítást felírjuk külön diszkrét és külön folytonos esetre.


Bevezetés

Az diszkrét és folytonos esetek közötti egyetlen különbség az, hogy a diszkrét esetben Összegzést a folytonos esetben Integrált használunk. Nézzük például a valószínűségi Tömegfüggvényt[1] és a Sűrűségfüggvényt[2]. Mind a kettő ugyanazt mutatja: mekkora a valószínűsége, hogy x értéket figyeljük meg a populációból.[3] Nézzünk egy példát:

Sűrűség és tömegfügvény

Mint tudjuk a teljes valószínűség a Sűrűségfüggvény alatti terület:

 1 = \int_{-\infty}^{\infty} f_X(x) \text{ dx}

A Tömegfüggvény esetén pedig:

1 = \sum_{i=-\infty}^{\infty} P_X(x_i)

Ez eddig egyszerű, de mi van akkor, ha sokkal de sokkal több pontunk van a Tömegfüggvényben? Pl:

Sűrűség és tömegfügvény sok pontal

És mi van ha mondjuk végtelen sok pont? Az elég folytonosnak látszik nem? Nekem erről ez jutott eszembe:

Darboux felső integrál[4]

Na mi ez? Igen-igen. A Darboux felső integrál számítás szemléltetése. A határozatlan integrálás célját általában úgy szokták bevezetni, hogy: “az görbék alatti területek kiszámítására való”. Majd következik a fenti ábra.

Ebből a hozzám hasonló egyszerű lelkek azt gondolják, hogy az integrál lényegeben egyfajta Összegzés: Van egy rakás végtelenül kicsi szélességű oszlopunk és összeadjuk a területüket. De milyen kicsi az a végtelenül kicsi oszlop szélesség? Leibniz és Newton nemes egyszerűséggel nem foglalkoztak ezzel a kérdéssel, amiért sok kritikát kaptak később. Viszont mi megtesszük, nem mintha sokkal okosabbak lennék, hanem mert mások már elvégezték a munkát számunkra és mindig könnyű más tollaival ékeskedni. Tehát mi legyen ez a végtelenül kicsi szám? Ha mondjuk az mondom hogy legyen a legkisebb pozitív Racionális szám? Vagy inkább a legkisebb pozitív Valós szám? Mi az pont amikor azt mondjuk ez még diszkrét, (tehát összegezzük), de az már folytonos (tehát integráljuk).

Maga a definíciója a diszkrétnek megadja a választ erre a kérdésre. Diszkrét az ami megszámolható, a folytonos pedig nem. A folytonosság pedig alapfeltétele az integrálásnak. És ezzel elérkeztünk ahhoz, amiről lényegében írni szeretnék. Miért megszámolható a Racionális számok halmaza és miért nem a Valósoké?

Miért megszámolhatóak a Racionális számok?

Van egy számhalmaz, ami definíciója szerint megszámolható, ez a Természetes számok halmaza (jele az N). Ezt nekem úgy tanították az általános iskolában, hogy a pozitív egész számok halmaza.[5] Ezek a számok a 0, 1, 2, 3, 4 … számok, és a dolgok számosságát jelentik. Ha erre emlékszünk, akkor már egy nem nagy logikai ugrással tudjuk, hogy valami csakis akkor megszámolható, ha egy az egyben le lehet vetíteni[6] a Természetes számok halmazára.

Vagyis ha a Racionális számok (jele a Q) megszámolhatóak, akkor ez a vetítés lehetséges. De nincs itt valami ellentmondás? A Természetes számok a racionális számok alhalmaza nem?

Számhalmazok

Legalább mintha így tanítanák: minden N benne van az Egész számok halmazában (jele a Z), és minden Z benne van a Racionális számok halmazában. Logikus. De ha ez igaz akkor, nem kellene a Q halmaznak nagyobbnak lennie mint az N halmazé?

Nem. Ezt pedig először egy bizonyos Georg Ferdinand Ludwig Philipp Cantor nevű német matematikus ismerte fel. Neki köszönhetjük a megszámolható és megszámlálhatatlan halmazok megkülönböztetését.

A trükk ott van, hogy minden megszámolható ami sorba rendezhető. ??? Igen, itt bizony a természetes számok egy eltérő értelmezésével állunk szemben. Az N halmaz elemeit két oldalról közelíthetjük meg:

  • egyrészt tekinthetjük mint: 0,1,2,3… — Ezeket nevezzük Kardinális számnak, és matematikába való bevezetésüket szintén Cantor-nak köszönhetjük. Értelmük lényegében megegyezik az elemszámával, vagyis a “Mennyi?” kérdésre válaszolunk vele. Például az {a, b, c, d, e} halmaznak 5 a kardinális száma, mivel 5 eleme van.
  • másrészt mint: első, második etc. — A második értelmezést nevezzük Rendszámnak[7], és a “Melyik?” kérdésre válaszolunk velük.

A Racionális számok pedig sorba rendezhetők. Mégpedig az alábbi módon:

Racionális számok sorba rendezése

Ez nagyon érdekes. Ez azt bizonyítja, hogy ugyanannyi Természetes számunk van mint ahány Racionális számunk. Mennyi? Végtelen! De ez a két végtelen egyenlő.

Minden végtelen egyenlő, de a Valós számok végtelenje egyenlőbb

De akkor miért nem megszámolhatóak a Valós számok? Az is végtelen számú nem? Igen! De ez a végtelen nagyobb mint az előző. Ezt pedig a Átlós eljárással lehet könnyen bizonyítani:

Átlós eljárás

Úgy néz ki Cantor lendületben volt a Racionális számok megszámolása után és úgy gondolta akkor megnézi hány darab Valós szám van. Mint kiderült ez nem megszámolható. Ehhez először azt bizonyította, hogy 0 és 1 között megszámolhatatlan sok van. A bizonyítás első lépésében felírunk egy rakás racionális számot egymás után. Pl. nulladik legyen a 0,236436775676…, az első mondjuk 0,098473294543… és így tovább. Tegyük fel, hogy rengeteg időnk van és felírjuk az összes (végtelen mennyiségű) lehetséges Racionális számot. Ezután vegyük a felírt számok átlóját, a fenti képen pirossal jelöltem ezt. Ez átlón szereplő számjegyek egy számot adnak nekünk. A fenti példában: 0,293233992132… Ebből a számból készíthetünk egy új számot, méghozzá úgy, hogy az minden számjegyét kicseréljük egy számra ami nem egyezik vele, és 0-val vagy 9-el.[8] Például az első kettes helyébe írjunk 7-et (bármit írhatunk kivéve 2, 0 és 9), a második 9 helyébe mondjuk 4-et. A lényeg csak, hogy ne egyezzen. Mit tudunk az így kapott számról (a példában 0,746894310875…)? Nem egyezik a nulladik számmal, mivel az első tizedesnél eltér tőle. Nem egyezik az első számmal, mivel a második tizedesnél eltérnek … Vagyis nem egyezik egyik számmal se a listán. És mit jelent ez, ha felírtuk mind a végtelen mennyiségű Racionális számot? Pontosan! Ez a szám nagyobb mint az a Természetes számok végtelenje.

Csodálatos! Egyrészt kiderült, hogy a végtelenek nagysága nem egyforma, másrészt, hogy több Valós szám van mint Természetes. A második következménye pedig, hogy a Valós számok halmaza nem megszámolható, tehát nem diszkrét. A csodálatos dolog, hogy két egymáshoz végtelenül közel lévő Racionális szám között is végtelen számú Valós szám van. Ez a folytonosság.

Röviden ez az oka annak, hogy mindent kétszer mondunk el a valószínűségszámításban…

Nem egyenlő végtelenség

a.k.a. miért nem integrálunk mindent?

Lássuk be: lusta vagyok. Ennek egyik következménye, hogy néha olyan dolgokon gondolkodom amin jó dolgos emberek nem. Valószínűleg ez az oka, hogy reggel azon gondolkodtam miért duplázzuk meg lényegében a valószínűségszámítást azzal, hogy ugyanazt a számítást felírjuk külön diszkrét és külön folytonos esetre.

Most ezt nem mondom el megint :-)

Lábjegyzet

  1. Angolul: Probability mass function ↩︎

  2. Angolul: Probability density function ↩︎

  3. Tudom-tudom. A Sűrűségfüggvénynél nincs a pont értéknek valószínűsége, és a terület fejezi ki az adott valószínűséget, míg a Tömegfüggvénynél van. De ez a különbség a számítás módjából következik. Most pont erről van szó. Miért használjuk az egyik vagy másik számítási módot. ↩︎

  4. Forrás: Wikipédia ↩︎

  5. Most hagyjuk azt kérdést, hogy a 0 az Természetes szám vagy nem. ↩︎

  6. Angolul ezt a nagyon szép: “Bijective mapping” kifejezéssel illetik. ↩︎

  7. Angolul: ordinal number ↩︎

  8. Miért diszkrimináljuk a 0 és 9 számjegyeket? Ha érdekel itt elolvashatod mit írtam erről. ↩︎

Szólj hozzá!
süti beállítások módosítása