Sztuczna_empatia/SE8.ipynb

1.2 MiB

baner aitech


Sztuczna empatia 8

Rozpoznawanie emocji

Joanna Siwek


Spis treści

  1. Wstęp
  2. Emocje
  3. Metody rozpoznania emocji
  4. Zastosowania ER
  5. Rozpoznawanie emocji a sztuczna empatia
  6. Zadania

baner ue

Wstęp


Rozpoznawanie emocji jest podstawą skutecznej sztucznej empatii. Aby możliwe było "współodczuwanie", konieczne jest wykrycie i nazwanie emocji, które są odczuwane. Co więcej, emocje stanowią dużą część przekazu, nadawanego przez użytkownika. Aby dokładnie zrozumieć jego intencje, system musi potrafić połączyć treść przekazu wraz z emocjami mu towarzyszącymi. Aby móc w odpowiedni sposób zareagować na sygnał od użytkownika, system potrzebuje zarejestrować i przetworzyć sygnał emocjonalny. Najpłynniejsza komunikacja następuje wtedy, kiedy sygnał taki jest wykrywany w czasie rzeczywistym, a reakcja na niego następuje bardzo szybko. Jednak nie zawsze taka sytuacja jest możliwa. Co więcej, problem stanowi różnorodność emocji człowieka, różnice kulturowe w sposobie wyrażania emocji, wiele dróg ich wyrażania (treść wypowiedzi, mimika, ton głosu, język ciała). Wszystkie te problemy, skumulowane, powodują, iż rozpoznanie i przetwarzanie emocji nie jest prostym zagadnieniem. Jednakże jego ujarzmienie przynosi wiele korzyści.

Obecnie badania w dziedzinie rozpoznawania emocji skupiają się na [13]:
  • korelacji pomiędzy różnymi rodzajami sygnałów fizycznych a emocjami
  • wyborze właściwych impulsów, wywołujących porządane emocje
  • wyodrębnianiu właściwych cech sygnałów emocjonalnych
  • machanizch przyczynowo-skutkowości w wywoływaniu emocji
  • wielokanałowym rozpoznawaniu emocji

Emocje


W informatyce i sztucznej inteligencji emocje określa się jako [6]:
  • przybliżone: szybkie reakcje uwzględniające pamięć (ale nie skomplikowane procesy poznawcze na dostępnych danych)
  • reaktywne: wykonywane automatycznie w razie potrzeby;
  • adaptacyjne: dynamicznie dostosowujące się do środowiska;
  • ewolucyjne: tymczasowe, z możliwością nauczenia się ich;
  • zbiorowe: np. emocje tłumu;
  • zaraźliwe: np. reakcje na emocje innych osób generowane przez neurony lustrzane.
Dla kontrastu: humory są dłuższe i stabilne, moga wynikać z procesów kognitywnych; myśli są kognitywnie racjonalne a uczucia są złożone i rozmyte.

Jednym z głównych pytań przy konstruowaniu systemów rozpoznania emocji jest to, co tak naprawdę chcemy wykrywać. Czy emocje, które odczuwa użytkownik, czy też te, które pokazuje? Nie zawsze przecież stan emocjonalny człowieka zgadza się z tym, co mówi jego mowa ciała. Problematycznym jest już sam sarkazm.
Inne pytanie brzmi, kiedy stosować emocjonalne maszyny. Nie każde ich zastosowanie jest przecież pozytywnie odbierane przez użytkownika (patrz Clippy Microsoftu). Istnieje też problem z możliwością manipulacji emocjami ludzkimi, zwłaszcza w marketingu. Inne znane problemy to niedostateczny wachlarz rozpoznawanych emocji, różnice kulturowe w ich okazywaniu, dyskryminacja (np. przy profilowaniu pracowników czy przydzielaniu kredytu).

Formalnie, aby móc stworzyć model umożliwiający analizę i zarządzanie emocjami, należy przyjąć pewne założenia [13]:
  • emocje są instynktowne
  • różni ludzie w tych samych sytuacjach odczuwają te same emocje
  • różni ludzie wyrażają te same proste emocje w ten sam sposób
  • podczas odczuwania podstawowych emocji, wzorce reakcji fizjologicznych różnych ludzi są takie same

Metody rozpoznawania emocji


Głównym celem badań nad rozpoznawaniem emocji jest uzyskanie bardziej naturalnego, harmonijnego i przyjaznego interfejsu HCI oraz przekształcenie komputera z logicznej maszyny obliczeniowej w intuicyjny perceptron, przechodząc w ten sposób do projektowania maszyn zorientowanego na człowieka [13].

Rozpoznawanie emocji, czyli automatyczna identyfikacja emocji człowieka przez system, działa najlepiej, kiedy rozważany jest więcej niż jeden kanał komunikacji. Przedmiotem rozpoznania moga być zdjęcia, pliki video, audio, tekst, czy sygnały fizjologiczne (EEG, przewodnictwo skórne, pocenie się, puls, ruchy szkieletowe [11], etc.).

