OpenVINO hackathon: Raspberry Pi-də səs və emosiyaların tanınması

30 noyabr - 1 dekabr Nijni Novqorodda keçirildi OpenVINO hakatonu. İştirakçılardan Intel OpenVINO alətlər dəstindən istifadə edərək məhsul həllinin prototipini yaratmağı xahiş etdilər. Təşkilatçılar tapşırığı seçərkən rəhbər tutula biləcək təxmini mövzuların siyahısını təklif etdilər, lakin yekun qərar komandalarda qaldı. Bundan əlavə, məhsula daxil olmayan modellərin istifadəsi təşviq edildi.

OpenVINO hackathon: Raspberry Pi-də səs və emosiyaların tanınması

Bu yazıda sizə məhsulun prototipini necə yaratdığımızı və nəticədə birinci yeri tutduğumuzu izah edəcəyik.

Hakatona 10-dan çox komanda qatılıb. Onların bəzilərinin başqa rayonlardan gəlməsi sevindirici haldır. Hakatonun keçirildiyi yer Nijni Novqorodun qədim fotoşəkillərinin içərisinə asıldığı “Kremlinsky on Pochain” kompleksi idi! (Xatırladıram ki, hazırda Intel-in mərkəzi ofisi Nijni Novqorodda yerləşir). İştirakçılara kod yazmaq üçün 26 saat vaxt verilib və sonda onlar öz həll yollarını təqdim etməli olublar. Ayrı bir üstünlük, planlaşdırılan hər şeyin həqiqətən həyata keçirildiyinə və təqdimatda ideya olaraq qalmamasına əmin olmaq üçün demo sessiyanın olması idi. Məhsullar, qəlyanaltılar, yeməklər, hər şey orada idi!

Bundan əlavə, Intel isteğe bağlı olaraq kameralar, Raspberry PI, Neural Compute Stick 2 təqdim etdi.

Tapşırıq seçimi

Sərbəst formada hakatona hazırlaşmağın ən çətin hissələrindən biri problem seçməkdir. Dərhal məhsulda olmayan bir şeylə tanış olmaq qərarına gəldik, çünki elanda bunun çox xoş olduğunu söylədik.

Təhlil edərək modelləri, cari buraxılışda məhsula daxil olan, biz onların əksəriyyətinin müxtəlif kompüter görmə problemlərini həll etdiyi qənaətinə gəlirik. Üstəlik, kompüter görmə sahəsində OpenVINO istifadə edərək həll edilə bilməyən bir problemlə qarşılaşmaq çox çətindir və icad edilə bilsə belə, ictimai sahədə əvvəlcədən hazırlanmış modelləri tapmaq çətindir. Biz başqa istiqamətə - nitqin işlənməsi və analitikaya doğru qazmaq qərarına gəlirik. Danışıqdan duyğuları tanımaq üçün maraqlı bir vəzifəni nəzərdən keçirək. Demək lazımdır ki, OpenVINO-da artıq insanın sifətinə görə duyğularını müəyyən edən bir model var, lakin:

  • Teorik olaraq, həm səs, həm də təsvir üzərində işləyəcək birləşmiş alqoritm yaratmaq mümkündür, bu da dəqiqliyin artmasına səbəb olmalıdır.
  • Kameralar adətən dar baxış bucağına malikdir, geniş ərazini əhatə etmək üçün birdən çox kamera tələb olunur, səsin belə bir məhdudiyyəti yoxdur.

Gəlin ideyanı inkişaf etdirək: pərakəndə satış seqmenti ideyasını əsas götürək. Mağaza kassalarında müştəri məmnuniyyətini ölçə bilərsiniz. Müştərilərdən biri xidmətdən narazıdırsa və tonunu yüksəltməyə başlayırsa, dərhal administratora zəng vuraraq kömək edə bilərsiniz.
Bu halda insan səsinin tanınmasını əlavə etməliyik, bu, mağaza işçilərini müştərilərdən ayırmağa və hər bir fərd üçün analitika təqdim etməyə imkan verəcək. Yaxşı, əlavə olaraq, mağaza işçilərinin davranışlarını təhlil etmək, komandadakı atmosferi qiymətləndirmək mümkün olacaq, yaxşı səslənir!

