OpenVINO hackathon: Raspberry Pi-da ovoz va hissiyotlarni tanib olish

30 noyabr - 1 dekabr Nijniy Novgorodda bo'lib o'tdi OpenVINO xackathon. Ishtirokchilardan Intel OpenVINO asboblar to'plamidan foydalangan holda mahsulot yechimining prototipini yaratish so'ralgan. Tashkilotchilar vazifani tanlashda yo'naltirilishi mumkin bo'lgan taxminiy mavzular ro'yxatini taklif qilishdi, ammo yakuniy qaror jamoalarda qoldi. Bundan tashqari, mahsulotga kiritilmagan modellardan foydalanish rag'batlantirildi.

OpenVINO hackathon: Raspberry Pi-da ovoz va hissiyotlarni tanib olish

Ushbu maqolada biz sizga mahsulotning prototipini qanday yaratganimiz haqida gapirib beramiz, natijada biz birinchi o'rinni egalladik.

Hakatonda 10 dan ortiq jamoalar ishtirok etishdi. Ularning ba’zilari boshqa viloyatlardan kelgani ma’qul. Hakaton o'tkaziladigan joy "Kremlinskiy on Pochain" majmuasi bo'lib, u erda Nijniy Novgorodning qadimiy fotosuratlari osilgan edi. (Eslatib o'tamiz, hozirda Intelning markaziy ofisi Nijniy Novgorodda joylashgan). Ishtirokchilarga kod yozish uchun 26 soat vaqt berildi va oxirida ular o'z yechimlarini taqdim etishlari kerak edi. Alohida afzallik, rejalashtirilgan hamma narsa haqiqatda amalga oshirilganligiga va taqdimotda g'oyalar bo'lib qolmasligiga ishonch hosil qilish uchun demo-sessiyaning mavjudligi edi. Tovarlar, gazaklar, oziq-ovqat, hamma narsa ham bor edi!

Bundan tashqari, Intel ixtiyoriy ravishda Raspberry PI, Neural Compute Stick 2 kameralarini taqdim etdi.

Vazifa tanlash

Erkin shakldagi xakatonga tayyorgarlikning eng qiyin qismlaridan biri bu tanlovni tanlashdir. Biz darhol mahsulotda bo'lmagan narsani o'ylab topishga qaror qildik, chunki e'londa bu juda mamnuniyat bilan aytilgan.

Tahlil qilib modellari, joriy nashrda mahsulotga kiritilgan, biz ularning aksariyati kompyuterni ko'rishning turli muammolarini hal qiladi degan xulosaga keldik. Bundan tashqari, kompyuterni ko'rish sohasida OpenVINO yordamida hal qilib bo'lmaydigan muammoni o'ylab topish juda qiyin va hatto ixtiro qilish mumkin bo'lsa ham, jamoat mulkida oldindan o'qitilgan modellarni topish qiyin. Biz boshqa yo'nalishda - nutqni qayta ishlash va tahlil qilish yo'nalishida qazishga qaror qildik. Keling, nutqdan his-tuyg'ularni tanib olishning qiziqarli vazifasini ko'rib chiqaylik. Aytish kerakki, OpenVINO allaqachon odamning his-tuyg'ularini yuziga qarab belgilaydigan modelga ega, ammo:

  • Nazariy jihatdan, tovush va tasvir ustida ishlaydigan kombinatsiyalangan algoritmni yaratish mumkin, bu aniqlikni oshirishi kerak.
  • Kameralar odatda tor ko'rish burchagiga ega, katta maydonni qamrab olish uchun bir nechta kameralar talab qilinadi, ovozda bunday cheklov yo'q.

Keling, fikrni ishlab chiqaylik: keling, chakana segment uchun g'oyani asos qilib olaylik. Siz do'kon kassalarida xaridorlarning qoniqishini o'lchashingiz mumkin. Agar mijozlardan biri xizmatdan norozi bo'lsa va ohangini ko'tara boshlasa, darhol administratordan yordam so'rashingiz mumkin.
Bunday holda, biz inson ovozini aniqlashni qo'shishimiz kerak, bu bizga do'kon xodimlarini mijozlardan ajratish va har bir shaxs uchun tahliliy ma'lumotlarni taqdim etish imkonini beradi. Bundan tashqari, do'kon xodimlarining xatti-harakatlarini tahlil qilish, jamoadagi muhitni baholash mumkin bo'ladi, yaxshi eshitiladi!

Biz yechimimiz uchun talablarni shakllantiramiz:

  • Maqsadli qurilmaning kichik o'lchami
  • Haqiqiy vaqtda operatsiya
  • Kam narx
  • Oson masshtablilik

Natijada maqsadli qurilma sifatida Raspberry Pi 3 c ni tanlaymiz Intel NCS 2.

Bu erda NCS ning bir muhim xususiyatini ta'kidlash muhim - u standart CNN arxitekturalari bilan eng yaxshi ishlaydi, lekin agar siz maxsus qatlamlari bo'lgan modelni ishga tushirishingiz kerak bo'lsa, unda past darajadagi optimallashtirishni kuting.

Bitta kichik narsa qilish kerak: siz mikrofon olishingiz kerak. Oddiy USB mikrofoni yordam beradi, lekin u RPI bilan birga yaxshi ko'rinmaydi. Ammo bu erda ham yechim tom ma'noda "yaqin joyda". Ovozni yozib olish uchun biz to'plamdagi Voice Bonnet taxtasidan foydalanishga qaror qildik Google AIY ovozli to'plami, uning ustida simli stereo mikrofon mavjud.

Raspbian dan yuklab oling AIY loyihalari ombori va uni flesh-diskga yuklang, mikrofonning quyidagi buyruq yordamida ishlashini tekshiring (u 5 soniya davomida audio yozib oladi va uni faylga saqlaydi):

arecord -d 5 -r 16000 test.wav

Darhol shuni ta'kidlashim kerakki, mikrofon juda sezgir va shovqinni yaxshi qabul qiladi. Buni tuzatish uchun alsamixer-ga o'tamiz, Capture devices-ni tanlaymiz va kirish signali darajasini 50-60% gacha kamaytiramiz.

OpenVINO hackathon: Raspberry Pi-da ovoz va hissiyotlarni tanib olish
Biz tanani fayl bilan o'zgartiramiz va hamma narsa mos keladi, siz hatto uni qopqoq bilan yopishingiz mumkin

Ko'rsatkich tugmasi qo'shilmoqda

AIY Voice Kit-ni ajratib olayotganda, biz RGB tugmasi mavjudligini eslaymiz, uning orqa nuri dasturiy ta'minot tomonidan boshqarilishi mumkin. Biz “Google AIY Led” ni qidiramiz va hujjatlarni topamiz: https://aiyprojects.readthedocs.io/en/latest/aiy.leds.html
Nega tan olingan his-tuyg'ularni namoyish qilish uchun ushbu tugmani ishlatmasligingiz kerak, bizda atigi 7 ta sinf bor va tugma 8 ta rangga ega, shunchaki etarli!

Biz tugmani GPIO orqali Voice Bonnet-ga ulaymiz, kerakli kutubxonalarni yuklaymiz (ular allaqachon AIY loyihalarining tarqatish to'plamiga o'rnatilgan)

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

Keling, har bir his-tuyg'u RGB Tuple va aiy.leds.Leds sinfining ob'ekti ko'rinishidagi mos rangga ega bo'ladigan dict yarataylik, bu orqali biz rangni yangilaymiz:

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

Va nihoyat, hissiyotning har bir yangi bashoratidan so'ng, biz tugma rangini unga muvofiq yangilaymiz (kalit bo'yicha).

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