Techniki rozpoznania emocji łączą ze sobą dziedziny przetwarzania sygnałow, uczenia maszynowego, widzenia komputerowego i przetwarzania mowy. Wykorzystują w tym celu takie metody jak np. sieci Baysa, ukryte modele markowa, konwolucyjne sieci neuronowe, itd. Ogólnie wyróżnia się trzy podajścia - oparte na wiedzy, na statystyce i mieszane.

Podejście oparte na wiedzy może używać wiedzy z danej dziedziny do stworzenia modelu, może być oparte a ustalonym słowniku emocji bądź też może powstać na podstawie informacji wyinferowanych z dużego korpusu danych. Podejście statystyczne opiera się na uczeniu maszynowym (np. Support Vector Machines) i deep learningu (np. konwolucyjne sieci neuronowe, Long Short-Term Memory). Możliwe są również metody mieszane.

Jednym z największych wyzwań ER jest działanie w czasie rzeczywistym. Najczęściej wykorzystuje się w tym celu rozpoznanie wyrazów twarzy (FER). Dużą przeszkodą w tym są nieidealne warunki rozpoznawania - światło, okulary, zarost. Powoduje to, iż rozpoznanie emocji w czasie rzeczywistym, szczególnie przy bardziej skomplikowanych modelach wykorzystywanych w dalszych celach, np. empatii, jest trudne. Problem ten rozwiązuje się między innymi poprzez zmiejszenie ilości cech wyciąganych z sygnału nadawanego przez użytkownika. Zmniejsza to skomplikowanie modelu oraz czas potrzebny na jego wykonanie.
Techniki stosowane w FER to między innymi [4]:
  • rozpoznanie na podstawie pikseli
  • local binary pattern (LBP) - oparte na histogramach map binarnych, które są lokalną reprezentacją relacji pomiędzy pikselem a jego sąsiadami
  • wavelet transform
  • dyskretna transformacja kosinusowa
  • Gabor feature extraction (GFE) - używa filtrów Gabora, metoda odporna na światło, skalę i przesunięcie
  • wykrywanie krawędzi i skóry
  • wykrywanie konturu twarzy
  • metody logiki rozmytej (np. FURIA)
Zwykle emocje są opisywane przez jednostki akcji (Action Units, AU) albo określone jako punkt w przestrzeni wartościowość-pobudzenie (Valence-Arousal, V-A). Metoda AU nie definiuje emocji bezpośrednio, ale podaje zbiór stanów dla każdej części twarzy (np. otwarte usta, podniesiona brew, zmarszczony nos). Emocje są określone jako grupy różnych AU. W metodzie V-A, emocje są zdefiniowane na podstawie wiedzy psychologicznej w przestrzeni kartezjańskiej w ten sposób, że podobne emocje znajdują się blisko siebie [12].

Jako klasyfikatory w FER wykorzystuje się [12]:
  • algorytm k-najbliższych sąsiadów
  • naiwne sieci Bayesa
  • Space-Representation based Classifier (SRC)
  • Support Vector Machine (całkiem dobrze wyjaśnione w [13])
Rozpoznanie audio działa niestety trochę gorzej. System rozpoznania emocji w mowie to aplikacja przetwarzania mowy, która wywodzi z niej wzorce takie jak współczynnik mel-frequency cepstral (MFCC) czy też wysokość głosu. Wzorce te sa następnie mapowane przez klasyfikator w fazie trenowania i testowania, przy użyciu algorytmów rozpoznawania wzorców, w celu rozpoznania emocji dla każdego ze wzorców [5].

Ogólny schemat działania takiego systemu ma postać:

dane wejściowe (mowa) --> ekstrakcja cech --> wybór cech do analizy --> klasyfikacja --> rozpoznanie emocji

Na wstępnym etapie mowa jest obrabiana w celu usunięcia szumów. Następnie wyodrębniane są jej cechy (ton, barwa głosu, wysokość, szybkość i inne) i wybierane są cechy, które będą wchodziły w skład wektórów tworzących przestrzeń emocji (w podejściu wektorowym). W tym celu plik audio jest dzielony na segmenty oraz filtrowany. Tak przetworzony sygnał jest następnie reprezentowany w postaci n-wymiarowego wektora cech. Wektory te są przechowywane w celu późniejszej analizy przez kalsyfikator.

Klasyfikatorem może być sieć neuronowa czy tez drzewo decyzyjne. Klasyfikatory są uczone na danych treningowych (dużej ilości), a następnie na ich podstawie do wyuczonych wzorców porównywane są wektory wyodrębnione z danych wejściowych. Skuteczność obecnych metod to średnio 80%.

Zastosowania ER


