J'essaie de créer une fonction de perte pondérée simple.
Disons que j'ai des dimensions d'entrée 100 * 5 et des dimensions de sortie également 100 * 5. J'ai également une matrice de poids de la même dimension.
Quelque chose comme ceci:
import numpy as np
train_X = np.random.randn(100, 5)
train_Y = np.random.randn(100, 5)*0.01 + train_X
weights = np.random.randn(*train_X.shape)
def custom_loss_1(y_true, y_pred):
return K.mean(K.abs(y_true-y_pred)*weights)
from keras.layers import Dense, Input
from keras import Model
import keras.backend as K
input_layer = Input(shape=(5,))
out = Dense(5)(input_layer)
model = Model(input_layer, out)
model.compile('adam','mean_absolute_error')
model.fit(train_X, train_Y, epochs=1)
model.compile('adam',custom_loss_1)
model.fit(train_X, train_Y, epochs=10)
Il donne la trace de pile suivante:
InvalidArgumentError (see above for traceback): Incompatible shapes: [32,5] vs. [100,5]
[[Node: loss_9/dense_8_loss/mul = Mul[T=DT_FLOAT, _device="/job:localhost/replica:0/task:0/device:CPU:0"](loss_9/dense_8_loss/Abs, loss_9/dense_8_loss/mul/y)]]
D'où vient le numéro 32?
def custom_loss_2(y_true, y_pred):
return K.mean(K.abs(y_true-y_pred)*K.ones_like(y_true))
Cette fonction semble faire le travail. Donc, suggère probablement qu'un tenseur Keras en tant que matrice de poids fonctionnerait. J'ai donc créé une autre version de la fonction de perte.
from functools import partial
def custom_loss_3(y_true, y_pred, weights):
return K.mean(K.abs(y_true-y_pred)*K.variable(weights, dtype=y_true.dtype))
cl3 = partial(custom_loss_3, weights=weights)
L'ajustement des données à l'aide de cl3 donne la même erreur que ci-dessus.
InvalidArgumentError (see above for traceback): Incompatible shapes: [32,5] vs. [100,5]
[[Node: loss_11/dense_8_loss/mul = Mul[T=DT_FLOAT, _device="/job:localhost/replica:0/task:0/device:CPU:0"](loss_11/dense_8_loss/Abs, loss_11/dense_8_loss/Variable/read)]]
Je me demande ce qui me manque! J'aurais pu utiliser la notion de sample_weight dans Keras; mais alors je devrais remodeler mes entrées en un vecteur 3D.
Je pensais que cette fonction de perte personnalisée aurait vraiment dû être triviale.
Dans model.fit
La taille du lot est de 32 par défaut, c'est de là que vient ce nombre. Voici ce qui se passe:
Dans custom_loss_1
, Le tenseur K.abs(y_true-y_pred)
a la forme (batch_size=32, 5)
, Tandis que le tableau numpy weights
a la forme (100, 5)
. Il s'agit d'une multiplication non valide, car les dimensions ne correspondent pas et la diffusion ne peut pas être appliquée.
Dans custom_loss_2
, Ce problème n'existe pas car vous multipliez 2 tenseurs de même forme (batch_size=32, 5)
.
Dans custom_loss_3
, Le problème est le même que dans custom_loss_1
, Car la conversion de weights
en une variable Keras ne change pas leur forme.
PDATE: Il semble que vous souhaitiez donner un poids différent à chaque élément de chaque échantillon d'apprentissage, donc le tableau weights
devrait avoir la forme (100, 5)
. Dans ce cas, j'entrerais le tableau de vos poids dans votre modèle, puis j'utiliserais ce tenseur dans la fonction de perte:
import numpy as np
from keras.layers import Dense, Input
from keras import Model
import keras.backend as K
from functools import partial
def custom_loss_4(y_true, y_pred, weights):
return K.mean(K.abs(y_true - y_pred) * weights)
train_X = np.random.randn(100, 5)
train_Y = np.random.randn(100, 5) * 0.01 + train_X
weights = np.random.randn(*train_X.shape)
input_layer = Input(shape=(5,))
weights_tensor = Input(shape=(5,))
out = Dense(5)(input_layer)
cl4 = partial(custom_loss_4, weights=weights_tensor)
model = Model([input_layer, weights_tensor], out)
model.compile('adam', cl4)
model.fit(x=[train_X, weights], y=train_Y, epochs=10)