Emotionserkennung unter Verwendung eines Faltungs-Neuronalen Netzwerks


Das Erkennen von Emotionen war für Wissenschaftler schon immer eine spannende Herausforderung. Kürzlich arbeite ich an einem experimentellen SER-Projekt (Speech Emotion Recognition), um das Potenzial dieser Technologie zu verstehen. Dazu habe ich die beliebtesten Repositories auf Github ausgewählt und sie zur Grundlage meines Projekts gemacht.

Bevor wir anfangen, das Projekt zu verstehen, wird es schön sein, sich daran zu erinnern, welche Engpässe SER hat.

Haupthindernisse


  • Emotionen sind subjektiv, sogar Menschen interpretieren sie anders. Es ist schwierig, das Konzept der „Emotion“ zu definieren.
  • Audio zu kommentieren ist schwierig. Sollten wir irgendwie jedes einzelne Wort, jeden Satz oder die gesamte Kommunikation als Ganzes markieren? Eine Reihe von Emotionen, die zur Erkennung verwendet werden sollen?
  • Das Sammeln von Daten ist ebenfalls nicht einfach. Viele Audiodaten können aus Filmen und Nachrichten gesammelt werden. Beide Quellen sind jedoch „voreingenommen“, da die Nachrichten neutral sein müssen und die Emotionen der Schauspieler gespielt werden. Es ist schwierig, eine „objektive“ Quelle für Audiodaten zu finden.
  • Markup-Daten erfordern große personelle und zeitliche Ressourcen. Im Gegensatz zum Zeichnen von Rahmen auf Bildern muss speziell geschultes Personal ganze Audioaufnahmen anhören, analysieren und Kommentare abgeben. Und dann müssen diese Kommentare von vielen anderen Menschen geschätzt werden, da die Bewertungen subjektiv sind.


Projektbeschreibung


Verwenden eines neuronalen Faltungsnetzwerks zum Erkennen von Emotionen in Audioaufnahmen. Und ja, der Eigentümer des Repositorys hat keine Quellen angegeben.

Datenbeschreibung


Es gibt zwei Datensätze, die in den RAVDESS- und SAVEE-Repositorys verwendet wurden. Ich habe RAVDESS gerade in meinem Modell angepasst. Im RAVDESS-Kontext gibt es zwei Arten von Daten: Sprache und Lied.

Datensatz RAVDESS (Die audiovisuelle Ryerson-Datenbank für emotionale Sprache und Gesang) :

  • 12 Schauspieler und 12 Schauspielerinnen nahmen ihre Rede und Lieder in ihrer Aufführung auf;
  • Schauspieler Nr. 18 hat keine aufgenommenen Songs;
  • Emotionen Ekel (Ekel), Neutral (Neutral) und Überraschungen (Überraschung) fehlen in den "Lied" -Daten.

Aufschlüsselung der Emotionen:


Emotionsverteilungsdiagramm:


Merkmalsextraktion


Wenn wir mit Spracherkennungsaufgaben arbeiten, sind die Cepstral-Koeffizienten (MFCCs) eine fortschrittliche Technologie, obwohl sie in den 80er Jahren aufgetaucht sind.

Zitat aus dem MFCC Tutorial :
Diese Form bestimmt den Ausgangston. Wenn wir die Form genau bestimmen können, erhalten wir eine genaue Darstellung des ertönten Phonems . Die Form des Vokaltrakts manifestiert sich in einer Hüllkurve eines kurzen Spektrums, und die Aufgabe des MFCC besteht darin, diese Hüllkurve genau anzuzeigen.


Wellenform


Spektrogramm

Wir verwenden MFCC als Eingabefunktion. Wenn Sie mehr über MFCC erfahren möchten, ist dieses Tutorial genau das Richtige für Sie. Das Herunterladen und Konvertieren von Daten in das MFCC-Format kann mit dem librosa Python-Paket problemlos durchgeführt werden.

Standardmodellarchitektur


Der Autor entwickelte ein CNN-Modell unter Verwendung des Keras-Pakets, wobei 7 Schichten erstellt wurden - sechs Con1D-Schichten und eine Dichteschicht (Dense).