Rozpoznawanie emocji znajduje coraz szersze zastosowania w wielu dziedziniach życia. Warto tutaj wspomnieć między innymi o:
  • zastosowaniach w marketingu - dostosowanie treści do reakcji użytkownika; celowane reklamy; prognozowanie rynku

  • zastosowanie w samochodach - kontrola stanu kierowcy, pasażera

  • Snapchat

  • szeroko rozumiane zbieranie informacji zwrotnej od użytkownika

  • API

  • edukacja - dostosowanie do stanu emocjonalnego uczącego się

  • gry komputerowe - immersja

  • zdrowie i medycyna

  • monitorowanie obywateli (!)

    Na ten moment ER jest najbardziej rozpowszechnione w dziedzinie sprzedaży i promowania produktów.

    Jednym z popularniejszych rozwiązań w ER w marketingu jest wspominana już na tych zajęciach Affectiva. Systemy Affectivy rozpoznają emocje z użyciem smartfonów oraz kamerek internetowych. Algorytm najpierw odnajduje twarz wykrywając jej cechy charakterystyczne, a następnie mapuje je na wyrazy twarzy, te natomiast na emocje (rozłożone w czasie). Affectiva bada reakcje użytkowników na reklamy i produkty, pomagając budować bazę klientów [3]. Więcej o Affectivie można znaleźć w materiałach szóstych.

    Na rynku dostępne są również roboty, które wkorzystują emocje w trochę inny sposób. Zamiast antropomorficznie upodabniać się do człowieka, wykorzystują one do komunikacji inne formy przekazu - na przykład wyrażanie emocji przy pomocy koloru [8].

Rozpoznawanie emocji a sztuczna empatia


Rozpozanwanie emocji jako narzędzie do obsługi sztucznej empatii jest stosowane w robotach służących do interakcji z człowiekiem, w celu zwiększenia ich akceptacji. Badania wskazują, iż jej zastosowanie w znacznym stopniu poprawia interakcję z robotem, nawet jeżeli nie jest on antropomorficzny [7].

Jednakże sztuczna empatia wymaga trochę innego podejścia niż tylko proste rozpoznanie emocji. Empatia zakłada nawiązanie pewnego rodzaju łączności z drugim podmiotem - oznacza ona interakcję w czasie a nie tylko wywołanie pojedynczej emocji. Oznacza to, iż w takim przypadku konieczne jest rozważanie kontekstu i historii interakcji, w celu określenia procesu emocjonalnego rozmówców. Takie podejście do rozpoznawania emocji można spotkać w przypadku ER w konwersacjech. W przypadku rozmowy pomiędzy dwoma podmiotami, emocje są rozpoznawane w pewnym kontekście, z uwzględnieniem historii, emocji drugiego podmiotu, stanu mówiącego i treści samej wypowiedzi [9]. Takie podejście umożliwia implementację inercji emocjonalnej, znanej z psychologii [14]. Stosowane rozwiązania to np. Long Short-Term Memory (LSTM) czy Conversational Memory Networks (CMN).

Badania wskazują również, iż właściwie rozpoznane i wyrażone emocje pozytywnie wpływają na empatię użytkownika wobec AI. Według badań aktywności mózgu, wyrazy twarzy robota są odbierane przez mózg tak samo, jak wyrazy twarzy człowieka. Ludzi nie mają problemów z rozpoznaniem u robota takich emocji jak radość, zaskoczenie czy złość, nie potrafią natomiast rozpoznać strachu czy zniesmaczenia! Podobnie, pozytywnie odbierana jest mowa ciała robota. Szczególnie pozytywnie na emocjonalne roboty reagują dzieci. Co ciekawe, ludzie wykazują też większą agresję wobec emocjonalnych robotów niż wobec tych bez emocji [10].

Zadania


Zadanie 1 Zrób sobie 6 zdjęć przedstawiających różne emocje: złość, strach, szczęście, smutek, zaskoczenie, neutralny wyraz twarzy. Następnie spróbuj rozpoznać emocje przy pomocy następującego kodu (wymagane openCV, TensorFlow, fer). Możesz skorzystać z przykładu w [1]. Wykonaj poniższe kroki, wpisując odpowiedni kod w puste miejsca:
  1. Zainstaluj bibliotekę fer do rozpoznawania emocji. Z fer zaimportuj FER, w celu rozpoznania emocji twarzy.

Zaimportuj pyplot.

import matplotlib.pyplot as plt 

Wczytaj jedno ze zdjęć, które zrobiłeś/zrobiłaś.

img = plt.imread("happy.jpg")

Wykryj twarz.

Wykryj emocję funkcją detect_emotions przyjmującą argument w postaci obrazka.

from fer import FER
detector = FER(mtcnn=True)
plt.imshow(img)
<matplotlib.image.AxesImage at 0x1dfbc25b730>

Pokarz wykryte emocje.

print(detector.detect_emotions(img))
[{'box': [337, 144, 260, 362], 'emotions': {'angry': 0.0, 'disgust': 0.0, 'fear': 0.0, 'happy': 1.0, 'sad': 0.0, 'surprise': 0.0, 'neutral': 0.0}}]

Sprawdź wszystkie 6 zdjęć. Czy emocje zostały dobrze rozpoznane?

