web-dev-qa-db-fra.com

Keras: poids de classe (class_weight) pour l'encodage à chaud

Je voudrais utiliser l'argument class_weight dans keras model.fit pour gérer les données d'entraînement déséquilibrées. En regardant certains documents, j'ai compris que nous pouvons passer un dictionnaire comme celui-ci:

class_weight = {0 : 1,
    1: 1,
    2: 5}

(Dans cet exemple, la classe 2 recevra une pénalité plus élevée dans la fonction de perte.)

Le problème est que la sortie de mon réseau a un codage à chaud, c'est-à-dire classe-0 = (1, 0, 0), classe-1 = (0, 1, 0) et classe-3 = (0, 0, 1).

Comment pouvons-nous utiliser le poids_classe pour une sortie codée à chaud?

En regardant certains codes dans Keras , cela ressemble à _feed_output_names contient une liste des classes de sortie, mais dans mon cas, model.output_names/model._feed_output_names résultats ['dense_1']

Connexes: Comment définir les poids de classe pour les classes déséquilibrées dans Keras?

16
Naoto Usuyama

Je suppose que nous pouvons utiliser sample_weights au lieu. À l'intérieur de Keras, en fait, class_weights sont convertis en sample_weights.

sample_weight: tableau facultatif de la même longueur que x, contenant des poids à appliquer à la perte du modèle pour chaque échantillon. Dans le cas des données temporelles, vous pouvez passer un tableau 2D avec une forme (échantillons, longueur_séquence), pour appliquer un poids différent à chaque pas de temps de chaque échantillon. Dans ce cas, vous devez vous assurer de spécifier sample_weight_mode = "temporal" dans compile ().

https://github.com/fchollet/keras/blob/d89afdfd82e6e27b850d910890f4a4059ddea331/keras/engine/training.py#L1392

3
Naoto Usuyama

Voici une solution un peu plus courte et plus rapide. Si votre y codé à chaud est un tableau np:

import numpy as np
from sklearn.utils.class_weight import compute_class_weight

y_integers = np.argmax(y, axis=1)
class_weights = compute_class_weight('balanced', np.unique(y_integers), y_integers)
d_class_weights = dict(enumerate(class_weights))

d_class_weights peut ensuite être transmis à class_weight dans .fit.

13
Melissa

Une réponse un peu compliquée, mais la meilleure que j'ai trouvée jusqu'à présent. Cela suppose que vos données sont codées à chaud, multi-classes et fonctionnent uniquement sur les étiquettes DataFrame df_y:

import pandas as pd
import numpy as np

# Create a pd.series that represents the categorical class of each one-hot encoded row
y_classes = df_y.idxmax(1, skipna=False)

from sklearn.preprocessing import LabelEncoder

# Instantiate the label encoder
le = LabelEncoder()

# Fit the label encoder to our label series
le.fit(list(y_classes))

# Create integer based labels Series
y_integers = le.transform(list(y_classes))

# Create dict of labels : integer representation
labels_and_integers = dict(Zip(y_classes, y_integers))

from sklearn.utils.class_weight import compute_class_weight, compute_sample_weight

class_weights = compute_class_weight('balanced', np.unique(y_integers), y_integers)
sample_weights = compute_sample_weight('balanced', y_integers)

class_weights_dict = dict(Zip(le.transform(list(le.classes_)), class_weights))

Il en résulte un sample_weights vecteur calculé pour équilibrer un ensemble de données déséquilibré qui peut être transmis au Keras sample_weight, et un class_weights_dict pouvant être alimenté au Keras class_weight propriété dans le .fit méthode. Vous ne voulez pas vraiment utiliser les deux, choisissez-en un. J'utilise class_weight maintenant parce que c'est compliqué d'obtenir sample_weight travailler avec fit_generator.

6
tw0000

dans _standardize_weights, keras fait:

if y.shape[1] > 1:
    y_classes = y.argmax(axis=1)

donc, fondamentalement, si vous choisissez d'utiliser un codage à chaud, les classes sont l'index des colonnes.

Vous pouvez également vous demander comment mapper l'index de colonne aux classes d'origine de vos données. Eh bien, si vous utilisez la classe LabelEncoder de scikit apprenez à effectuer un codage à chaud, l'index de colonne mappe l'ordre du unique labels calculé par le .fit une fonction. Le doc dit

Extraire un tableau ordonné d'étiquettes uniques

Exemple:

from sklearn.preprocessing import LabelBinarizer
y=[4,1,2,8]
l=LabelBinarizer()
y_transformed=l.fit_transorm(y)
y_transormed
> array([[0, 0, 1, 0],
   [1, 0, 0, 0],
   [0, 1, 0, 0],
   [0, 0, 0, 1]])
l.classes_
> array([1, 2, 4, 8])

En conclusion, les clés du class_weights le dictionnaire doit refléter l'ordre dans le classes_ attribut de l'encodeur.

2
pglaser