web-dev-qa-db-fra.com

Accès aux données de validation dans un rappel personnalisé

J'adapte un train_generator et au moyen d'un rappel personnalisé, je veux calculer des métriques personnalisées sur mon validation_generator. Comment puis-je accéder aux paramètres validation_steps et validation_data Dans un rappel personnalisé? Ce n'est pas dans self.params, ne le trouve pas dans self.model Soit. Voici ce que j'aimerais faire. Toute approche différente serait la bienvenue.

model.fit_generator(generator=train_generator,
                    steps_per_Epoch=steps_per_Epoch,
                    epochs=epochs,
                    validation_data=validation_generator,
                    validation_steps=validation_steps,
                    callbacks=[CustomMetrics()])


class CustomMetrics(keras.callbacks.Callback):

    def on_Epoch_end(self, batch, logs={}):        
        for i in validation_steps:
             # features, labels = next(validation_data)
             # compute custom metric: f(features, labels) 
        return

keras: 2.1.1

Mise à jour

J'ai réussi à transmettre mes données de validation au constructeur d'un rappel personnalisé. Cependant, cela se traduit par un ennuyeux "Le noyau semble être mort. Il redémarrera automatiquement." message. Je doute que ce soit la bonne façon de procéder. Toute suggestion?

class CustomMetrics(keras.callbacks.Callback):

    def __init__(self, validation_generator, validation_steps):
        self.validation_generator = validation_generator
        self.validation_steps = validation_steps


    def on_Epoch_end(self, batch, logs={}):

        self.scores = {
            'recall_score': [],
            'precision_score': [],
            'f1_score': []
        }

        for batch_index in range(self.validation_steps):
            features, y_true = next(self.validation_generator)            
            y_pred = np.asarray(self.model.predict(features))
            y_pred = y_pred.round().astype(int) 
            self.scores['recall_score'].append(recall_score(y_true[:,0], y_pred[:,0]))
            self.scores['precision_score'].append(precision_score(y_true[:,0], y_pred[:,0]))
            self.scores['f1_score'].append(f1_score(y_true[:,0], y_pred[:,0]))
        return

metrics = CustomMetrics(validation_generator, validation_steps)

model.fit_generator(generator=train_generator,
                    steps_per_Epoch=steps_per_Epoch,
                    epochs=epochs,
                    validation_data=validation_generator,
                    validation_steps=validation_steps,
                    shuffle=True,
                    callbacks=[metrics],
                    verbose=1)
16
Enrico Rotundo

Vous pouvez parcourir directement self.validation_data pour agréger toutes les données de validation à la fin de chaque époque. Si vous souhaitez calculer la précision, rappeler et F1 sur l'ensemble de données de validation complet:

# Validation metrics callback: validation precision, recall and F1
# Some of the code was adapted from https://medium.com/@thongonary/how-to-compute-f1-score-for-each-Epoch-in-keras-a1acd17715a2
class Metrics(callbacks.Callback):

    def on_train_begin(self, logs={}):
        self.val_f1s = []
        self.val_recalls = []
        self.val_precisions = []

    def on_Epoch_end(self, Epoch, logs):
        # 5.4.1 For each validation batch
        for batch_index in range(0, len(self.validation_data)):
            # 5.4.1.1 Get the batch target values
            temp_targ = self.validation_data[batch_index][1]
            # 5.4.1.2 Get the batch prediction values
            temp_predict = (np.asarray(self.model.predict(
                                self.validation_data[batch_index][0]))).round()
            # 5.4.1.3 Append them to the corresponding output objects
            if(batch_index == 0):
                val_targ = temp_targ
                val_predict = temp_predict
            else:
                val_targ = np.vstack((val_targ, temp_targ))
                val_predict = np.vstack((val_predict, temp_predict))

        val_f1 = round(f1_score(val_targ, val_predict), 4)
        val_recall = round(recall_score(val_targ, val_predict), 4)
        val_precis = round(precision_score(val_targ, val_predict), 4)

        self.val_f1s.append(val_f1)
        self.val_recalls.append(val_recall)
        self.val_precisions.append(val_precis)

        # Add custom metrics to the logs, so that we can use them with
        # EarlyStop and csvLogger callbacks
        logs["val_f1"] = val_f1
        logs["val_recall"] = val_recall
        logs["val_precis"] = val_precis

        print("— val_f1: {} — val_precis: {} — val_recall {}".format(
                 val_f1, val_precis, val_recall))
        return

valid_metrics = Metrics()

Ensuite, vous pouvez ajouter valid_metrics à l'argument de rappel:

your_model.fit_generator(..., callbacks = [valid_metrics])

Assurez-vous de le mettre au début des rappels au cas où vous souhaiteriez que d'autres rappels utilisent ces mesures.

2
Verdant89

J'étais en train de verrouiller la solution pour le même problème, puis je trouve la vôtre et une autre solution dans la réponse acceptée ici . Si la deuxième solution fonctionne, je pense que ce sera mieux que d'itérer de nouveau une validation approfondie à "on Epoch end"

L'idée est d'enregistrer les espaces réservés cibles et précédents dans des variables et de mettre à jour les variables via un rappel personnalisé à la fin du lot.

0
W. Sam