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 с тандайбыз Intel NCS 2.

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

Бир эле кичинекей нерсе бар: микрофон алышыңыз керек. Кадимки USB микрофону жарайт, бирок RPI менен бирге жакшы көрүнбөйт. Бирок бул жерде да чечим түзмө-түз "жакын жерде жатат". Үн жаздыруу үчүн биз топтомдогу Voice Bonnet тактасын колдонууну чечтик Google AIY Voice Kit, анын үстүндө зымдуу стерео микрофон бар.

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 Tuple жана 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×20ms/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 (Intermediate Representation) форматына айландырышыңыз керек. Биз 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 технологиясына (http over tcp протоколуна) негизделген алдыңкы жана Raspberry Pi ортосундагы билдирүү каналы.

    Биринчи этап - малинадан иштетилген маалыматты алуу, башкача айтканда, json ичинде топтолгон божомолдоочулар, алар маалымат базасында алардын жолунун жарымында сакталат, ошондуктан колдонуучунун ошол мезгилдеги эмоционалдык фону жөнүндө статистика түзүлөт. Андан кийин бул пакет жазылууну колдонгон жана вебсокеттин акыркы чекитинен пакеттерди кабыл алган фронтонго жөнөтүлөт. Бүткүл backend механизми голанг тилинде курулган; ал горутиндер жакшы аткарган асинхрондук тапшырмаларга ылайыктуу болгондуктан тандалган.
    Акыркы чекитке кирүүдө колдонуучу катталып, структурага кирет, андан кийин анын билдирүүсү кабыл алынат. Колдонуучу да, билдирүү да жалпы хабга киргизилет, андан билдирүүлөр андан ары (жазылуу фронтуна) жөнөтүлөт жана эгер колдонуучу байланышты жапса (малина же фронт), анда анын жазылуусу жокко чыгарылат жана ал чыгарылат. Борбор.

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

    Front-end иштеп чыгуу процессин тездетүү жана жөнөкөйлөтүү үчүн React китепканасын колдонуу менен JavaScript-те жазылган веб-тиркеме. Бул колдонмонун максаты - арткы тарапта жана түздөн-түз Raspberry Piде иштеген алгоритмдердин жардамы менен алынган маалыматтарды визуализациялоо. Баракта реактивдүү роутердин жардамы менен ишке ашырылган секциялык маршруттук бар, бирок кызыктырган негизги бет 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де үн жана эмоцияларды таануу
    Чарчадык бирок бактылуубуз

    Сөзүмдүн аягында уюштуруучуларга жана катышуучуларга ыраазычылык билдирем. Башка командалардын долбоорлорунун ичинен бизге бекер унаа токтотуучу жайларды көзөмөлдөө боюнча чечим жакты. Биз үчүн бул өнүмгө жана иштеп чыгууга чөмүлүүнүн абдан сонун тажрыйбасы болду. Аймактарда, анын ичинде AI темаларында дагы кызыктуу иш-чаралар өткөрүлөт деп ишенем.

Source: www.habr.com

Комментарий кошуу