30. november â 1. detsember toimus Nizhni Novgorodis. Osalejatele pakuti vĂ”imalust luua tooteprototĂŒĂŒpi, kasutades Intel OpenVINO tööriistu. Korraldajad esitasid soovitusliku teemade loendi, millele orienteeruda, kuid lĂ”plik otsus jĂ€i tiimide otsustada. Samuti julgustati kasutama mudeleid, mis ei kuulu toote koosseisu.

Artiklis rÀÀgime sellest, kuidas me lĂ”ime oma tooteprototĂŒĂŒbi, millega lĂ”puks saavutasime esimese koha.
Hackathonil osales ĂŒle 10 tiimi. Tore on, et mĂ”ned neist tulid teistest piirkondadest. Hackathoni toimumiseks valiti âKreml Kremli kanalilâ kompleks, kus olid vĂ€ljapanekud vanadest Nizhni Novgorodi fotodest, atmosfÀÀriliselt! (meenutan, et praegu asub Intel'i keskasutus just Nizhni Novgorodis). Osalejatele anti koodi kirjutamiseks aega 26 tundi, lĂ”puks tuli oma lahendus esitleda. Ăheks plussiks oli demo-sessiooni olemasolu, et veenduda, et kĂ”ik ellu viidud ideed ei jÀÀ ainult esitlusse. Ka kaubad, suupisted ja toit olid olemas!
Lisaks pakkus Intel soovi korral kaamerad, Raspberry PI'd, Neural Compute Stick 2.
Ălesande valik
Ăks keerukamaid osi avatud teemadega hackathonile valmistumisel on ĂŒlesande valimine. Otsustasime kohe vĂ€lja mĂ”elda midagi, mida tootest veel ei leidu, kuna teadaanne ĂŒtles, et seda tervitatakse.
AnalĂŒĂŒsides , mis praeguses vĂ€ljaandes toote koosseisu kuuluvad, jĂ”uame jĂ€reldusele, et enamik neist lahendab erinevaid arvutinĂ€gemise ĂŒlesandeid. On vĂ€ga keeruline vĂ€lja mĂ”elda arvutinĂ€gemise ala ĂŒlesannet, mille lahendamiseks ei saaks OpenVINO't kasutada, ja kui selline ĂŒlesanne ka olemas on, siis on raske leida eelĂ”petatud mudeleid avatud juurdepÀÀsuga. Otsustame kaevata veel ĂŒhes suunas â kĂ”ne töötlemise ja analĂŒĂŒsi poole. Uurime huvitavat ĂŒlesannet kĂ”ne emotsioonide tuvastamiseks. Tuleb öelda, et OpenVINO's on juba mudel, mis mÀÀrab inimese emotsioonid nĂ€o jĂ€rgi, kuid:
- Teoorias on vÔimalik luua kombineeritud algoritm, mis töötab nii heli kui ka pildi pÔhjal, mis peaks suurendama tÀpsust.
- Kaamerad on tavaliselt kitsaste vaatenurkadega, seega vajatakse suure ala katmiseks mitut kaamerat, heli ei oma sellist piirangut.
Arendame ideed: vĂ”tame aluseks jaemĂŒĂŒgisektori idee. Klientide rahulolu saab mÀÀrata kaupluste kassades. Kui mĂ”ni klient on teenindusega rahulolematu ja hakkab hÀÀlt tĂ”stma, saab kohe administraatori abi kutsuda.
Sel juhul tuleb lisada inimese hÀÀletuvastus, mis vĂ”imaldab meil eristada poe töötajaid ostjatest ning saada analĂŒĂŒtikat iga indiviidi kohta. Lisaks sellele saame analĂŒĂŒsida ka poe töötajate kĂ€itumist ning hinnata meeskonna atmosfÀÀri, see kĂ”lab hĂ€sti!
Koostame nÔuded meie lahendusele:
- Sihtseadme vÀike suurus
- Töötamine reaalajas
- Madal hind
- Lihtne skaleeritavus
LÔpuks valime sihtseadmeks Raspberry Pi 3 koos .
Siin on oluline mĂ€rkida ĂŒht olulist omadust NCS-i kohta â see töötab kĂ”ige paremini standardsete CNN arhitektuuridega, kuid kui on vajalik kĂ€ivitada sellised mudelid, kus on kohandatud kihid, siis oodake madalate tasemete optimeerimisega seotud tantsu.
Mis seal ikka: tuleb leida mikrofon. Sobib ka tavaline USB-mikrofon, kuigi see ei vaata koos RPI-ga hea vÀlja. Kuid ka siin on lahendus praktiliselt "kÀeulatuses". HÀÀle salvestamiseks otsustame kasutada Voice Bonnet kaarti komplektist , millel on paigaldatud stereomikrofon.
Laadige Raspbian alla ja laadige see mÀlupulgale, testige, et mikrofon töötab jÀrgmise kÀsuga (see salvestab 5-sekundilise audio ja salvestab faili):
arecord -d 5 -r 16000 test.wavTahan kohe mĂ€rkida, et mikrofon on vĂ€ga tundlik ja pĂŒĂŒab hĂ€sti hÀÀlestamine. Selle parandamiseks siseneme alsamixerisse, valime Capture devices ja langetame sisendsignaali taset 50-60%-ni.

Viimistleme korpuse viiliga ja kÔik mahub sisse, isegi kaane saame sulgeda.
Lisame indikaatorklÔpsu.
AIY Voice Kit'i lahti vÔtmise ajal meenutame, et seal on RGB-nupp, mille valgustust saab programmiliselt juhtida. Otsime "Google AIY Led" ja leidsime dokumentatsiooni:
Miks mitte kasutada seda nuppu tuvastatud emotsiooni kuvamiseks, meil on vaid 7 klassi, kuid nupul on 8 vÀrvi, just piisavalt!
Ăhendame nuppu GPIO kaudu Voice Bonnet'iga, laadime vajalikud teegid (need on juba AIY projektide jaotises installitud)
from aiy.leds import Leds, Color
from aiy.leds import RgbLedsLoome dict, kus igale emotsioonile vastab vÀrv RGB Tuple formaadis ja aiy.leds.Leds klassi objekt, mille kaudu vÀrvi uuendame:
led_dict = {'neutral': (255, 255, 255), 'happy': (0, 255, 0), 'sad': (0, 255, 255), 'angry': (255, 0, 0), 'fearful': (0, 0, 0), 'disgusted': (255, 0, 255), 'surprised': (255, 255, 0)}
leds = Leds()
Ja lÔpuks, pÀrast iga uut emotsiooni ennustust uuendame nupu vÀrvi vastavalt sellele (vÔtme alusel).
leds.update(Leds.rgb_on(led_dict.get(classes[prediction])))
Nupp, sĂŒĂŒta!
Töötame hÀÀlega
Kasutame pyaudio't mikrofonist voolu salvestamiseks ja webrtcvad'i mĂŒra filtreerimiseks ning hÀÀle tuvastamiseks. Lisaks loome jĂ€rjekorra, kuhu lisame ja kust vĂ”tame asĂŒnkroonselt helinatuke.
Kuna webrtcvad'il on piirmÀÀr sisendfragments - see peab olema 10/20/30 ms, ja emotsioonide tuvastamiseks mudeli koolitamine (nagu me hiljem teada saame) toimus 48kHz andmestikul, siis salvestame 48000Ă20ms/1000Ă1 (mono) = 960 baiti suurused tĂŒkid. Webrtcvad tagastab True/False iga sellise tĂŒki kohta, mis vastab hÀÀle olemasolule vĂ”i puudumisele.
Rakendame jÀrgmise loogika:
- Lisame list'i need tĂŒkid, kus on hÀÀl; kui hÀÀlt pole, suurendame tĂŒhi tĂŒkki loenduri.
- Kui tĂŒhi tĂŒkkide loendur >=30 (600 ms), siis vaatame akumuleeritud tĂŒkkide suurust; kui see >250, lisame jĂ€rjekorda; kui mitte, siis loeme, et salvestamise pikkus ei ole piisav, et esitada see mudelile kĂ”nelejate tuvastamiseks.
- Ja kui tĂŒhi tĂŒkki loendur on endiselt < 30, kuid akumuleeritud tĂŒkkide suurus ĂŒletab 300, lisame tĂŒkikese jĂ€rjekorda tĂ€psema ennustuse jaoks. (sest emotsioonidele on aja jooksul iseloomulik muutuda)
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 = []On jÀÀnud aeg otsida avalikest allikatest eelĂ”petatud mudeleid, suundume githubi, otsime google'ist, kuid peame meeles pidama, et meil on arhitektuuri kasutamise osas piirangud. See on ĂŒsna keeruline osa, kuna tuleb testida mudeleid oma sisendandmetega ja peale selle konverteerida need OpenVINO sisemisse formaati â IR (Intermediate Representation). Oleme proovinud umbes 5-7 erinevat lahendust githubist, ja kuigi emotsioonide tuvastamise mudel töötas kohe, siis hÀÀle tuvastamiseks tuli kauem vaeva nĂ€ha â seal kasutatakse keerukamaid arhitektuure.
Peatutakse jÀrgmistele:
- HÀÀljĂ”ududest emotsioonid â
See töötab jĂ€rgmise pĂ”himĂ”tte jĂ€rgi: heli jagatakse kindla suurusega lĂ”ikudeks, iga lĂ”igu puhul eraldame ja toome need siis sisse CNN-i - HÀÀletuvastus â
Siin töötame MFCC asemel spektraalide peal, pÀrast FFT-d toome signaali CNN-i, kus saame vÀljundina hÀÀle vektorise esinduse.
Edasi rÀÀgime mudelite konverteerimisest, alustame teooriast. OpenVINO sisaldab mitmeid mooduleid:
- Open Model Zoo, mille mudeleid sai kasutada ja oma toote sisse lisada
- Model Optimizer, mille abil saab konverteerida mudelit erinevates formaadist raamistikest (Tensorflow, ONNX jne) Intermediate Representation formaati, millega me hiljem töötame
- Inference Engine vÔimaldab kÀivitada mudeleid IR formaadis Intel'i protsessoritel, Myriad kiipidel ja Neural Compute Stick kiirenditel
- TÔhusaim versioon OpenCV-st (Inference Engine'i toega)
Iga mudel IR formaadis on kirjeldatud kahe failiga: .xml ja .bin.
Mudeleid konverteeritakse IR formaati Model Optimizer abil jÀrgmiselt:python /opt/intel/openvino/deployment_tools/model_optimizer/mo_tf.py --input_model speaker.hdf5.pb --data_type=FP16 --input_shape [1,512,1000,1]--data_typevalib valima andmeid, millega mudel töötab. Toetatakse FP32, FP16, INT8. Optimaalse andmeformaadi valimine vÔib anda hea kasvu jÔudluses.
--input_shapenĂ€itab sisendandmete mÔÔtmeid. DĂŒnaamilise muutmise vĂ”imalus nĂ€ib olevat C++ API-s, kuid me ei uurinud seda nii sĂŒgavale ja kinnitasime selle ĂŒhe mudeli jaoks lihtsalt.
JÀrgmisena proovime laadida juba konverteeritud mudeli IR formaadis OpenCV DNN mooduli kaudu ja teha sellele forward.import cv2 as cv emotionsNet = cv.dnn.readNet('emotions_model.bin', 'emotions_model.xml') emotionsNet.setPreferableTarget(cv.dnn.DNN_TARGET_MYRIAD)Viimane rida selles kontekstis suunab arvutused Neural Compute Stick'ile, pÔhimÔtteliselt toimuvad arvutused protsessoril, kuid Raspberry Pi puhul ei sobi see, vajame stick'i.
JÀrgmisena on loogika jÀrgmine: jagame oma audio kindla suurusega akendeks (meie puhul 0,4s), iga selline aken muudetakse MFCC-ks, mis siis antakse vÔrku:
emotionsNet.setInput(MFCC_from_window) result = emotionsNet.forward()PĂ€rast seda vĂ”tame kĂ”ige sagedamini esineva klassi kĂ”igist akendest. Lihtne lahendus, kuid hackathon'i jaoks ei ole liiga keerulist midagi vĂ€lja mĂ”elda, kui on aega. Meil on veel palju tööd, seega liigume edasi â uurime hÀÀletuvastust. Peame looma andmebaasi, kuhu salvestatakse eelnevalt salvestatud hÀÀlte spektraalid. Kuna aega on jÀÀnud vĂ€he, lahendame selle kĂŒsimuse nii hĂ€sti kui oskame.
Ehkki, loome skripti hÀÀle lÔigu salvestamiseks (see töötab sama moodi nagu eespool kirjeldatud, ainult et klaviatuurilt katkestamisel salvestab see hÀÀle faili).
Proovime:
python3 voice_db/record_voice.py test.wavSalvestame mitme inimese hÀÀli (meie puhul kolme meeskonnaliikme hÀÀli)
SeejÀrel teeme iga salvestatud hÀÀle korral kiire vÔi palju transformatsiooni, saame spektraali ja salvestame selle numpy massiivina (.npy):for file in glob.glob("voice_db/*.wav"): spec = get_fft_spectrum(file) np.save(file[:-4] + '.npy', spec)Rohkem teavet failis
create_base.py
LĂ”puks, kui kĂ€ivitatakse pĂ”hiskript, saame alguses need spektraalide embeddingud: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Ă€rast helikatke vĂ€ljavĂ”tmist saame mÀÀrata, kellele see kuulub, vĂ”ttes kosinus-distaansi katke ja kĂ”igi andmebaasi hÀÀle vahel (mida vĂ€iksem, seda tĂ”enĂ€olisem) â demo jaoks seadsime valiku piiri 0.3):
dist_list = cdist(emb, enroll_embs, metric="cosine") distances = pd.DataFrame(dist_list, columns = df.speaker)LĂ”petuseks mĂ€rgin, et inferentsi kiirus oli kiire ning vĂ”imaldas lisada veel 1-2 mudelit (7-sekundilise nĂ€idise inferentsiks kulus 2.5). Uute mudelite lisamisega me enam Ă”igeks ajaks ei jĂ”udnud ja keskendusime veebirakenduse prototĂŒĂŒbi kirjutamisele.
Veebirakendus
Oluline punkt: vĂ”tame kaasa kodus oleva ruuteri ja seadistame oma kohaliku vĂ”rgu, see aitab ĂŒhendada seadmeid ja sĂŒlearvuteid vĂ”rku.
Tagaplaan esindab pidevat sĂ”numite kanalit esiplaani ja Raspberry Pi vahel, mis pĂ”hineb websocket tehnoloogial (http ĂŒle tcp protokolli).
Esimene etapp on töötlemise teabe hankimine Raspberry Piâlt, st JSON-formaadis prognoosid, mis oma teekonna keskosas salvestatakse andmebaasi, et saaksime koostada statistikat kasutaja emotsionaalsest taustast ajavahemikus. Edasi saadetakse see pakett esiplaani, mis kasutab tellimust ja pakettide vastuvĂ”ttu websocketi lĂ”pp-punktist. Kogu tagaplaani mehhanism on ĂŒles ehitatud Golangi keeles, valik langes sellele, kuna see sobib hĂ€sti asĂŒnkroonseteks ĂŒlesanneteks, millega gorutiinid hĂ€sti toime tulevad.
LĂ”pp-punkti juures registreeritakse kasutaja ja kantakse struktuuri, seejĂ€rel toimub tema sĂ”numi vastuvĂ”tmine. Nii kasutaja kui sĂ”num registreeritakse ĂŒhises hubis, millest sĂ”numid saadetakse edasi (tellitud esiplaani), ja kui kasutaja sulgeb ĂŒhenduse (Raspberry Pi vĂ”i esiplaan), lĂ”petatakse tema tellimus ja ta eemaldatakse hubist.
Ootame ĂŒhendust tagaprogrammigaFront-end on web-rakendus, mis on kirjutatud JavaScriptis ja kasutab Reacti teeki arenduse kiirendamiseks ja lihtsustamiseks. Selle rakenduse eesmĂ€rk on visualiseerida andmeid, mis on saadud back-endi poolel kĂ€ivitatud algoritmide abil ja otse Raspberry Pi-lt. Lehelt leiab sektsioonide vahel navigeerimise, mis on teostatud react-routeri abil, kuid peamine huvi pakub esileht, kus reaalajas voolab serverilt pidev andmete voog WebSocketi tehnoloogia kaudu. Raspberry Pi tuvastab hÀÀlt, mÀÀrab kindlaks, kellele see kuulub registreeritud andmebaasis, ja saadab kliendile tĂ”enĂ€osuste loendi. Klient kuvab viimased asjakohased andmed, kuvab inimese avatar, kellel on kĂ”ige tĂ”enĂ€olisem rÀÀgitu mikrofonis, samuti emotsiooni, millega ta sĂ”nu ĂŒtleb.

Esileht uuenevate ennustustegaKokkuvÔte
Me ei jĂ”udnud kĂ”ike lĂ”pule viia, aega lihtsalt ei piisanud, seetĂ”ttu oli peamine lootus demole, et kĂ”ik töötab. Eeskujul rÀÀgiti sellest, kuidas kĂ”ik on korraldatud, milliseid mudeleid on kasutatud ja millega oleme silmitsi seisnud. SeejĂ€rel toimus demoaeg - eksperdid kĂ€isid saalis juhuslikus jĂ€rjestuses ja lĂ€henesid igale meeskonnale, et vaadata töötavat prototĂŒĂŒpi. Nad esitasid kĂŒsimusi ka meile, igaĂŒks vastas oma osa kohta, arvutis oli veeb ja kĂ”ik toimis tĂ”eliselt nagu ootatud.
Toote kogumaksumus oli 150$:
- Raspberry Pi 3 ~ 35$
- Google AIY Voice Bonnet (vÔib kasutada respeakeri plaati) ~ 15$
- Intel NCS 2 ~ 100$
Kuidas parandada:
- Kasutada kliendi registreerimist - paluda lugeda teksti, mille genereerime juhuslikult
- Lisada veel mitmeid mudeleid: hÀÀle abil saame mÀÀrata soo ja vanuse
- Erinevaid samal ajal kostvaid hÀÀli eristama (diariseerimine)
Repo:

VĂ€sinud, aga Ă”nnelikud olemeLĂ”petuseks tahaksin tĂ€nada korraldajaid ja osalejaid. Teiste meeskondade projektidest meeldis meile isiklikult lahendus parkimiskohtade jĂ€lgimiseks. See oli meie jaoks ÀÀrmiselt vinge kogemus tootmisse ja arendusse sĂŒveneda. Loodan, et piirkondades korraldatakse ĂŒha rohkem huvitavaid ĂŒritusi, sealhulgas AI-teemal.
Allikas: habr.com



