TensorFlow Lite voor microcontrollers: Een introductie
op
TensorFlow Lite voor Microcontrollers maakt het mogelijk om machine learning-modellen uit te voeren op apparaten met beperkte bronnen. Wil je meer leren? Je kunt het gebruiken met Edge Impulse voor spraakherkenning op een Arduino Nano 33 BLE Sense.
AI aan de rand
Kunstmatige intelligentie (AI) en machine learning (ML) zijn de nieuwe modewoorden en soms worden ze verkeerd door elkaar gebruikt. Facebook, Amazon, Google en vele anderen gebruiken ML-systemen om u content te bieden die zo goed mogelijk is afgestemd op uw smaak en gewoonten. ChatGPT is een ander voorbeeld van een zeer spectaculaire en populaire dienst die ML gebruikt. Wat deze bedrijven gemeen hebben is de toegang tot servers met enorme rekenkracht om de modellen te trainen door gigantische hoeveelheden data te verwerken, en om vlot te reageren op vragen van een groot aantal gebruikers.
Dit is echter aan het veranderen met de opkomst van AI "on the edge". Edge AI verwijst naar de inzet van algoritmen en verwerking van kunstmatige intelligentie aan de rand van het netwerk, wat betekent dichter bij de databron en ver van een server, waardoor realtime data-analyse en besluitvorming mogelijk wordt met minder latentie en bandbreedtegebruik. Hoewel het begrip netwerk vaak naar voren wordt geschoven, werkt het ook helemaal zonder netwerk – bijvoorbeeld op een bescheiden microcontrollerboard, dat niet per se met het internet verbonden hoeft te zijn.
TensorFlow Lite voor Microcontrollers
Een interessante ontwikkeling op dit gebied vond een paar jaar geleden plaats met het verschijnen van TensorFlow Lite voor microcontrollers (TFLite Micro) . Het is een afgeslankte versie van TensorFlow, een open-source machine learning framework ontwikkeld door Google, ontworpen om machine learning modellen uit te voeren op microcontrollers, waardoor ML-toepassingen op kleine, resource-beperkte apparaten mogelijk worden. Dus, kunt u TFlite Micro draaien op uw Arduino-board? Ja, maar niet op alle Arduino's. Het is geschreven in C++ 17 en vereist een 32-bit platform, evenals een paar kilobytes RAM. Het kan gebruikt worden met veel ARM Cortex-M microcontrollers, en het kan ook gebruikt worden met ESP32. De volledige lijst van compatibele platformen is beschikbaar op . Dus, terwijl de eerbiedwaardige Arduino Uno niet opgewassen is tegen de taak, kan de Arduino Nano 33 BLE Sense (figuur 1) worden gebruikt. Dit is een krachtig board, en het is eigenlijk best ideaal om mee te spelen, omdat het al vol zit met sensoren: een 9-assige traagheidssensor, vochtigheids-, temperatuur-, kleur- en lichtintensiteitssensor, een druksensor en een microfoon.
Hoewel dit Arduino board krachtig is, is het nog steeds niet krachtig genoeg om het model direct op het board te trainen. Bij de meeste ML-projecten op basis van microcontrollers is de gebruikelijke methode om de brondata voor te bereiden en een model te trainen op een krachtige machine, zoals een PC of een externe server. Dit resulteert in het aanmaken van een binair modelbestand dat later moet worden omgezet in een C-taal headerbestand. Tot slot kan een Arduino-programma worden gemaakt met behulp van de functies in de TFLite Micro bibliotheek en gecompileerd met de Arduino IDE.
Voor degenen die niet bang zijn hun handen vuil te maken en die alles zelf doen: kijk eens naar de officiële TensorFlow Lite documentatie . Ik vond ook interessante artikelen gepubliceerd door DigiKey . Zij raden aan om een Linux PC met Python te gebruiken en dan onder andere TensorFlow, Keras, Anaconda en Jupyter Notebook te installeren. Een andere oplossing is om Python-code uit te voeren in Google Colab , een gratis cloudgebaseerd platform van Google waarmee gebruikers Python-code kunnen schrijven en uitvoeren in een onlineomgeving. Als beginner vond ik de TensorFlow documentatie moeilijk te volgen. Het vereist ook een goede kennis van neurale netwerken om iets functioneels te kunnen doen, wat ontmoedigend kan werken.
Eenvoudige voorbeelden
Tutorials op het internet laten vaak zeer vergelijkbare dingen zien, waarvan sommige een beetje praktisch nut missen om echt stimulerend te zijn. Er wordt bijvoorbeeld vaak getoond hoe men een model kan trainen om een outputwaarde te produceren die overeenkomt met een benadering van de sinus van de inputwaarde. Hierbij worden natuurlijk de vooraf berekende waarden van de sinusfunctie gebruikt als trainingsdataset. Eenmaal goed getraind kan het model dus een benaderende waarde van sin(x) geven aan de uitgang, gegeven een ingangswaarde x tussen 0 en 2π en zonder gebruik te maken van een wiskundig geïmplementeerde sinusfunctie. Natuurlijk is dit waarschijnlijk de meest absurde en onpraktische manier om een sinus te berekenen, vooral op een microcontroller waar de rekencapaciteit beperkt is.
Een ander, nuttiger voorbeeld is spraakherkenning. Op deze manier kan de microcontroller luisteren naar wat er in zijn omgeving gebeurt met behulp van een microfoon, een paar woorden onderscheiden (bijvoorbeeld ja en nee, of kat en hond, enz.) en verschillende acties starten. In dit artikel, geschreven door een beginner voor beginners, wil ik de dingen eenvoudig houden. Ik laat het gebruik van spraakherkenning zien op een Arduino Nano 33 BLE Sense.
Spraakherkenning
Hiervoor gebruik ik de Google Speech Command Dataset. Deze bevat 65.000 samples van een seconde lang, waarbij elke clip een van de dertig verschillende woorden bevat, uitgesproken door duizenden verschillende mensen. Om het model te trainen, gebruik ik Edge Impulse . Edge Impulse is een platform dat ontwikkelaars in staat stelt om machine learning-modellen te maken, te trainen en implementeren op edge-apparaten zoals microcontrollers, door zich te richten op gebruiksgemak, zonder al te veel programmering te vereisen. Het ondersteunt intern TensorFlow Lite voor microcontrollers en biedt een gemakkelijke manier om het model en de TFLite-bibliotheek op het Arduino-board zelf te implementeren, wat erg handig is.
Om te beginnen heeft u een aantal audiosamples nodig. Maak een map aan die uw werkmap wordt. Ik heb de mijne tflite_elektor genoemd. Download de Google Speech Command Dataset . Zorg voor een goede internetverbinding, want het bestand is 2,3 GB groot. Omdat het een bestand is met een .tar.gz extensie, is het twee keer gecomprimeerd. Gebruik 7-Zip of gelijkwaardige software (ik raad het ingebouwde hulpprogramma van Windows niet aan voor zulke grote bestanden) om het .tar-bestand te verkrijgen en decomprimeer vervolgens de inhoud. Het resultaat is een map speech_commands_v0.02. Plaats deze map in uw werkmap. U kunt de map speech_commands_v0.02 een eenvoudiger naam geven, in mijn geval: dataset.
Data voorbereiden
Vervolgens moet u de data voorbereiden. Hiervoor stel ik voor om het uitstekende Python-script te gebruiken dat is ontwikkeld door Shawn Hymel en dat hij vrijgevig aanbiedt onder een open-source licentie. Download de bestanden dataset-curation.py en utils.py van zijn GitHub repository en sla ze op in uw werkmap. Dit script vereist dat de map _background_noise_ in de dataset wordt gescheiden van de trefwoorden. Sleep deze map dus buiten de dataset om hem in uw werkmap te plaatsen. U kunt het ook hernoemen naar noise. Uw werkmap bevat nu de twee mappen dataset en noise en de twee Python-bestanden (figuur 2)
Het Python-script maakt het veel gemakkelijker om de enorme hoeveelheid data in de dataset van Google te gebruiken. Daarnaast is het, zoals u later zult zien, flexibel. U zou het kunnen gebruiken met andere datasets dan deze, en ook met audiobestanden die u zelf hebt opgenomen. Het zou onpraktisch zijn om meerdere gigabytes aan bestanden te uploaden naar de servers van Edge Impulse. Om te beginnen kiest u een of meer trefwoorden, die de doelwoorden zijn die de Arduino moet detecteren. Voor dit voorbeeld heb ik het woord zero gekozen. Het script maakt een aantal mappen aan: een map voor elk trefwoord, dus in dit geval een map met de naam zero, en een map _noise, die willekeurige ruis bevat, en een map _unknown, die willekeurige andere woorden dan de trefwoorden bevat.
Het script mengt achtergrondruis met trefwoordsamples om de robuustheid van het model te verbeteren. Eerst maakt het de benodigde mappen aan, dan haalt het kleinere geluidsfragmenten uit achtergrondruissegmenten. Vervolgens worden deze geluidsfragmenten gemengd met voorbeelden van trefwoorden en trefwoorden die niet bij het doel horen. Dit verbetert de bestendigheid van het model tegen achtergrondgeluiden en creëert een gecureerde dataset, veel kleiner in omvang (ongeveer 140 megabytes) waar Edge Impulse gemakkelijk mee kan werken.
Werken met Python
De code is getest met Python 3.7. Om verschillende Python-omgevingen met verschillende versies en met verschillende geïnstalleerde pakketten te beheren, kunt u Anaconda gebruiken, waarmee u eenvoudig een schone installatie van de gewenste versie kunt maken. Hier maak ik een nieuwe omgeving aan met de naam jf:
conda create -n jf python=3.7
Vervolgens moet u de pakketten librosa, numpy en soundfile installeren:
python -m pip install librosa numpy soundfile
Het shutil pakket is ook vereist, maar wordt gewoonlijk meegeleverd met Python 3.7.
Navigeer vanaf de Anaconda prompt of vanaf de opdrachtregelinterface van uw systeem naar uw werkmap en voer het script uit met de opdracht:
python dataset-curation.py -t "zero" -n 1500 -w 1.0 -g 0.1 -s 1.0 -r 16000 -e PCM_16 -b "./noise" -o "./keywords_curated" "./dataset"
En wacht een paar minuten tot het klaar is (figuur 3).
Vervolgens een korte blik op de argumenten die het script gebruikt:
-t is voor doeltrefwoorden. Hier gebruik ik -t "zero".
-n is het aantal uitvoersamples per categorie. 1500 is een goed uitgangspunt.
-w en -g zijn de volumeniveaus van respectievelijk het gesproken woord en het achtergrondgeluid. -w 1.0 -g 0.1 zijn aanbevolen waarden.
-s en -r zijn de sample-lengte (1 s) en sampling rate (16 kHz). Gebruik -s 1.0 -r 16000.
-e is de bitdiepte, hier gebruiken we 16-bit PCM.
-b is de locatie van de map met achtergrondruis, -o is de uitvoermap en tot slot is het laatste ongelabelde argument de lijst met invoermappen. Hier is dat de map van de dataset.
Als het script klaar is, zou het een map keywords_curated moeten hebben aangemaakt die drie mappen bevat: _noise, _unknown en zero. (figuur 4)
Importeren naar Edge Impulse
De volgende stap is het importeren van deze bestanden naar Edge Impulse. Ga naar hun website en maak een account aan als u die nog niet hebt. Nadat u bent ingelogd, maakt u een nieuw project. Navigeer in het linkermenu naar Data Acquisition en klik vervolgens op Add Data and Upload Data. Vink Select a folder aan en kies de eerste map, bijvoorbeeld _noise.
Zorg ervoor dat u de optie Automatically split between training and testing aanvinkt. Op deze manier gebruikt Edge Impulse eerst 80% van de geüploade samples om het model te trainen. Vervolgens kunnen we de prestaties van het getrainde model testen door het te vragen data te verwerken die het nog niet eerder heeft gezien; de resterende 20% is hiervoor gereserveerd.
Schakel ook de optie Label: infer from filename in, zodat Edge Impulse aan de hand van de bestandsnaam herkent welke samples het (de) te herkennen woord(en) bevatten en welke samples ruis bevatten. Klik ten slotte op de knop Upload data in de rechterbenedenhoek en wacht tot beëindiging van de overdracht. Herhaal dit voor de twee resterende mappen _unknown en zero.
Nadat het uploaden is voltooid, gaat u terug naar Data Acquisition om alle geüploade samples te bekijken. Zorg ervoor dat ongeveer 20% van uw bestanden zich in de testset bevindt en de rest in de trainingsset en controleer of de labels correct zijn gelezen (figuur 5).
Vervolgens is het nodig om een Processing Block toe te voegen. In Edge Impulse is dit een component die wordt gebruikt om ruwe sensordata om te zetten in een formaat dat geschikt is voor het trainen van het machine-learningmodel en voor inferentie. Het omvat veel complexe zaken in een eenvoudig blok, zoals de voorbewerking van ruwe invoerdata, extractie van kenmerken (zie hieronder), optionele stappen zoals Fouriertransformaties, enz. en tenslotte voert het de data uit in een formaat dat compatibel is met de volgende stappen in de ML-keten.
In algemene Machine Learning-termen zijn kenmerken afzonderlijke, kwantificeerbare kenmerken of eigenschappen van de geobserveerde data. Hier zijn de te extraheren kenmerken de Mel-frequentie cepstral coëfficiënten (MFCC's) , die vaak worden gebruikt in audiosignaalverwerking en spraakherkenning. Ze vertegenwoordigen het kortdurende energiespectrum van een geluidssignaal op een niet-lineaire mel-frequentieschaal.
Ga dus naar Impulse Design en klik op de knop Add a Processing Block. Selecteer de eerste optie, Audio (MFCC), door rechts op Add te klikken. Klik vervolgens op de knop Add a Learning Block en kies de eerste optie, Classification, wat de aanbevolen optie is. Klik ten slotte rechts op Save Impulse (figuur 6).
Training van het model
Selecteer MFCC in het linkermenu onder Impulse Design. Navigeer naar het tabblad Generate Features en klik op Generate Features (figuur 7). Wacht tot de functiegeneratie is voltooid. Zodra dit klaar is, gaat u naar de Classifier-sectie, die zich net onder MFCC in het linkermenu bevindt. Klik in de rechterbovenhoek op target en selecteer Arduino Nano 33 BLE Sense. U kunt de parameters van het neurale netwerk aanpassen, maar de standaardinstellingen zijn, niet verrassend, beter dan alles wat ik zelf had kunnen doen.
Merk op dat u het neurale netwerk kunt bewerken met hun grafische tool of kunt overschakelen naar expertmodus via het pop-upmenu als u bekend bent met Keras. Voor dit voorbeeld klik ik gewoon op Start Training onderaan de pagina om te beginnen met het trainen van het model op de data. Als het trainen klaar is, bekijkt u de resultaten in het kader Model rechtsonder. U ziet een algemene nauwkeurigheidsscore, en 90% wordt als vrij goed beschouwd; hier kreeg ik 92,8% (figuur 8).
Er is ook een matrix, de zogenaamde confusion matrix, die de prestaties van het model controleert. De rijen geven de werkelijke labels weer en de kolommen de voorspelde labels. De getallen langs de diagonaal, waar het voorspelde label overeenkomt met het werkelijke label, moeten veel hoger zijn dan de andere waarden. Hier toont de diagonaal 98,8%, 87% en 92,8%, wat goed genoeg zou moeten zijn. Een moeilijkere test is om het model te evalueren door het data te geven die het nog niet eerder heeft gezien. Ga hiervoor naar de sectie Model testing in het linkermenu. Klik op Classify All en laat het uitvoeren tot het klaar is. In het kader Results onderaan is de score een paar procent lager dan de score ervoor, maar dat is te verwachten. Hier kreeg ik 90,56%, wat een goed teken is (figuur 9).
Implementatie voor Arduino
Laten we nu naar de pagina Deployment gaan. Edge Impulse biedt verschillende opties om het model te verpakken: een generieke C++-bibliotheek voor algemeen microcontrollergebruik, Cube MX voor STM32-componenten, WebAssembly voor JavaScript-omgevingen en nog veel meer. Klik op Search deployment options en selecteer Arduino library. Klik vervolgens op de knop Build onder aan de pagina. Enkele seconden later downloadt uw browser een ZIP-bestand met de Arduino-bibliotheek.
Ik gebruik de Arduino IDE-versie 1.8.19. Open de Arduino IDE en sluit uw Arduino Nano 33 BLE Sense aan op uw computer. Als het de eerste keer is dat u uw Nano 33 BLE gebruikt, zal de IDE voorstellen om het Arduino Mbed OS Nano Boards package te downloaden, wat inderdaad vereist is. Daarna kunt u de bibliotheek toevoegen met de gebruikelijke techniek, klik op Sketch, Include Library, Add .ZIP Library en selecteer het .zip-bestand dat u zojuist hebt gedownload van Edge Impulse. Ga vervolgens naar File, Examples en zoek de bibliotheek die u zojuist hebt geïnstalleerd. Mogelijk moet u de Arduino IDE opnieuw laden om deze te laten verschijnen. De naam moet overeenkomen met uw Edge Impulse projectnaam, dus voor mij is het tflite_elektor_inferencing.
Merk op dat er twee aparte mappen zijn, nano_ble33_sense en nano_ble33_sense_rev2 (figuur 10). Het microphone_continuous voorbeeld dat hier gebruikt wordt staat alleen in de eerste, maar ik heb het met succes getest op zowel Rev1 als Rev2 hardware. Mogelijkerwijs moet u de juiste versie kiezen, afhankelijk van het board dat u heeft, of als u wilt spelen met de andere voorbeeldsketches die de ingebouwde accelerometer gebruiken. Open het voorbeeld microphone_continuous.
Optioneel kunt u de voorbeeldsketch bekijken om te zien hoe alles is ingesteld en welke functies worden aangeroepen voor inferentie. In de lus wacht de microcontroller tot de microfoonbuffer gevuld is en roept dan de functie run_classifier_continuous op om de inferentie met het neurale netwerk uit te voeren op de opgenomen audiodata. De resultaten worden slechts eenmaal per seconde afgedrukt op de seriële monitor. De code in de meegeleverde bibliotheek is soms niet eenvoudig te volgen, maar het kan een lonende oefening zijn om te proberen en te zien wat er onder de motorkap zit.
Het board flashen
Controleer in het menu Tools van de Arduino IDE of het juiste board (Nano 33 BLE Sense) is geselecteerd, evenals de juiste COM-poort, die u kunt controleren met Apparaatbeheer als u Windows gebruikt. Klik op de knop Uploaden en wacht! Houd er rekening mee dat het compileren van het project even duurt omdat de bibliotheek, die de TensorFlow Lite-functies voor inferentie en het model dat is gemaakt op Edge Impulse in binair formaat bevat, vrij omvangrijk is. Zodra het klaar is, zult u zien dat het ongeveer 171 kilobyte flash gebruikt en ongeveer 47 kilobyte RAM voor globale variabelen.
Het werkt!
Open nu de Serial Monitor om de uitvoer te bekijken. Elke seconde geeft het drie getallen die de waarschijnlijkheid zijn dat een bepaald patroon is gedetecteerd, waaronder: willekeurige ruis, een woord dat niet zero is en ten slotte het woord zero. Figuur 11 is een voorbeeld waarbij niets bijzonders gebeurt. Als ik het woord "zero" relatief dicht bij het Arduino-board zeg, bereikt de derde score een zeer hoge waarde, bijna 100% (figuur 12).
Niet slecht! Nu is de volgende stap om het Arduino-board iets nuttigs te laten doen met die informatie. Ik weet zeker dat u interessante toepassingen zult vinden om spraakcommando's te kunnen sturen naar Arduino-aangedreven gadgets. Het hierboven beschreven proces en het Python-script van Shawn Hymel kunnen ook worden gebruikt om meer dan één woord te detecteren. Het maximale aantal wordt beperkt door de opslagruimte in de Arduino flash en de beschikbare rekenkracht. In de code vertelt de regel #define EI_CLASSIFIER_SLICES_PER_MODEL_WINDOW 4 ons dat elk venster van één seconde wordt verdeeld in vier segmenten van 250 ms, en de uitvoer in de Serial Monitor vertelt ons dat de tijd die door de sketch wordt gebruikt 76 + 6 = 82 ms per segment van 250 ms is, wat ongeveer gelijk is aan 33% CPU-gebruik. Er is nog wat rekenkracht over om uw eigen programma toe te voegen.
Verder gaan
Om het eenvoudig te houden, heb ik een van de woorden gebruikt die al beschikbaar zijn in de Google Speech Command dataset. Om een model te trainen om een woord te herkennen dat geen deel uitmaakt van deze set, moet u een groot aantal audiosamples opnemen waarin het woord wordt uitgesproken, bij voorkeur door een groot aantal mensen met verschillende stemmen, leeftijden en intonaties. De Google set bevat duizenden samples per woord, maar als u zelf aangepaste woorden opneemt, zou vijftig tot honderd samples een goed begin kunnen zijn. Natuurlijk heb ik slechts een tipje van de sluier opgelicht met dit eenvoudige voorbeeld. Wie geïnteresseerd is, wordt aangeraden om dieper op de materie in te gaan! Heeft u een idee in gedachten voor een project met ML?
Het artikel, “TensorFlow Lite op kleine microcontrollers” (240357-03), verschijnt in Elektor november/december 2024.
Discussie (0 opmerking(en))