Keras'ta özel bir performans metriği nasıl tanımlanır?


12

Aşağıdakilere göre Keras'ta (Tensorflow arka ucu) özel bir metrik işlev (F1-Puanı) tanımlamaya çalıştım:

def f1_score(tags, predicted):

    tags = set(tags)
    predicted = set(predicted)

    tp = len(tags & predicted)
    fp = len(predicted) - tp 
    fn = len(tags) - tp

    if tp>0:
        precision=float(tp)/(tp+fp)
        recall=float(tp)/(tp+fn)
        return 2*((precision*recall)/(precision+recall))
    else:
        return 0

Şimdiye kadar çok iyi, ama model derlemede uygulamaya çalıştığımda:

model1.compile(loss="binary_crossentropy", optimizer=Adam(), metrics=[f1_score])

hata veriyor:

TypeError                                 Traceback (most recent call last)
<ipython-input-85-4eca4def003f> in <module>()
      5 model1.add(Dense(output_dim=10, activation="sigmoid"))
      6 
----> 7 model1.compile(loss="binary_crossentropy", optimizer=Adam(), metrics=[f1_score])
      8 
      9 h=model1.fit(X_train, Y_train, batch_size=500, nb_epoch=5, verbose=True, validation_split=0.1)

/home/buda/anaconda2/lib/python2.7/site-packages/keras/models.pyc in compile(self, optimizer, loss, metrics, sample_weight_mode, **kwargs)
    522                            metrics=metrics,
    523                            sample_weight_mode=sample_weight_mode,
--> 524                            **kwargs)
    525         self.optimizer = self.model.optimizer
    526         self.loss = self.model.loss

/home/buda/anaconda2/lib/python2.7/site-packages/keras/engine/training.pyc in compile(self, optimizer, loss, metrics, loss_weights, sample_weight_mode, **kwargs)
    664                 else:
    665                     metric_fn = metrics_module.get(metric)
--> 666                     self.metrics_tensors.append(metric_fn(y_true, y_pred))
    667                     if len(self.output_names) == 1:
    668                         self.metrics_names.append(metric_fn.__name__)

<ipython-input-84-b8a5752b6d55> in f1_score(tags, predicted)
      4     #tf.convert_to_tensor(img.eval())
      5 
----> 6     tags = set(tags)
      7     predicted = set(predicted)
      8 

/home/buda/anaconda2/lib/python2.7/site-packages/tensorflow/python/framework/ops.pyc in __iter__(self)
    493       TypeError: when invoked.
    494     """
--> 495     raise TypeError("'Tensor' object is not iterable.")
    496 
    497   def __bool__(self):

TypeError: 'Tensor' object is not iterable.

Burada sorun nedir? Benim f1_score fonksiyon girişlerimin Tensorflow dizileri olmaması mı? Öyleyse, nerede / nasıl doğru şekilde dönüştürebilirim?


Hmm, hata mesajı tensör nesneleri aldığınız anlamına geliyor. Belki sonuçta eval gerekir! Eğer öyleyse, evaleval()
Neil Slater

Yanıtlar:


17

Keras arka uç işlevlerini kullanmanız gerekir . Ne yazık ki &-operator'ı desteklemiyorlar , böylece bir geçici çözüm oluşturmalısınız: Boyutun matrislerini üretiyoruz batch_size x 3, burada (örneğin gerçek pozitif için) ilk sütun zemin gerçeği vektörü, ikincisi gerçek tahmin ve üçüncüsü yalnızca pozitif olanları içeren bir tür etiket yardımcı sütun. Ardından, hangi örneklerin pozitif örnek olduğunu, pozitif olarak tahmin edildiğini ve etiket yardımcısının da pozitif olduğunu kontrol ederiz. Bunlar gerçek pozitifler.

Bu analogu, yanlış pozitifler, yanlış negatifler ve etiketlerin bazı ters hesaplamaları ile gerçek negatifler ile yapabiliriz.

F1 metriğiniz aşağıdaki gibi görünebilir:

def f1_score(y_true, y_pred):
    """
    f1 score

    :param y_true:
    :param y_pred:
    :return:
    """
    tp_3d = K.concatenate(
        [
            K.cast(y_true, 'bool'),
            K.cast(K.round(y_pred), 'bool'),
            K.cast(K.ones_like(y_pred), 'bool')
        ], axis=1
    )

    fp_3d = K.concatenate(
        [
            K.cast(K.abs(y_true - K.ones_like(y_true)), 'bool'),
            K.cast(K.round(y_pred), 'bool'),
            K.cast(K.ones_like(y_pred), 'bool')
        ], axis=1
    )

    fn_3d = K.concatenate(
        [
            K.cast(y_true, 'bool'),
            K.cast(K.abs(K.round(y_pred) - K.ones_like(y_pred)), 'bool'),
            K.cast(K.ones_like(y_pred), 'bool')
        ], axis=1
    )

    tp = K.sum(K.cast(K.all(tp_3d, axis=1), 'int32'))
    fp = K.sum(K.cast(K.all(fp_3d, axis=1), 'int32'))
    fn = K.sum(K.cast(K.all(fn_3d, axis=1), 'int32'))

    precision = tp / (tp + fp)
    recall = tp / (tp + fn)
    return 2 * ((precision * recall) / (precision + recall))

Keras-arka uç hesap makinesi sıfıra bölme için nan döndürdüğünden, return ifadesi için if-else-deyimine ihtiyacımız yoktur.

Düzenleme: Kesin bir uygulama için oldukça iyi bir fikir buldum. İlk yaklaşımımızdaki sorun, toplu olarak hesaplandığı ve daha sonra ortalama alındığı için sadece "yaklaşık" olmasıdır. Ayrıca keras.callbacks ile yapılan her dönemden sonra da hesaplanabilir . Lütfen fikri burada bulabilirsiniz: https://github.com/fchollet/keras/issues/5794

Örnek bir uygulama:

import keras
import numpy as np
import sklearn.metrics as sklm


class Metrics(keras.callbacks.Callback):
    def on_train_begin(self, logs={}):
        self.confusion = []
        self.precision = []
        self.recall = []
        self.f1s = []
        self.kappa = []
        self.auc = []

    def on_epoch_end(self, epoch, logs={}):
        score = np.asarray(self.model.predict(self.validation_data[0]))
        predict = np.round(np.asarray(self.model.predict(self.validation_data[0])))
        targ = self.validation_data[1]

        self.auc.append(sklm.roc_auc_score(targ, score))
        self.confusion.append(sklm.confusion_matrix(targ, predict))
        self.precision.append(sklm.precision_score(targ, predict))
        self.recall.append(sklm.recall_score(targ, predict))
        self.f1s.append(sklm.f1_score(targ, predict))
        self.kappa.append(sklm.cohen_kappa_score(targ, predict))

        return

Şebekenin bu işlevi çağırmasını sağlamak için basitçe

metrics = Metrics()
model.fit(
    train_instances.x,
    train_instances.y,
    batch_size,
    epochs,
    verbose=2,
    callbacks=[metrics],
    validation_data=(valid_instances.x, valid_instances.y),
)

Ardından, metricsdeğişkenin üyelerine kolayca erişebilirsiniz .


4
Teşekkürler, bu zaten çok faydalı oldu. Eğitim sırasında izlenebilmeleri için özel metrikleri bir tensorboard geri aramasına nasıl dahil edeceğinizi biliyor musunuz?
N.Kaiser
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.