Jak moc komplikované je takové to domácí vytvoření docela funkční neuronky, která bude rozpoznávat objekty před kamerou, nejrůznější gesta rukou anebo třeba hlasové povely? Možná vás to překvapí, ale s trochou vůle to zvládnou i vaše děti a vystačí si jen s webovým prohlížečem. Dnes si to ukážeme v praxi.
Google před lety zveřejnil svůj set knihoven pro práci se strojovým učením a zpracováváním hotových neuronových sítí TensorFlow. Jeho součástí je také projekt TensorFlow.js, který je už podle svého názvu napsaný v Javascriptu, a tak může běžet přímo ve webovém prohlížeči a bez potřeby instalace jakéhokoliv těžkého softwaru.
Fajn, toto si ale přečtete i na Wikipedii. Problém je někde jinde. Můžete vymyslet sebelepší knihovnu, bez perfektní znalosti matematiky a architektury neuronových sítí vám to ale nakonec bude stejně k ničemu.
Vycvičte si neuronku jako psa na cvičišti
Je si toho vědom i Google, a tak stále dokola vymýšlí nejrůznější experimenty, jak ze strojového učení a neuronových sítí udělat naprosto jednoduchý black box – černou skříňku, kterou prostě vycvičíte jako psa, aniž byste tušili, jak v nitru funguje jeho mozek. Bez jediného řádku zdrojového kódu!
Přesně o to se snaží služba Teachable Machine, která se pokouší přiblížit svět aplikovaných neuronových sítí naprosto běžným smrtelníkům, kteří poslední půlrok nestrávili na MIT. Díky TensorFlow.js vše běží přímo v prohlížeči a web nabízí také jednoduché grafické rozhraní, ve kterém si v tuto chvíli můžete přeučit tři různé neuronové sítě – s trochou nadsázky tři psí mozky.
Webové prostředí Google Teachable Machine umí přímo v prohlížeči vytvořit tři typy neuronové sítě, kterou můžete použít ve svých projektech
Tyto tři neuronky už mají nacvičené své základy, a tak je potřeba k jejich přeučení do alespoň trošku použitelné podoby poměrně málo studijních dat a výpočetního času vašeho počítače. Pokud bychom si měli opět vypůjčit paralelu se psem, tento už umí příkazy sedni, lehni, dej pac a teď ho prostě jen vezmeme na cvičák, kde jej naučíme příkaz dělej sudy.
Pro našeho digitálního psíka to bude mnohem snazší úkol než pro divokého vlčáka, kterého nikdo nikdy nenaučil ani základní sociální návyky v domácí smečce, a tak bude na cvičišti jen slintat a hloupě civět do prázdna.
Teachable Machine nabízí tři předučené neuronové sítě pro:
- Rozpoznávání objektů v obrazu
- Rozpoznávání prvků těla/pózy
- Rozpoznávání zvuku
Vstupem může být externí obrazový nebo zvukový soubor, technologie ale nabízí i podporu webkamery počítače a mikrofonu skrze rozhraní webového prohlížeče, což si dnes vyzkoušíme i my.
Vytváříme detektor krtečka
Princip přeučení všech neuronek Teachable Machine je stejný. Dejme tomu, že bychom si chtěli vytvořit detektor českého krtečka. Vytvoříme si tedy nový projekt s využitím obrazové detekční neuronky, a jak je patrné na obrázku níže, generátor nás požádá o nějaké třídy. Co to proboha je?
Class – třída – jsou entity, které budeme chtít neuronkou rozlišit. Když tedy naučené síti předložíme fotografii nebo filmové políčko z kamery, odpoví nám seznamem tříd, na kterých se už dříve učila, a pravděpodobností, se kterou každou z nich vidí v obrazu.
Máváním s krtečkem před kamerou vytvoříme první rozlišovací třídu krtek
Jelikož v našem případě probíhá veškeré učení v prohlížeči s využitím integrované kamery notebooku, vytvoříme pomocí ní dostatek studijních dat. Vezmeme do ruky plyšového krtka, stiskneme nahrávací tlačítko a budeme s ním šermovat před kamerou tak dlouho, dokud nebudeme mít alespoň pár desítek snímků s jeho záběrem ze všech možných úhlů.
Jedna třída ale nestačí. Ještě potřebujeme pravý opak krtka, což bude běžné pozadí – šum. Jednoduše tedy stejným způsobem nahrajeme pár sekund dění před kamerou, když před jejím objektivem žádný krtek není. Tuto třídu nazveme třeba pozadi.
Aby mohla neuronka rozlišit krtka oproti pozadí, vytvoříme ještě druhou třídu s „šumem“ – tedy s běžnou scénou před kamerou, ve které se ale nesmí vyskytovat krtek!
Na pracovní ploše je patrné tlačítko „Add a class,“ analogicky bychom tedy mohli přidat hromadu dalších tříd a vedle krtka hledat i další objekty. Pro základní seznámení to ale stačí. Nyní už máme studijní data a můžeme spustit učení stisknutím tlačítka „Train Model.“
Padesát epoch
Ve výchozím stavu učení absolvuje 50 průchodů studijními daty, kterým se v A.I. hantýrce říká epocha. Čím více epoch (a zároveň pestrých studijních dat), tím často také i vyšší kvalita hotového detekčního modelu.
Neuronová síť si právě vytváří svůj pravděpodobnostní model toho, co je to, na pixelové úrovni, třída krtek a co třída pozadi
My si to ale nebudeme nijak komplikovat, spustíme jen přednastavený trénink a za pár desítek sekund by mělo být vše hotovo (přinejmenším na mém pracovním laptopu se starším mobilním procesorem Intel Core i5).
Jakmile bude model hotový, o jeho kvalitě se můžeme přesvědčit v poslední části Preview s živým náhledem z kamery. Všimněte si, že pod kamerou se zobrazuje pravděpodobnost, se kterou naše nová neuronka vidí na vstupu každou z tříd.
V okně Preview si můžeme otestovat, jak se síť naučila rozpoznávat obě třídy. Jak vidno, krtek se tak dobře liší oproti pozadí, že s tímto příkladem nemá jediný problém.
Pokud nebude v záběru krtek, síť bude vracet třídu pozadí, jakmile ale zpoza obrazovky vykouknou krtčí oči, poměr se změní.
Hotovou neuronku můžeme použít ve vlastních aplikacích
Právě jsme si vytvořili vlastní neuronovou síť ve formátu TensorFlow.js, aniž bychom věděli, co se v nitru vlastně odehrálo. Co je však zdaleka nejdůležitější a čím se Teachable Machine liší oproti mnoha jiným ukázkám, náš hotový model nyní můžeme použít ve svých vlastních projektech, převést jej třeba do formátu Tensorflow Lite a vyrobit si detektor krtka na Raspberry Pi, mobilním telefonu a tak dále.
Celé nám to přitom zabralo všeho všudy pár minut času.
Pojďme si to vyzkoušet v praxi. A nebojte se, Raspberry Pi nebudete rozhodně potřebovat. Vše opět pojede v prohlížeči a v jednom HTML souboru. Teachable Machine totiž může uložit vaši neuronovou síť přímo na svých serverech a nabízí jednoduché aplikační rozhraní pro Javascript.
Ani toho se však nemusíte bát, objedete se totiž i bez dokumentace, neboť Teachable Machine za vás vygeneruje celou kostru programu, kterou si budete moci postupně upravit k obrazu svému a naučit se, jak to vlastně celé funguje.
Počítadlo doušků kávy
Namísto detektoru krtků si pohrajeme s poněkud komplikovanější úlohou. Jak jsme si už řekli výše, Teachable Machine nabízí také neuronku PoseNet, která se specializuje na detekci lidské postavy od jednotlivých končetin až po prvky tváře.
PoseNet můžete přímo v prohlížeči spustit nad obrazem z webkamery a detekovat nejen oči, nos, ústa apod., ale třeba i zvednutou pravou ruku nebo jiné libovolné gesto.
Neuronová síť PoseNet tentokrát nehledá ve scéně naučené objekty, ale naučené pózy těla. Modře vykreslený skelet znázorňuje pózu, jak ji právě vidí neuronová síť ve vstupu z kamery. Rozpoznala horní končetiny a prvky tváře.
Na stranu druhou, taková ruční analýza gesta může být pro začátečníka opravdový horor s příliš velkým množstvím nejistých proměnných, a tak celou detekci komplexního gesta tělem opět předáme k naučení neuronové síti.
Máme rádi redakční kávu a konzumujeme ji od rána do večera, naučíme proto neuronku rozpoznávat pohyb ruky s šálkem dobré brazilské kávy směrem k ústům. Kdykoliv pak přeučený PoseNet detekuje právě toto gesto, dá nám o tom vědět a my jej můžeme zpracovat. Vyrobíme si počítadlo doušků kávy!
Stačí nahrát pohyb ruky a spustit učení
Základní princip učení neuronky je opět totožný jako u krtka z prvního příkladu. Tentokrát však budou studijní data tvořit změny v lidské postavě při zvedání a pokládání šálku s kávou. Nahrajeme tedy sekvenci snímků, ve které zvedáme šálek nahoru a dolu a pojmenujeme tuto třídu jako dousek.
Vytváříme studijní data pro třídu doušek, které obsahují pózu s postupně se zvedající rukou směrem k ústům.
Stejně jako v případě krtka potřebujeme přinejmenším ještě jednu třídu, kterou bude tvořit opět šum – tedy pozadi. Tato třída bude představovat naši běžnou práci na klávesnici.
Opakem třídy dousek bude třída pozadi, která obsahuje klidové snímky. Obě ruce v tomto případě leží na klávesnici a právě a v potu a krvi datlují tento článek.
S dostatkem studijních dat nakonec spustíme proces přeučení a budeme doufat, že neuronová síť v první třídě rozpozná, že obsahuje velmi typický pohyb jedné z ruk nahoru a dolu, který se v té druhé naopak vůbec nevyskytuje, anebo jen sporadicky.
Po naučení gesta s douškem si můžeme opět ověřit kvalitu jeho detekce v panelu PReview
Pokud se budou studijní snímky z obou tříd dostatečně lišit a ve všech dokáže PoseNet rozpoznat základní lidskou kostru horních partií těla, měl by náš detektor fungovat poměrně dobře, a jakmile zamíříme šálkem s kávou směrem k ústům, pravděpodobnost třídy dousek vystřelí střemhlav vzhůru.
Podívejte se na test naučeného gesta v akci:
Generátor vytvoří hotový Javasceript
Fajn, neuronka na rozpoznávání zvednutého hrníčku nám funguje, ale teď ji ještě pojďme použít ve skutečné aplikaci mimo prostředí Teachable Machine. Stačí klepnout na tlačítko „Export Model,“ a na kartě zvolit buď nahrání modelu na servery Googlu, anebo jeho stažení do počítače.
Hotový model můžeme nahrát na úložiště Googlu, anebo klidně uložit do počítače, pokud s ním budeme pracovat v klasickém prostředí TensorFlow
My využijeme bezplatného hostingu, model nahrajeme na server a zkopírujeme si hotový kód, který stačí vložit do libovolného HTML souboru mezi základní značky <body> a </body>.
Počítadlo doušků v HTML
Co vygenerovaný kód provede? Zobrazí tlačítko. Když na něj klepneme, nastartuje se kamera, jejíž živý náhled se zobrazí přímo na stránce, a následně se spustí samotná detekce. Program pak bude pod okno kamery vypisovat pravděpodobnost, s jakou v obrazu vidí buď třídu pozadi, anebo třídu dousek.
Douškoměr 1.0: Za pět minut hotovo!
My kód drobně upravíme (a pro přehlednost jsem přeložil i názvy proměnných a funkcí) takovým způsobem, že když si bude neuronová síť myslet, že právě vidí třídu dousek s pravděpodobností nad 80 %, zvýší se hodnota počítadla doušků, která se zároveň zobrazuje na stránce.
Aby se hodnota počítadla během pohybu nezvýšila hned několikrát, k dalšímu připočítání dojde až tehdy, kdy neuronka uvidí opět klidové pozadí/šum a začne nový pohyb rukou směrem k obličeji.
Podívejte se na Douškoměr v akci:
Po celou dobu máme zároveň přístup k datům o rozpoznané kostře těla, takže nehledě na náš model můžeme využívat i další data jako pozici prvků tváře, pozici jednotlivých uzlů těla (horní/dolní končetiny) atp. To vše totiž uměla síť už před tím, než jsme ji naučili nový fígl.
Dnes jsme si tedy ukázali, že k základnímu cvičení a následné aplikaci tří různých obrazových a zvukových neuronových sítí nepotřebujete ani doktorát z matematiky, ani vysokoškolské znalosti programování, ale zhruba to, s čím se přinejmenším ti mladší setkali v hodinách informatiky na ZŠ/SŠ.
Takže vítejte ve světě aplikované umělé inteligence a směle do vlastních experimentů!
Na úplný závěr nesmí jako vždy chybět komentovaný zdrojový kód. Pro přehlednost jsem jej rozdělil na HTML soubor detektor.html a javascriptový soubor se samotným programem aplikace.js.
Obsah souboru detektor.html:
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="utf-8" />
<link href="https://fonts.googleapis.com/css?family=Comfortaa&display=swap&subset=latin-ext" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.3.1/dist/tf.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@teachablemachine/pose@0.8/dist/teachablemachine-pose.min.js"></script>
<script src="aplikace.js"></script>
<title>Douškoměr - počítadlo doušků kávy</title>
<style>
html,body{
font-family: 'Comfortaa', cursive;
background: black;
color:bisque;
font-size: medium;
}
button{
bordeR: 1px solid bisque;
background: black;
color: bisque;
font-family: 'Comfortaa', cursive;
padding: 5px 5px;
}
button:hover{
background: bisque;
color: black;
}
button:focus{
outline: none !important;
}
#kamera{
display:block;
margin: 10px 10px;
}
</style>
</head>
<body>
<h1 id="pocitadlo">Doušky kávy: 0</h1>
<button onclick="setup()">Začni počítat doušky</button>
<canvas id="kamera"></canvas>
<div id="popisky"></div>
</body>
</html>
Obsah souboru aplikace.js
// Pomocna promenna, zdali gesto dousku uz skoncilo, nebo jeste probiha
let zamek = false;
// Pocitadlo dousku
let dousky = 0;
//Adresa naseho modelu na serveru Googlu
let URL = "https://teachablemachine.withgoogle.com/models/djKXbeADi/";
// Objekty modelu, kamery, popisku/trid atp.
let model, kamera, ctx, popiskyTrid, vsechnyTridy;
// Funkci setup zavolame po stisku tlacitka na strance
// Funkce setup nastartuje kameru a zpracovavani neuronove site
async function setup() {
// Stazeni a nahrani modelu neuronove site do pameti
const modelURL = URL + "model.json";
const metadataURL = URL + "metadata.json";
model = await tmPose.load(modelURL, metadataURL);
vsechnyTridy = model.getTotalClasses();
// Nastartovani kamery s rozlisenim 200x200 a zrcadlove pretoceni
kamera = new tmPose.Webcam(200, 200, true);
await kamera.setup();
await kamera.play();
// Spusteni nekonecne smycky, ktera bude neustale volat funkci loop
window.requestAnimationFrame(loop);
// Propojeni kamery s tagem <canvas> v HTML kodu,
// do ktereho se bude vykreslovat obraz
const canvas = document.getElementById("kamera");
canvas.width = 200;
canvas.height = 200;
ctx = canvas.getContext("2d");
// Vytvoreni tagu <div> pro jendotlive tridy (nas model pouziva dve: dousek a pozadi)
popiskyTrid = document.getElementById("popisky");
for (let i = 0; i < vsechnyTridy; i++) {
popiskyTrid.appendChild(document.createElement("div"));
}
}
// Smycku loop bude animacni/WebGL subsystem prohlizece volat stale dokola
// Pripomina tedy stejnojmennou funkci ze sveta Arduina
async function loop(ts) {
//Sejmi snimek z kamery
kamera.update();
// Zavolej funkci detekce, ktera snimek preda neuronove siti
await detekce();
// Zavolej znovu tuto funkci
window.requestAnimationFrame(loop);
}
// Funkce detekce provadi samotnou analyzu snimku z kamery pomoci neuronove site
async function detekce() {
// Vyhledej ve snimku z kamery lidskou kostru a uloz ji do objektu 'pose'
const { pose, posenetOutput } = await model.estimatePose(kamera.canvas);
// Vyhledej ve snimku nase gesto se zvedajici se rukou se salkem
// a uloz vysledky do pole predikce
const predikce = await model.predict(posenetOutput);
// Projdi jednotlive tridy a na stranku vypis jejich nazvy a pravdepodobnost
for (let i = 0; i < vsechnyTridy; i++) {
popiskyTrid.childNodes[i].innerHTML = predikce[i].className + ": " + predikce[i].probability.toFixed(2);
// Pokud ma aktualni trida nazev dousek
if(predikce[i].className == "dousek"){
// Pokud ma tato trida zaroven pravdepodobnost 80 % a vice
// V tuto chvili tedy velmi pravdepodobne probiha nase gesto rukou smerem k ustum
if(predikce[i].probability > 0.8){
// Pokud gesto prave zacalo (zamek je odemceny)
if(!zamek){
// Zvys pocitadlo dousku
dousky++;
// Zamkni zamek
zamek = true;
// Vypis pocet dousku na stranku
document.getElementById("pocitadlo").innerHTML = "Doušky kávy: " + dousky;
}
}
// Pokud pravdepodobnost tridy dousek klesla pod 10 %,
// uz asi gesto postupne konci, ruka klesa ke stolu,
// a tak opet odemknu zamek gesta
else if(predikce[i].probability < 0.1){
zamek = false;
}
}
}
// Vykresli do obrazu kamery lidskou kostru
// Pose je JSON struktura, kterou muzeme projit
// a zjisitt souradnice jendotlivych prvku tela
nakresliPostavu(pose);
}
// Funkce pro vykresleni lidske kostry
function nakresliPostavu(postava) {
// Pokud bezi kamera a maem pristup k jejimu platnu
if (kamera.canvas) {
// Nakresli obraz z kamery na stranku
ctx.drawImage(kamera.canvas, 0, 0);
// Pokud neuronka rozpoznala kostru cloveka
if (postava) {
// Nakresli do obrazu uzly, pokud maji pravdepodobnost alespon 50 %
tmPose.drawKeypoints(postava.keypoints, 0.5, ctx);
// Nakresli do obrazu propojovaci linky kostry, pokud maji pravdepodobnsot alespon 50 %
tmPose.drawSkeleton(postava.keypoints, 0.5, ctx);
}
}
}