Обучение и внедряване на модел TensorFlow към Arduino

Ще обуча алгоритъм за играчка и ще го разположа за изводи върху Arduino Nano 33 BLE Sense. Търся да създам и тествам обвивка, използвайки възможно най-малко компоненти, които да бъдат подобрени по-късно.

Ще използвам „AutoMPG Dataset“, обучавайки модел, който ще използва една функция, конски сили, за да предвиди мили на галон на превозното средство. Ще взаимодействаме с модела с помощта на Arduino Serial Monitor.

Обучение на модела

„Тетрадката за обучение“, която да следвате.

Няма да отделям много време за подготовка на данни, това е доста ясен набор от данни, единствената бележка е, тъй като искам да извикам това и да получа прогноза от серийния монитор, ще използваме само една функция, конски сили.

Така че тук изпускаме нули, разделяме данните, получаваме нашия етикет (MPG) и единствената ни функция (конски сили).

След това изграждам своя модел. Имам нужда само от един вход (конски сили) и изграждам много прост модел с един скрит слой. Освен това имам само един изходен неврон за прогнозиране на MPG.

Накрая ще запазя модела, за да мога да направя реализациите си по-късно.

Преобразуване на модела

Сега ще конвертираме модела. На нашия GPU моделът използва числа float32 за улавяне на тегла и отклонения, на нашите микроконтролери, които биха работили много бавно, ако изобщо работят. Ще квантуваме модела след тренировка, по-малки тежести и активации могат да се използват по време на тренировка, което е отделна тема.

Трябва да преобразуваме в цели числа, за да работим на ограничен хардуер на микроконтролера. Това често има минимално влияние върху точността. Има няколко опции за конвертиране на модел;

  • float32 до float16, това може да намали размера на модела наполовина и драматично да ускори изводите на някои хардуери, това означава, че параметрите са float16 и изводите се извършват float32
  • int8 параметри, моделът използва смесено изчисление, когато е налично
  • int8 параметри и активации, изпълняващи се само с цели числа

Удобно дърво на решенията и допълнителни подробности тук.

Искаме да квантуваме до последното, int8 всичко с наложени операции само с цели числа. За да направим това, трябва да генерираме представителен набор от данни. Това е необходимо, защото за ефективно преобразуване на 8-битовите стойности е необходимо линейно преобразуване в реални числа. За тегла това може да се направи автоматично, защото TensorFlow може да изчисли обхвата за всеки слой от обучените стойности. За активациите е по-трудно, защото не е очевидно от параметрите какъв е диапазонът на изходите на всеки слой. Ако произволно избран диапазон е твърде малък, стойностите ще бъдат отрязани от минимума или максимума, ако диапазонът е твърде голям, точността ще бъде загубена.

TensorFlow използва представителния набор от данни, за да извърши това изчисление за активациите и да ги преобразува.

Тук вземаме тестовия набор от данни и го преобразуваме в тензор, като използваме това в нашата функция represent_dataset, която дава запис при извикване.

Всъщност запазваме два модела тук, единият, който просто се преобразува във формат TFLite, но запазва теглата и активациите като float32, така че можем да видим как това влияе на точността. След това моделът се запазва с квантуване, налагайки само int (защото може да се върне обратно към float32 за неподдържани операции, ако не е посочено). Предоставя се представителен набор от данни, моделът се конвертира и запазва.

Зареждането и показването на подробностите за входа и изхода показва скалата на квантуване и нулевата точка. Ще ги използваме, за да подготвим по подходящ начин входа и изхода при извикване на модела. Това може да се види, когато оценяваме квантувания модел.

Тук улавяме данните за входа и изхода, показани по-горе, след което използваме мащаба и нулевата точка, за да коригираме тестовите данни, преди да ги конвертираме в цяло число. След като изводът е извършен, ние правим същото за изходите на модела.

Размер и точност

Сега, след като имаме обучени модели, преобразувани и известна точност на извадката, до каква разлика се е стигнало както по отношение на размера на модела, така и по отношение на влиянието върху точността?

За точност можем да видим, че е минимална, TFLite и неконвертираният модел са идентични, което бихме очаквали, тъй като не е настъпило квантуване. Квантуваният модел е минимално по-малко точен с MSE от 23,871 до MSE от 24,809 за неквантувания модел. Тъй като това е много малък и несложен модел, квантуването също не намали размера на модела много, спестявайки само 228 байта. Ще бъде спестено повече място за модели с повече слоеве и неврони.

Сега ще използвам xxd, за да конвертирам модела от TFLite, за да направя шестнадесетичен дъмп на файла, което ни позволява да копираме и поставим модела директно в програмата Arduino.

Резултатът от този шестнадесетичен дъмп може да бъде копиран директно във файла model.ccp на нашата програма Arduino. И съдържанието, и g_model_len трябва да бъдат добавени и съвпадащи, както се вижда по-долу;

Програмата Arduino

„Репото“, което съдържа „mpgModel.ino“.

Сега, след като имаме модела, нека преминем през част от програмата, за да я извикаме на контролера.

Всичко интересно се случва в autoTest.ino. Това настройва нашата среда и преминава през прихващане на входа и извикване на модела. Първо трябва да импортираме операциите, от които се нуждаем.

Този модел не изисква много операции, други ще имат вложени пространства от имена и ще извикват специфични части от архитектурата като слоеве за максимално обединяване и конв. kTensorArenaSize е количеството памет, разпределено за модела. Към днешна дата няма много елегантен начин за оценка на това освен пробата и грешката; намаляване на броя, докато моделът се срине.

Настройка на модела

Сега трябва да разпределим паметта на модела, да конфигурираме указатели и да проверим версиите на схемата.

TensorFlow lite предоставя куки за докладване и регистриране, ние ще настроим това, ще го използваме в нашата проверка, за да сме сигурни, че версиите на схемата съвпадат с модела. Разпределяме памет и получаваме нашите указатели.

Извикване на модела

По-интересното всъщност е извикването на модела в нашия цикъл.

Получаваме нашия вход и го анализираме като число с плаваща запетая. Точно както когато оценявахме модела, трябва да мащабираме и актуализираме нулевата точка, докато преобразуваме входа с плаваща фигура в цяло число. След това моделът се захранва с това като вход. Моделът (интерпретатор) се извиква на входа и се уверяваме, че всичко е наред.

Резултатът се улавя от неговия изходен тензор и се съхранява, но трябва да бъде мащабиран с нулева точка, актуализирана преди преобразуването обратно в плаващо число.

След това отпечатваме прогнозата заедно с куп незадължителна информация, която показва как нашият вход е модифициран и как изглежда изходът преди и след квантуването.