OpenVINO хакатоны: Raspberry Pi-де дауыс пен эмоцияларды тану

30 қараша - 1 желтоқсан Нижний Новгород қаласында өтті OpenVINO хакатоны. Қатысушыларға Intel OpenVINO құралдар жинағы арқылы өнім шешімінің прототипін жасау ұсынылды. Ұйымдастырушылар тапсырманы таңдау кезінде басшылыққа алуға болатын шамамен тақырыптардың тізімін ұсынды, бірақ соңғы шешім командаларда қалды. Сонымен қатар, өнімге кірмейтін үлгілерді пайдалану ынталандырылды.

OpenVINO хакатоны: Raspberry Pi-де дауыс пен эмоцияларды тану

Бұл мақалада біз өнімнің прототипін қалай жасағанымыз туралы айтып береміз, нәтижесінде біз бірінші орынға ие болдық.

Хакатонға 10-нан астам команда қатысты. Олардың кейбірі басқа облыстардан келгені қуантады. Хакатон өткізілетін орын «Почейндегі Кремль» кешені болды, оның ішінде Нижний Новгородтың ежелгі фотосуреттері ілулі тұрған. (Қазіргі уақытта Intel орталық кеңсесі Нижний Новгородта орналасқанын еске саламын). Қатысушыларға код жазуға 26 сағат берілді, соңында олар өз шешімін ұсынуы керек болды. Жоспарланғанның барлығы іс жүзінде орындалғанына және презентацияда идеялар болып қалмайтынына көз жеткізу үшін демо-сессияның болуы бөлек артықшылық болды. Тауар, тағамдар, тамақ, бәрі де сонда болды!

Сонымен қатар, Intel қосымша камераларды, Raspberry PI, Neural Compute Stick 2 ұсынады.

Тапсырманы таңдау

Еркін формадағы хакатонға дайындықтың ең қиын бөліктерінің бірі - сынақ таңдау. Біз бірден өнімде жоқ нәрсені ойлап табуға шешім қабылдадық, өйткені хабарландыруда бұл өте құпталатыны айтылған.

Талдап отырып модельдер, ағымдағы шығарылымдағы өнімге енгізілген, біз олардың көпшілігі компьютерлік көрудің әртүрлі мәселелерін шешеді деген қорытындыға келеміз. Оның үстіне, компьютерлік көру саласында OpenVINO көмегімен шешуге болмайтын мәселені шешу өте қиын, тіпті ойлап табуға болатын болса да, қоғамдық доменде алдын ала дайындалған модельдерді табу қиын. Біз басқа бағытқа - сөйлеуді өңдеуге және аналитикаға бағыттауды шештік. Сөйлеуден эмоцияны танудың қызықты тапсырмасын қарастырайық. Айта кету керек, OpenVINO-да адамның эмоцияларын олардың бет-әлпетіне қарай анықтайтын моделі бар, бірақ:

  • Теорияда дыбыста да, кескінде де жұмыс істейтін аралас алгоритм құруға болады, бұл дәлдікті арттыруға тиіс.
  • Камералар әдетте тар көру бұрышына ие; үлкен аумақты қамту үшін бірнеше камера қажет, дыбыста мұндай шектеу жоқ.

Идеяны дамытайық: бөлшек сегмент үшін идеяны негізге алайық. Сіз тұтынушылардың қанағаттануын дүкен кассаларында өлшей аласыз. Егер тұтынушылардың бірі қызметке көңілі толмай, үнін көтере бастаса, сіз дереу әкімшіге көмек сұрай аласыз.
Бұл жағдайда бізге адам дауысын тану мүмкіндігін қосу керек, бұл дүкен қызметкерлерін тұтынушылардан ажыратуға және әрбір жеке тұлға үшін аналитиканы қамтамасыз етуге мүмкіндік береді. Сонымен қатар, дүкен қызметкерлерінің мінез-құлқын талдауға, ұжымдағы атмосфераны бағалауға болады, жақсы естіледі!