Həllimiz üçün tələbləri formalaşdırırıq:

  • Hədəf cihazın kiçik ölçüsü
  • Real vaxt əməliyyatı
  • Aşağı qiymət
  • Asan miqyaslılıq

Nəticədə hədəf cihaz olaraq Raspberry Pi 3 c seçirik Intel NCS 2.

Burada NCS-nin bir vacib xüsusiyyətini qeyd etmək vacibdir - o, standart CNN arxitekturaları ilə ən yaxşı şəkildə işləyir, lakin üzərində xüsusi təbəqələri olan bir modeli işə salmaq lazımdırsa, aşağı səviyyəli optimallaşdırma gözləyin.

Sadəcə bir kiçik iş var: mikrofon almalısınız. Adi bir USB mikrofon işini görəcək, lakin RPI ilə birlikdə yaxşı görünməyəcək. Ancaq burada da həll sözün əsl mənasında "yaxınlıqdadır". Səs yazmaq üçün biz dəstdəki Voice Bonnet lövhəsindən istifadə etmək qərarına gəlirik Google AIY Səs Dəsti, üzərində simli stereo mikrofon var.

Raspbian-dan yükləyin AIY layihələr deposu və onu flash sürücüyə yükləyin, aşağıdakı əmrdən istifadə edərək mikrofonun işlədiyini yoxlayın (5 saniyəlik audio yazacaq və onu faylda saxlayacaq):

arecord -d 5 -r 16000 test.wav

Dərhal qeyd etməliyəm ki, mikrofon çox həssasdır və səs-küyü yaxşı qəbul edir. Bunu düzəltmək üçün alsamixer-ə keçək, Capture devices seçin və giriş siqnalının səviyyəsini 50-60%-ə endirək.

OpenVINO hackathon: Raspberry Pi-də səs və emosiyaların tanınması
Bədəni bir fayl ilə dəyişdiririk və hər şey uyğun gəlir, hətta bir qapaq ilə bağlaya bilərsiniz

Göstərici düyməsinin əlavə edilməsi

AIY Voice Kit-i ayırarkən, arxa işığı proqramla idarə oluna bilən RGB düyməsinin olduğunu xatırlayırıq. Biz “Google AIY Led” axtarırıq və sənədləri tapırıq: https://aiyprojects.readthedocs.io/en/latest/aiy.leds.html
Niyə tanınan emosiyanı göstərmək üçün bu düymədən istifadə etməyək, bizdə cəmi 7 sinif var və düymənin 8 rəngi var, kifayətdir!

Düyməni GPIO vasitəsilə Voice Bonnet-ə bağlayırıq, lazımi kitabxanaları yükləyirik (onlar artıq AIY layihələrindən paylama dəstində quraşdırılıb)

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

Gəlin hər bir duyğunun RGB Tuple və aiy.leds.Leds sinfinin obyekti şəklində uyğun rəngə sahib olacağı bir diktə yaradaq, onun vasitəsilə rəngi yeniləyəcəyik:

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

Və nəhayət, bir duyğunun hər yeni proqnozundan sonra biz düymənin rəngini ona uyğun olaraq yeniləyəcəyik (açarla).

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

OpenVINO hackathon: Raspberry Pi-də səs və emosiyaların tanınması
Düymə, yandır!

Səslə işləmək

Mikrofondan axını çəkmək üçün pyaudio və səs-küyü süzmək və səsi aşkar etmək üçün webrtcvaddan istifadə edəcəyik. Bundan əlavə, biz asinxron olaraq səs çıxarışlarını əlavə edəcəyimiz və çıxaracağımız bir növbə yaradacağıq.

