ML i C
De som har testat att bygga någonting med ML känner nog till bibliotek såsom PyTorch eller Tensorflow. Dessa har blivit extremt populära eftersom de abstraherar bort mycket av de jobbiga sakerna såsom att se till så att beräkningarna görs hypereffektivt. Biblioteken är även gjorda för att användas i Python, ett väldigt användarvänligt programmeringsspråk. Det låter en helt enkelt att jobba på de viktiga sakerna, att bygga riktigt grymma modeller.
För att få en bättre förståelse för hur algoritmerna fungerar matematiskt men även vad som händer "inuti datorn" försökte jag bygga mitt egna ML bibliotek från scratch i C. Detta var inte lätt men jag fick en mycket större uppskattning för PyTorch och lärde mig en hel del. Jag kommer visa hur jag implementerade ett "fully connected"/linear/dense layer.
I ett neural network har man lager vilket enkelt förklarat är olika typer av operationer som görs på datan. Det enklaste lagret "dense layer" (så jag kallar det i mitt bibliotek även fast jag mestadels använder PyTorch lol) tar en samling nummer som representerar någonting, multiplicerar det med en "vikt" och adderas med en "bias". Vikter och bias kallas för parametrar och påverkar outputen av nätverket, det är dessa man vill ändra på för att uppnå ett så bra resultat som möjligt. För att göra multiplikationen generell för hur stora datamängder som helst använder man matrismultiplikation. Note: Matriser och linjär algebra är utanför scopet av denna post men rekommenderar starkt att lära sig det om man vill bli bra på ML och förstå algoritmerna.
Att gå igenom ett dense layer kan kompakt skrivas som:
Y = WX + b, där W är en matris med alla vikter, Y är outputen, X är inputdatan och b är bias.
För att implementera detta i mitt program var jag först tvungen att implementera en matris struktur. (Se första bild). En matris kan ses som en tabell där man har rader och kolumner. Detta kan ses som motsvarigheten till en klass i Python. För att skapa matriser implementerade jag, createMatrix på detta vis (Se andra bild). Lägg märke till funktionen malloc. I andra mer high level språk är det väldigt enkelt att definiera arrays, man definierar en ny variabel och sen kanske man använder [] eller liknande tecken. I C fungerar det inte riktigt likadant, man måste istället definiera exakt hur stor del av ram minnet som ska användas. Eftersom arrayen kommer ha längd cols * rows och vara av typ floats innebär det att storleken kommer vara antal element gånger storleken på datatypen. Jag har även implementerat andra funktioner relaterade till matriser som jag inte kommer gå igenom en som finns på min github att kika på.
Som nämnt ovan behövs det i ett dense layer, input datan, vikter och bias. Detta gjorde att att jag definierade strukturen för mitt dense layer på detta sättet ( Se tredje bild). Jag valde även att lägga till fälten in_features och out_features för att kunna bestämma hur många element som kommer in och hur många som kommer ut, likt hur det görs i PyTorch.
För att sedan gå igenom lagret och få en output implementerade jag denseLayer (Se fjärde bild). Funktionen tar in som argument en pekare till inputDatan men också datan för lagret som innehåller information om bland annat vikterna och biasen. Pekare är en typ av variabel som inte håller ett värde utan en address i minne till en variabel, den beskriver för datorn hur den ska hitta den variabeln. Detta är extremt kraftfullt eftersom man kan manipulera variabler som skickats in i argumenten. Detta finns i de allra flesta low level språk.
I funktione utför jag som nämnt innan operation WX + b genom att multiplicera input datan med vikterna och addera med bias. Sedan ser jag till att spara datan på rätt sätt för senare bruk.
Detta är hur jag implementerat ett denseLayer i ren C, hela vägen från matriser till neural networks. Uppmanar de som är nyfikna att kolla in mitt github repository: https://github.com/AlexanderJernstrom/alex-net där ni kan se exakt hur all kod är skriven. Om något var otydligt eller generellt dåligt förklarat är det bara att skriva så ska jag göra mitt bästa för att förklara det.
Har även implementerat backwardspropagation, nätverkets metod för att uppdatera parametrarna. Blir dock lite mycket att skriva om det i denna post. Om ni är intresserade kan jag lägga upp en ny post där jag förklarar hur jag implementerade backwardspropagation.
1
4 comments
Alexander Vivas Jernström
1
ML i C
<hackersson>
skool.com/hackersson-7455
Här samlas Sveriges bästa programmerare och hackers för att bygga framtiden. Häng på.
Leaderboard (30-day)
powered by