img = plt.imread("sad.jpg")
plt.imshow(img)
print(detector.detect_emotions(img))
[{'box': [34, 211, 542, 685], 'emotions': {'angry': 0.09, 'disgust': 0.0, 'fear': 0.04, 'happy': 0.0, 'sad': 0.25, 'surprise': 0.0, 'neutral': 0.61}}]
img = plt.imread("angry.jpg")
plt.imshow(img)
print(detector.detect_emotions(img))
[{'box': [829, 189, 365, 500], 'emotions': {'angry': 0.99, 'disgust': 0.0, 'fear': 0.01, 'happy': 0.0, 'sad': 0.0, 'surprise': 0.0, 'neutral': 0.0}}]
img = plt.imread("surprised.jpg")
plt.imshow(img)
print(detector.detect_emotions(img))
[{'box': [308, 130, 156, 254], 'emotions': {'angry': 0.08, 'disgust': 0.0, 'fear': 0.13, 'happy': 0.0, 'sad': 0.0, 'surprise': 0.79, 'neutral': 0.0}}]
img = plt.imread("neutral.jpg")
plt.imshow(img)
print(detector.detect_emotions(img))
[{'box': [168, 68, 133, 171], 'emotions': {'angry': 0.01, 'disgust': 0.0, 'fear': 0.01, 'happy': 0.0, 'sad': 0.26, 'surprise': 0.0, 'neutral': 0.72}}]
img = plt.imread("fear.jpg")
plt.imshow(img)
print(detector.detect_emotions(img))
[{'box': [171, 68, 171, 246], 'emotions': {'angry': 0.39, 'disgust': 0.02, 'fear': 0.52, 'happy': 0.03, 'sad': 0.0, 'surprise': 0.04, 'neutral': 0.0}}]
Zadanie 2 Nagraj krótki film ze swoją twarzą przedstawiający jakąś emocję. Następnie użyj tej samej biblioteki fer i sprawdź, czy emocja została dobrze rozpoznana. Jako wynik kodu powinna powstać kopia filmiku z zaznaczoną twarzą oraz przynależność do każdego z rodzaju emocji. Może to chwilę potrwać.

Z fer zaimportuj FER i Video, w celu rozpoznania emocji z filmu.

from fer import FER, Video
import cv2

Wczytaj film.

input_video_path = "face.mp4"
output_video_path = "out.mp4"

Przypisz film do zmiennej video.

video = Video(input_video_path)

Przeanalizuj wideo wykorzystując FER.

detector = FER(mtcnn=True)
analysis = video.analyze(detector, display=False)
INFO:fer:30.00 fps, 80 frames, 2.67 seconds
INFO:fer:Making directories at output
100%|██████████| 80/80 [00:06<00:00, 11.67frames/s]
INFO:fer:Completed analysis: saved to output\face_output.mp4
INFO:fer:Starting to Zip
INFO:fer:Compressing: 62%
INFO:fer:Zip has finished

Wypisz wynik analizy. Sama analiza może zająć chwilę. W wyniku powinna powstać kopia filmu z zaznaczoną twarzą oraz opis emocji w każdej klatce.

