OpenVINO hakatons: balss un emociju atpazÄ«Å”ana vietnÄ Raspberry Pi
30. novembris - 1. decembris Å ižÅijnovgorodÄ notika OpenVINO hakatons. DalÄ«bniekiem tika lÅ«gts izveidot produkta risinÄjuma prototipu, izmantojot Intel OpenVINO rÄ«ku komplektu. Organizatori piedÄvÄja sarakstu ar aptuvenÄm tÄmÄm, pÄc kurÄm varÄtu vadÄ«ties, izvÄloties uzdevumu, taÄu gala lÄmums palika komandÄm. TurklÄt tika mudinÄts izmantot modeļus, kas nav iekļauti izstrÄdÄjumÄ.
Å ajÄ rakstÄ mÄs jums pastÄstÄ«sim par to, kÄ mÄs izveidojÄm mÅ«su produkta prototipu, ar kuru mÄs galu galÄ ieÅÄmÄm pirmo vietu.
HakatonÄ piedalÄ«jÄs vairÄk nekÄ 10 komandas. PatÄ«kami, ka daži no viÅiem nÄkuÅ”i no citiem novadiem. Hakatona norises vieta bija komplekss āKremlsky on Pochainā, kurÄ iekÅ”Ä svÄ«tÄ bija izkÄrtas senÄs Å ižÅijnovgorodas fotogrÄfijas! (AtgÄdinu, ka Å”obrÄ«d Intel centrÄlais birojs atrodas Å ižÅijnovgorodÄ). DalÄ«bniekiem tika dotas 26 stundas koda rakstÄ«Å”anai, un beigÄs viÅiem bija jÄprezentÄ savs risinÄjums. AtseviŔķa priekÅ”rocÄ«ba bija demo sesijas klÄtbÅ«tne, lai pÄrliecinÄtos, ka viss iecerÄtais ir reÄli Ä«stenots un nepaliek idejas prezentÄcijÄ. Preces, uzkodas, Ädiens, viss arÄ« bija!
Viena no grÅ«tÄkajÄm daļÄm, gatavojoties brÄ«vas formas hakatonam, ir izaicinÄjuma izvÄle. MÄs nekavÄjoties nolÄmÄm nÄkt klajÄ ar kaut ko tÄdu, kas vÄl nebija produktÄ, jo paziÅojumÄ bija teikts, ka tas ir ļoti apsveicami.
IzanalizÄjot modeļi, kas ir iekļauti produktÄ paÅ”reizÄjÄ laidienÄ, nonÄkam pie secinÄjuma, ka lielÄkÄ daļa no tiem atrisina dažÄdas datorredzes problÄmas. TurklÄt ir ļoti grÅ«ti nÄkt klajÄ ar problÄmu datorredzes jomÄ, kuru nevar atrisinÄt, izmantojot OpenVINO, un pat ja to var izgudrot, ir grÅ«ti atrast iepriekÅ” apmÄcÄ«tus modeļus publiskajÄ telpÄ. MÄs nolemjam rakt citÄ virzienÄ - runas apstrÄdes un analÄ«tikas virzienÄ. ApskatÄ«sim interesantu uzdevumu atpazÄ«t emocijas no runas. JÄteic, ka OpenVINO jau ir modelis, kas nosaka cilvÄka emocijas pÄc sejas, taÄu:
TeorÄtiski ir iespÄjams izveidot kombinÄtu algoritmu, kas darbosies gan ar skaÅu, gan attÄlu, kam vajadzÄtu dot precizitÄtes pieaugumu.
KamerÄm parasti ir Å”aurs skata leÅÄ·is; ir nepiecieÅ”ama vairÄk nekÄ viena kamera, lai aptvertu lielu laukumu; skaÅai nav Å”Ädu ierobežojumu.
AttÄ«stÄ«sim ideju: par pamatu Åemsim ideju par mazumtirdzniecÄ«bas segmentu. JÅ«s varat izmÄrÄ«t klientu apmierinÄtÄ«bu pie veikala kasÄm. Ja kÄds no klientiem ir neapmierinÄts ar pakalpojumu un sÄk paaugstinÄt tonusu, nekavÄjoties var saukt pÄc palÄ«dzÄ«bas administratoram.
Å ajÄ gadÄ«jumÄ mums ir jÄpievieno cilvÄka balss atpazÄ«Å”ana, kas ļaus mums atŔķirt veikala darbiniekus no klientiem un nodroÅ”inÄt analÄ«zi katram indivÄ«dam. Nu, turklÄt bÅ«s iespÄjams analizÄt paÅ”u veikala darbinieku uzvedÄ«bu, novÄrtÄt atmosfÄru kolektÄ«vÄ, izklausÄs labi!
MÄs formulÄjam prasÄ«bas savam risinÄjumam:
MÄrÄ·a ierÄ«ces mazs izmÄrs
DarbÄ«ba reÄllaikÄ
Zema cena
Viegla mÄrogojamÄ«ba
RezultÄtÄ kÄ mÄrÄ·a ierÄ«ci mÄs izvÄlamies Raspberry Pi 3 c Intel NCS 2.
Å eit ir svarÄ«gi atzÄ«mÄt vienu svarÄ«gu NCS iezÄ«mi - tÄ vislabÄk darbojas ar standarta CNN arhitektÅ«rÄm, taÄu, ja jums ir nepiecieÅ”ams palaist modeli ar pielÄgotiem slÄÅiem, sagaidiet zema lÄ«meÅa optimizÄciju.
Ir tikai viena maza lieta, kas jÄdara: jums ir jÄiegÄdÄjas mikrofons. Parasts USB mikrofons derÄs, taÄu tas neizskatÄ«sies labi kopÄ ar RPI. Bet pat Å”eit risinÄjums burtiski āatrodas blakusā. Lai ierakstÄ«tu balsi, mÄs nolemjam izmantot komplektÄ iekļauto Voice Bonnet paneli Google AIY balss komplekts, uz kura ir vadu stereo mikrofons.
LejupielÄdÄjiet Raspbian no AIY projektu krÄtuve un augÅ”upielÄdÄjiet to zibatmiÅas diskÄ, pÄrbaudiet, vai mikrofons darbojas, izmantojot Å”Ädu komandu (tas ierakstÄ«s audio 5 sekundes un saglabÄs to failÄ):
arecord -d 5 -r 16000 test.wav
Uzreiz jÄatzÄ«mÄ, ka mikrofons ir ļoti jutÄ«gs un labi uztver troksni. Lai to labotu, dodieties uz alsamixer, atlasiet UztverÅ”anas ierÄ«ces un samaziniet ievades signÄla lÄ«meni lÄ«dz 50-60%.
PÄrveidojam korpusu ar vÄ«li un viss der, var pat aizvÄrt ar vÄku
Indikatora pogas pievienoŔana
Izjaucot AIY Voice Kit, atceramies, ka ir RGB poga, kuras fona apgaismojumu var vadÄ«t ar programmatÅ«ru. MÄs meklÄjam āGoogle AIY Ledā un atrodam dokumentÄciju: https://aiyprojects.readthedocs.io/en/latest/aiy.leds.html
KÄpÄc neizmantot Å”o pogu, lai parÄdÄ«tu atpazÄ«to emociju, mums ir tikai 7 klases, un pogai ir 8 krÄsas, tikai pietiekami!
MÄs savienojam pogu caur GPIO ar Voice Bonnet, ielÄdÄjam nepiecieÅ”amÄs bibliotÄkas (tÄs jau ir instalÄtas izplatÄ«Å”anas komplektÄ no AIY projektiem)
from aiy.leds import Leds, Color
from aiy.leds import RgbLeds
Izveidosim diktu, kurÄ katrai emocijai bÅ«s atbilstoÅ”a krÄsa RGB Tuple formÄ un aiy.leds.Leds klases objekts, caur kuru mÄs atjauninÄsim krÄsu:
MÄs izmantosim pyaudio, lai tvertu straumi no mikrofona, un webrtcvad, lai filtrÄtu troksni un noteiktu balsi. TurklÄt mÄs izveidosim rindu, kurai asinhroni pievienosim un noÅemsim balss fragmentus.
TÄ kÄ Webrtcvad ir ierobežots piegÄdÄtÄ fragmenta izmÄrs - tam jÄbÅ«t vienÄdam ar 10/20/30 ms, un emociju atpazÄ«Å”anas modeļa apmÄcÄ«ba (kÄ mÄs uzzinÄsim vÄlÄk) tika veikta uz 48kHz datu kopas, mÄs tveriet gabalus ar izmÄru 48000 Ć 20 ms/1000 Ć 1 (mono) = 960 baiti. Webrtcvad atgriezÄ«s True/False katram no Å”iem gabaliem, kas atbilst balsojuma esamÄ«bai vai neesamÄ«bai daļÄ.
IeviesÄ«sim Å”Ädu loÄ£iku:
MÄs pievienosim sarakstam tos gabalus, kur ir balsojums, ja balsoÅ”anas nav, tad palielinÄsim tukÅ”o gabalu skaitÄ«tÄju.
Ja tukÅ”o gabalu skaitÄ«tÄjs ir >=30 (600 ms), tad skatÄmies uzkrÄto gabalu saraksta lielumu; ja tas ir >250, tad pievienojam rindai; ja nÄ, uzskatÄm, ka garums ar ierakstu nepietiek, lai to ievadÄ«tu modelim, lai identificÄtu runÄtÄju.
Ja tukÅ”o gabalu skaitÄ«tÄjs joprojÄm ir < 30 un uzkrÄto gabalu saraksta lielums pÄrsniedz 300, fragmentu pievienosim rindai precÄ«zÄkai prognozei. (jo emocijas laika gaitÄ mÄdz mainÄ«ties)
def to_queue(frames):
d = np.frombuffer(b''.join(frames), dtype=np.int16)
return d
framesQueue = queue.Queue()
def framesThreadBody():
CHUNK = 960
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 48000
p = pyaudio.PyAudio()
vad = webrtcvad.Vad()
vad.set_mode(2)
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
false_counter = 0
audio_frame = []
while process:
data = stream.read(CHUNK)
if not vad.is_speech(data, RATE):
false_counter += 1
if false_counter >= 30:
if len(audio_frame) > 250:
framesQueue.put(to_queue(audio_frame,timestamp_start))
audio_frame = []
false_counter = 0
if vad.is_speech(data, RATE):
false_counter = 0
audio_frame.append(data)
if len(audio_frame) > 300:
framesQueue.put(to_queue(audio_frame,timestamp_start))
audio_frame = []
Ir pienÄcis laiks meklÄt iepriekÅ” apmÄcÄ«tus modeļus publiskajÄ domÄnÄ, dodieties uz github, Google, taÄu atcerieties, ka mums ir ierobežojumi attiecÄ«bÄ uz izmantoto arhitektÅ«ru. Å Ä« ir diezgan sarežģīta daļa, jo jums ir jÄpÄrbauda modeļi uz jÅ«su ievades datiem un papildus jÄpÄrveido tie OpenVINO iekÅ”ÄjÄ formÄtÄ - IR (Intermediate Representation). IzmÄÄ£inÄjÄm kÄdus 5-7 dažÄdus risinÄjumus no github, un, ja emociju atpazÄ«Å”anas modelis nostrÄdÄja uzreiz, tad ar balss atpazÄ«Å”anu bija jÄgaida ilgÄk - viÅi izmanto sarežģītÄku arhitektÅ«ru.
MÄs koncentrÄjamies uz sekojoÅ”o:
Emocijas no balss - https://github.com/alexmuhr/Voice_Emotion
Tas darbojas pÄc Å”Äda principa: audio tiek sagriezts noteikta izmÄra fragmentos, katram no Å”iem fragmentiem mÄs atlasÄm MFCC un pÄc tam iesniedziet tos kÄ ievadi CNN
TÄlÄk mÄs runÄsim par modeļu konvertÄÅ”anu, sÄkot ar teoriju. OpenVINO ietver vairÄkus moduļus:
Atveriet Modeļu zoodÄrzu, kuru modeļus varÄtu izmantot un iekļaut jÅ«su produktÄ
Model Optimzer, pateicoties kuram jÅ«s varat pÄrveidot modeli no dažÄdiem ietvara formÄtiem (Tensorflow, ONNX utt.) Intermediate Representation formÄtÄ, ar kuru mÄs strÄdÄsim tÄlÄk
Inference Engine ļauj palaist modeļus IR formÄtÄ Intel procesoros, Myriad mikroshÄmÄs un Neural Compute Stick paÄtrinÄtÄjos
VisefektÄ«vÄkÄ OpenCV versija (ar Inference Engine atbalstu)
Katrs modelis IR formÄtÄ ir aprakstÄ«ts ar diviem failiem: .xml un .bin.
Modeļi tiek pÄrveidoti IR formÄtÄ, izmantojot modeļa optimizÄtÄju:
--data_type ļauj izvÄlÄties datu formÄtu, ar kÄdu modelis darbosies. Tiek atbalstÄ«ti FP32, FP16, INT8. OptimÄlÄ datu veida izvÄle var dot labu veiktspÄjas palielinÄjumu. --input_shape norÄda ievades datu izmÄru. Å Ä·iet, ka C++ API ir iespÄja to dinamiski mainÄ«t, taÄu mÄs tik tÄlu nemeklÄjÄm un vienkÄrÅ”i labojÄm to vienam no modeļiem.
TÄlÄk mÄÄ£inÄsim ielÄdÄt jau pÄrveidoto modeli IR formÄtÄ caur DNN moduli OpenCV un pÄrsÅ«tÄ«t uz to.
import cv2 as cv
emotionsNet = cv.dnn.readNet('emotions_model.bin',
'emotions_model.xml')
emotionsNet.setPreferableTarget(cv.dnn.DNN_TARGET_MYRIAD)
PÄdÄjÄ rindiÅa Å”ajÄ gadÄ«jumÄ Ä¼auj novirzÄ«t aprÄÄ·inus uz Neural Compute Stick, pamata aprÄÄ·ini tiek veikti procesoram, bet Raspberry Pi gadÄ«jumÄ tas nedarbosies, jums bÅ«s nepiecieÅ”ams stick.
TÄlÄk loÄ£ika ir Å”Äda: mÄs sadalÄm savu audio noteikta izmÄra logos (mums tas ir 0.4 s), mÄs pÄrvÄrÅ”am katru no Å”iem logiem par MFCC, ko pÄc tam ievadÄm režģī:
emotionsNet.setInput(MFCC_from_window)
result = emotionsNet.forward()
TÄlÄk Åemsim visizplatÄ«tÄko klasi visiem logiem. VienkÄrÅ”s risinÄjums, taÄu hakatonam nav jÄizdomÄ kaut kas pÄrÄk abstrakts, tikai tad, ja ir laiks. Mums vÄl daudz jÄstrÄdÄ, tÄpÄc ejam tÄlÄk ā tiksim galÄ ar balss atpazÄ«Å”anu. Vajag izveidot kaut kÄdu datu bÄzi, kurÄ glabÄtos iepriekÅ” ierakstÄ«to balsu spektrogrammas. TÄ kÄ laika ir palicis maz, mÄs Å”o problÄmu atrisinÄsim, cik vien spÄsim.
Proti, veidojam skriptu balss fragmenta ierakstÄ«Å”anai (tas darbojas tÄpat kÄ iepriekÅ” aprakstÄ«ts, tikai pÄrtraucot no tastatÅ«ras saglabÄs balsi failÄ).
PamÄÄ£inÄsim:
python3 voice_db/record_voice.py test.wav
MÄs ierakstÄm vairÄku cilvÄku (mÅ«su gadÄ«jumÄ trÄ«s komandas locekļu) balsis
PÄc tam katrai ierakstÄ«tajai balsij veicam Ätro FurjÄ transformÄciju, iegÅ«stam spektrogrammu un saglabÄjam to kÄ numpy masÄ«vu (.npy):
for file in glob.glob("voice_db/*.wav"):
spec = get_fft_spectrum(file)
np.save(file[:-4] + '.npy', spec)
SÄ«kÄka informÄcija failÄ create_base.py
RezultÄtÄ, palaižot galveno skriptu, mÄs paÅ”Ä sÄkumÄ iegÅ«sim iegulÅ”anu no Ŕīm spektrogrammÄm:
for file in glob.glob("voice_db/*.npy"):
spec = np.load(file)
spec = spec.astype('float32')
spec_reshaped = spec.reshape(1, 1, spec.shape[0], spec.shape[1])
srNet.setInput(spec_reshaped)
pred = srNet.forward()
emb = np.squeeze(pred)
PÄc iegulÅ”anas saÅemÅ”anas no apskaÅotÄ segmenta, mÄs varÄsim noteikt, kam tas pieder, Åemot kosinusa attÄlumu no fragmenta lÄ«dz visÄm balsÄ«m datubÄzÄ (jo mazÄka, jo lielÄka iespÄja) - demonstrÄcijai mÄs uzstÄdÄm slieksni lÄ«dz 0.3):
NobeigumÄ vÄlos atzÄ«mÄt, ka secinÄjuma Ätrums bija Ätrs un ļÄva pievienot vÄl 1-2 modeļus (7 sekunžu garam paraugam bija nepiecieÅ”ami 2.5 secinÄjumi). Mums vairs nebija laika pievienot jaunus modeļus un koncentrÄjÄmies uz tÄ«mekļa lietojumprogrammas prototipa rakstÄ«Å”anu.
Tīmekļa lietojumprogramma
SvarÄ«gs punkts: mÄs paÅemam lÄ«dzi marÅ”rutÄtÄju no mÄjÄm un izveidojam savu lokÄlo tÄ«klu, tas palÄ«dz savienot ierÄ«ci un klÄpjdatorus tÄ«klÄ.
AizmugursistÄma ir tieÅ”s ziÅojumu kanÄls starp priekÅ”pusi un Raspberry Pi, kura pamatÄ ir tÄ«mekļa ligzdas tehnoloÄ£ija (http, izmantojot tcp protokolu).
Pirmais posms ir apstrÄdÄtas informÄcijas saÅemÅ”ana no Raspberry, tas ir, json iesaiÅoti prognozÄtÄji, kas tiek saglabÄti datu bÄzÄ ceļojuma pusceļÄ, lai varÄtu Ä£enerÄt statistiku par lietotÄja emocionÄlo fonu attiecÄ«gajÄ periodÄ. PÄc tam Ŕī pakete tiek nosÅ«tÄ«ta uz priekÅ”galu, kas izmanto abonementu un saÅem paketes no tÄ«mekļa ligzdas galapunkta. Viss aizmugursistÄmas mehÄnisms ir veidots golang valodÄ; tas tika izvÄlÄts, jo tas ir labi piemÄrots asinhroniem uzdevumiem, ar kuriem goroutines labi tiek galÄ.
Piekļūstot galapunktam, lietotÄjs tiek reÄ£istrÄts un ievadÄ«ts struktÅ«rÄ, pÄc tam tiek saÅemts viÅa ziÅojums. Gan lietotÄjs, gan ziÅojums tiek ievadÄ«ti kopÄjÄ centrmezglÄ, no kura ziÅojumi jau tiek sÅ«tÄ«ti tÄlÄk (uz abonÄto fronti), un, ja lietotÄjs noslÄdz savienojumu (aveÅu vai priekÅ”puse), tad viÅa abonements tiek atcelts un viÅÅ” tiek noÅemts no centrs.
MÄs gaidÄm savienojumu no aizmugures
PriekÅ”gals ir tÄ«mekļa lietojumprogramma, kas rakstÄ«ta JavaScript valodÄ, izmantojot React bibliotÄku, lai paÄtrinÄtu un vienkÄrÅ”otu izstrÄdes procesu. Å Ä«s lietojumprogrammas mÄrÄ·is ir vizualizÄt datus, kas iegÅ«ti, izmantojot algoritmus, kas darbojas aizmugures pusÄ un tieÅ”i Raspberry Pi. LapÄ ir ieviesta sekciju marÅ”rutÄÅ”ana, izmantojot react-router, bet galvenÄ interesÄjoÅ”Ä lapa ir galvenÄ lapa, kurÄ no servera tiek saÅemta nepÄrtraukta datu plÅ«sma reÄllaikÄ, izmantojot WebSocket tehnoloÄ£iju. Raspberry Pi nosaka balsi, no reÄ£istrÄtÄs datu bÄzes nosaka, vai tÄ pieder konkrÄtai personai, un nosÅ«ta klientam varbÅ«tÄ«bu sarakstu. Klients parÄda jaunÄkos attiecÄ«gos datus, parÄda tÄs personas iemiesojumu, kura, visticamÄk, runÄja mikrofonÄ, kÄ arÄ« emocijas, ar kurÄm viÅÅ” izrunÄ vÄrdus.
MÄjas lapa ar atjauninÄtÄm prognozÄm
SecinÄjums
Nebija iespÄjams visu paveikt, kÄ plÄnots, mums vienkÄrÅ”i nebija laika, tÄpÄc galvenÄ cerÄ«ba bija demonstrÄcijÄ, ka viss izdosies. PrezentÄcijÄ viÅi runÄja par to, kÄ viss darbojas, kÄdus modeļus paÅÄma, ar kÄdÄm problÄmÄm saskÄrÄs. TÄlÄk sekoja demonstrÄcijas daļa ā eksperti nejauÅ”Ä secÄ«bÄ staigÄja pa telpu un piegÄja pie katras komandas, lai apskatÄ«tu strÄdÄjoÅ”o prototipu. ViÅi arÄ« uzdeva mums jautÄjumus, katrs atbildÄja uz savu daļu, viÅi atstÄja tÄ«mekli klÄpjdatorÄ, un viss patieÅ”Äm darbojÄs, kÄ paredzÄts.
Ä»aujiet man atzÄ«mÄt, ka mÅ«su risinÄjuma kopÄjÄs izmaksas bija USD 150:
Raspberry Pi 3 ~ 35 USD
Google AIY Voice Bonnet (varat iekasÄt maksu par runÄtÄju) ~ 15 USD
Intel NCS 2 ~ 100 USD
KÄ uzlabot:
Izmantojiet klienta reÄ£istrÄciju - lÅ«dziet izlasÄ«t tekstu, kas tiek Ä£enerÄts nejauÅ”i
Pievienojiet vÄl dažus modeļus: pÄc balss varat noteikt dzimumu un vecumu
NobeigumÄ vÄlos pateikt paldies organizatoriem un dalÄ«bniekiem. No citu komandu projektiem mums personÄ«gi patika bezmaksas stÄvvietu uzraudzÄ«bas risinÄjums. Mums tÄ bija ļoti forÅ”a pieredze, iedziļinoties produktÄ un attÄ«stÄ«bÄ. Ceru, ka reÄ£ionos notiks arvien vairÄk interesantu pasÄkumu, arÄ« par AI tÄmÄm.