Webrtcvad təchiz edilmiş fraqmentin ölçüsündə məhdudiyyət olduğundan - o, 10/20/30 ms-ə bərabər olmalıdır və emosiyaların tanınması üçün modelin təlimi (daha sonra öyrənəcəyik) 48 kHz verilənlər bazasında aparılmışdır. 48000×20ms/1000×1(mono)=960 bayt ölçülü parçaları çəkin. Webrtcvad bu hissələrin hər biri üçün True/False qaytaracaq ki, bu da yığında səsin olub-olmamasına uyğundur.

Aşağıdakı məntiqi həyata keçirək:

  • Siyahıya səs verən hissələri əlavə edəcəyik, səs yoxdursa, boş parçaların sayğacını artıracağıq.
  • Əgər boş parçaların sayğacı >=30 (600 ms) olarsa, o zaman yığılmış parçaların siyahısının ölçüsünə baxırıq, >250-dirsə, onu növbəyə əlavə edirik, əgər yoxsa, uzunluğu hesab edirik. Qeydin dinamiki müəyyən etmək üçün onu modelə qidalandırmaq üçün kifayət deyil.
  • Boş parçaların sayğacı hələ də < 30-dursa və yığılmış parçaların siyahısının ölçüsü 300-dən çox olarsa, daha dəqiq proqnoz vermək üçün fraqmenti növbəyə əlavə edəcəyik. (çünki emosiyalar zamanla dəyişməyə meyllidir)

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

İctimai sahədə əvvəlcədən hazırlanmış modelləri axtarmağın, github-a, Google-a getməyin vaxtıdır, lakin yadda saxlayın ki, istifadə olunan arxitekturada məhdudiyyətimiz var. Bu olduqca çətin bir hissədir, çünki siz giriş məlumatlarınızda modelləri sınaqdan keçirməli və əlavə olaraq onları OpenVINO-nun daxili formatına - IR (aralıq nümayəndəlik) formatına çevirməlisiniz. Github-dan təxminən 5-7 fərqli həlli sınadıq və emosiyaların tanınması modeli dərhal işlədisə, səsin tanınması ilə daha çox gözləməli olduq - onlar daha mürəkkəb arxitekturalardan istifadə edirlər.

Biz aşağıdakılara diqqət yetiririk:

