จะกำหนดเมตริกประสิทธิภาพที่กำหนดเองใน Keras ได้อย่างไร


12

ฉันพยายามกำหนด fuction เมตริกที่กำหนดเอง (คะแนน F1) ใน Keras (Tensorflow แบ็กเอนด์) ตามต่อไปนี้:

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

จนถึงตอนนี้ดีมาก แต่เมื่อฉันพยายามใช้มันในการรวบรวมแบบจำลอง:

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

มันให้ข้อผิดพลาด:

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.

ปัญหาที่นี่คืออะไร? ข้อเท็จจริงที่ว่าฟังก์ชั่นอินพุต f1_score ของฉันไม่ใช่อาร์เรย์ Tensorflow? ถ้าเป็นเช่นนั้นฉันจะแปลงได้อย่างถูกต้องที่ไหน?


อืมข้อความแสดงข้อผิดพลาดบ่งบอกว่าคุณได้รับวัตถุเทนเซอร์ บางทีคุณอาจต้องการ Eval หลังจากทั้งหมด! ถ้าเป็นเช่นนั้นความผิดพลาดของคุณน่าจะถูกใช้evalเมื่อคุณหมายถึงeval()
Neil Slater

คำตอบ:


17

คุณต้องใช้Keras ฟังก์ชั่นแบ็กเอนด์ น่าเสียดายที่พวกเขาไม่สนับสนุนผู้&ปฏิบัติงานดังนั้นคุณต้องสร้างวิธีแก้ปัญหา: เราสร้างเมทริกซ์ของมิติbatch_size x 3ที่ (เช่นบวกจริง) คอลัมน์แรกคือเวกเตอร์ความจริงพื้นดินที่สองการทำนายจริงและที่สามคือ ชนิดของคอลัมน์ผู้ช่วยเลเบลซึ่งมีในกรณีที่เป็นค่าบวกที่แท้จริงเท่านั้น จากนั้นเราจะตรวจสอบว่าอินสแตนซ์ใดเป็นอินสแตนซ์บวกคาดว่าเป็นค่าบวกและตัวช่วยเลเบลก็เป็นค่าบวกเช่นกัน สิ่งเหล่านี้เป็นผลบวกที่แท้จริง

เราสามารถทำให้อะนาล็อกนี้มีผลบวกปลอม, ลบเท็จและลบจริงด้วยการคำนวณย้อนกลับบางส่วนของฉลาก

f1-metric ของคุณอาจมีลักษณะดังนี้:

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-backend ส่งคืนน่านสำหรับการหารด้วยศูนย์เราไม่จำเป็นต้องใช้คำสั่ง if-else-statement สำหรับคำสั่ง return

แก้ไข: ฉันได้พบความคิดที่ดีงามสำหรับการใช้งานที่แน่นอน ปัญหาเกี่ยวกับวิธีการแรกของเราคือมันเป็น "โดยประมาณ" เท่านั้นเพราะมันถูกคำนวณเป็นชุดและตามมาค่าเฉลี่ยในภายหลัง เราสามารถคำนวณสิ่งนี้ได้หลังจากยุคแต่ละครั้งด้วยkeras.callbacks กรุณาค้นหาความคิดที่นี่: https://github.com/fchollet/keras/issues/5794

ตัวอย่างการใช้งานจะเป็น:

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

ในการทำให้เครือข่ายเรียกใช้ฟังก์ชั่นนี้คุณเพียงแค่เพิ่มเข้าไปในการโทรกลับเช่น

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),
)

จากนั้นคุณสามารถเข้าถึงสมาชิกของmetricsตัวแปร


4
ขอบคุณสิ่งนี้มีประโยชน์จริงๆ คุณรู้วิธีรวมเมตริกที่กำหนดเองไว้ในการเรียกกลับแบบเทนเซอร์บอร์ดเพื่อให้สามารถตรวจสอบได้ในระหว่างการฝึกอบรมหรือไม่?
N.Kaiser
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.