Skip to content

Latest commit

 

History

History

week7

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

Week 7

  • Werken met Neural Networks in Javascript
  • Data, trainen en model opslaan
  • Voorspellingen doen
  • Expert level
  • Troubleshooting




Neural Networks


In week 6 hebben we pose data leren herkennen met het "K-Nearest-Neighbour" algoritme. We gaan nu het "Neural Network" algoritme gebruiken. Een aantal voordelen:

  • Het KNN model moet altijd alle data onthouden.
  • Een KNN model kan erg groot zijn als er veel data is.
  • Het NN model kan juist erg klein zijn, ongeacht hoeveel data er is.
  • Een NN is beter in het vinden van complexe of onlogisch lijkende patronen (een grote dikke kat wordt toch als kat herkend en niet als hond)
  • Een NN kan focussen op de belangrijke onderdelen (de "claws" van een kat bepalen eigenlijk al dat het een kat is)



Neural Network: the basics

Om te oefenen gebruiken we dezelfde cat/dog data als in week 6.

Body length Height Weight Ear length Label
18 9.2 8.1 2 'cat'
20.1 17 15.5 5 'dog'
17 9.1 9 1.95 'cat'
23.5 20 20 6.2 'dog'
16 9.0 10 2.1 'cat'
21 16.7 16 3.3 'dog'

We voegen de ML5 library toe aan ons project met een <script> tag.

<script src="https://unpkg.com/ml5@latest/dist/ml5.min.js"></script>

We maken een neural network aan voor classification, en voegen de cat/dog data toe. Vul dit zelf helemaal in.

const nn = ml5.neuralNetwork({ task: 'classification', debug: true })
nn.addData([18,9.2,8.1,2], {label:"cat"})
nn.addData([20.1,17,15.5.5], {label:"dog"})
// vul hier zelf de rest van de data in
// ...
nn.normalizeData()
nn.train({ epochs: 10 }, () => finishedTraining()) 
async function finishedTraining(){    
    const results = await nn.classify([29,11,10,3])
    console.log(results)
}

Zorg dat je cats and dogs kan voorspellen voordat je verder gaat met de mediapipe oefening.

In bovenstaande code wordt zowel een callback als een async await code gebruikt. Je moet wachten tot het trainen klaar is, en je moet ook wachten tot een classify klaar is. Vergeet dit niet bij het bouwen van je eigen app.




Workflow

We gaan nu werken aan opdracht 2. Je gaat posedata gebruiken om een neural network te trainen. Je werkt in drie projecten:

Voorbereiding Training Applicatie
Data verzamelen uit MediaPipe Data gereed maken Webcam stream lezen
Opslaan in JSON of JS file Neural Network trainen Model laden
Model opslaan Voorspelling doen




Werken met posedata

Zorg dat je posedata beschikbaar is in je project. Data kan in de vorm van objecten of arrays zijn. Voor een neural network is het belangrijk om je data te randomizen.

let data = [
    {pose:[4,2,5,2,1,...], label:"rock"},
    {pose:[3,1,4,4,1,...], label:"rock"},
    {pose:[5,2,5,3,3,...], label:"paper"},
    ...
]
data = data.toSorted(() => (Math.random() - 0.5))




Data gereed maken voor Neural network

Na het randomizen kan je poses aan het neural network toevoegen via de addData functie. Dit doe je door je data op te splitsen in een array van numbers: [3,5,2,1,4,3,5,2], gevolgd door een object met het label: {label:"rock"}. Je voegt één pose als volgt toe:

nn.addData([3,5,2,1,4,3,5,2], {label:"rock"})

Je hebt een for loop nodig om één voor één al je pose data toe te voegen.

🚨 Een veel voorkomende fout is dat je posedata uit mediapipe niet naar de juiste vorm is omgezet voor de addData functie. Wat ook vaak fout gaat is dat niet elke pose evenveel punten bevat, of dat je labels niet overeenkomen.




Trainen

Nadat je al je data hebt toegevoegd roep je de normalize functie aan. Daarna begin je met trainen. Bij het trainen kan je experimenteren met het aantal epochs. De blauwe lijn moet zo dicht mogelijk bij de waarde 0 komen.

Als de blauwe lijn nauwelijks verbetert, ook bij een hoog aantal epochs, dan is er waarschijnlijk een probleem met je data. Zie het troubleshooting hoofdstuk.

function startTraining() {
    nn.normalizeData()
    nn.train({ epochs: 10 }, () => finishedTraining()) 
}
async function finishedTraining(){
    console.log("Finished training!")
}
Training kan beter Training gaat goed