model = Sequential() model.add(Conv1D(256, 5,padding='same', input_shape=(216,1))) #1 model.add(Activation('relu')) model.add(Conv1D(128, 5,padding='same')) #2 model.add(Activation('relu')) model.add(Dropout(0.1)) model.add(MaxPooling1D(pool_size=(8))) model.add(Conv1D(128, 5,padding='same')) #3 model.add(Activation('relu')) #model.add(Conv1D(128, 5,padding='same')) #4 #model.add(Activation('relu')) #model.add(Conv1D(128, 5,padding='same')) #5 #model.add(Activation('relu')) #model.add(Dropout(0.2)) model.add(Conv1D(128, 5,padding='same')) #6 model.add(Activation('relu')) model.add(Flatten()) model.add(Dense(10)) #7 model.add(Activation('softmax')) opt = keras.optimizers.rmsprop(lr=0.00001, decay=1e-6) 

Der Autor hat die Ebenen 4 und 5 in der neuesten Version (18. September 2018) kommentiert, und die endgültige Dateigröße dieses Modells passt nicht zum bereitgestellten Netzwerk, sodass ich nicht das gleiche Ergebnis bei der Genauigkeit erzielen kann - 72%.

Das Modell wird einfach mit den Parametern batch_size=16 und epochs=700 ohne Trainingsplan usw. trainiert.

 # Compile Model model.compile(loss='categorical_crossentropy', optimizer=opt,metrics=['accuracy']) # Fit Model cnnhistory=model.fit(x_traincnn, y_train, batch_size=16, epochs=700, validation_data=(x_testcnn, y_test)) 

Hier ist die categorical_crossentropy Kreuzentropie eine Funktion der Verluste, und das Maß für die Bewertung ist die Genauigkeit.

Mein Experiment


Explorative Datenanalyse


Im RAVDESS-Datensatz zeigt jeder Schauspieler 8 Emotionen, indem er 2 Sätze ausspricht und singt, jeweils 2 Mal. Infolgedessen werden von jedem Schauspieler 4 Beispiele für jede Emotion erhalten, mit Ausnahme der oben genannten neutralen Emotionen, des Ekels und der Überraschung. Jedes Audio dauert ungefähr 4 Sekunden, in der ersten und letzten Sekunde ist es meistens Stille.

Typische Angebote :

Beobachtung


Nachdem ich einen Datensatz aus 1 Schauspieler und 1 Schauspielerin ausgewählt und dann alle ihre Aufzeichnungen angehört hatte, stellte ich fest, dass Männer und Frauen ihre Gefühle auf unterschiedliche Weise ausdrücken. Zum Beispiel:

  • männlicher Zorn (wütend) ist nur lauter;
  • Männerfreude (glücklich) und Frustration (traurig) - ein Merkmal beim Lachen und Weinen während der "Stille";
  • weibliche Freude (glücklich), Wut (wütend) und Frustration (traurig) sind lauter;
  • weiblicher Ekel (Ekel) enthält das Geräusch von Erbrechen.

Wiederholung des Experiments


Der Autor entfernte die neutralen, angewiderten und überraschten Klassen, um die RAVDESS 10-Klassen-Erkennung des Datensatzes zu ermöglichen. Beim Versuch, die Erfahrung des Autors zu wiederholen, habe ich folgendes Ergebnis erhalten:



Ich habe jedoch festgestellt, dass ein Datenleck vorliegt, wenn der zu validierende Datensatz mit dem Testdatensatz identisch ist. Daher wiederholte ich die Trennung der Daten und isolierte die Datensätze von zwei Akteuren und zwei Schauspielerinnen so, dass sie während des Tests nicht sichtbar waren:

  • Die Akteure 1 bis 20 werden für Train / Valid-Sets im Verhältnis 8: 2 verwendet.
  • Die Akteure 21 bis 24 sind von den Tests isoliert.
  • Train Set-Parameter: (1248, 216, 1);
  • Gültige Set-Parameter: (312, 216, 1);
  • Test Set-Parameter: (320, 216, 1) - (isoliert).

Ich habe das Modell neu trainiert und hier ist das Ergebnis:


Leistungstest


Aus dem Diagramm Zuggültiges Brutto geht hervor, dass für die ausgewählten 10 Klassen keine Konvergenz besteht. Daher habe ich beschlossen, die Komplexität des Modells zu reduzieren und nur männliche Emotionen zu belassen. Ich isolierte zwei Schauspieler im Test-Set und legte den Rest in das Zug / gültige Set im Verhältnis 8: 2. Dadurch wird sichergestellt, dass der Datensatz kein Ungleichgewicht aufweist. Dann habe ich die männlichen und weiblichen Daten getrennt trainiert, um den Test durchzuführen.