print(analysis)
[{'box0': [72, 192, 207, 269], 'angry0': 0.19, 'disgust0': 0.0, 'fear0': 0.06, 'happy0': 0.0, 'sad0': 0.17, 'surprise0': 0.0, 'neutral0': 0.58}, {'box0': [72, 192, 208, 269], 'angry0': 0.14, 'disgust0': 0.0, 'fear0': 0.04, 'happy0': 0.0, 'sad0': 0.14, 'surprise0': 0.0, 'neutral0': 0.68}, {'box0': [71, 191, 208, 271], 'angry0': 0.2, 'disgust0': 0.0, 'fear0': 0.02, 'happy0': 0.0, 'sad0': 0.15, 'surprise0': 0.0, 'neutral0': 0.62}, {'box0': [71, 192, 208, 267], 'angry0': 0.24, 'disgust0': 0.0, 'fear0': 0.02, 'happy0': 0.0, 'sad0': 0.15, 'surprise0': 0.0, 'neutral0': 0.59}, {'box0': [72, 193, 206, 266], 'angry0': 0.28, 'disgust0': 0.0, 'fear0': 0.02, 'happy0': 0.0, 'sad0': 0.13, 'surprise0': 0.0, 'neutral0': 0.56}, {'box0': [69, 189, 209, 265], 'angry0': 0.33, 'disgust0': 0.0, 'fear0': 0.04, 'happy0': 0.0, 'sad0': 0.11, 'surprise0': 0.0, 'neutral0': 0.51}, {'box0': [70, 191, 205, 262], 'angry0': 0.3, 'disgust0': 0.0, 'fear0': 0.02, 'happy0': 0.0, 'sad0': 0.12, 'surprise0': 0.0, 'neutral0': 0.56}, {'box0': [69, 190, 206, 263], 'angry0': 0.25, 'disgust0': 0.0, 'fear0': 0.02, 'happy0': 0.0, 'sad0': 0.11, 'surprise0': 0.0, 'neutral0': 0.62}, {'box0': [69, 190, 206, 262], 'angry0': 0.22, 'disgust0': 0.0, 'fear0': 0.02, 'happy0': 0.0, 'sad0': 0.14, 'surprise0': 0.0, 'neutral0': 0.62}, {'box0': [73, 189, 203, 264], 'angry0': 0.17, 'disgust0': 0.0, 'fear0': 0.02, 'happy0': 0.0, 'sad0': 0.14, 'surprise0': 0.0, 'neutral0': 0.67}, {'box0': [72, 188, 203, 262], 'angry0': 0.17, 'disgust0': 0.0, 'fear0': 0.02, 'happy0': 0.0, 'sad0': 0.1, 'surprise0': 0.0, 'neutral0': 0.7}, {'box0': [72, 187, 202, 263], 'angry0': 0.16, 'disgust0': 0.0, 'fear0': 0.02, 'happy0': 0.0, 'sad0': 0.11, 'surprise0': 0.0, 'neutral0': 0.7}, {'box0': [72, 187, 204, 263], 'angry0': 0.12, 'disgust0': 0.0, 'fear0': 0.02, 'happy0': 0.0, 'sad0': 0.08, 'surprise0': 0.0, 'neutral0': 0.78}, {'box0': [72, 186, 204, 263], 'angry0': 0.1, 'disgust0': 0.0, 'fear0': 0.03, 'happy0': 0.0, 'sad0': 0.09, 'surprise0': 0.0, 'neutral0': 0.79}, {'box0': [70, 185, 206, 264], 'angry0': 0.15, 'disgust0': 0.0, 'fear0': 0.03, 'happy0': 0.0, 'sad0': 0.12, 'surprise0': 0.0, 'neutral0': 0.7}, {'box0': [69, 186, 206, 260], 'angry0': 0.18, 'disgust0': 0.0, 'fear0': 0.04, 'happy0': 0.0, 'sad0': 0.14, 'surprise0': 0.0, 'neutral0': 0.64}, {'box0': [70, 188, 205, 255], 'angry0': 0.14, 'disgust0': 0.0, 'fear0': 0.04, 'happy0': 0.0, 'sad0': 0.14, 'surprise0': 0.0, 'neutral0': 0.67}, {'box0': [71, 189, 204, 254], 'angry0': 0.17, 'disgust0': 0.0, 'fear0': 0.03, 'happy0': 0.0, 'sad0': 0.17, 'surprise0': 0.0, 'neutral0': 0.63}, {'box0': [61, 180, 213, 265], 'angry0': 0.36, 'disgust0': 0.0, 'fear0': 0.01, 'happy0': 0.0, 'sad0': 0.08, 'surprise0': 0.0, 'neutral0': 0.54}, {'box0': [71, 189, 203, 257], 'angry0': 0.24, 'disgust0': 0.0, 'fear0': 0.03, 'happy0': 0.0, 'sad0': 0.14, 'surprise0': 0.0, 'neutral0': 0.59}, {'box0': [68, 188, 204, 258], 'angry0': 0.15, 'disgust0': 0.0, 'fear0': 0.03, 'happy0': 0.0, 'sad0': 0.17, 'surprise0': 0.0, 'neutral0': 0.64}, {'box0': [64, 181, 210, 265], 'angry0': 0.24, 'disgust0': 0.0, 'fear0': 0.03, 'happy0': 0.0, 'sad0': 0.24, 'surprise0': 0.0, 'neutral0': 0.49}, {'box0': [64, 179, 209, 264], 'angry0': 0.35, 'disgust0': 0.0, 'fear0': 0.02, 'happy0': 0.0, 'sad0': 0.13, 'surprise0': 0.0, 'neutral0': 0.5}, {'box0': [69, 182, 205, 255], 'angry0': 0.44, 'disgust0': 0.0, 'fear0': 0.02, 'happy0': 0.0, 'sad0': 0.23, 'surprise0': 0.0, 'neutral0': 0.31}, {'box0': [71, 182, 202, 252], 'angry0': 0.41, 'disgust0': 0.0, 'fear0': 0.01, 'happy0': 0.0, 'sad0': 0.3, 'surprise0': 0.0, 'neutral0': 0.27}, {'box0': [71, 180, 201, 251], 'angry0': 0.44, 'disgust0': 0.0, 'fear0': 0.01, 'happy0': 0.0, 'sad0': 0.25, 'surprise0': 0.0, 'neutral0': 0.3}, {'box0': [65, 177, 207, 258], 'angry0': 0.41, 'disgust0': 0.0, 'fear0': 0.02, 'happy0': 0.0, 'sad0': 0.23, 'surprise0': 0.0, 'neutral0': 0.34}, {'box0': [73, 181, 200, 248], 'angry0': 0.48, 'disgust0': 0.0, 'fear0': 0.03, 'happy0': 0.0, 'sad0': 0.29, 'surprise0': 0.0, 'neutral0': 0.2}, {'box0': [72, 179, 201, 251], 'angry0': 0.4, 'disgust0': 0.0, 'fear0': 0.05, 'happy0': 0.0, 'sad0': 0.34, 'surprise0': 0.0, 'neutral0': 0.21}, {'box0': [61, 172, 208, 257], 'angry0': 0.39, 'disgust0': 0.0, 'fear0': 0.03, 'happy0': 0.0, 'sad0': 0.15, 'surprise0': 0.0, 'neutral0': 0.42}, {'box0': [63, 174, 205, 252], 'angry0': 0.4, 'disgust0': 0.0, 'fear0': 0.04, 'happy0': 0.0, 'sad0': 0.19, 'surprise0': 0.0, 'neutral0': 0.37}, {'box0': [64, 175, 205, 252], 'angry0': 0.49, 'disgust0': 0.0, 'fear0': 0.04, 'happy0': 0.0, 'sad0': 0.25, 'surprise0': 0.0, 'neutral0': 0.22}, {'box0': [65, 174, 204, 251], 'angry0': 0.42, 'disgust0': 0.0, 'fear0': 0.03, 'happy0': 0.0, 'sad0': 0.21, 'surprise0': 0.0, 'neutral0': 0.32}, {'box0': [64, 175, 204, 250], 'angry0': 0.34, 'disgust0': 0.0, 'fear0': 0.06, 'happy0': 0.0, 'sad0': 0.27, 'surprise0': 0.0, 'neutral0': 0.33}, {'box0': [64, 174, 205, 251], 'angry0': 0.42, 'disgust0': 0.0, 'fear0': 0.05, 'happy0': 0.0, 'sad0': 0.24, 'surprise0': 0.0, 'neutral0': 0.28}, {'box0': [64, 174, 205, 251], 'angry0': 0.45, 'disgust0': 0.0, 'fear0': 0.05, 'happy0': 0.0, 'sad0': 0.23, 'surprise0': 0.0, 'neutral0': 0.26}, {'box0': [63, 173, 206, 253], 'angry0': 0.48, 'disgust0': 0.0, 'fear0': 0.04, 'happy0': 0.0, 'sad0': 0.2, 'surprise0': 0.01, 'neutral0': 0.27}, {'box0': [62, 173, 207, 255], 'angry0': 0.38, 'disgust0': 0.0, 'fear0': 0.04, 'happy0': 0.0, 'sad0': 0.21, 'surprise0': 0.01, 'neutral0': 0.36}, {'box0': [62, 173, 207, 257], 'angry0': 0.35, 'disgust0': 0.0, 'fear0': 0.03, 'happy0': 0.0, 'sad0': 0.22, 'surprise0': 0.01, 'neutral0': 0.38}, {'box0': [66, 176, 202, 254], 'angry0': 0.43, 'disgust0': 0.0, 'fear0': 0.05, 'happy0': 0.01, 'sad0': 0.25, 'surprise0': 0.0, 'neutral0': 0.26}, {'box0': [65, 176, 206, 258], 'angry0': 0.33, 'disgust0': 0.0, 'fear0': 0.04, 'happy0': 0.0, 'sad0': 0.15, 'surprise0': 0.0, 'neutral0': 0.47}, {'box0': [65, 175, 207, 260], 'angry0': 0.17, 'disgust0': 0.0, 'fear0': 0.05, 'happy0': 0.01, 'sad0': 0.14, 'surprise0': 0.0, 'neutral0': 0.64}, {'box0': [65, 174, 209, 263], 'angry0': 0.22, 'disgust0': 0.0, 'fear0': 0.02, 'happy0': 0.01, 'sad0': 0.15, 'surprise0': 0.0, 'neutral0': 0.6}, {'box0': [66, 177, 208, 259], 'angry0': 0.14, 'disgust0': 0.0, 'fear0': 0.02, 'happy0': 0.07, 'sad0': 0.11, 'surprise0': 0.0, 'neutral0': 0.67}, {'box0': [67, 173, 210, 262], 'angry0': 0.07, 'disgust0': 0.0, 'fear0': 0.01, 'happy0': 0.35, 'sad0': 0.05, 'surprise0': 0.0, 'neutral0': 0.52}, {'box0': [67, 174, 209, 262], 'angry0': 0.02, 'disgust0': 0.0, 'fear0': 0.01, 'happy0': 0.66, 'sad0': 0.03, 'surprise0': 0.0, 'neutral0': 0.29}, {'box0': [68, 175, 208, 260], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 0.89, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.1}, {'box0': [72, 176, 202, 256], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 0.93, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.07}, {'box0': [69, 174, 204, 259], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 0.97, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.03}, {'box0': [65, 173, 208, 266], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 0.99, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.01}, {'box0': [61, 172, 213, 269], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 1.0, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.0}, {'box0': [61, 174, 211, 270], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 1.0, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.0}, {'box0': [63, 174, 210, 269], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 1.0, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.0}, {'box0': [63, 174, 210, 270], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 1.0, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.0}, {'box0': [63, 175, 213, 271], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 1.0, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.0}, {'box0': [64, 174, 209, 271], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 0.99, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.0}, {'box0': [64, 173, 210, 271], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 0.99, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.01}, {'box0': [66, 174, 209, 271], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 0.99, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.01}, {'box0': [67, 174, 208, 270], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 0.99, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.01}, {'box0': [66, 173, 211, 271], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 0.99, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.01}, {'box0': [62, 172, 224, 271], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 1.0, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.0}, {'box0': [65, 171, 216, 276], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 0.99, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.01}, {'box0': [62, 172, 224, 270], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 1.0, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.0}, {'box0': [60, 172, 224, 272], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 0.99, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.01}, {'box0': [67, 173, 214, 274], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 0.99, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.01}, {'box0': [60, 172, 223, 272], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 1.0, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.0}, {'box0': [61, 171, 224, 270], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 1.0, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.0}, {'box0': [62, 172, 223, 270], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 1.0, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.0}, {'box0': [66, 170, 213, 275], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 0.99, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.01}, {'box0': [59, 171, 225, 270], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 1.0, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.0}, {'box0': [61, 172, 223, 269], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 1.0, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.0}, {'box0': [60, 172, 223, 270], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 1.0, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.0}, {'box0': [61, 171, 223, 270], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 1.0, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.0}, {'box0': [64, 165, 216, 280], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 0.99, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.01}, {'box0': [60, 170, 222, 271], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 0.99, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.01}, {'box0': [63, 172, 221, 270], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 1.0, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.0}, {'box0': [66, 174, 209, 269], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 0.98, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.02}, {'box0': [70, 178, 211, 264], 'angry0': 0.0, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 0.93, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.07}, {'box0': [71, 181, 209, 266], 'angry0': 0.01, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 0.58, 'sad0': 0.0, 'surprise0': 0.0, 'neutral0': 0.4}, {'box0': [73, 186, 198, 251], 'angry0': 0.03, 'disgust0': 0.0, 'fear0': 0.0, 'happy0': 0.06, 'sad0': 0.01, 'surprise0': 0.0, 'neutral0': 0.89}]
Zadanie 3 Ostatnie zadanie będzie polegało na wykrywaniu emocji w mowie. Naszym zadaniem jest stworzyć sieć neuronową, którą nauczymy rozpoznawać emocję z plików dźwiękowych. Możesz wspierać się przykładem z [2]. Poniżej przedstawiona jest lista koniecznych kroków. Wpisz odpowiedni kod w pola pod każdym z kroków.
  1. Zacznijmy od ściągnięcia danych dzwiękowych. Można skorzystać np. z [15].
  2. Następnie instalujemy i importujemy potrzebne biblioteki. Przyda się np. sklearn do sieci neuronowych, librosa, soundfile do dźwięków.