Біз шешімімізге қойылатын талаптарды тұжырымдаймыз:

  • Мақсатты құрылғының шағын өлшемі
  • Нақты уақыттағы операция
  • Төмен баға
  • Жеңіл масштабтау

Нәтижесінде мақсатты құрылғы ретінде Raspberry Pi 3 c таңдаймыз Intel NCS 2.

Бұл жерде NCS бір маңызды ерекшелігін атап өту маңызды - ол стандартты CNN архитектураларымен жақсы жұмыс істейді, бірақ егер сізге реттелетін қабаттары бар үлгіні іске қосу қажет болса, онда төмен деңгейлі оңтайландыруды күтіңіз.

Бір ғана кішкене нәрсе істеу керек: микрофон алу керек. Кәдімгі USB микрофоны жұмыс істейді, бірақ ол RPI-мен бірге жақсы көрінбейді. Бірақ бұл жерде де шешім сөзбе-сөз «жақын жерде». Дауысты жазу үшін жинақтағы Voice Bonnet тақтасын пайдалануды шештік Google AIY дауыс жинағы, оның үстінде сымды стереомикрофон бар.

Raspbian сайтынан жүктеп алыңыз AIY жобаларының репозиторийі және оны флэш-дискке жүктеп салыңыз, микрофонның келесі пәрменді пайдаланып жұмыс істейтінін тексеріңіз (ол дыбысты 5 секунд бойы жазып алады және оны файлға сақтайды):

arecord -d 5 -r 16000 test.wav

Микрофон өте сезімтал және шуды жақсы қабылдайтынын бірден атап өткен жөн. Бұны түзету үшін alsamixer-ке өтіп, Capture devices таңдаңыз және кіріс сигналының деңгейін 50-60% дейін төмендетейік.

OpenVINO хакатоны: Raspberry Pi-де дауыс пен эмоцияларды тану
Біз корпусты файлмен өзгертеміз және бәрі сәйкес келеді, оны тіпті қақпақпен жабуға болады

Көрсеткіш түймешігін қосу

AIY Voice Kit құрылғысын бөлшектеу кезінде біз RGB түймесі бар екенін есте ұстаймыз, оның артқы жарығы бағдарламалық құрал арқылы басқарылады. Біз «Google AIY Led» іздеп, құжаттаманы табамыз: https://aiyprojects.readthedocs.io/en/latest/aiy.leds.html
Неліктен танылған эмоцияны көрсету үшін осы түймені пайдаланбасқа, бізде тек 7 сынып бар, ал түйменің 8 түсі бар, жеткілікті!

Біз түймені GPIO арқылы Voice Bonnet-ке қосамыз, қажетті кітапханаларды жүктейміз (олар AIY жобаларының тарату жинағында орнатылған)

from aiy.leds import Leds, Color
from aiy.leds import RgbLeds

Әрбір эмоцияның RGB кортежі және aiy.leds.Leds класының нысаны түріндегі сәйкес түсі болатын дикт жасайық, ол арқылы біз түсті жаңартамыз:

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()

Ақырында, эмоцияның әрбір жаңа болжамынан кейін біз түйменің түсін оған сәйкес жаңартамыз (кілт бойынша).

leds.update(Leds.rgb_on(led_dict.get(classes[prediction])))

OpenVINO хакатоны: Raspberry Pi-де дауыс пен эмоцияларды тану
Түйме, күйдіріңіз!

Дауыспен жұмыс

Біз микрофоннан ағынды түсіру үшін pyaudio және шуды сүзгілеу және дауысты анықтау үшін webrtcvad пайдаланамыз. Сонымен қатар, біз дауыс үзінділерін асинхронды түрде қосатын және алып тастайтын кезек жасаймыз.

Webrtcvad берілген фрагменттің өлшеміне шектеу қойғандықтан - ол 10/20/30 мс тең болуы керек және эмоцияларды тану моделін оқыту (кейінірек білетініміздей) 48 кГц деректер жинағында жүзеге асырылды, біз 48000×20мс/1000×1(моно)=960 байт өлшемді бөліктерді түсіру. Webrtcvad осы бөліктердің әрқайсысы үшін True/False мәнін қайтарады, бұл бөлікте дауыстың бар немесе жоқтығына сәйкес келеді.