OpenVINO hackathon: Raspberry Pi-da ovoz va hissiyotlarni tanib olish
Tugma, kuy!

Ovoz bilan ishlash

Biz mikrofondan oqimni olish uchun pyaudio va shovqinni filtrlash va ovozni aniqlash uchun webrtcvaddan foydalanamiz. Bundan tashqari, biz navbat yaratamiz, unga asinxron ravishda ovozli parchalarni qo'shamiz va olib tashlaymiz.

Webrtcvad taqdim etilgan fragmentning o'lchamida cheklovga ega bo'lganligi sababli - u 10/20/30 ms ga teng bo'lishi kerak va his-tuyg'ularni tanib olish uchun modelni o'rgatish (keyinroq bilib olamiz) 48 kHz ma'lumotlar to'plamida amalga oshirildi. 48000×20ms/1000×1(mono)=960 bayt oʻlchamdagi boʻlaklarni suratga olish. Webrtcvad ushbu bo'laklarning har biri uchun True/False qiymatini qaytaradi, bu bo'lakda ovoz mavjudligi yoki yo'qligiga mos keladi.

Keling, quyidagi mantiqni amalga oshiramiz:

  • Ovoz berilgan bo'laklarni ro'yxatga qo'shamiz, agar ovoz bo'lmasa, bo'sh bo'laklar hisoblagichini oshiramiz.
  • Agar bo'sh bo'laklar hisoblagichi >=30 (600 ms) bo'lsa, biz to'plangan bo'laklar ro'yxatining hajmini ko'rib chiqamiz; agar u > 250 bo'lsa, biz uni navbatga qo'shamiz, agar bo'lmasa, biz uzunlik deb hisoblaymiz. ma'ruzachini aniqlash uchun uni modelga boqish uchun yozuvning o'zi etarli emas.
  • Agar bo'sh bo'laklar hisoblagichi hali ham <30 bo'lsa va to'plangan bo'laklar ro'yxati hajmi 300 dan oshsa, biz aniqroq bashorat qilish uchun fragmentni navbatga qo'shamiz. (chunki his-tuyg'ular vaqt o'tishi bilan o'zgaradi)

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