import os
import soundfile
import numpy as np
import librosa
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier
from sklearn.metrics import accuracy_score
  1. W następnym kroku definujemy funkcje, które będą wyodrębniać cechy z pliku dźwiękowego: mfcc, chroma i mel. Funkcje te odpowiadają cechom mowy, które chemy wyodrębnić. Otwieramy plik dźwiękowy przy pomocy Soundfile. Dla każdej cechy, jeżeli istnieje, odwołaj sie do właściwej funkcji z librosa.feature i znajdź wartosć średnią.
def extract_features(file_name, mfcc, chroma, mel):
    with soundfile.SoundFile(file_name) as sound_file:
        X = sound_file.read(dtype="float32")
        sample_rate = sound_file.samplerate
        if chroma:
            stft = np.abs(librosa.stft(X))
        result = np.array([])
        if mfcc:
            mfccs = np.mean(librosa.feature.mfcc(y=X, sr=sample_rate, n_mfcc=40).T, axis=0)
            result = np.hstack((result, mfccs))
        if chroma:
            chroma = np.mean(librosa.feature.chroma_stft(S=stft, sr=sample_rate).T, axis=0)
            result = np.hstack((result, chroma))
        if mel:
            mel = np.mean(librosa.feature.melspectrogram(y=X, sr=sample_rate).T, axis=0)
            result = np.hstack((result, mel))
    return result
  1. Definiujemy słownik emocji dostępny dla naszych danych. Zawęź liste do 3 wybranych emocji.
