54 votes

Fonction de perte personnalisée dans Keras

Je travaille sur une approche de classifier incremental de classe d'image en utilisant un CNN comme extracteur de fonctionnalités et un bloc entièrement connecté pour la classification.

Tout d'abord, j'ai effectué un fine-tuning d'un réseau pré-entraîné VGG pour effectuer une nouvelle tâche. Une fois que le réseau est entraîné pour la nouvelle tâche, je stocke quelques exemples pour chaque classe afin d'éviter d'oublier lorsque de nouvelles classes sont disponibles.

Lorsque certaines classes sont disponibles, je dois calculer chaque sortie des exemples inclus les exemples pour les nouvelles classes. Maintenant, en ajoutant des zéros aux sorties pour les anciennes classes et en ajoutant l'étiquette correspondant à chaque nouvelle classe sur les nouvelles sorties de classe, j'ai mes nouvelles étiquettes, c'est-à-dire : si 3 nouvelles classes entrent....

Sortie du type ancienne classe : [0.1, 0.05, 0.79, ..., 0 0 0]

Sortie du type nouvelle classe : [0.1, 0.09, 0.3, 0.4, ..., 1 0 0] **les dernières sorties correspondent à la classe.

Ma question est, comment puis-je changer la fonction de perte pour une personnalisée afin de m'entraîner pour les nouvelles classes ? La fonction de perte que je veux implémenter est définie comme suit :

fonction de perte

où la perte de distillation correspond aux sorties des anciennes classes pour éviter d'oublier, et la perte de classification correspond aux nouvelles classes.

Si vous pouvez me fournir un exemple de code pour changer la fonction de perte dans Keras, ce serait bien.

Merci!!!!!

84voto

Daniel Points 2149

Il vous suffit de définir une fonction à cet effet, en utilisant les fonctions backend de keras pour les calculs. La fonction doit prendre les vraies valeurs et les valeurs prédites par le modèle.

Maintenant, comme je ne suis pas sûr de ce que représentent g, q, x et y dans votre fonction, je vais juste créer un exemple de base ici sans me soucier de ce que cela signifie ou si c'est une fonction réellement utile :

import keras.backend as K

def customLoss(yTrue,yPred):
    return K.sum(K.log(yTrue) - K.log(yPred))

Toutes les fonctions backend peuvent être consultées ici.

Après cela, compilez votre modèle en utilisant cette fonction au lieu d'une fonction régulière :

model.compile(loss=customLoss, optimizer = .....)

0 votes

Okaay, c'est exactement ce que je cherchais, Merci beaucoup!!

3 votes

@Daniel Alors comment keras mappe-t-il les arguments de la fonction de perte personnalisée? Prend-il les sorties du modèle et les applique-t-il implicitement à la CustomLoss? Comme CustomLoss(*model_outputs)?

1 votes

perte_personnalisee(y_train_converted_to_tensor, model_outputs_tensor)

5voto

Nicolas Gervais Points 21795

Étant donné que Keras n'est plus un multi-backend (source), les opérations pour les pertes personnalisées doivent être réalisées directement dans Tensorflow, plutôt que d'utiliser le backend.

Vous pouvez créer une perte personnalisée avec Tensorflow en créant une fonction qui prend comme arguments y_true et y_pred, comme suggéré dans la documentation:

import tensorflow as tf

x = tf.random.uniform(minval=0, maxval=1, shape=(10, 1), dtype=tf.float32)
y = tf.random.uniform(minval=0, maxval=1, shape=(10, 1), dtype=tf.float32)

def custom_mse(y_true, y_pred):
    squared_difference = tf.square(y_true - y_pred)
    return tf.reduce_mean(squared_difference, axis=-1)

custom_mse(x, y)

Ensuite, vous pouvez définir votre perte personnalisée dans model.compile(). Voici un exemple complet :

x = tf.random.uniform(minval=0, maxval=1, shape=(1000, 4), dtype=tf.float32)
y = tf.multiply(tf.reduce_sum(x, axis=-1), 5) # y est une fonction de x

model = tf.keras.Sequential([
    tf.keras.layers.Dense(16, input_shape=[4], activation='relu'),
    tf.keras.layers.Dense(32, activation='relu'),
    tf.keras.layers.Dense(1)
])

model.compile(loss=custom_mse, optimizer='adam')

history = model.fit(x, y, epochs=10)

Entraînement sur 1000 échantillons
Epoch 1/5
  32/1000 [..............................] - ETA: 10s - loss: 99.5402
1000/1000 [==============================] - 0s 371us/sample - loss: 105.6800
Epoch 2/5
  32/1000 [..............................] - ETA: 0s - loss: 89.2909
1000/1000 [==============================] - 0s 35us/sample - loss: 98.8208
Epoch 3/5
  32/1000 [..............................] - ETA: 0s - loss: 86.4339
1000/1000 [==============================] - 0s 34us/sample - loss: 82.7988
Epoch 4/5
  32/1000 [..............................] - ETA: 0s - loss: 75.2580
1000/1000 [==============================] - 0s 33us/sample - loss: 52.4585
Epoch 5/5
  32/1000 [..............................] - ETA: 0s - loss: 28.1625
1000/1000 [==============================] - 0s 34us/sample - loss: 17.8190

2 votes

Donc, la réponse acceptée renvoie un scalaire de la fonction de perte personnalisée, mais votre réponse renvoie un tenseur (10,) (ce qui semble clairement fonctionner). Sommes-nous vraiment libres de faire l'un ou l'autre, ou la réponse acceptée est-elle incorrecte, ou est-ce que l'un ou l'autre est un retour valide de la fonction de perte personnalisée ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X