Reconnaissance des émotions à l'aide d'un réseau neuronal convolutif


La reconnaissance des émotions a toujours été un défi passionnant pour les scientifiques. Récemment, je travaille sur un projet SER expérimental (Speech Emotion Recognition) pour comprendre le potentiel de cette technologie - pour cela, j'ai sélectionné les référentiels les plus populaires sur Github et en ai fait la base de mon projet.

Avant de commencer à comprendre le projet, il sera bon de se rappeler quel type de goulots d'étranglement SER a.

Obstacles principaux


  • les émotions sont subjectives, même les gens les interprètent différemment. Il est difficile de définir le concept même d '«émotion»;
  • commenter l'audio est difficile. Devrions-nous en quelque sorte marquer chaque mot, chaque phrase ou la communication dans son ensemble? Un ensemble d'émotions à utiliser en reconnaissance?
  • la collecte de données n'est pas non plus facile. De nombreuses données audio peuvent être collectées à partir de films et d'actualités. Cependant, les deux sources sont «biaisées» car les informations doivent être neutres et les émotions des acteurs se jouent. Il est difficile de trouver une source «objective» de données audio.
  • les données de balisage nécessitent des ressources humaines et temporelles importantes. Contrairement au dessin de cadres sur des images, il faut du personnel spécialement formé pour écouter des enregistrements audio entiers, les analyser et fournir des commentaires. Et puis ces commentaires doivent être appréciés par beaucoup d' autres personnes, car les notes sont subjectives.


Description du projet


Utilisation d'un réseau de neurones convolutionnels pour reconnaître les émotions dans les enregistrements audio. Et oui, le propriétaire du référentiel n'a fait référence à aucune source.

Description des données


Il y a deux jeux de données qui ont été utilisés dans les référentiels RAVDESS et SAVEE, je viens d'adapter RAVDESS dans mon modèle. Il existe deux types de données dans le contexte RAVDESS: la parole et la chanson.

Ensemble de données RAVDESS (la base de données audiovisuelle Ryerson de la parole et des chansons émotionnelles) :

  • 12 acteurs et 12 actrices ont enregistré leur discours et leurs chansons dans leur performance;
  • l'acteur n ° 18 n'a enregistré aucune chanson;
  • émotions Le dégoût (dégoût), le neutre (neutre) et les surprises (surpris) sont absents dans les données du "chant".

Répartition des émotions:


Tableau de répartition des émotions:


Extraction de fonctionnalités


Lorsque nous travaillons avec des tâches de reconnaissance vocale, les coefficients cepstraux (MFCC) sont une technologie avancée, malgré le fait qu'ils soient apparus dans les années 80.

Citation du tutoriel MFCC :
Cette forme détermine le son de sortie. Si nous pouvons identifier la forme, cela nous donnera une représentation précise du phonème sonné. La forme du tractus vocal se manifeste dans une enveloppe à court spectre, et le travail du MFCC est d'afficher avec précision cette enveloppe.


Forme d'onde


Spectrogramme

Nous utilisons MFCC comme fonctionnalité d'entrée. Si vous souhaitez en savoir plus sur ce qu'est le MFCC, ce didacticiel est fait pour vous. Le téléchargement des données et leur conversion au format MFCC peuvent être facilement effectués à l'aide du paquet librosa Python.

Architecture du modèle par défaut


L'auteur a développé un modèle CNN à l'aide du package Keras, créant 7 couches - six couches Con1D et une couche de densité (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) 

L'auteur a commenté les couches 4 et 5 dans la dernière version (18 septembre 2018) et la taille finale du fichier de ce modèle ne correspond pas au réseau fourni, donc je ne peux pas obtenir le même résultat en précision - 72%.

Le modèle est simplement formé avec les paramètres batch_size=16 et batch_size=16 epochs=700 , sans programme de formation, etc.

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

Ici, la categorical_crossentropy est fonction des pertes et la mesure de l'évaluation est la précision.

Mon expérience


Analyse exploratoire des données