Келесі логиканы жүзеге асырайық:

  • Біз тізімге дауыс берілген бөліктерді қосамыз, егер дауыс болмаса, бос бөліктердің санауышын көбейтеміз.
  • Егер бос бөліктердің есептегіші >=30 (600 мс) болса, онда жинақталған бөліктер тізімінің өлшемін қарастырамыз, егер ол >250 болса, онда оны кезекке қосамыз, егер жоқ болса, ұзындығы деп есептейміз. динамикті анықтау үшін оны үлгіге беру үшін жазбаның саны жеткіліксіз.
  • Егер бос бөліктердің есептегіші әлі де < 30 болса және жинақталған бөліктер тізімінің өлшемі 300-ден асса, дәлірек болжау үшін фрагментті кезекке қосамыз. (себебі эмоциялар уақыт өте өзгереді)

 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 = []

Қоғамдық доменде алдын ала дайындалған үлгілерді іздеудің уақыты келді, github, Google сайтына барыңыз, бірақ бізде қолданылған архитектурада шектеулер бар екенін есте сақтаңыз. Бұл өте қиын бөлік, өйткені сіз өзіңіздің кіріс деректеріңізде үлгілерді сынап көруіңіз керек, сонымен қатар оларды OpenVINO ішкі пішіміне - IR (аралық өкілдік) түрлендіру керек. Біз github-дан шамамен 5-7 түрлі шешімдерді қолданып көрдік, егер эмоцияларды тану моделі бірден жұмыс істесе, дауысты тану арқылы бізге ұзағырақ күтуге тура келді - олар күрделі архитектураларды пайдаланады.

Біз мыналарға назар аударамыз:

  • Дауыстағы эмоциялар - https://github.com/alexmuhr/Voice_Emotion
    Ол келесі принцип бойынша жұмыс істейді: дыбыс белгілі бір өлшемдегі үзінділерге кесіледі, осы үзінділердің әрқайсысы үшін біз таңдаймыз MFCC содан кейін оларды CNN-ге кіріс ретінде жіберіңіз
  • Дауысты тану - https://github.com/linhdvu14/vggvox-speaker-identification
    Мұнда MFCC орнына біз спектрограммамен жұмыс істейміз, FFT-ден кейін сигналды CNN-ге береміз, онда шығыста дауыстың векторлық көрінісін аламыз.