Sonra nəzəriyyədən başlayaraq modelləri çevirmək haqqında danışacağıq. OpenVINO-ya bir neçə modul daxildir:

  • Model Zoo-nu açın, onlardan istifadə oluna və məhsulunuza daxil edilə bilər
  • Model Optimzer, bunun sayəsində modeli müxtəlif çərçivə formatlarından (Tensorflow, ONNX və s.) Aralıq Nümayəndəlik formatına çevirə bilərsiniz, onunla daha da işləyəcəyik.
  • İnference Engine sizə Intel prosessorları, saysız-hesabsız çiplər və Neural Compute Stick sürətləndiricilərində IR formatında modelləri işə salmağa imkan verir.
  • OpenCV-nin ən səmərəli versiyası (Inference Engine dəstəyi ilə)
    IR formatında olan hər bir model iki fayl ilə təsvir olunur: .xml və .bin.
    Modellər Model Optimizer vasitəsilə IR formatına aşağıdakı kimi çevrilir:

    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 modelin işləyəcəyi məlumat formatını seçməyə imkan verir. FP32, FP16, INT8 dəstəklənir. Optimal məlumat növünün seçilməsi yaxşı performans artımı verə bilər.
    --input_shape giriş məlumatlarının ölçüsünü göstərir. Onu dinamik şəkildə dəyişdirmək qabiliyyəti C++ API-də mövcuddur, lakin biz o qədər də uzaqlara getmədik və sadəcə modellərdən biri üçün düzəltdik.
    Sonra, DNN modulu vasitəsilə IR formatında artıq çevrilmiş modeli OpenCV-ə yükləməyə və ona yönləndirməyə çalışaq.

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

    Bu vəziyyətdə sonuncu sətir hesablamaları Neural Compute Stick-ə yönləndirməyə imkan verir, əsas hesablamalar prosessorda aparılır, lakin Raspberry Pi vəziyyətində bu işləməyəcək, sizə çubuq lazımdır.

    Sonra, məntiq belədir: səsimizi müəyyən ölçülü pəncərələrə ayırırıq (bizim üçün bu 0.4 s-dir), bu pəncərələrin hər birini MFCC-yə çeviririk, sonra onu şəbəkəyə qidalandırırıq:

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

    Sonra, bütün pəncərələr üçün ən ümumi sinfi götürək. Sadə bir həll, lakin bir hakathon üçün çox abstrakt bir şey tapmağa ehtiyac yoxdur, yalnız vaxtınız varsa. Hələ çox işimiz var, ona görə də davam edək - səsin tanınması ilə məşğul olacağıq. Əvvəlcədən qeydə alınmış səslərin spektroqramlarının saxlanacağı bir növ məlumat bazası yaratmaq lazımdır. Çox az vaxt qaldığından, bacardığımız qədər bu məsələni həll edəcəyik.

    Məhz, biz səs çıxarışını yazmaq üçün skript yaradırıq (yuxarıda təsvir edildiyi kimi işləyir, yalnız klaviaturadan kəsildikdə səsi faylda saxlayacaq).

    Gəlin cəhd edək:

    python3 voice_db/record_voice.py test.wav

    Bir neçə insanın səsini yazırıq (bizim vəziyyətimizdə üç komanda üzvü)
    Sonra, hər bir qeydə alınmış səs üçün biz sürətli Fourier çevrilməsini həyata keçiririk, spektroqram əldə edirik və onu bir sıra (.npy) kimi saxlayırıq:

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

    Daha ətraflı faylda create_base.py
    Nəticə olaraq, əsas skripti işə saldığımız zaman, biz ən başlanğıcda bu spektroqramlardan daxiletmələr alacağıq:

    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)

    Səslənən seqmentdən daxiletməni aldıqdan sonra verilənlər bazasındakı bütün səslərə keçiddən kosinus məsafəsini götürməklə onun kimə aid olduğunu müəyyən edə biləcəyik (daha kiçik, daha çox ehtimal) - demo üçün həddi təyin etdik. 0.3-ə qədər):

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

    Sonda qeyd etmək istərdim ki, nəticə çıxarma sürəti sürətli idi və daha 1-2 model əlavə etməyə imkan verdi (7 saniyəlik bir nümunə üçün nəticə çıxarmaq üçün 2.5 vaxt lazım idi). Artıq yeni modellər əlavə etməyə vaxtımız yox idi və diqqətimizi veb tətbiqinin prototipini yazmağa cəmləşdirdik.

    Veb tətbiqi

    Əhəmiyyətli bir məqam: evdən özümüzlə bir router götürürük və yerli şəbəkəmizi qururuq, bu, cihazı və noutbukları şəbəkə üzərində birləşdirməyə kömək edir.

    Backend veb-socket texnologiyasına (tcp üzərindən http protokolu) əsaslanan ön və Raspberry Pi arasında başdan-ayağa mesaj kanalıdır.

    Birinci mərhələ, moruqdan işlənmiş məlumatı, yəni json-da qablaşdırılan, məlumat bazasında səyahətin yarısında saxlanılan proqnozlaşdırıcıları qəbul etməkdir ki, istifadəçinin dövr üçün emosional fonu haqqında statistika yaradılsın. Bu paket daha sonra abunəlikdən istifadə edən və vebsoket son nöqtəsindən paketləri qəbul edən ön hissəyə göndərilir. Bütün backend mexanizmi qolanq dilində qurulmuşdur; o seçilmişdir, çünki o, qorutinlərin yaxşı idarə etdiyi asinxron tapşırıqlar üçün uyğundur.
    Son nöqtəyə daxil olduqda istifadəçi qeydiyyatdan keçərək struktura daxil olur, sonra onun mesajı qəbul edilir. Həm istifadəçi, həm də mesaj ümumi bir mərkəzə daxil edilir, ondan mesajlar artıq göndərilir (abunə edilmiş cəbhəyə) və istifadəçi əlaqəni bağlayırsa (moruq və ya ön), o zaman abunəliyi ləğv edilir və o, şəbəkədən çıxarılır. mərkəz.

    OpenVINO hackathon: Raspberry Pi-də səs və emosiyaların tanınması
    Arxadan əlaqə gözləyirik

    Front-end, inkişaf prosesini sürətləndirmək və sadələşdirmək üçün React kitabxanasından istifadə edərək JavaScript-də yazılmış veb proqramdır. Bu proqramın məqsədi arxa tərəfdə və birbaşa Raspberry Pi üzərində işləyən alqoritmlərdən istifadə edərək əldə edilən məlumatları vizuallaşdırmaqdır. Səhifədə react-router istifadə edərək həyata keçirilən bölməli marşrutlaşdırma var, lakin maraq doğuran əsas səhifə WebSocket texnologiyasından istifadə edərək serverdən real vaxt rejimində davamlı məlumat axınının qəbul edildiyi əsas səhifədir. Raspberry Pi səsi aşkarlayır, qeydiyyatdan keçmiş verilənlər bazasından onun konkret şəxsə aid olub-olmadığını müəyyənləşdirir və müştəriyə ehtimal siyahısını göndərir. Müştəri ən son müvafiq məlumatları göstərir, çox güman ki, mikrofona danışan şəxsin avatarını, həmçinin sözləri tələffüz etdiyi emosiyanı göstərir.

    OpenVINO hackathon: Raspberry Pi-də səs və emosiyaların tanınması
    Yenilənmiş proqnozlarla əsas səhifə

    Nəticə

    Hər şeyi planlaşdırıldığı kimi tamamlamaq mümkün deyildi, sadəcə vaxtımız yox idi, ona görə də əsas ümid demoda idi ki, hər şey işləyəcək. Təqdimatda hər şeyin necə işlədiyi, hansı modelləri götürdükləri, hansı problemlərlə qarşılaşdıqları barədə danışdılar. Sonrakı demo hissəsi idi - mütəxəssislər təsadüfi qaydada otağı gəzdi və işləyən prototipə baxmaq üçün hər komandaya yaxınlaşdı. Bizə də suallar verdilər, hər kəs öz üzərinə düşəni cavablandırdı, noutbukda interneti tərk etdilər və hər şey həqiqətən gözlənildiyi kimi işlədi.

    Qeyd edim ki, həllimizin ümumi dəyəri 150 dollar idi:

    • Raspberry Pi 3 ~ 35 dollar
    • Google AIY Voice Bonnet (siz danışıq haqqı ala bilərsiniz) ~ 15$
    • Intel NCS 2 ~ 100$

    Necə yaxşılaşdırmaq olar:

    • Müştəridən qeydiyyatdan istifadə edin - təsadüfi yaradılan mətni oxumağı xahiş edin
    • Daha bir neçə model əlavə edin: cinsiyyət və yaşı səslə müəyyən edə bilərsiniz
    • Eyni zamanda səslənən səsləri ayırın (diarizasiya)

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

    OpenVINO hackathon: Raspberry Pi-də səs və emosiyaların tanınması
    Yorğun amma xoşbəxtik

    Sonda təşkilatçılara və iştirakçılara təşəkkürümü bildirmək istəyirəm. Digər komandaların layihələri arasında pulsuz park yerlərinin monitorinqi üçün həlli şəxsən bəyəndik. Bizim üçün bu, məhsula və inkişafa dalmaq üçün çox gözəl bir təcrübə idi. Ümid edirəm ki, regionlarda, o cümlədən süni intellekt mövzularında daha çox maraqlı tədbirlər keçiriləcək.

Mənbə: www.habr.com

Добавить комментарий