Dette opslag omhandler et sideprojekt jeg har lavet i Machine Learning med algoritmen af neurale netværk. Sideprojektet omdrejer sig om spillet League of legends som jeg er stor fan af. Det er et spil jeg har brugt meget tid på at spille.
Jeg fandte det derfor interessant at lave et projekt omkring det. Derfor har jeg udviklet en beregner som skal forudse om man har spillet dårligt eller spillet godt. Det er et strategisk spil hvor man spiller 5 mod 5 og omhandler om at dræbe hinanden og ødelægge hinandens baser.
Det neurale netværk algoritme skal kunne forudse om man har spillet dårligt eller spillet godt ved at pumpe data ind:
- Antal dræbte
- Antal gange man har været død
- Antal assisterende dræbte
- Antal Wards placeret
- Antal Pinkwards placeret
- Antal wards ødelagte
- Hvor meget skade man har lavet
- Hvor mange CS (Creep store) man har
Udefra de værdier skal algoritmen fortælle om man har klaret det godt eller ej.
Der er blevet lavet en neural netværk algoritme. En kunstige neural netværk bentter matematiske værktøjer til at implementere algoritmen. Det neurale netværk er inspieret af den menneskelig hjerne og derfor navnet.
Det neurale netværk der anvendes er indenfor paradigmet for Supervised Learning som er et princip i machine learning som man kan anvende når man har med Labeled data at gøre. Under det princip har vi valgt tilgangen for classification. Classification omhandler at man klassificere sit output enten boolske eller lignende (dvs enten ja/nej, true/false, 0/1) der er dog blevet anvendt et karakter lignende skema hvor man får en karakter på hvor godt man har spillet og derfor klassificere det således.

Som vi kan se på ovenstående billede har vi input layer det er det data der bliver pumpet ind i algoritmen – i dette tilfælde af det spillets data. Det kaldes også input dimensions som i teorien bare er de features som datasættet har.
Så har vi hidden layer som ligger imellem input og output noderne, og som indeholder nogle BIAS værdier som laver en udregning og udefra uderegninger aktivere den noget der hedder (activiation function) og producere et output.
Så har vi vores output layer som er den endelig klassificering altså forudsigelsen.
Pilene kaldes for weights parameters som repræsentere værdier som bliver brugt til styrken i forbindelsen mellem neuronerne. Det var meget abstrakt forklaret – men jeg håber i forstår pointen.
I starten af projektet har vi følgendes implementering vi tager det linje for linje

Numpy biblioteket indeholder stor samling af matematiske funktioner på højt niveau og understøtter multidimensionelle arrays og matrixer. Vi anvender det i hele projektet.
Vi starter med at definere en funktion og denne funktion tager brug af numpy biblioteket. Vi køre linjen random seed som skal give os de samme random værdier til vores bias hidden layer så vi hele tiden har samme random værdier hver gang. Derefter Sætter vi vores synaptics weights til at være 8×1 matrix da vi har 8 features. med værdierne mellem -1 til 1. Så vi hele tiden arbejder i små værdier.

Så definere vi en sigmoid funktion. Sigmoid funktionen anvendes til at beslutte om en neuron skal aktiveres eller ej. Om informationen som det neurale netværk får er relevant for aktivationen af et neural netværk eller ej.
Vi definere også en sigmod derivative funktion som bliver brugt til at justere vores synaptic weights efter hver iteration.
Så definere vi en trænings funktion. Som får noget træningsinput (som er feature værdier i vores data) nogle træningsoutputs(som er outputted i vores datasæt) og hvor mange iterationer vi gerne vil igennem. Funktionens body indeholder et for each loop som siger at for hver iteration vi har i vores training_iterations vil vi gerne kalde metoden think som er i selve klassen og giver den trænings input som parameter. Derefter finder vi resultat af fejl ved at trække træningsoutput fra det beregenede output. Derefter justere vi vores synaptic weights ved at inkludere vores trænings input, fejl resultat og vores sigmoid deritative funktion.

Som vi kan se på ovenstående function er vores think function som tager imod et input og caster det til en float. Det er input brugeren indtaster i consolen. Vi får så returneret et output ved brug af sigmoid funktionen som tager imod inputsne og de predefinered synaptic weigthts.
np.dot hvis det ene array er et multidimensional array og b er et 1-D array som det er i vores tilfælde er det summen af produktet over den sidste axe af a og b. Derefter returnere vi outputtet.

Ovenstående billede er vores trainings input. Vi anvender numpys biblioteket igen til at lave det om til et numpy array grunden til vi bruger et numpy array er fordi at man så har adgang til en masse vector og matrix operationer samt er numpy arrays meget mere effektiv i runtime.
Værdierne er i arrayet er kronologisk rækkefølge: Antal dræbte, antal gange man har været død, antal assist, mængde af damage, antal wards placeret, antal pinkwards placeret, antal wards ødelagte og CS(creep store)
så har vi vores training output som indeholder karakteren i tal for 4 er det bedste og 1 er det laveste. Vi derefter laver det til et np array hvor vi transposer det således at værdierne er proportional.

Som det sidste kodestykke – viser ovenstående billede hvordan vi kalder vores train metoder som vi fik defineret tidligere, og giver den vores training inputs, training outputs og trainings iteration altså hvor mange gange vi vil itere igennem. Derefter printer vi synaptic weights efter at vi har trænet vores model.
Derefter udskriver vi til consollen som venter på at modtage input fra brugeren. Når brugeren har indtastet dataen vil vi smide dem ind som parameter inde i vores think metode som vi defineret før. Den går ind og anvender sigmoid funktionen med synaptics weight og udregner en beregning på korrekthed.

På ovenstående billede kan vi se resultatet vi får 99% korrekthed med at finde en karaktere til spilleren efter at have indtastet dataen. Det er meget præcist, fordi vi har trænet modellen med mange iterationer.
Refleksion
Under udførelsen af dette projekt stødte vi på nogle problemer i forhold til hvor store tallene var i vores data. da vi endte med weights der havde så mange decimaler at det ikke var muligt at regne med dem f.eks. 3.6234474e-20, derfor var vi nødt til at gå ind og mindske størrelsen på tallene for vores inputs. Først prøvede vi med at reducere, så der kun var tal mellem 40 – 0, men det virkede stadig ikke, så vi gik ind og dividerede det hele med 10, så vi endte med tal mellem 4 og 0, der lykkedes det os endeligt at få det til at fungere. Dette kan være problematisk da vi ikke har ændret noget i koden, kun i de inputs vi arbejder med, så hvis en person ville bruge vores pogram og taster inputs fra spillet uden at vide hvilket format tallene skal omregnes til, vil det fejle og personen vil få et forkert resultat ud.