Jamoat mulkida oldindan tayyorlangan modellarni izlash, github, Google-ga borish vaqti keldi, lekin bizda ishlatiladigan arxitekturada cheklov borligini unutmang. Bu juda qiyin qism, chunki siz kiritilgan ma'lumotlaringizda modellarni sinab ko'rishingiz va qo'shimcha ravishda ularni OpenVINO ning ichki formatiga - IR (Intermediate Representation) ga aylantirishingiz kerak. Biz github-dan taxminan 5-7 xil echimlarni sinab ko'rdik va agar his-tuyg'ularni tanib olish modeli darhol ishlagan bo'lsa, ovozni aniqlash bilan biz uzoqroq kutishimiz kerak edi - ular murakkabroq arxitekturalardan foydalanadilar.

Biz quyidagilarga e'tibor qaratamiz:

Keyinchalik nazariyadan boshlab modellarni konvertatsiya qilish haqida gaplashamiz. OpenVINO bir nechta modullarni o'z ichiga oladi:

  • Model hayvonot bog'ini oching, ulardan foydalanish va mahsulotingizga qo'shilishi mumkin bo'lgan modellar
  • Model Optimzer, buning yordamida siz modelni turli xil ramka formatlaridan (Tensorflow, ONNX va boshqalar) Intermediate Representation formatiga o'zgartirishingiz mumkin, biz bundan keyin ham ishlaymiz.
  • Inference Engine Intel protsessorlari, Myriad chiplari va Neural Compute Stick tezlatgichlarida IR formatidagi modellarni ishga tushirish imkonini beradi.
  • OpenCV ning eng samarali versiyasi (Inference Engine yordamida)
    IR formatidagi har bir model ikkita fayl bilan tavsiflanadi: .xml va .bin.
    Modellar Model Optimizer orqali IR formatiga quyidagi tarzda aylantiriladi:

    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 model ishlaydigan ma'lumotlar formatini tanlash imkonini beradi. FP32, FP16, INT8 qo'llab-quvvatlanadi. Optimal ma'lumotlar turini tanlash yaxshi samaradorlikni oshirishi mumkin.
    --input_shape kirish ma'lumotlarining o'lchamini ko'rsatadi. Uni dinamik ravishda o'zgartirish qobiliyati C++ API-da mavjud bo'lib tuyuladi, lekin biz unchalik uzoqqa bormadik va uni modellardan biri uchun tuzatdik.
    Keyinchalik, DNN moduli orqali IR formatida allaqachon o'zgartirilgan modelni OpenCV-ga yuklashga harakat qilaylik va uni unga yo'naltiramiz.

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

    Bu holatda oxirgi qator hisoblarni Neural Compute Stick-ga yo'naltirishga imkon beradi, asosiy hisoblar protsessorda amalga oshiriladi, ammo Raspberry Pi-da bu ishlamaydi, sizga tayoq kerak bo'ladi.

    Keyinchalik, mantiq quyidagicha: biz ovozimizni ma'lum o'lchamdagi oynalarga ajratamiz (biz uchun bu 0.4 s), biz ushbu oynalarning har birini MFCC-ga aylantiramiz, keyin biz uni tarmoqqa o'tkazamiz:

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

    Keyinchalik, barcha oynalar uchun eng keng tarqalgan sinfni olaylik. Oddiy yechim, lekin hackathon uchun siz juda mavhum narsani o'ylab topishingiz shart emas, faqat vaqtingiz bo'lsa. Bizda hali ko‘p ish bor, keling, davom etaylik – ovozni aniqlash bilan shug‘ullanamiz. Oldindan yozib olingan ovozlarning spektrogrammalari saqlanadigan ma'lumotlar bazasini yaratish kerak. Vaqt oz qolgani uchun bu masalani imkon qadar hal qilamiz.

    Ya'ni, biz ovozli parchani yozish uchun skript yaratamiz (u yuqorida tavsiflangan tarzda ishlaydi, faqat klaviaturadan uzilib qolganda u ovozni faylga saqlaydi).

    Kel urinib ko'ramiz:

    python3 voice_db/record_voice.py test.wav

    Biz bir nechta odamlarning ovozini yozamiz (bizning holatlarimizda uchta jamoa a'zosi)
    Keyin, har bir yozilgan ovoz uchun biz tez furye transformatsiyasini amalga oshiramiz, spektrogramma olamiz va uni numpy massiv (.npy) sifatida saqlaymiz:

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

    Batafsil ma'lumot faylda create_base.py
    Natijada, biz asosiy skriptni ishga tushirganimizda, biz eng boshida ushbu spektrogrammalardan o'rnatishlarni olamiz:

    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)

    Ovozlangan segmentdan joylashtirishni olgandan so'ng, biz ma'lumotlar bazasidagi barcha ovozlargacha bo'lgan o'tish joyidan kosinus masofasini (qanchalik kichikroq bo'lsa, shunchalik ko'p) olish orqali uning kimga tegishli ekanligini aniqlashimiz mumkin - demo uchun biz chegarani o'rnatamiz. 0.3 gacha):

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

    Oxir-oqibat shuni ta'kidlashni istardimki, xulosa chiqarish tezligi tez edi va yana 1-2 modelni qo'shishga imkon berdi (namuna uchun 7 soniya davomida xulosa chiqarish uchun 2.5 vaqt kerak bo'ldi). Biz endi yangi modellarni qo'shishga vaqtimiz yo'q edi va veb-ilovaning prototipini yozishga e'tibor qaratdik.

    Veb ilova

    Muhim nuqta: biz uydan o'zimiz bilan yo'riqnoma olib, mahalliy tarmog'imizni o'rnatamiz, bu qurilma va noutbuklarni tarmoq orqali ulashga yordam beradi.

    Backend veb-socket texnologiyasiga asoslangan (tcp protokoli orqali http) old va Raspberry Pi o'rtasidagi uchdan-end xabar kanalidir.

    Birinchi bosqich - bu ahudududan qayta ishlangan ma'lumotni olish, ya'ni json-ga o'rnatilgan bashorat qiluvchilar, ular ma'lumotlar bazasida sayohatning yarmida saqlanadi, shuning uchun foydalanuvchining davr uchun hissiy holati haqida statistik ma'lumotlarni yaratish mumkin. Keyin ushbu paket obunadan foydalanadigan va veb-soket so'nggi nuqtasidan paketlarni qabul qiluvchi frontendga yuboriladi. Butun backend mexanizmi golang tilida qurilgan; u gorutinlar yaxshi bajara oladigan asinxron vazifalar uchun juda mos bo'lgani uchun tanlangan.
    Oxirgi nuqtaga kirishda foydalanuvchi ro'yxatdan o'tadi va tuzilishga kiradi, so'ngra uning xabari qabul qilinadi. Foydalanuvchi ham, xabar ham umumiy markazga kiritilgan bo'lib, undan xabarlar allaqachon yuboriladi (obuna bo'lgan old tomonga) va agar foydalanuvchi ulanishni yopsa (malina yoki old), u holda uning obunasi bekor qilinadi va u o'chirib tashlanadi. markaz.

    OpenVINO hackathon: Raspberry Pi-da ovoz va hissiyotlarni tanib olish
    Biz orqa tomondan ulanishni kutmoqdamiz

    Front-end - bu ishlab chiqish jarayonini tezlashtirish va soddalashtirish uchun React kutubxonasidan foydalangan holda JavaScript-da yozilgan veb-ilova. Ushbu ilovaning maqsadi orqa tomonda va to'g'ridan-to'g'ri Raspberry Pi-da ishlaydigan algoritmlar yordamida olingan ma'lumotlarni vizualizatsiya qilishdir. Sahifada react-router yordamida amalga oshiriladigan bo'limli marshrutlash mavjud, ammo asosiy sahifa qiziqish uyg'otadi, bu erda WebSocket texnologiyasidan foydalangan holda real vaqt rejimida serverdan doimiy ma'lumotlar oqimi olinadi. Raspberry Pi ovozni aniqlaydi, uning ro'yxatdan o'tgan ma'lumotlar bazasidan ma'lum bir shaxsga tegishli ekanligini aniqlaydi va mijozga ehtimollik ro'yxatini yuboradi. Mijoz so'nggi tegishli ma'lumotlarni ko'rsatadi, mikrofonga gapirgan odamning avatarini, shuningdek, u so'zlarni talaffuz qilgan hissiyotini ko'rsatadi.

    OpenVINO hackathon: Raspberry Pi-da ovoz va hissiyotlarni tanib olish
    Yangilangan bashoratlar bilan bosh sahifa

    xulosa

    Hamma narsani rejalashtirilgan tarzda yakunlashning iloji yo'q edi, bizda shunchaki vaqt yo'q edi, shuning uchun asosiy umid demoda edi, hamma narsa ishlaydi. Taqdimotda ular hamma narsa qanday ishlashi, qanday modellarni olishlari, qanday muammolarga duch kelganliklari haqida gaplashdilar. Keyingi demo qismi bo‘ldi – ekspertlar xona bo‘ylab tasodifiy tartibda yurishdi va har bir jamoaga ishchi prototipni ko‘rish uchun yaqinlashishdi. Ular bizga ham savollar berishdi, har kim o'z qismiga javob berdi, noutbukda internetni tark etishdi va hamma narsa haqiqatan ham kutilganidek ishladi.

    Shuni ta'kidlash kerakki, bizning yechimimizning umumiy qiymati 150 dollarni tashkil etdi:

    • Raspberry Pi 3 ~ 35 dollar
    • Google AIY Voice Bonnet (siz repeaker uchun haq olishingiz mumkin) ~ 15$
    • Intel NCS 2 ~ 100$

    Qanday yaxshilash mumkin:

    • Mijozdan ro'yxatdan o'tishdan foydalaning - tasodifiy yaratilgan matnni o'qishni so'rang
    • Yana bir nechta modellarni qo'shing: siz jins va yoshni ovoz bilan aniqlashingiz mumkin
    • Bir vaqtning o'zida eshitiladigan ovozlarni ajratish (diarizatsiya)

    Repozitoriy: https://github.com/vladimirwest/OpenEMO

    OpenVINO hackathon: Raspberry Pi-da ovoz va hissiyotlarni tanib olish
    Charchagan, lekin xursandmiz

    Xulosa qilib, tashkilotchilar va ishtirokchilarga rahmat aytmoqchiman. Boshqa jamoalarning loyihalari orasida bizga bepul to'xtash joylarini kuzatish bo'yicha yechim yoqdi. Biz uchun bu mahsulot va rivojlanishga sho'ng'ishning ajoyib tajribasi edi. Hududlarda, jumladan, sun’iy intellekt mavzularida ham qiziqarli tadbirlar ko‘proq o‘tkaziladi, degan umiddaman.

Manba: www.habr.com

a Izoh qo'shish