I'm fitting a train_generator and by means of a custom callback I want to compute custom metrics on my validation_generator. How can I access params validation_steps
and validation_data
within a custom callback? It’s not in self.params
, can’t find it in self.model
either. Here's what I'd like to do. Any different approach'd be welcomed.
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
Update
I managed to pass my validation data to a custom callback's constructor. However, this results in an annoying "The kernel appears to have died. It will restart automatically." message. I doubt if this is the right way to do it. Any 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)
You can iterate directly over self.validation_data to aggregate all the validation data at the end of each epoch. If you want to calculate precision, recall and F1 across the complete validation dataset:
# 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()
Then you can add valid_metrics to the callback argument:
your_model.fit_generator(..., callbacks = [valid_metrics])
Be sure to put it at the beginning of the callbacks in case you want other callbacks to use these measures.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With