emotions = {
    '03': 'happy',
    '04': 'sad',
    '05': 'angry'
}
  1. Wczytujemy dane. Z nazw plików dźwiękowych wyodrębniamy fragment będący etykietą emocji. Wybieramy tylko te 3, które chcemy obserwować. Tworzymy dwie listy. Jedna zawiera cechy, a druga emocje. Wywołujemy funkcję train_test_split.
def load_data(test_size=0.2):
    x, y = [], []
    main_data_folder = "C:\\\\Users\\\\jadamski\\\\Downloads\\\\speech-emotion-recognition-ravdess-data"
    

    # Iterate through each actor's folder
    for actor_folder in os.listdir(main_data_folder):
        actor_folder_path = os.path.join(main_data_folder, actor_folder)

        # Ensure it's a directory
        if os.path.isdir(actor_folder_path):
            
            # Iterate through each file inside the actor's folder
            for file in os.listdir(actor_folder_path):
                emotion_code = file.split("-")[2]
                
                # Process only files with the emotions you're interested in
                if emotion_code in emotions:
                    file_name = os.path.join(actor_folder_path, file)
                    emotion = emotions[emotion_code]
                    
                    # Extract features from the audio file
                    feature = extract_features(file_name, mfcc=True, chroma=True, mel=True)
                    
                    # Append features and emotion to the lists
                    x.append(feature)
                    y.append(emotion)
                
    return train_test_split(np.array(x), y, test_size=test_size, random_state=9)
  1. Dzielimy dane na cześć treningową (75%) i testową (25%).