Maak een voorspelling

Als je een model hebt, kan je met de classify functie testen of je nieuwe data kan voorspellen. Neem bijvoorbeeld handmatig een pose uit je data, of uit mediapipe, en kijk of dit ook goed voorspeld wordt. Let op dat je posedata evenveel punten bevat als bij het trainen!

async function makePrediction() {
    const results = await nn.classify([2,4,2,1,3,5,6]) // dit is een pose uit mediapipe
    console.log(results)
}



Model opslaan

Omdat je niet telkens opnieuw een model wil trainen gaan we het opslaan.

nn.save("model", () => console.log("model was saved!"))



De frontend applicatie bouwen

Dit is je game of applicatie die door de eindgebruiker gebruikt gaat worden. Hierin wordt de live webcam getoond met poses. Je gaat nu ook weer posedata uit de webcam halen. Het doel is nu om te voorspellen welke pose de gebruiker aanneemt, dit doen we met ons getrainde model.

  • Toon de webcam en lees posedata met mediapipe
  • Laad het getrainde model
  • Maak een voorspelling van de live posedata




Model laden

const nn = ml5.neuralNetwork({ task: 'classification', debug: true })
const modelDetails = {
    model: 'model/model.json',
    metadata: 'model/model_meta.json',
    weights: 'model/model.weights.bin'
}
nn.load(modelDetails, () => console.log("het model is geladen!"))

Nadat het model is geladen (let op de callback functie), kan je live posedata uit de webcam gaan voorspellen met het neural network. Verzamel data van één live pose, en roep hiermee de classify() functie aan.




Expert level




Troubleshooting

Workflow

Bij het werken met Neural Networks heb je vaak meerdere projecten tegelijk open staan:

  • Het project waarin je data verzamelt uit de webcam en er een label aan geeft.
  • Het project waarin je een model aan het trainen bent met de gelabelde data. Hier heb je de webcam input niet nodig.
  • Het project waarin je test of je model goed werkt met nieuwe input. Dit kan je doen met testdata of met live webcam input. In het eindproduct hoef je niet altijd de pose als lijntjes over het webcam beeld heen te tekenen.

Asynchrone functies en callbacks

Een ML5 neural network werkt met callbacks en asynchrone functies. Dat betekent dat je moet wachten totdat een bepaalde taak is afgrond, voordat je de volgende taak kan uitvoeren! Bijvoorbeeld:

  • Laden van een JSON file met fetch
  • Trainen van een ML5 Neural Network
  • Inladen van een model
  • Doen van een voorspelling

Je moet wachten totdat een call klaar is voordat je naar de volgende stap door kan gaan. In dit codevoorbeeld wachten we tot het laden van het model klaar is:

nn.load(modelDetails, () => nextStep())

function nextStep(){
    console.log("het model is geladen!")
}

🚨Een veel voorkomende fout is om te proberen een voorspelling te doen terwijl het trainen nog niet klaar is, of als het model nog niet is ingeladen.


Fouten bij trainen

Het trainen van een model kan makkelijk mis gaan. De meest voorkomende oorzaken:

  • De data is niet consistent. De inhoud van elk datapunt (een array met getallen) moet hetzelfde zijn (bv. een array van 20 numbers).
  • Er is te weinig data. Probeer minimaal 20 tot 30 poses per label op te slaan. 100 poses zou nog beter zijn.
  • De data bevat niet genoeg variatie. Dit valt op als het trainen wel goed gaat maar het voorspellen werkt niet goed. Probeer voor elk label verschillende variaties op te slaan (dichtbij camera, ver van camera, links in beeld, rechts in beeld).
  • De labels kloppen niet of je bent labels vergeten.
  • Er is iets mis gegaan bij het omzetten van je webcam data naar training data. Je moet een array van getallen en een object met een label doorgeven [3,3,4,32,2], {label:"Rock"}.
  • De labels komen niet overeen (bv. "Rock" en "rock" is niet hetzelfde).
  • Je data in de classify aanroep heeft een andere vorm dan de data die je bij addData hebt gebruikt.

🚫 De pose is hier een object, maar het moet alleen een array met numbers zijn

nn.addData({pose:[2,4,5,3]}, {label:"rock"})

🚫 De classify aanroep is niet hetzelfde als de addData aanroep

nn.addData([2,3,4], {label:"rock"})
nn.addData([5,3,1], {label:"paper"})
let result = await nn.classify([2,3,4,5,6,7])



Documentatie