Männlicher Datensatz

  • Zugset - 640 Proben von Schauspielern 1-10;
  • Gültiges Set - 160 Proben von Schauspielern 1-10;
  • Test Set - 160 Proben von Schauspielern 11-12.

Referenzzeile: Männer


Weiblicher Datensatz

  • Train Set - 608 Proben von Schauspielerinnen 1-10;
  • Gültiges Set - 152 Proben von Schauspielerinnen 1-10;
  • Test Set - 160 Proben von Schauspielerinnen 11-12.

Referenzzeile: Frauen


Wie Sie sehen können, sind Fehlermatrizen unterschiedlich.

Männer: Wütend und glücklich sind die wichtigsten vorhergesagten Klassen im Modell, aber sie sind nicht gleich.

Frauen: Unordnung (traurig) und Freude (glücklich) - im Grunde vorhergesagte Klassen im Modell; Wut und Freude sind leicht zu verwechseln.

Ich erinnere mich an die Beobachtungen aus der Intelligence Data Analysis und vermute, dass weibliche Angry und Happy dem Punkt der Verwirrung ähnlich sind, weil ihre Ausdrucksweise einfach darin besteht, ihre Stimmen zu erheben.

Darüber hinaus bin ich gespannt, ob ich, wenn ich das Modell noch weiter vereinfache, nur die Klassen Positiv, Neutral und Negativ belasse. Oder nur positiv und negativ. Kurz gesagt, ich habe Emotionen in 2 bzw. 3 Klassen eingeteilt.

2 Klassen:

  • Positiv: Freude (glücklich), ruhig (ruhig);
  • Negativ: Wut, Angst (ängstlich), Frustration (traurig).

3 Klassen:

  • Positiv: Freude (glücklich);
  • Neutral: ruhig (ruhig), neutral (neutral);
  • Negativ: Wut, Angst (ängstlich), Frustration (traurig).

Bevor ich mit dem Experiment begann, habe ich die Modellarchitektur unter Verwendung männlicher Daten eingerichtet und eine 5-Klassen-Erkennung durchgeführt.

 #   -  target_class = 5 #  model = Sequential() model.add(Conv1D(256, 8, padding='same',input_shape=(X_train.shape[1],1))) #1 model.add(Activation('relu')) model.add(Conv1D(256, 8, padding='same')) #2 model.add(BatchNormalization()) model.add(Activation('relu')) model.add(Dropout(0.25)) model.add(MaxPooling1D(pool_size=(8))) model.add(Conv1D(128, 8, padding='same')) #3 model.add(Activation('relu')) model.add(Conv1D(128, 8, padding='same')) #4 model.add(Activation('relu')) model.add(Conv1D(128, 8, padding='same')) #5 model.add(Activation('relu')) model.add(Conv1D(128, 8, padding='same')) #6 model.add(BatchNormalization()) model.add(Activation('relu')) model.add(Dropout(0.25)) model.add(MaxPooling1D(pool_size=(8))) model.add(Conv1D(64, 8, padding='same')) #7 model.add(Activation('relu')) model.add(Conv1D(64, 8, padding='same')) #8 model.add(Activation('relu')) model.add(Flatten()) model.add(Dense(target_class)) #9 model.add(Activation('softmax')) opt = keras.optimizers.SGD(lr=0.0001, momentum=0.0, decay=0.0, nesterov=False) 

Ich habe 2 Schichten Conv1D, eine Schicht MaxPooling1D und 2 Schichten BarchNormalization hinzugefügt. Ich habe auch den Dropout-Wert auf 0,25 geändert. Schließlich habe ich den Optimierer auf SGD mit einer Lerngeschwindigkeit von 0,0001 geändert.

 lr_reduce = ReduceLROnPlateau(monitor='val_loss', factor=0.9, patience=20, min_lr=0.000001) mcp_save = ModelCheckpoint('model/baseline_2class_np.h5', save_best_only=True, monitor='val_loss', mode='min') cnnhistory=model.fit(x_traincnn, y_train, batch_size=16, epochs=700, validation_data=(x_testcnn, y_test), callbacks=[mcp_save, lr_reduce]) 

Um das Modell zu trainieren, habe ich eine Reduzierung des „Trainingsplateaus“ angewendet und nur das beste Modell mit einem Mindestwert von val_loss . Und hier sind die Ergebnisse für die verschiedenen Zielklassen.

Neue Modellleistung


Männer, 5 Klassen



Frauen, Klasse 5

Männer, Klasse 2


Männer, 3 Klassen


Erhöhen (Augmentation)