x_train, x_test, y_train, y_test = load_data(test_size=0.25)
  1. Obserwujemy kształt danych treningowych i testowych.
print(f'Treningowe: {x_train.shape[0]}, Testowe: {x_test.shape[0]}')
Treningowe: 432, Testowe: 144
  1. Obliczamy liczbę wyodrębnionych cech.
print(f'Liczba cech: {x_train.shape[1]}')
Liczba cech: 180
  1. Inicjujemy klasyfikator.
model = MLPClassifier(alpha=0.01, batch_size=256, epsilon=1e-08, hidden_layer_sizes=(300,), learning_rate='adaptive', max_iter=500)
  1. Trenujemy model.
model.fit(x_train, y_train)
WARNING:py.warnings:c:\Users\jadamski\.conda\envs\empatia\lib\site-packages\sklearn\neural_network\_multilayer_perceptron.py:686: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (500) reached and the optimization hasn't converged yet.
  warnings.warn(

MLPClassifier(alpha=0.01, batch_size=256, hidden_layer_sizes=(300,),
              learning_rate='adaptive', max_iter=500)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
MLPClassifier(alpha=0.01, batch_size=256, hidden_layer_sizes=(300,),
              learning_rate='adaptive', max_iter=500)
  1. Dokonujemy predykcji wartości dla zbioru testowego.
y_pred = model.predict(x_test)
  1. Obliczamy dokładność modelu przy pomocy funkcji accuracy_score() ze sklearn.
accuracy = accuracy_score(y_true=y_test, y_pred=y_pred)
print("Dokładność: {:.2f}%".format(accuracy * 100))
Dokładność: 80.56%

Źródła:

[1] https://analyticsindiamag.com/face-emotion-recognizer-in-6-lines-of-code/

[2] https://data-flair.training/blogs/python-mini-project-speech-emotion-recognition/

[3] https://www.skyword.com/contentstandard/what-marketers-should-know-about-artificial-empathy/

[4] Bahreini, K., Van der Vegt, W., & Westera, W. (2019). A fuzzy logic approach to reliable real-time recognition of facial emotions. Multimedia Tools and Applications, 78(14), 18943-18966.

[5] Lanjewar, R. B., & Chaudhari, D. S. (2013). Speech emotion recognition: a review. International Journal of Innovative Technology and Exploring Engineering (IJITEE), 2(4), 68-71.

[6] Franzoni, V., Vallverdù, J., & Milani, A. (2019, October). Errors, biases and overconfidence in artificial emotional modeling. In IEEE/WIC/ACM International Conference on Web Intelligence-Companion Volume (pp. 86-90).

[7] James, J., Watson, C. I., & MacDonald, B. (2018, August). Artificial empathy in social robots: An analysis of emotions in speech. In 2018 27th IEEE International Symposium on Robot and Human Interactive Communication (RO-MAN) (pp. 632-637). IEEE.

[8] Terada, K., Yamauchi, A., & Ito, A. (2012, September). Artificial emotion expression for a robot by dynamic color change. In 2012 IEEE RO-MAN: The 21st IEEE International Symposium on Robot and Human Interactive Communication (pp. 314-321). IEEE.

[9] Poria, S., Majumder, N., Mihalcea, R., & Hovy, E. (2019). Emotion recognition in conversation: Research challenges, datasets, and recent advances. IEEE Access, 7, 100943-100953.

[10] Hortensius, R., Hekele, F., & Cross, E. S. (2018). The perception of emotion in artificial agents. IEEE Transactions on Cognitive and Developmental Systems, 10(4), 852-864.

[11] Sapiński, T., Kamińska, D., Pelikant, A., & Anbarjafari, G. (2019). Emotion recognition from skeletal movements. Entropy, 21(7), 646.

[12] Domnich, A., & Anbarjafari, G. (2021). Responsible AI: Gender bias assessment in emotion recognition. arXiv preprint arXiv:2103.11436.

[13] Zhang, J., Yin, Z., Chen, P., & Nichele, S. (2020). Emotion recognition using multi-modal data and machine learning techniques: A tutorial and review. Information Fusion, 59, 103-126.

[14] Hazarika, D., Poria, S., Zadeh, A., Cambria, E., Morency, L. P., & Zimmermann, R. (2018, June). Conversational memory network for emotion recognition in dyadic dialogue videos. In Proceedings of the conference. Association for Computational Linguistics. North American Chapter. Meeting (Vol. 2018, p. 2122). NIH Public Access.

[15] https://drive.google.com/file/d/1wWsrN2Ep7x6lWqOXfr4rpKGYrJhWc8z7/view