Боюсь, ты не сможешь этого сделать. Keras ожидает функцию, которая принимает 2 аргумента (y_true, y_pred). Вы передаете функцию, которая принимает 1 аргумент (self), поэтому она никогда не будет совместимой. Вы не можете изменить это поведение, потому что именно керасы определяют этот интерфейс. Вот почему вы получаете все ошибки:
TypeError: f1_score() takes 1 positional argument but 2 were given
Вы передали функцию, которая принимает 1 аргумент (self), но Keras передал 2 (y_true, y_pred).
TypeError: f1_score() missing 1 required positional argument: 'self'
Передавая с ()
, вы на самом деле не передаете функцию, а вызываете . Вы назвали это без аргументов, но он ожидает 1 (self).
TypeError: __init__() missing 2 required positional arguments: 'y_true' and 'y_pred'
Вы создаете экземпляр объекта Metrics
с 0 аргументами, но ваш конструктор ( init ) ожидает 2: y_true и y_pred.
Если вы хотите сгруппировать все ваши собственные метрики в классе, они должны быть статическими методами. Статический метод не может получить доступ к переменным экземпляра, потому что он не получает аргумент self
. Это будет выглядеть так:
class Metrics:
@staticmethod
def precision_score(tp, fp):
precision = tp / (tp + fp + K.epsilon())
return precision
@staticmethod
def recall_score(tp, fn):
recall = tp / (tp + fn + K.epsilon())
return recall
@staticmethod
def f1_score(y_true,y_pred):
tp = K.sum(K.cast(y_true * y_pred, 'float'), axis=0)
fp = K.sum(K.cast((1 - y_true) * y_pred, 'float'), axis=0)
fn = K.sum(K.cast(y_true*(1 - y_pred), 'float'), axis=0)
precision = Metrics.precision_score(tp,fp)
recall = Metrics.recall_score(tp, fn)
f1 = 2 * precision * recall / (precision + recall + K.epsilon())
f1 = tf.where(tf.is_nan(f1), tf.zeros_like(f1), f1)
f1 = K.mean(f1)
return f1
Таким образом, вы можете передать Metrics.f1_score
Керасу. Практически нет разницы между этим классом Metrics и наличием всех этих трех статических методов в качестве функций уровня модуля, это просто другой способ сгруппировать связанные функции вместе. Есть даже третий способ: использовать вложенные функции и вообще удалить класс:
def f1_score(y_true,y_pred):
def precision_score(tp, fp):
precision = tp / (tp + fp + K.epsilon())
return precision
def recall_score(tp, fn):
recall = tp / (tp + fn + K.epsilon())
return recall
tp = K.sum(K.cast(y_true * y_pred, 'float'), axis=0)
fp = K.sum(K.cast((1 - y_true) * y_pred, 'float'), axis=0)
fn = K.sum(K.cast(y_true*(1 - y_pred), 'float'), axis=0)
precision = precision_score(tp,fp)
recall = recall_score(tp, fn)
f1 = 2 * precision * recall / (precision + recall + K.epsilon())
f1 = tf.where(tf.is_nan(f1), tf.zeros_like(f1), f1)
f1 = K.mean(f1)
return f1