{"id":12045,"date":"2021-11-17T09:29:01","date_gmt":"2021-11-17T08:29:01","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=12045"},"modified":"2023-05-18T15:49:25","modified_gmt":"2023-05-18T13:49:25","slug":"tinyml-uczenie-maszynowe-w-systemach-wbudowanych","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/tinyml-uczenie-maszynowe-w-systemach-wbudowanych\/","title":{"rendered":"TinyML: Uczenie maszynowe w systemach wbudowanych"},"content":{"rendered":"\n<p>W niniejszym artykule zaprezentuj\u0119 przyk\u0142ad wykorzystania modelu sieci neuronowej utworzonej w oparciu o framework TensorFlow Lite na platform\u0119 bazuj\u0105c\u0105 na mikrokontrolerze z rodziny STM32. Mam nadziej\u0119, \u017ce pozwoli to w prosty i przyst\u0119pny spos\u00f3b pokaza\u0107, w jaki spos\u00f3b mo\u017cna rozpocz\u0105\u0107 swoj\u0105 przygod\u0119 z uczeniem maszynowym na mikrokontrolerach. Poznanie i zrozumienie podstaw dzia\u0142ania frameworku TensorFlow Lite umo\u017cliwi nie tylko orientacj\u0119 w trendach w dziedzinie sztucznej inteligencji, lecz tak\u017ce mo\u017ce zaowocowa\u0107 utworzeniem zar\u00f3wno u\u017cytecznych jak i ciekawych projekt\u00f3w na urz\u0105dzeniach wbudowanych.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">TinyML \u2013 co to jest?<\/h2>\n\n\n\n<p>TinyML to stosunkowo nowa dziedzina sztucznej inteligencji. Dotyczy g\u0142\u00f3wnie przetwarzania sieci g\u0142\u0119bokiej bezpo\u015brednio na urz\u0105dzeniu wbudowanym. Urz\u0105dzenia wbudowane z regu\u0142y nie nadaj\u0105 si\u0119 do treningu modeli sieci g\u0142\u0119bokich ze wzgl\u0119du na ograniczone zasoby pami\u0119ciowe oraz obliczeniowe. Jednak w przypadku uruchomienia gotowego modelu wymagania sprz\u0119towe zwykle s\u0105 mniej restrykcyjne. Gotowy model, zwany inferencyjnym, mo\u017ce by\u0107 zoptymalizowany, np. pod wzgl\u0119dem architektury sieci, jej parametr\u00f3w czy u\u017cytych typ\u00f3w danych. Podzia\u0142 na trening i inferencje, kt\u00f3re mog\u0105 by\u0107 realizowane niezale\u017cnie od platformy sprz\u0119towej, daje mo\u017cliwo\u015b\u0107 wykorzystania sztucznej inteligencji w mikrokontrolerach.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Pierwsze kroki<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Platforma sprz\u0119towa<\/h3>\n\n\n\n<p>W ramach demonstracji zaprezentowany zostanie prosty przyk\u0142ad dotycz\u0105cy klasyfikacji cyfr na podstawie dostarczonego obrazu. W tym celu b\u0119dzie nam potrzebny zestaw uruchomieniowy STM32F429I-DISC1 oparty na mikrokontrolerze STM32F429ZIT6, do kt\u00f3rego dostarczony jest dotykowy ekran LCD. Obraz uzyskany podczas rysowania na ekranie pos\u0142u\u017cy jako wej\u015bcie do modelu sieci neuronowej. Uzyskany z modelu rezultat klasyfikacji zostanie zaprezentowany na ekranie.<\/p>\n\n\n\n<div class=\"wp-block-image wp-image-12086\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Ryc.-1-Zestaw-uruchomieniowy-STM32F429I-DISC1-uzyty-w-przykladzie.png\"><img decoding=\"async\" width=\"1024\" height=\"558\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Ryc.-1-Zestaw-uruchomieniowy-STM32F429I-DISC1-uzyty-w-przykladzie-1024x558.png\" alt=\"Ryc. 1 Zestaw uruchomieniowy STM32F429I-DISC1 wykorzystany w przyk\u0142adzie\" class=\"wp-image-12086\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Ryc.-1-Zestaw-uruchomieniowy-STM32F429I-DISC1-uzyty-w-przykladzie-1024x558.png 1024w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Ryc.-1-Zestaw-uruchomieniowy-STM32F429I-DISC1-uzyty-w-przykladzie-300x164.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Ryc.-1-Zestaw-uruchomieniowy-STM32F429I-DISC1-uzyty-w-przykladzie-768x419.png 768w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Ryc.-1-Zestaw-uruchomieniowy-STM32F429I-DISC1-uzyty-w-przykladzie.png 1251w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption>Ryc. 1 <a href=\"https:\/\/botland.com.pl\/img\/art\/inne\/01940_3.jpg\" rel=\"nofollow\" >Zestaw uruchomieniowy STM32F429I-DISC1 wykorzystany w przyk\u0142adzie<\/a><\/figcaption><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Model<\/h3>\n\n\n\n<p>Do uzyskania modelu sieci potrzebujemy zestawu danych treningowych, walidacyjnych i testowych. Aby zaopiekowa\u0107 przedstawiony problem powinna wystarczy\u0107 w zupe\u0142no\u015bci baza odr\u0119cznie zapisanych cyfr <a href=\"http:\/\/yann.lecun.com\/exdb\/mnist\/\" rel=\"nofollow\" >bazy MNIST<\/a>. Ka\u017cdy rekord w bazie zawiera zestaw sk\u0142adaj\u0105cy si\u0119 z obrazu przedstawiaj\u0105cego cyfr\u0119 oraz etykiety oznaczaj\u0105cej kategori\u0119, do kt\u00f3rej nale\u017cy obraz. W przypadku MNIST mamy 10 kategorii, kt\u00f3re odpowiadaj\u0105 cyfrom 0-9.<\/p>\n\n\n\n<p>Proces tworzenia, uczenia i przygotowania modelu do wdro\u017cenia na mikrokontroler przeprowadzimy przy pomocy frameworku <a href=\"https:\/\/www.tensorflow.org\/lite\" rel=\"nofollow\" >TensorFlow Lite<\/a>. Framework ten posiada zestaw narz\u0119dzi, kt\u00f3re umo\u017cliwiaj\u0105 uruchamianie modeli na urz\u0105dzeniach mobilnych, wbudowanych oraz IoT. Aktualn\u0105 <a href=\"https:\/\/www.tensorflow.org\/lite\/microcontrollers#supported_platforms\" rel=\"nofollow\" >list\u0119 wspieranych platform sprz\u0119towych<\/a> mo\u017cna znale\u017a\u0107 na stronie.<\/p>\n\n\n\n<p>W przypadku mikrokontroler\u00f3w opartych na procesorze Cortex-M (jak w przypadku u\u017cytej tu platformy sprz\u0119towej), TensorFlow Lite wykorzystuje bibliotek\u0119 <a href=\"https:\/\/arm-software.github.io\/CMSIS_5\/NN\/html\/index.html\" rel=\"nofollow\" >CMSIS NN<\/a>. Biblioteka ta zawiera list\u0119 operacji wykorzystywanych w sieciach neuronowych zoptymalizowanych pod Cortex-M. Dzi\u0119ki temu dzia\u0142anie modelu mo\u017ce by\u0107 efektywniejsze.<\/p>\n\n\n\n<p>Model mo\u017cemy utworzy\u0107 samodzielnie, b\u0105d\u017a zaimportowa\u0107 z <a href=\"https:\/\/google.github.io\/flatbuffers\/\" rel=\"nofollow\" >formatu TensorFlow<\/a> (gotowych modeli w tym formacie jest znacznie wi\u0119cej) i dokona\u0107 konwersji z wykorzystaniem narz\u0119dzia <a href=\"https:\/\/www.tensorflow.org\/lite\/convert\/index\" rel=\"nofollow\" >TensorFlow Lite Converter<\/a>. Podczas konwersji mo\u017cna u\u017cy\u0107 szeregu optymalizacji pozwalaj\u0105cych przyk\u0142adowo na zmniejszenie rozmiaru modelu czy ilo\u015bci wykorzystywanej pami\u0119ci podczas dzia\u0142ania. Po konwersji, za pomoc\u0105 narz\u0119dzia <a href=\"https:\/\/www.tensorflow.org\/lite\/guide\/inference\" rel=\"nofollow\" >TensorFlow Lite Interpreter<\/a>, gotowy model zostanie za\u0142adowany do pami\u0119ci mikrokontrolera.<\/p>\n\n\n\n<p>Uproszczony schemat dzia\u0142ania TensorFlow Lite zosta\u0142 zaprezentowany poni\u017cej.<\/p>\n\n\n\n<div class=\"wp-block-image wp-image-12052\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/rys2.png\"><img decoding=\"async\" width=\"800\" height=\"492\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/rys2.png\" alt=\"Schemat konwersji modelu TensorFlow na model TensorFlow Lite\" class=\"wp-image-12052\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/rys2.png 800w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/rys2-300x185.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/rys2-768x472.png 768w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/a><figcaption>Ryc. 2 <a href=\"https:\/\/imgs.developpaper.com\/imgs\/4133696927-5ca2bd0485b21_articlex.png\" rel=\"nofollow\" >Schemat konwersji modelu TensorFlow na model TensorFlow Lite<\/a><\/figcaption><\/figure><\/div>\n\n\n\n<p>W przypadku treningu tak prostego modelu, jak w tym przyk\u0142adzie, kompilacja TensorFlow Lite ze \u017ar\u00f3de\u0142 i implementacja z u\u017cyciem C++ nie b\u0119d\u0105 nam potrzebne. Tworzenie modelu oraz trening przeprowadzimy z u\u017cyciem tzw. Google Colab, kt\u00f3ry w odr\u00f3\u017cnieniu od <a href=\"https:\/\/jupyter.org\/\" rel=\"nofollow\" >Jupyter notebook<\/a>, dzia\u0142a z wykorzystaniem serwer\u00f3w Google\u2019a oferuj\u0105c darmowy dost\u0119p do GPU oraz TPU. Dzi\u0119ki temu proces uczenia mo\u017ce trwa\u0107 kr\u00f3cej.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Tworzenie modelu, trening i konwersja<\/h2>\n\n\n\n<p>Model utworzymy od podstaw, wykorzystuj\u0105c format TensorFlow. Nast\u0119pnie wykonamy konwersj\u0119 na format TensorFlow Lite. W ramach optymalizacji model mo\u017ce zosta\u0107 dodatkowo poddany kwantyzacji. W takim przypadku, po kwantyzacji ka\u017cda operacja, kt\u00f3ra oryginalnie bazowa\u0142a na zapisie zmiennoprzecinkowym zostanie zmieniona na zapis sta\u0142oprzecinkowy. Ma to dodatkow\u0105 zalet\u0119 w przypadku, gdy docelowa architektura nie wspiera operacji zmiennoprzecinkowych. Instrukcje do tworzenia modelu i jego uczenia mo\u017cna znale\u017a\u0107 na stronie.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Tworzenie modelu<\/h3>\n\n\n\n<p>Do utworzenia modelu potrzebujemy TensorFlow przynajmniej w wersji 2.3. Opr\u00f3cz importu samego TensorFlow, zaimportujmy bibliotek\u0119 NumPy, zaprojektowan\u0105 do wykonywania oblicze\u0144 na wielowymiarowych macierzach. Dodajmy te\u017c logowanie, kt\u00f3re mo\u017ce przyda\u0107 si\u0119 podczas treningu:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-1.png\"><img decoding=\"async\" width=\"873\" height=\"184\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-1.png\" alt=\"\" class=\"wp-image-12053\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-1.png 873w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-1-300x63.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-1-768x162.png 768w\" sizes=\"(max-width: 873px) 100vw, 873px\" \/><\/a><\/figure><\/div>\n\n\n\n<p>Kolejnym krokiem b\u0119dzie utworzenie samego modelu. Nie ma potrzeby, aby samodzielnie pobiera\u0107 i manipulowa\u0107 baz\u0105 MNIST. TensorFlow umo\u017cliwia wygodny dost\u0119p zar\u00f3wno do zestawu danych treningowych, jak i testowych.<\/p>\n\n\n\n<p>Zanim przyst\u0105pimy do projektowania warstw sieci, zajmijmy si\u0119 obr\u00f3bk\u0105 danych wej\u015bciowych, tzw. feature preprocessing. Pozwala ona na przekszta\u0142cenie danych wej\u015bciowych w taki spos\u00f3b, aby by\u0142y dopasowane do architektury sieci np. poprzez redukcj\u0119 wymiar\u00f3w.<\/p>\n\n\n\n<p>W ramach obr\u00f3bki danych zostanie przeprowadzony tzw. feature scaling, kt\u00f3ry polega na normalizacji danych wej\u015bciowych. Powinno to przyspieszy\u0107 proces uczenia. Obrazy zawieraj\u0105ce cyfry s\u0105 reprezentowane w 8-bitowej skali odcieni szaro\u015bci o wymiarach 28&#215;28. Minimaln\u0105 warto\u015bci\u0105 jest 0, za\u015b maksymaln\u0105 255, do uzyskania zakresu [0,1] wystarczy wi\u0119c, \u017ce dane podzielimy przez 255.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Architektura sieci<\/h3>\n\n\n\n<p>Kolejny krok to okre\u015blenie architektury sieci. W tym przypadku problem rozpoznawania cyfr jest problemem z dziedziny klasyfikacji, zatem architektur\u0119 mo\u017cna podzieli\u0107 na dwie cz\u0119\u015bci:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>ekstrakcj\u0119 cech (tzw. feature extraction),<\/li><li>klasyfikacj\u0119.<\/li><\/ul>\n\n\n\n<p>W przypadku ekstrakcji cech algorytmy pr\u00f3buj\u0105 wydoby\u0107 charakterystyczne cechy jak np. ilo\u015b\u0107 linii czy ich nachylenie. W przyk\u0142adzie wej\u015bciem s\u0105 obrazy, wi\u0119c efektywnym sposobem wydobycia cech jest stosowanie m.in. naprzemiennie warstw konwolucyjnej i warstwy zbiorczej (tzw. pooling).<\/p>\n\n\n\n<p>Pierwsza z nich stosuje <strong>operacj\u0119 konwolucji<\/strong>. Zapewnia ona kompozycyjno\u015b\u0107 (tzw. compositionality). Kompozycyjno\u015b\u0107 pozwala sieci na rozpoznawanie coraz bardziej z\u0142o\u017conych kszta\u0142t\u00f3w. Przyk\u0142adowo, pierwsza warstwa konwolucyjna pozwala wydoby\u0107 kraw\u0119dzie z pikseli, kolejna warstwa konwolucyjna kszta\u0142ty a kolejna obiekty na podstawie kszta\u0142t\u00f3w. Klasyfikacj\u0119 obiektu niezale\u017cnie od miejsca (tzw. local invariance) zapewnia nam warstwa zbiorcza.<\/p>\n\n\n\n<p>W analizowanym przyk\u0142adzie potrzebujemy 10 wyj\u015b\u0107. Ka\u017cde z nich odpowiada\u0107 b\u0119dzie prawdopodobie\u0144stwu, z jakim dana cyfra wyst\u0105pi\u0142a na obrazie. Aby uzyska\u0107 10-elementowe wyj\u015bcie potrzebujemy warstwy, kt\u00f3ra po\u0142\u0105czy nasz\u0105 ostatni\u0105 warstw\u0119 zbiorcz\u0105 z wyj\u015bciow\u0105.<\/p>\n\n\n\n<p>Metryk\u0105, pozwalaj\u0105c\u0105 okre\u015bli\u0107 jako\u015b\u0107 procesu uczenia, b\u0119dzie dok\u0142adno\u015b\u0107 pomi\u0119dzy prawdziwym rezultatem a rezultatem uzyskanym na wyj\u015bciu sieci. Nast\u0119pnie wykorzystamy funkcj\u0119 b\u0142\u0119du (tzw. error function) oraz algorytm pr\u00f3buj\u0105cy ten b\u0142\u0105d zminimalizowa\u0107 (tzw. optimizer). Jako funkcji b\u0142\u0119du u\u017cyjemy entropii krzy\u017cowej przeznaczonej dla problemu klasyfikacji. Jako algorytmu optymalizacji u\u017cyjemy algorytmu Adam (tzw. Adaptive Moment Estimation). Wyniki procesu uczenia mo\u017cna zobaczy\u0107 na poni\u017cszym rysunku.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-2.png\"><img decoding=\"async\" width=\"872\" height=\"217\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-2.png\" alt=\"\" class=\"wp-image-12054\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-2.png 872w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-2-300x75.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-2-768x191.png 768w\" sizes=\"(max-width: 872px) 100vw, 872px\" \/><\/a><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-3.png\"><img decoding=\"async\" width=\"871\" height=\"634\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-3.png\" alt=\"\" class=\"wp-image-12055\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-3.png 871w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-3-300x218.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-3-768x559.png 768w\" sizes=\"(max-width: 871px) 100vw, 871px\" \/><\/a><\/figure><\/div>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-image wp-image-12057\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Ryc.-3.png\"><img decoding=\"async\" width=\"928\" height=\"171\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Ryc.-3.png\" alt=\"Wyniki uzyskane podczas uczenia sieci\" class=\"wp-image-12057\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Ryc.-3.png 928w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Ryc.-3-300x55.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Ryc.-3-768x142.png 768w\" sizes=\"(max-width: 928px) 100vw, 928px\" \/><\/a><figcaption>Ryc. 3 Wyniki uzyskane podczas uczenia sieci<\/figcaption><\/figure><\/div>\n\n\n\n<p>Kolejny etap to konwersja modelu na format wykorzystywany przez TensorFlow Lite. W tym celu dodamy nast\u0119puj\u0105ce instrukcje:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-4.png\"><img decoding=\"async\" width=\"766\" height=\"69\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-4.png\" alt=\"\" class=\"wp-image-12058\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-4.png 766w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-4-300x27.png 300w\" sizes=\"(max-width: 766px) 100vw, 766px\" \/><\/a><\/figure><\/div>\n\n\n\n<p>Ostatnim krokiem przed wdro\u017ceniem jest pobranie utworzonego modelu. W tym celu najpierw zapiszemy model w formacie .tflite:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-5.png\"><img decoding=\"async\" width=\"838\" height=\"198\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-5.png\" alt=\"\" class=\"wp-image-12059\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-5.png 838w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-5-300x71.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-5-768x181.png 768w\" sizes=\"(max-width: 838px) 100vw, 838px\" \/><\/a><\/figure><\/div>\n\n\n\n<p>Niestety, w przypadku u\u017cytej platformy sprz\u0119towej, sam plik nie wystarczy. Standardowo, TensorFlow Lite Interpreter dzia\u0142a na modelu, kt\u00f3ry dostarczany jest przy u\u017cyciu okre\u015blonego systemu plik\u00f3w. Aby za\u0142adowa\u0107 model do pami\u0119ci mikrokontrolera, dokonamy konwersji modelu na posta\u0107 pliku \u017ar\u00f3d\u0142owego. Plik ten potem do\u0142\u0105czymy do aplikacji, a nast\u0119pnie skompilujemy dla docelowej platformy. Do konwersji <strong>mnist_model.tflite<\/strong> do <strong>mnist_model.cc<\/strong> wykorzystamy program <strong>xxd<\/strong>:<br><\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-6.png\"><img decoding=\"async\" width=\"865\" height=\"120\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-6.png\" alt=\"\" class=\"wp-image-12060\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-6.png 865w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-6-300x42.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-6-768x107.png 768w\" sizes=\"(max-width: 865px) 100vw, 865px\" \/><\/a><\/figure><\/div>\n\n\n\n<p>Po utworzeniu pliku <strong>mnist_model.cc<\/strong> mo\u017cna go pobra\u0107 na lokalny komputer. B\u0119dzie on nam p\u00f3\u017aniej potrzebny.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Aplikacja i wdro\u017cenie modelu<\/h2>\n\n\n\n<p>Po utworzeniu modelu przejdziemy do przygotowania aplikacji. B\u0119dzie ona pobiera\u0142a dane wej\u015bciowe od u\u017cytkownika, dokonywa\u0142a predykcji za pomoc\u0105 zintegrowanego modelu a nast\u0119pnie prezentowa\u0142a uzyskany rezultat.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Przygotowanie aplikacji<\/h3>\n\n\n\n<p>Pierwszy krok to przygotowanie aplikacji, kt\u00f3ra umo\u017cliwi u\u017cytkownikowi rysowanie. Aby nie odkrywa\u0107 ko\u0142a na nowo, w ramach artyku\u0142u, jako podstaw\u0119 wykorzystamy gotowy przyk\u0142ad. W kolejnych etapach b\u0119dziemy go przerabia\u0107 do naszych potrzeb.<\/p>\n\n\n\n<p>Nasz\u0105 baz\u0119, przyk\u0142ad <strong>LTDC_Paint<\/strong> (Ryc. 4), wygenerujemy za pomoc\u0105 STM32CubeMX. Po konfiguracji z domy\u015blnymi opcjami, przyst\u0105pimy do kompilacji jego pierwszego uruchomienia, w moim przypadku, za pomoc\u0105 STM32CubeIDE.<\/p>\n\n\n\n<p>Kolejnym krokiem jest import do projektu TensorFlow Lite jako niezb\u0119dnej biblioteki. Niestety, tw\u00f3rcy TensorFlow Lite nie oferuj\u0105 bezpo\u015brednio dost\u0119pu do binarnej wersji pod mikrokontrolery. W dokumentacji mo\u017cna jedynie znale\u017a\u0107 instrukcj\u0119 jak wygenerowa\u0107 za pomoc\u0105 narz\u0119dzia <strong>Make<\/strong> szereg przyk\u0142adowych projekt\u00f3w i na ich podstawie rozwija\u0107 swoje w\u0142asne.<\/p>\n\n\n\n<p>To podej\u015bcie nie sprawdzi si\u0119 w naszym przypadku, poniewa\u017c bazowy projekt, LTDC_Paint, ju\u017c istnieje. Najlepszym wi\u0119c wyj\u015bciem wydaje si\u0119 r\u0119czny import wszystkich niezb\u0119dnych plik\u00f3w do projektu i kompilacja TensorFlow Lite ze \u017ar\u00f3de\u0142. Pomocn\u0105 <a href=\"https:\/\/www.digikey.com\/en\/maker\/projects\/tinyml-getting-started-with-tensorflow-lite-for-microcontrollers\/c0cdd850f5004b098d263400aa294023\" rel=\"nofollow\" >instrukcj\u0119 do importu TensorFlow Lite<\/a> mo\u017cna znale\u017a\u0107 na stronie. Przed przyst\u0105pieniem do budowania i kompilacji projektu z TensorFlow Lite warto upewni\u0107 si\u0119, \u017ce:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Projekt z aplikacj\u0105 wykorzystuje docelowo j\u0119zyk C++ a nie C. W STM32CubeIDE istnieje opcja konwersji z C na C++.<\/li><li>Nale\u017cy upewni\u0107 si\u0119, \u017ce w\u0142\u0105czone pliki TensorFlowLite s\u0105 dost\u0119pne z poziomu kompilatora C++ a nie tylko C.<\/li><li>Katalog examples w tensorflow_lite\/tensorflow\/lite\/micro jest usuni\u0119ty (zawiera plik main.c, kt\u00f3rego nie b\u0119dziemy u\u017cywa\u0107)<\/li><\/ol>\n\n\n\n<div class=\"wp-block-image wp-image-12061\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/rys4.png\"><img decoding=\"async\" width=\"1024\" height=\"677\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/rys4-1024x677.png\" alt=\"Wyb\u00f3r bazowej aplikacji z STM32CubeMX\" class=\"wp-image-12061\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/rys4-1024x677.png 1024w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/rys4-300x198.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/rys4-768x508.png 768w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/rys4.png 1383w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption>Ryc. 4 Wyb\u00f3r bazowej aplikacji z STM32CubeMX<\/figcaption><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Przetwarzanie danych<\/h3>\n\n\n\n<p>W ramach modelu wymagane jest przygotowanie obraz\u00f3w wej\u015bciowych, w skali odcieni szaro\u015bci, o rozmiarach 28&#215;28. Nale\u017cy dokona\u0107 obr\u00f3bki danych przed dostarczeniem ich do sieci. W ramach przetwarzania danych wykorzystamy trzy operacje:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>konwersja do odcieni szaro\u015bci,<\/li><li>interpolacja dwuliniowa,<\/li><li>normalizacja.<\/li><\/ul>\n\n\n\n<p>Pierwsza konwersja b\u0119dzie polega\u0107 na zamianie kolorowych obraz\u00f3w na obrazy w skali odcieni szaro\u015bci. Ka\u017cdy 32-bitowy piksel formacie ARGB zostanie zamieniony na 8-bitowy pixel:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-7.png\"><img decoding=\"async\" width=\"857\" height=\"533\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-7.png\" alt=\"\" class=\"wp-image-12062\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-7.png 857w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-7-300x187.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-7-768x478.png 768w\" sizes=\"(max-width: 857px) 100vw, 857px\" \/><\/a><\/figure><\/div>\n\n\n\n<p>Nast\u0119pnie obraz nale\u017cy przeskalowa\u0107 do rozmiaru 28&#215;28. W ramach przekszta\u0142cenia rozmiaru wykonamy interpolacj\u0119 dwuliniow\u0105:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-8.png\"><img decoding=\"async\" width=\"859\" height=\"263\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-8.png\" alt=\"\" class=\"wp-image-12063\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-8.png 859w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-8-300x92.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-8-768x235.png 768w\" sizes=\"(max-width: 859px) 100vw, 859px\" \/><\/a><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-9.png\"><img decoding=\"async\" width=\"837\" height=\"699\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-9.png\" alt=\"\" class=\"wp-image-12064\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-9.png 837w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-9-300x251.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-9-768x641.png 768w\" sizes=\"(max-width: 837px) 100vw, 837px\" \/><\/a><\/figure><\/div>\n\n\n\n<p>Ostatnia operacja polega na znormalizowaniu danych do warto\u015bci z zakresu [0,1]:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-10.png\"><img decoding=\"async\" width=\"834\" height=\"125\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-10.png\" alt=\"\" class=\"wp-image-12065\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-10.png 834w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-10-300x45.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-10-768x115.png 768w\" sizes=\"(max-width: 834px) 100vw, 834px\" \/><\/a><\/figure><\/div>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Sie\u0107<\/h3>\n\n\n\n<p>Ostatnim etapem jest dostarczenie przerobionych danych do modelu. Do uruchomienia modelu do\u0142\u0105czymy niezb\u0119dne nag\u0142\u00f3wki oraz zmienne, kt\u00f3re b\u0119d\u0105 przechowywa\u0107 potrzebne obiekty TensorFlow Lite. Klasa <strong>MicroErrorReporter<\/strong> udost\u0119pnia mechanizm rejestrowania informacji podczas inferencji. Klasa ta przyda si\u0119 do raportowania napotkanych b\u0142\u0119d\u00f3w.<\/p>\n\n\n\n<p>Po dodaniu wska\u017anik\u00f3w na model, interpreter oraz tensory wej\u015bciowe i wyj\u015bciowe, nast\u0119pn\u0105 rzecz\u0105, kt\u00f3r\u0105 nale\u017cy zrobi\u0107, jest przydzielenie obszaru pami\u0119ci roboczej, kt\u00f3rego model b\u0119dzie potrzebowa\u0142 podczas dzia\u0142ania (tzw. arena tensorowa). Ten obszar pami\u0119ci b\u0119dzie u\u017cywany do przechowywania tensor\u00f3w wej\u015bciowych, wyj\u015bciowych i po\u015brednich modelu.<\/p>\n\n\n\n<p>Jak du\u017ca powinna by\u0107 arena tensorowa? Niestety, nie ma konkretnej odpowiedzi, gdy\u017c wszystko zale\u017cy od architektury modelu. Warto\u015b\u0107 mo\u017cna ustali\u0107 metod\u0105 pr\u00f3b i b\u0142\u0119d\u00f3w, rozpoczynaj\u0105c od takiej, kt\u00f3ra pozwala na uruchomienie modelu, a nast\u0119pnie stopniowo j\u0105 redukuj\u0105c.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-11.png\"><img decoding=\"async\" width=\"852\" height=\"589\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-11.png\" alt=\"\" class=\"wp-image-12066\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-11.png 852w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-11-300x207.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-11-768x531.png 768w\" sizes=\"(max-width: 852px) 100vw, 852px\" \/><\/a><\/figure><\/div>\n\n\n\n<p>W funkcji <strong>setup()<\/strong> uruchomimy logowanie, za\u0142adujemy model, skonfigurujemy interpreter i zaalokujemy pami\u0119\u0107. Zamiast klasy <strong>AllOpsResolver<\/strong>, ograniczymy si\u0119 do u\u017cycia klasy <strong>MicroMutableOpResolver<\/strong>, gdy\u017c potrzeba tylko czterech operacji:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>conv 2D,<\/li><li>max pooling 2D,<\/li><li>fully connected,<\/li><li>reshape.<\/li><\/ul>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-12.png\"><img decoding=\"async\" width=\"866\" height=\"812\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-12.png\" alt=\"\" class=\"wp-image-12067\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-12.png 866w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-12-300x281.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-12-768x720.png 768w\" sizes=\"(max-width: 866px) 100vw, 866px\" \/><\/a><\/figure><\/div>\n\n\n\n<p>Nast\u0119pnie wype\u0142nimy tensor wej\u015bciowy danymi uzyskanymi po przeskalowaniu obrazu wej\u015bciowego i uruchomimy model:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-13.png\"><img decoding=\"async\" width=\"860\" height=\"151\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-13.png\" alt=\"\" class=\"wp-image-12068\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-13.png 860w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-13-300x53.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-13-768x135.png 768w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-14.png\"><img decoding=\"async\" width=\"851\" height=\"153\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-14.png\" alt=\"\" class=\"wp-image-12069\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-14.png 851w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-14-300x54.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-14-768x138.png 768w\" sizes=\"(max-width: 851px) 100vw, 851px\" \/><\/a><\/figure><\/div>\n\n\n\n<p>Do uzyskania cyfry, dla kt\u00f3rej prawdopodobie\u0144stwo jest najwi\u0119ksze skorzystamy z:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-15.png\"><img decoding=\"async\" width=\"866\" height=\"93\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-15.png\" alt=\"\" class=\"wp-image-12070\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-15.png 866w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-15-300x32.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Kod-15-768x82.png 768w\" sizes=\"(max-width: 866px) 100vw, 866px\" \/><\/a><\/figure><\/div>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Uruchomienie<\/h2>\n\n\n\n<p>Z przyk\u0142adowym dzia\u0142aniem aplikacji mo\u017cecie zapozna\u0107 si\u0119 na <a href=\"https:\/\/www.youtube.com\/watch?v=mpjnD-ehBOI\" rel=\"nofollow\" >przygotowanym przeze mnie filmie<\/a>.<\/p>\n\n\n\n<div class=\"wp-block-image size-full wp-image-12087\"><figure class=\"aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Ryc.-5-Przykladowy-efekt-zastosowania-uczenia-maszynowego-na-mikrokontrolerach.png\"><img decoding=\"async\" width=\"391\" height=\"615\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Ryc.-5-Przykladowy-efekt-zastosowania-uczenia-maszynowego-na-mikrokontrolerach.png\" alt=\"Przyk\u0142adowy efekt zastosowania uczenia maszynowego na mikrokontrolerach\" class=\"wp-image-12087\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Ryc.-5-Przykladowy-efekt-zastosowania-uczenia-maszynowego-na-mikrokontrolerach.png 391w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/Ryc.-5-Przykladowy-efekt-zastosowania-uczenia-maszynowego-na-mikrokontrolerach-191x300.png 191w\" sizes=\"(max-width: 391px) 100vw, 391px\" \/><\/a><figcaption>Ryc. 5 <a href=\"https:\/\/www.youtube.com\/watch?v=mpjnD-ehBOI\" rel=\"nofollow\" >Przyk\u0142adowy efekt zastosowania uczenia maszynowego na mikrokontrolerach<\/a><\/figcaption><\/figure><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Podsumowanie<\/h2>\n\n\n\n<p>Powy\u017cszy przyk\u0142ad przedstawi\u0142 kroki, za pomoc\u0105 kt\u00f3rych mo\u017cna stworzy\u0107 od podstaw sw\u00f3j w\u0142asny model sieci neuronowej i dostarczy\u0107 go do aplikacji przeznaczonej na platform\u0119 wbudowan\u0105. Raz wdro\u017cony model mo\u017ce dzia\u0142a\u0107 samodzielnie, bez dost\u0119pu do sieci. Dzi\u0119ki temu podobne podej\u015bcie mo\u017cna zastosowa\u0107 dodatkowo w przypadku, kiedy istotne jest zachowanie prywatno\u015bci danych.<\/p>\n\n\n\n<p><strong>\u0179r\u00f3d\u0142a<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\"><li><a href=\"https:\/\/www.tensorflow.org\/lite\" rel=\"nofollow\" >TensorFlow Lite<\/a><\/li><li>TinyLM: Machine Learning with TensorFlow Lite on Arduino and Ultra-Low-Power Microcontrollers, Daniel Situnayake, Pete Warden, 2020<\/li><\/ol>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;12045&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;6&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;5\\\/5 ( votes: 6)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;TinyML: Uczenie maszynowe w systemach wbudowanych&quot;,&quot;width&quot;:&quot;139.5&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 139.5px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            5\/5 ( votes: 6)    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>W niniejszym artykule zaprezentuj\u0119 przyk\u0142ad wykorzystania modelu sieci neuronowej utworzonej w oparciu o framework TensorFlow Lite na platform\u0119 bazuj\u0105c\u0105 na &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/tinyml-uczenie-maszynowe-w-systemach-wbudowanych\/\">Continued<\/a><\/p>\n","protected":false},"author":281,"featured_media":12080,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":8,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1314],"tags":[563,1161],"class_list":["post-12045","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development-na-twardo","tag-embedded","tag-mikrokontroler"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/11\/TinyML.png","category_names":["Development na twardo"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/12045"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/281"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=12045"}],"version-history":[{"count":3,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/12045\/revisions"}],"predecessor-version":[{"id":21728,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/12045\/revisions\/21728"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/12080"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=12045"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=12045"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=12045"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}