1.2 MiB
Sztuczna empatia 8
Rozpoznawanie emocji
Joanna Siwek
Spis treści
- Wstęp
- Emocje
- Metody rozpoznania emocji
- Zastosowania ER
- Rozpoznawanie emocji a sztuczna empatia
- Zadania
Wstęp
- 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
- 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.
- 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].
- 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)
- 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])
Zastosowania ER
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
Zadania
- 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}}]
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}]
- Zacznijmy od ściągnięcia danych dzwiękowych. Można skorzystać np. z [15].
- 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
- 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
- Definiujemy słownik emocji dostępny dla naszych danych. Zawęź liste do 3 wybranych emocji.
emotions = {
'03': 'happy',
'04': 'sad',
'05': 'angry'
}
- 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)
- Dzielimy dane na cześć treningową (75%) i testową (25%).
x_train, x_test, y_train, y_test = load_data(test_size=0.25)
- Obserwujemy kształt danych treningowych i testowych.
print(f'Treningowe: {x_train.shape[0]}, Testowe: {x_test.shape[0]}')
Treningowe: 432, Testowe: 144
- Obliczamy liczbę wyodrębnionych cech.
print(f'Liczba cech: {x_train.shape[1]}')
Liczba cech: 180
- Inicjujemy klasyfikator.
model = MLPClassifier(alpha=0.01, batch_size=256, epsilon=1e-08, hidden_layer_sizes=(300,), learning_rate='adaptive', max_iter=500)
- 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)
- Dokonujemy predykcji wartości dla zbioru testowego.
y_pred = model.predict(x_test)
- 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