Әрі қарай теориядан бастап модельдерді түрлендіру туралы айтатын боламыз. OpenVINO бірнеше модульдерді қамтиды:

  • Модель хайуанаттар бағын ашыңыз, оның үлгілері пайдаланылуы және өніміңізге қосылуы мүмкін
  • Model Optimzer, соның арқасында сіз модельді әртүрлі фреймворк форматтарынан (Tensorflow, ONNX т.
  • Inference Engine Intel процессорларында, Myriad чиптерінде және Neural Compute Stick үдеткіштерінде IR пішіміндегі үлгілерді іске қосуға мүмкіндік береді.
  • OpenCV ең тиімді нұсқасы (Inference Engine қолдауымен)
    IR пішіміндегі әрбір үлгі екі файлмен сипатталады: .xml және .bin.
    Модельдер Model Optimizer арқылы IR пішіміне төмендегідей түрлендіріледі:

    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_type модель жұмыс істейтін деректер пішімін таңдауға мүмкіндік береді. FP32, FP16, INT8 қолдау көрсетіледі. Оңтайлы деректер түрін таңдау жақсы өнімділікті арттыруға мүмкіндік береді.
    --input_shape кіріс деректерінің өлшемін көрсетеді. Оны динамикалық түрде өзгерту мүмкіндігі C++ API интерфейсінде бар сияқты, бірақ біз онша көп іздеген жоқпыз және оны үлгілердің біріне бекіттік.
    Содан кейін DNN модулі арқылы IR пішімінде түрлендірілген модельді OpenCV-ге жүктеп, оны оған жіберіп көрейік.

    import cv2 as cv
    emotionsNet = cv.dnn.readNet('emotions_model.bin',
                              'emotions_model.xml')
    emotionsNet.setPreferableTarget(cv.dnn.DNN_TARGET_MYRIAD)

    Бұл жағдайда соңғы жол есептеулерді Neural Compute Stick-ке қайта бағыттауға мүмкіндік береді, негізгі есептеулер процессорда орындалады, бірақ Raspberry Pi жағдайында бұл жұмыс істемейді, сізге таяқша қажет болады.

    Әрі қарай, логика келесідей: біз дыбысты белгілі бір өлшемдегі терезелерге бөлеміз (біз үшін бұл 0.4 с), біз осы терезелердің әрқайсысын MFCC-ге түрлендіреміз, содан кейін біз торға береміз:

    emotionsNet.setInput(MFCC_from_window)
    result = emotionsNet.forward()

    Әрі қарай, барлық терезелер үшін ең көп таралған классты алайық. Қарапайым шешім, бірақ хакатон үшін тым абструкцияны ойлап табудың қажеті жоқ, тек уақытыңыз болса ғана. Бізде әлі көп жұмыс бар, сондықтан әрі қарай жүрейік - біз дауысты танумен айналысамыз. Алдын ала жазылған дауыстардың спектрограммалары сақталатын қандай да бір дерекқорды құру қажет. Уақыт аз болғандықтан, бұл мәселені мүмкіндігінше шешеміз.

    Атап айтқанда, біз дауыстық үзіндіні жазу үшін сценарий жасаймыз (ол жоғарыда сипатталғандай жұмыс істейді, тек пернетақтадан үзілгенде ол дауысты файлға сақтайды).

    Тырысып көрейік:

    python3 voice_db/record_voice.py test.wav

    Біз бірнеше адамның дауысын жазамыз (біздің жағдайда үш команда мүшесі)
    Әрі қарай, әрбір жазылған дауыс үшін біз жылдам фурье түрлендіруін орындаймыз, спектрограмма аламыз және оны сандық массив (.npy) ретінде сақтаймыз:

    for file in glob.glob("voice_db/*.wav"):
            spec = get_fft_spectrum(file)
            np.save(file[:-4] + '.npy', spec)

    Толық мәліметтер файлда create_base.py
    Нәтижесінде, біз негізгі сценарийді іске қосқан кезде, біз ең басында осы спектрограммалардан ендірулерді аламыз:

    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)

    Дыбысталған сегменттен ендіруді алғаннан кейін біз оның кімге тиесілі екенін мәліметтер қорындағы барлық дауыстарға дейінгі косинус қашықтықты алу арқылы анықтай аламыз (неғұрлым кішірек болса, соғұрлым ықтимал) - демонстрация үшін біз шекті орнаттық. 0.3 дейін):

            dist_list = cdist(emb, enroll_embs, metric="cosine")
            distances = pd.DataFrame(dist_list, columns = df.speaker)

    Қорытындылай келе, қорытынды шығару жылдамдығы жылдам болғанын және тағы 1-2 модельді қосуға мүмкіндік бергенін атап өткім келеді (үлгіге 7 секунд ұзақтықта қорытынды жасау үшін 2.5 қажет болды). Біз енді жаңа үлгілерді қосуға уақыт таппадық және веб-қосымшаның прототипін жазуға назар аудардық.

    Веб-қосымша

    Маңызды сәт: біз үйден маршрутизаторды алып, жергілікті желіні орнатамыз, бұл құрылғы мен ноутбуктерді желі арқылы қосуға көмектеседі.

    Backend - бұл websocket технологиясына негізделген (tcp протоколы арқылы http).

    Бірінші кезең - таңқурайдан өңделген ақпаратты алу, яғни json-да жинақталған болжауыштар, олар деректер базасында саяхаттың жартысында сақталады, осылайша пайдаланушының кезеңдегі эмоционалдық фоны туралы статистиканы жасауға болады. Содан кейін бұл пакет жазылымды пайдаланатын және веб-сокет соңғы нүктесінен пакеттерді қабылдайтын фронтонға жіберіледі. Бүкіл бэк-энд механизмі голанг тілінде құрастырылған; ол горутиндер жақсы орындайтын асинхронды тапсырмалар үшін өте қолайлы болғандықтан таңдалды.
    Соңғы нүктеге қол жеткізу кезінде пайдаланушы тіркеледі және құрылымға енгізіледі, содан кейін оның хабарламасы қабылданады. Пайдаланушы да, хабарлама да ортақ хабқа енгізіледі, одан хабарламалар әрі қарай жіберіледі (жазылған фронтқа) ​​және егер пайдаланушы қосылымды жапса (таңқурай немесе фронт), онда оның жазылуы тоқтатылады және ол жойылады. хаб.

    OpenVINO хакатоны: Raspberry Pi-де дауыс пен эмоцияларды тану
    Артқы жағынан байланысты күтеміз

    Front-end – әзірлеу процесін жылдамдату және жеңілдету үшін React кітапханасын пайдаланып JavaScript тілінде жазылған веб-бағдарлама. Бұл қолданбаның мақсаты - артқы жағында және тікелей Raspberry Pi-де жұмыс істейтін алгоритмдер арқылы алынған деректерді визуализациялау. Бетте react-router көмегімен жүзеге асырылған секциялық маршруттау бар, бірақ қызығушылық танытатын басты бет WebSocket технологиясы арқылы серверден нақты уақыт режимінде үздіксіз деректер ағыны қабылданатын басты бет болып табылады. Raspberry Pi дауысты анықтайды, оның тіркелген дерекқордан белгілі бір адамға тиесілілігін анықтайды және клиентке ықтималдық тізімін жібереді. Клиент соңғы сәйкес деректерді көрсетеді, микрофонмен сөйлескен адамның аватарын, сондай-ақ ол сөздерді айтатын эмоцияны көрсетеді.

    OpenVINO хакатоны: Raspberry Pi-де дауыс пен эмоцияларды тану
    Жаңартылған болжамдары бар басты бет

    қорытынды

    Барлығын жоспарланғандай аяқтау мүмкін болмады, бізде уақыт болмады, сондықтан негізгі үміт демонстрацияда болды, бәрі жұмыс істейді. Тұсаукесерде олар барлығы қалай жұмыс істейтіні, қандай үлгілерді алғаны, қандай қиындықтарға тап болғаны туралы әңгімеледі. Келесі демонстрациялық бөлім болды - сарапшылар бөлмені кездейсоқ ретпен аралап, жұмыс прототипін қарау үшін әр командаға жақындады. Олар бізге де сұрақтар қойды, әркім өз бөлігіне жауап берді, олар интернетті ноутбукта қалдырды және бәрі шынымен де күткендей жұмыс істеді.

    Біздің шешіміміздің жалпы құны $150 болғанын атап өтейін:

    • Raspberry Pi 3 ~ 35 доллар
    • Google AIY Voice Bonnet (сіз спикер ақысын ала аласыз) ~ 15$
    • Intel NCS 2 ~ 100$

    Қалай жақсартуға болады:

    • Клиенттен тіркеуді пайдаланыңыз - кездейсоқ құрылған мәтінді оқуды сұраңыз
    • Тағы бірнеше модель қосыңыз: жыныс пен жасты дауыс арқылы анықтауға болады
    • Бір мезгілде шығатын дауыстарды ажырату (диаризация)

    Репозиторий: https://github.com/vladimirwest/OpenEMO

    OpenVINO хакатоны: Raspberry Pi-де дауыс пен эмоцияларды тану
    Шаршағанымызбен бақыттымыз

    Қорытындылай келе, ұйымдастырушылар мен қатысушыларға алғыс айтқым келеді. Басқа командалардың жобаларының ішінде бізге тегін автотұрақтарды бақылау шешімі ұнады. Біз үшін бұл өнім мен әзірлеуге енудің керемет тәжірибесі болды. Өңірлерде, соның ішінде АИ тақырыптарында қызықты шаралар жиі өткізіледі деп сенемін.

Ақпарат көзі: www.habr.com

пікір қалдыру