Reputation: 1659
I am trying to add percent mean absolute error (pmae) as a custom metric in keras. This is defined as (MAE divided by the mean absolute y-value multiplied by 100). I have tried:
def pmae(y_true,y_pred):
return K.mean(K.abs(y_pred - y_true)) / K.mean(K.abs(y_true)) * 100
...
model.compile(loss='mse', optimizer=Adam(),metrics=[pmae])
which runs, but the value is many orders of magnitude off (when I look at model.history.history.pmae
)
The working numpy version (on a test sample) is:
y_pred = model.predict(X_test)
pmae = abs(y_pred - y_test).mean() / abs(y_true).mean() * 100
I've also tried adding , axis=-1
to the K.mean()
calls, with no improvement (as suggested in other stackoverflow answers). Does anyone know what's wrong?
Resources
import keras.backend as K
def mean_pred(y_true, y_pred):
return K.mean(y_pred)
model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
metrics=['accuracy', mean_pred])
Upvotes: 1
Views: 2861
Reputation: 2599
Let's compare your implementation with the mean_absolute_percentage_error
in Keras:
def mean_absolute_percentage_error(y_true, y_pred):
if not K.is_tensor(y_pred):
y_pred = K.constant(y_pred)
y_true = K.cast(y_true, y_pred.dtype)
diff = K.abs((y_true - y_pred) / K.clip(K.abs(y_true),
K.epsilon(),
None))
return 100. * K.mean(diff, axis=-1)
Based on this, the following should work for your case:
def percent_mean_absolute_error(y_true, y_pred):
if not K.is_tensor(y_pred):
y_pred = K.constant(y_pred)
y_true = K.cast(y_true, y_pred.dtype)
diff = K.mean(K.abs((y_pred - y_true)) / K.mean(K.clip(K.abs(y_true),
K.epsilon(),
None)))
return 100. * K.mean(diff)
The main difference to your attempt is that here both y_true
and y_pred
are cast to the same datatype and the denominator is at least K.epsilon()
(which is set to 1e-7
by default), so the error does not go to infinity if y_true
approaches 0
.
Upvotes: 1