Vezetést segítő funkciók fejlesztése okostelefonra mély tanulás alapon
Szerző: Gróf Attila
Napjainkban a mély neurális hálózatok egyre több szoftver funkciónak a hajtómotorjává válnak, ahogy egyre több területen újabb és jobban teljesítő modelleket alkotnak a kutatók és fejlesztők. A hálózatok erőforrás igényei nem csak tanítási időben magasak, de számos esetben egy komplex, nagy méretű hálózatban a predikció kiszámítása is jelentős számítási kapacitást igényelhet.
Ebben a cikkben egy olyan szoftver rendszert mutatok be, amely egy általános megoldást ad, olyan szoftver rendszerek felépítésére, ahol mély neurális hálózat szolgáltat felhasználói funkciókat. A rendszer működésének demonstrálására vezetést segítő funkciót (objektum detektálást) mutatok be Android okostelefonon TensorFlow keretrendszer segítségével.
A cikkben ábrák és kódrészeletek is megtalálhatóak lesznek.
SSD (Single Shot Multibox Detector) hálózat
Az SSD modell alapvetően egy előre csatolt konvolúciós hálózat, amely fix méretű objektum kereteket ad meg, s ezután minden egyes prediktált kerethez egy értéket ad az objektum osztály előfordulásának valószínűségére. Az egymást átlapoló kereteket a hálózat összefésüli egy végleges keretbe, illetve, ha több osztály takarja egymást akkor több végső keret keletkezik. A hálózat struktúrája egy tradicionális konvolúciós hálózat a kezdete, amit a hálózat alapjának neveznek. Ehhez az alap hálózathoz adnak további rétegeket, melyek méretben jóval kisebbek, ezáltal futásuk is jóval gyorsabb lesz. Ezek a rétegek a detekciót állítják elő különböző méretekben. Emellett minden réteg képes objektumokat detektálni is. A hálózat felépítését az alábbi ábra mutatja.
Akit részletesebben érdekel a hálózat felépítése, itt részletesebben kifejtésre kerül: https://arxiv.org/abs/1512.02325
Android Pie (9.0) áttekintés
Az Android Pie verzióban a mesterséges intelligencia került a középpontba, a bemutatója során főleg a mesterséges intelligencia által meghajtott funkciókat demonstrálta a Google. Ezek között szerepelt intelligens akkumulátor optimalizálás, proaktív asszisztens funkciók, valamint a kamera kép feldolgozásánál több kamera helyett a szoftverre összpontosítanak. Érdekes módon a Google által fejlesztett TensorFlow gépi tanulásos könyvtár nem kapott natív támogatást a Pie rendszerben. Ezzel szemben az Apple iOS-nek van hivatalos támogatása, amely TensorFlow modelleket az Apple saját Core ML modell formátumra konvertálja.
Ennek ellenére a TensorFlow-ban elkészített modellek Android-on való futtatásásra rendelkezésre áll más lehetőség.
Aktív tanítás
Egy olyan rendszer tervezését mutatom be, amely vezetést segítő funkciókkal szolgál a felhasználóknak. A felhasználói funkciók mellé egy olyan szoftver ökoszisztémát alkottam meg, amely biztosítja, hogy a felhasználó funkciókat meghajtó mély neurális hálózat továbbfejlesztése lehetséges legyen. Ezeket a célokat és kapcsolatukat egy folyamatábra mutatja be.
1. Mély neurális hálózat használata az alkalmazásban: Az alkalmazásnak képes lesz mély neurális hálózat segítségével képen található objektumok detektálására. A hálózat számításait a készülék processzorán kell elvégezni.
2. Mély neurális hálózat használata az alkalmazásban: A készített alkalmazásnak tartalmaznia kell funkciót videó és egyéb metaadatok rögzítésére. A metaadatok között a legfontosabbak a készülék szenzorjai által gyűjtött adatok.
3. Alkalmazásban nyers adatok rögzítése: A készüléken gyűjtött nyers adatokat egy távoli tárhelyre fel kell tölteni, mindezt úgy, hogy a háttérben történjen és csak wifi kapcsolaton keresztül, ezzel a mobil internetes forgalmat kímélve.
4. Tárhelyre nyers adatok feltöltése: A mobil készüléken gyűjtött nyers adatot automatizált módszer segítségével fel kell tudni dolgozni és olyan struktúrában tárolni, amelyet később könnyen fel lehet használni. A feldolgozott adatot új tanító adattá alakítani automatizált módon mély neurális hálózat segítségével.
5. Nyers adat feldolgozása és tanító adattá konvertálása: A szerver oldalnak lehetőséget kell biztosítania a meglévő mély neurális hálózat tovább tanítására a rendszer által előállított új tanító adatokkal.
6. Mély neurális hálózat tovább tanítása: A tovább tanított hálózat teljesítményét tesztelni kell, hogy meg lehessen állapítani, hogy jobb predikciókat számol-e, mint a hálózat előző verziója.
7. Tanított hálózat tesztelése: Az új „okosabb” hálózatot valamilyen módon vissza kell szinkronizálni a már telepített applikációba úgy, hogy azt az alkalmazás használni legyen képes.
Rendszerterv
A rendszer több komponensből és eszközből épül fel, amelyeknek a kapcsolatát a következő ábra illusztrálja.
A rendszer 2 nagyobb komponensre osztható fel: Android alkalmazás és a szerver oldal. Az Android applikációt „DriverPhone”-nak neveztem el, ettől kezdve így is fogok hivatkozni rá. A komponensek és a modulok közötti nyilak az adat áramlást vagy használatot reprezentálnak. Az architektúra ábra célja a rendszer felépítésének átláthatósága és az esetleges hibák korai felderítésére szolgált a fejlesztés során.
Implementáció
Az implementációból csak a fontosabb modulokat és kódrészleteket emelném ki. A cikkben bemutatott rendszerhez tartozó kódok a github-on megtalálhatóak az alábbi linken: https://github.com/grofattila/tdk-driver-assistant
Most a modulok részeletes bemutatása következik.
DriverPhone — Tanító adat rögzítése
A modul videó rögzítésére is a camera2 API-t használja. A rögzített videót mp4 formátumban és 640x480-as felbontásban menti a készülék memóriájába. A 640x480 pixeles felbontás választásának oka leginkább a mentett videó mérete és később a feldolgozás költsége. A modul a videót a bejelentkezett felhasználó neve és egy időbélyeg konkatenálásával létrehozott néven menti a készüléken a /Android/data/hu.bme.tmit.driverphone/files mappába.
A videó rögzítése során párhuzamosan a háttérben egy csv fájl készül, amelyben az alábbi mezők szerepelnek:
- Időbélyeg (ms)
- Mobil internet helyzet hosszúsági és szélességi fokban
- GPS helyzet hosszúság és szélességi fokban
- Gyorsulás mérő x,y és z tengely mentén
- Giroszkóp x,y és z tengely mentén
Ezekből a videókból kinyert adatok fognak később tanító adatként szolgálni.
DriverPhone — mély neurális hálózat modul
Először egy interfészt definiálunk, amit a mély neurális hálózatot megvalósító osztálynak meg kell valósítania. Itt a legfontosabb metódus az executeGraph, ez a metódus fogja előállítani a prediktált értékeket.
/**
* Mély neurális hálózatoknak interfész.
* @param <T> Result Eredmény típus.
* @param <E> Data Bemeneti adat típus.
*/
public interface NeuralNet<T, E> {/**
* Bemeneti dimenzió lekérdezése.
* @return Dimenzió.
*/
Integer getInputSizeWidth();
/**
* Bemeneti dimenzió lekérdezése.
* @return Dimenzió.
*/
Integer getInputSizeHeight();
/**
* Bemeneti dimenzió lekérdezése.
* @return Dimenzió.
*/
Integer getInputSizeDepth();/**
* Bemeneti dimenzió lekérdezése.
* @return Dimenzió.
*/
long[] getInputSize();/**
* Predikció kiszámolása.
* @param byteImage Bemeneti kép.
* @return Eredmény objektum.
*/
T executeGraph(final byte[] byteImage);
}
Készítünk egy osztályt, amely implementálja az előbb definiált interfészt és a TensorFlow-nak a natív függvényeit be kell tölteni, hogy a mély neurális hálózat segítségével a predikciót képesek legyünk kiszámolni.
public class SsdMobileNet implements NeuralNet<SsdResult, SsdInput> {
// TensorFlow natív függvények betöltése
static {
System.loadLibrary("tensorflow_inference");
}
….
}
A predikciók kiszámításához még be kell tartani néhány szabályt ahhoz, hogy a készülék számító kapacitását jól tudjuk kihasználni. A TensorFlow “session”-t, amiben a kiértékeljük a modellt csak egyszer szabad inicializálni mert ez egy drága művelet és értékes ms-kat lehet vesztegetni a “session” folytonos bezárásával és megnyitásával.
A kamera által előállított képek egy Bitmap típusban érkeznek és az alábbi pixel elrendezést követi.
Ezt a 2 dimenziós és RGBA színcsatornákból álló képet kell egy 1 dimenziós byte tömbbé alakítani és átadni a tanított mély neurális hálózat modellnek.
Először is szükségünk néhány leíró adatra a tanított modellünkre.
public static final int INPUT_WIDTH = 300;
public static final int INPUT_HEIGHT = 300;
public static final int INPUT_DEPTH = 3;
private static final long[] INPUT_SIZE = {1, 300, 300, 3};
private static final String SSD_INPUT_NAME = "image_tensor";
private static final String[] SSD_OUTPUT_NAMES =
{"num_detections:0", "detection_classes:0", "detection_scores:0", "detection_boxes:0"};
Ezután már rendelkezésre áll a kamera képe és a mély neurális hálózatot leíró adatok. A következő lépés a predikció kiszámítása.
/**
* Predikció számolása.
*
* @param byteImage Kép 1 dimenzióban.
*/
public SsdResult executeGraph(final byte[] byteImage) {
// Ha nincs session akkor nem tudunk predikciót számolni
if (session != null) {
// Byte tömb TensroFlow-nak megfelelő Tensor típusra konvertálása.
ByteBuffer byteBuffer = ByteBuffer.wrap(byteImage);
final Tensor image = Tensor.create(UInt8.class, new long[]{1, INPUT_WIDTH, INPUT_HEIGHT, INPUT_DEPTH}, byteBuffer);// Predikció kiszámítására fordított időtartam mérése.
long timeStart = System.currentTimeMillis();// Predikció futtatása
List<Tensor<?>> resultList = session.runner()
.feed(SSD_INPUT_NAME, image)
.fetch(SSD_OUTPUT_NAMES[0])
.fetch(SSD_OUTPUT_NAMES[1])
.fetch(SSD_OUTPUT_NAMES[2])
.fetch(SSD_OUTPUT_NAMES[3])
.run();// Predikció eredmény típusának előállítása
calcSsdResult(resultList);final long inferenceTime = System.currentTimeMillis() - timeStart;
Log.d(TAG, "Inference time: " + inferenceTime + " ms");
}
// Predikcióval való visszatérés
return result;
}
Szerver oldali alkalmazás
A Python alkalmazás tartalmazza azokat a logikákat, amelyek magas számítási kapacitást és nagy tárhelyet igényelnek. Ez magába foglalja a nyers adatok feldolgozását, egy tanító adatbázis építését és mély neurális hálózat tovább tanítását. Az alkalmazás magába foglal egy feldolgozó scriptet, ami csak adatfeldolgozáskor fut és egy webszervert, amely mindig elérhető és rajta keresztül letölthető a legújabb mély neurális hálózat modell.
Szerver oldali alkalmazás — Adatfeldolgozó modul
Az adatfeldolgozó modul feladata a nyers videókból egy tanításra alkalmas TFRecords előállítása. A tanítani kívánt hálózat egy objektum detektálására alkalmas SSD MobileNet hálózat, a tanító adatok előállítása ennek fényében történik. Az adatfeldolgozási lépések erőforrás igényes feladatok, nagyobb méretű videók feldolgozási ideje akár a napokat is elérhetik egy átlagos felhasználói gépen.
A tanításra alkalmas adatok előállítása az alábbi 7 lépéses adat transzformáció végeztél áll elő.
A fenti ábrán látható lépéseket az alábbi Python script végzi el.
# A script futtatásához szükséges paraméterek beolvasása
parser = OptionParser()
parser.add_option("-s", "--source", dest="source",
help="folder to process")
parser.add_option("-d", "--destination", dest="destination",
help="destination folder")
parser.add_option("-v", "--verbose", dest="verbose",
help="Verbose to show (0=false,1=true)")(options, args) = parser.parse_args()verbose = int_to_bool(options.__getattribute__('verbose'))
source_folder = options.__getattribute__('source')
destination_folder = options.__getattribute__('destination')if verbose == True:
print("Source folder: " + str(source_folder))
if verbose == True:
print("Destination folder: " + str(destination_folder))# Cél mappák inicializálása
cutted_video_output_path = destination_folder + "/cutted_video_output"
cutted_stabilized_video_output_path = destination_folder + "/cutted_stabilized_video_output"
frames_output_path = destination_folder + "/frames"# Cél mappa létrehozása
mkdir(destination_folder)
# Vágott videók mappájának létrehozása
mkdir(cutted_video_output_path)
# Vágott és stabilizált videók mappájának létrehozása
mkdir(cutted_stabilized_video_output_path)
# Képkockák mappájának létrehozása
mkdir(frames_output_path)# Videók felvágása megadott hosszúra
cut_videos_to_parts(source_folder, cutted_video_output_path,'mp4', default_video_lenghts)
# Feldarabolt videók stabilizálása
stabilize_videos(cutted_video_output_path, cutted_stabilized_video_output_path)
# Feldarabolt és stabilizált videók képkockává való feldarabolása
videos_to_frames(cutted_video_output_path, frames_output_path, "mp4")
# Képen lévő objektumokat tartalmazó xml előállítása mély neurális hálózat segítségével
generate_xml_files_with_nn(frames_output_path)
# XML CSV-re való konvertálása, amely tartalmazza az összes képet leíró XML-t
generate_csv_from_xml(frames_output_path)
# Tanításra alkalmas TFRecords elkészítése
generate_tf_records(frames_output_path + "/labels.xml", frames_output_path + "/train.record")
Szerver oldali alkalmazás — Mély neurális hálózatot tanító modul
A tanításhoz az alábbi fájlok szükségesek:
- Mély neurális hálózatot leíró fájl
- Tanító adat
- Tesztelő adat
- Tanítási konfigurációs fájl
- Címke leíró fájl
- Előző tanításból checkpoint file (opcionális)
A mély neurális hálózatot leíró fájl maga a hálózat felépítését írja le, milyen csomópontok milyen más csomópontokhoz kapcsolódnak, az értékeknek milyen típusai vannak és milyen műveletek hajtódnak végre a csomópontokban.
A tanító és tesztelő adat az előző fejezet végén kép, xml és csv-ből generált TFRecords fájlok.
A tanítási konfigurációs fájl tartalmazza az összes tanítással kapcsolatos beállítást. A tanítást befolyásoló paramétert lehet konfigurálni, melyeket kötelező beállítani azok a tanító, tesztelő adatok, osztály címkék és ha már volt korábban tanítás, akkor az ahhoz tartozó checkpoint fájlt.
A tanítás egy model_main.py script-el (https://github.com/tensorflow/models/blob/master/research/object_detection/model_main.py) indul, aminek a forrás és célmappát meg kell adni. A tanítás előrehaladását a TensorBoard-al lehet monitorozni. A TensorBoard a legfontosabb értékeket a tanítás folyam vizualizálja, hogy a tanítás eredménye és folyamata érthetőbb és átláthatóbb legyen.
Tesztelés és eredmények
Az Android alkalmazást Android Studio segítségével írtam és Nokia 7 Plus HDMI Global és LG Nexus 5 készüléken teszteltem. Az alkalmazás futtatásához szükséges minimális követelmény a 6.0 (Marshmallow) verzió. A szerver oldali Python alkalmazást Visual Studio Code és Jupyter Lab segítségével írtam.
A detektáló funkció tesztelése két készüléken futott:
- LG Nexus 5
- Nokia 7 Plus HDMI Global
Nexus 5 CPU használat:
Nexus 5 memória használat:
A kék a natív kód és Java memóriáját jelöli, a sárga a grafikus megjelenítéshez szükséges memória és a türkiz kék a kód mérete a memóriában.
Nokia 7 Plus CPU:
Nokia 7 Plus memória:
Az alkalmazás lehetőséget nyújt új adatok rögzítésére, ami ebben az esetben videó felvételt jelent. A videó felvétel alatt a metaadat gyűjtés is elindul és ezeket a készülék háttértátára menti el. A videó 640x480-as felbontásban kerül rögzítésre és a metaadatok fájlba a készülék fontosabb szenzor adatai kerülnek.
A DriverPhone lehetőséget nyújt az adatok automatizált feltöltésére is, ezt a profil fül alól a „Ftp Upload” gombbal lehet megtenni. Az adatok felöltése után a lokális készülékről azok törlésre kerülnek, hogy ne foglaljon az alkalmazás feleslegesen helyet, illetve a feltöltés csak wifi kapcsolaton keresztül lehetséges.
A feltöltött nyers adatokból adattranszformációs lépések és egy konfigurálható mély neurális hálózat segítségével a rendszer képes előállítani a tanító adatokat. Az előállított adatokban kézzel is lehet javítani. A kulcs ebben a lépésben, hogy amennyiben kézzel nem szeretnénk javítani a szerver oldali szkript a nyers adatokból 1 gombnyomásra előállítja a tanításhoz használt TFRecords-ot.
A mély neurális hálózathoz a konfigurációs fájlokat létrehoztam, a tanító, tesztelő adatok és a hálózat megadásával a hálózat tovább tanítható. A tanítás során 500 cikluson át tanítottam és a veszteség majdnem elérte az 1-et (1.0954). A tanítás több mint 3 óráig tartott és ~ 100MB adattal tanítottam mert a tanításra használt számítógép egy közép kategóriás Lenovo laptop. Az osztályozás, amikor kép adott részén megállapítja, hogy milyen osztályú objektum van ott és a lokalizációs hiba magának az objektum helyének a megadása.
A szerver alkalmazás biztosít egy webszervert, amin keresztül a DriverPhone alkalmazás képes letölteni és elmenti a mély neurális hálózat új verzióját.
Az Android alkalmazásban a mély neurális hálózat cserélésének segítségével az újabb hálózatokon is lehetőség van a tesztelésre. A kódbázis módosítása nélkül az újabb SSD
MobilNet2 (ssdlite_mobilenet_v2_coco) hálózat már csak ~20 MB tárhelyet foglal és a Nokia 7 Plus-on a detektálás ~ 250 ms alatt történik meg, ami 4 FPS-t jelent.
Összefoglalás
A mély tanulás alapú informatikai megoldások egyre több helyen jelennek meg, okostelefonjaink is számos olyan funkcióval rendelkeznek, amely mögött egy mély neurális hálózat valósítja meg az üzleti logikát.
Ebben a cikkben egy olyan szoftver architektúrát mutattam be, amely egy általános megoldás, olyan rendszerekre nézve, ahol intelligens funkciókat mély neurális hálózatok hajtanak meg. A rendszer megvalósítás témájának vezetést támogató rendszert választottam. Ez egy igen fontos terület és a jövőben az okostelefonok sok aspektusban segíthetik a különböző járművekkel való utazást.
A rendszernek része egy Android alkalmazás, egy szerver oldali Python alkalmazás, egy FTP szerver és a Firebase szolgáltatása.
Az Android alkalmazás autók, buszok és jelző lámpák detektálását végzi a kamera képén folyamatosan. A konvolúciós mély neurális, amely a detektálást végezte, teljes egészében a készüléken fut. Másodperceként 2–3-szor volt képes az alkalmazás predikciót számolni. Emellett az alkalmazás képes felhasználó kezelésre, videó rögzítésre metaadatokkal együtt és tartalmaz konfigurálható beállításokat. A rögzített adatok egy kattintásra feltölthetőek egy FTP szerverre.
A szerver oldali alkalmazás a rögzített nyers adatokból tanító adatokat állít elő mély neurális hálózat segítségével automatizált módon és lehetőséget ad az SSD MobilNet konvolúciós mély neurális hálózat tovább tanítására. Az alkalmazás biztosít egy webszervert, ahonnan az újonnan tanított hálózat letölthető.
A megvalósított alkalmazásból néhány kép és videó futás közben:
A cikk a 2018-ban a Budapesti Műszaki és Gazdaságtudományi Egyetemem rendezett Tudományos Diákköri Konferencia Neurális Hálózatok szekciójában elért II. helyezett dolgozat alapján készült.
A dolgozat elérhető itt: http://tdk.bme.hu/VIK/Neural/Vezetest-segito-funkciok-fejlesztese
A kódbázis elérhető itt: https://github.com/grofattila/tdk-driver-assistant
Demó videó:
A cikkhez és a TDK dolgozathoz is köszönöm a támogatást a Budapest Műszaki és Gazdaságtudományi Egyetem Távközlési és Médiainformatikai Tanszéknek és Dr. Gyires-Tóth Bálintnak.