Als ich die Architektur des Modells, den Optimierer und die Trainingsgeschwindigkeit stärkte, stellte sich heraus, dass das Modell im Trainingsmodus immer noch nicht konvergiert. Ich schlug vor, dass dies ein Datenmengenproblem ist, da wir nur 800 Proben haben. Dies führte mich zu Methoden zur Erhöhung der Audioqualität. Am Ende verdoppelte ich die Datensätze. Werfen wir einen Blick auf diese Methoden.

Männer, 5 Klassen


Dynamisches Inkrement

 def dyn_change(data): """    """ dyn_change = np.random.uniform(low=1.5,high=3) return (data * dyn_change) 



Tonhöheneinstellung

 def pitch(data, sample_rate): """    """ bins_per_octave = 12 pitch_pm = 2 pitch_change = pitch_pm * 2*(np.random.uniform()) data = librosa.effects.pitch_shift(data.astype('float64'), sample_rate, n_steps=pitch_change, bins_per_octave=bins_per_octave) 


Offset

 def shift(data): """   """ s_range = int(np.random.uniform(low=-5, high = 5)*500) return np.roll(data, s_range) 


Hinzufügen von weißem Rauschen

 def noise(data): """    """ #     : https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.random.html noise_amp = 0.005*np.random.uniform()*np.amax(data) data = data.astype('float64') + noise_amp * np.random.normal(size=data.shape[0]) return data 


Es fällt auf, dass die Augmentation die Genauigkeit erheblich erhöht, im allgemeinen Fall um bis zu 70 +%. Insbesondere bei Zugabe von Weiß, wodurch die Genauigkeit auf 87,19% erhöht wird, sinken jedoch die Testgenauigkeit und das F1-Maß um mehr als 5%. Und dann kam mir die Idee, mehrere Augmentationsmethoden zu kombinieren, um ein besseres Ergebnis zu erzielen.

Mehrere Methoden kombinieren


Weißes Rauschen + Voreingenommenheit


Testen der Augmentation bei Männern


Männer, Klasse 2


Weißes Rauschen + Voreingenommenheit

Für alle Proben


Weißes Rauschen + Voreingenommenheit

Nur für positive Proben, da der 2-Klassen-Satz nicht ausgeglichen ist (gegenüber negativen Proben).


Tonhöhe + weißes Rauschen
Für alle Proben


Tonhöhe + weißes Rauschen

Nur für positive Proben


Fazit


Am Ende konnte ich nur mit einem männlichen Datensatz experimentieren. Ich habe die Daten neu aufgeteilt, um Ungleichgewichte und infolgedessen Datenlecks zu vermeiden. Ich habe das Modell so eingerichtet, dass es mit Männerstimmen experimentiert, da ich das Modell so weit wie möglich vereinfachen wollte, um loszulegen. Ich habe auch Tests mit verschiedenen Augmentationsmethoden durchgeführt. Das Hinzufügen von weißem Rauschen und Vorspannung hat bei unausgeglichenen Daten gut funktioniert.

Schlussfolgerungen


  • Emotionen sind subjektiv und schwer zu beheben;
  • Es ist notwendig, im Voraus zu bestimmen, welche Emotionen für das Projekt geeignet sind.
  • Vertraue Github nicht immer Inhalten, auch wenn es viele Sterne hat.
  • Datenaustausch - denken Sie daran;
  • Die explorative Datenanalyse liefert immer eine gute Idee, aber Sie müssen geduldig sein, wenn Sie mit Audiodaten arbeiten.
  • Bestimmen Sie, was Sie für die Eingabe Ihres Modells geben: einen Satz, einen gesamten Datensatz oder einen Ausruf?
  • Datenmangel ist ein wichtiger Erfolgsfaktor bei SER. Die Erstellung eines guten Datensatzes mit Emotionen ist jedoch eine komplexe und teure Aufgabe.
  • Vereinfachen Sie Ihr Modell bei Datenmangel.

Weitere Verbesserung


  • Ich habe nur die ersten 3 Sekunden als Eingabe verwendet, um die Gesamtdatengröße zu reduzieren - das ursprüngliche Projekt verwendete 2,5 Sekunden. Ich würde gerne mit Aufnahmen in voller Größe experimentieren.
  • Sie können die Daten vorverarbeiten: Trimmen Sie die Stille, normalisieren Sie die Länge durch Auffüllen mit Nullen usw.;
  • Versuchen Sie es mit wiederkehrenden neuronalen Netzen für diese Aufgabe.

Source: https://habr.com/ru/post/de461435/


All Articles