Dans le jeu de données RAVDESS, chaque acteur montre 8 émotions, prononçant et chantant 2 phrases, 2 fois chacune. En conséquence, 4 exemples de chaque émotion sont obtenus de chaque acteur, à l'exception des émotions neutres, du dégoût et de la surprise mentionnés ci-dessus. Chaque audio dure environ 4 secondes, dans les première et dernière secondes, il s'agit le plus souvent de silence.

Offres typiques :

Observation


Après avoir sélectionné un ensemble de données provenant d'un acteur et d'une actrice, puis écouté tous leurs enregistrements, j'ai réalisé que les hommes et les femmes exprimaient leurs émotions différemment. Par exemple:

  • la colère masculine (Angry) est juste plus forte;
  • la joie des hommes (heureux) et la frustration (triste) - une caractéristique dans les tons de rire et de pleurs pendant le «silence»;
  • la joie féminine (heureuse), la colère (en colère) et la frustration (triste) sont plus fortes;
  • le dégoût féminin (dégoût) contient le son des vomissements.

Répétition de l'expérience


L'auteur a supprimé les classes neutres, dégoûtées et surprises pour faire la reconnaissance RAVDESS 10 de l'ensemble de données. En essayant de répéter l'expérience de l'auteur, j'ai obtenu ce résultat:



Cependant, j'ai découvert qu'il y a une fuite de données lorsque l'ensemble de données pour la validation est identique à l'ensemble de données de test. Par conséquent, j'ai répété la séparation des données, isolant les ensembles de données de deux acteurs et deux actrices afin qu'ils ne soient pas visibles pendant le test:

  • les acteurs 1 à 20 sont utilisés pour les ensembles Train / Valid dans un rapport 8: 2;
  • les acteurs 21 à 24 sont isolés des tests;
  • Paramètres du train: (1248, 216, 1);
  • Paramètres Set valides: (312, 216, 1);
  • Paramètres de l'ensemble de tests: (320, 216, 1) - (isolé).

J'ai re-formé le modèle et voici le résultat:


Test de performance


D'après le graphique Train Valid Gross, il est clair qu'il n'y a pas de convergence pour les 10 classes sélectionnées. J'ai donc décidé de réduire la complexité du modèle et de ne laisser que des émotions masculines. J'ai isolé deux acteurs dans l'ensemble de test, et mis le reste dans le train / ensemble valide, rapport 8: 2. Cela garantit qu'il n'y a pas de déséquilibre dans l'ensemble de données. Ensuite, j'ai coaché ​​séparément les données masculines et féminines pour effectuer le test.

Ensemble de données masculin

  • Train Set - 640 échantillons des acteurs 1-10;
  • Ensemble valide - 160 échantillons des acteurs 1-10;
  • Test Set - 160 échantillons des acteurs 11-12.

Ligne de référence: hommes


Ensemble de données féminin

  • Train Set - 608 échantillons des actrices 1-10;
  • Ensemble valide - 152 échantillons des actrices 1-10;
  • Set de test - 160 échantillons des actrices 11-12.

Ligne de référence: femmes


Comme vous pouvez le voir, les matrices d'erreur sont différentes.

Hommes: Angry et Happy sont les principales classes prévues dans le modèle, mais elles ne se ressemblent pas.

Femmes: désordre (triste) et joie (heureux) - classes essentiellement prédites dans le modèle; la colère et la joie se confondent facilement.

Rappelant les observations de l' Intelligence Data Analysis , je soupçonne que les femmes Angry et Happy sont similaires au point de confusion parce que leur mode d'expression est simplement d'élever la voix.

En plus de cela, je suis curieux de savoir que si je simplifie encore plus le modèle, ne laisse que les classes positives, neutres et négatives. Ou seulement positif et négatif. En bref, j'ai regroupé les émotions en 2 et 3 classes, respectivement.

2 cours:

  • Positif: joie (heureux), calme (calme);
  • Négatif: colère, peur (peur), frustration (triste).

3 classes:

  • Positif: joie (heureux);
  • Neutre: calme (calme), neutre (neutre);
  • Négatif: colère, peur (peur), frustration (triste).

Avant de commencer l'expérience, j'ai mis en place l'architecture du modèle en utilisant des données masculines, faisant une reconnaissance à 5 classes.

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

J'ai ajouté 2 couches de Conv1D, une couche de MaxPooling1D et 2 couches de BarchNormalization; J'ai également changé la valeur d'abandon à 0,25. Enfin, j'ai changé l'optimiseur en SGD avec une vitesse d'apprentissage de 0,0001.

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

Pour entraîner le modèle, j'ai appliqué une réduction du «plateau d'entraînement» et enregistré uniquement le meilleur modèle avec une valeur minimale de val_loss . Et voici les résultats pour les différentes classes cibles.

Performances du nouveau modèle


Hommes, 5 classes



Femmes, 5e année

Hommes, 2e année


Hommes, 3 classes


Augmentation (augmentation)


Lorsque j'ai renforcé l'architecture du modèle, l'optimiseur et la vitesse d'entraînement, il s'est avéré que le modèle ne converge toujours pas en mode entraînement. J'ai suggéré qu'il s'agit d'un problème de quantité de données, car nous n'avons que 800 échantillons. Cela m'a conduit à des méthodes d'augmentation de l'audio, à la fin j'ai doublé les jeux de données. Jetons un coup d'œil à ces méthodes.

Hommes, 5 classes


Incrément dynamique

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



Réglage de la hauteur

 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) 


Décalage

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


Ajout de bruit blanc

 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 


Il est à noter que l'augmentation augmente considérablement la précision, jusqu'à 70 +% dans le cas général. Surtout dans le cas de l'ajout de blanc, qui augmente la précision à 87,19% - cependant, la précision du test et la mesure F1 baissent de plus de 5%. Et puis j'ai eu l'idée de combiner plusieurs méthodes d'augmentation pour un meilleur résultat.

Combiner plusieurs méthodes


Bruit blanc + biais


Test d'augmentation sur les hommes


Hommes, 2e année


Bruit blanc + biais

Pour tous les échantillons


Bruit blanc + biais

Uniquement pour les échantillons positifs, car l'ensemble à 2 classes est déséquilibré (vers les échantillons négatifs).


Pitch + White Noise
Pour tous les échantillons


Pitch + White Noise

Pour les échantillons positifs uniquement


Conclusion


En fin de compte, je n'ai pu expérimenter qu'avec un ensemble de données masculin. J'ai re-divisé les données afin d'éviter les déséquilibres et, par conséquent, les fuites de données. J'ai configuré le modèle pour expérimenter avec des voix masculines, car je voulais simplifier le modèle autant que possible pour commencer. J'ai également effectué des tests en utilisant différentes méthodes d'augmentation; l'ajout de bruit blanc et de biais a bien fonctionné sur les données asymétriques.

Conclusions


  • les émotions sont subjectives et difficiles à corriger;
  • il est nécessaire de déterminer à l'avance quelles émotions conviennent au projet;
  • Ne faites pas toujours confiance au contenu avec Github, même s'il a beaucoup d'étoiles;
  • partage de données - gardez cela à l'esprit;
  • l'analyse exploratoire des données donne toujours une bonne idée, mais il faut être patient quand il s'agit de travailler avec des données audio;
  • Déterminez ce que vous donnerez à l'entrée de votre modèle: une phrase, un dossier entier ou une exclamation?
  • le manque de données est un facteur de réussite important dans SER, cependant, créer un bon ensemble de données avec des émotions est une tâche complexe et coûteuse;
  • simplifiez votre modèle en cas de manque de données.

Nouvelle amélioration


  • J'ai utilisé uniquement les 3 premières secondes comme entrée pour réduire la taille globale des données - le projet d'origine utilisait 2,5 secondes. Je voudrais expérimenter avec des enregistrements en taille réelle;
  • vous pouvez prétraiter les données: couper le silence, normaliser la longueur en remplissant avec des zéros, etc.;
  • essayez les réseaux de neurones récurrents pour cette tâche.

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


All Articles