Làm cách nào để xác định số liệu hiệu suất tùy chỉnh trong Keras?


11

Tôi đã cố gắng xác định một phân đoạn số liệu tùy chỉnh (F1-Score) trong Keras (phụ trợ hàng chục) theo các điều sau:

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

Cho đến nay, rất tốt, nhưng khi tôi cố gắng áp dụng nó trong biên dịch mô hình:

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

nó báo lỗi:

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.

vấn đề ở đây là gì? Thực tế là các đầu vào chức năng F1_score của tôi không phải là mảng Tensorflow? Nếu vậy, ở đâu / làm thế nào tôi có thể chuyển đổi chúng một cách chính xác?


Hmm, thông báo lỗi không ngụ ý rằng bạn đang nhận được các đối tượng tenor. Có lẽ bạn cần eval sau khi tất cả! Nếu vậy, lỗi của bạn có thể sẽ được sử dụng evalkhi bạn muốn nóieval()
Neil Slater

Câu trả lời:


16

Bạn phải sử dụng các chức năng phụ trợ Keras . Thật không may, họ không hỗ trợ trình điều khiển &, do đó bạn phải xây dựng một cách giải quyết: Chúng tôi tạo ra ma trận của thứ nguyên batch_size x 3, trong đó (ví dụ cho dương thực sự), cột đầu tiên là vectơ chân thực, dự đoán thứ hai và thứ ba là loại cột của trình trợ giúp nhãn, trong trường hợp chỉ có cột dương thực sự. Sau đó, chúng tôi kiểm tra trường hợp nào là trường hợp tích cực, được dự đoán là dương tính và người trợ giúp nhãn cũng tích cực. Đó là những tích cực thực sự.

Chúng ta có thể tạo ra sự tương tự này với các kết quả dương tính giả, âm tính giả và âm tính thực với một số tính toán ngược của nhãn.

Số liệu F1 của bạn có thể trông như sau:

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

Vì máy tính phụ trợ Keras trả về nan cho phép chia cho 0, nên chúng ta không cần câu lệnh if-other-cho câu lệnh return.

Chỉnh sửa: Tôi đã tìm thấy một ý tưởng khá tốt để thực hiện chính xác. Vấn đề với cách tiếp cận đầu tiên của chúng tôi là, nó chỉ "gần đúng", vì nó được tính toán theo từng đợt và sau đó tính trung bình. Người ta cũng có thể tính toán điều này sau mỗi kỷ nguyên với keras.callbacks. Vui lòng tìm ý tưởng tại đây: https://github.com/fchollet/keras/issues/5794

Một ví dụ thực hiện sẽ là:

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

Để tạo mạng để gọi chức năng này, bạn chỉ cần thêm nó vào bạn gọi lại như

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

Sau đó, bạn có thể chỉ cần truy cập các thành viên của metricsbiến.


3
Cảm ơn bạn, điều này đã thực sự hữu ích. Bạn có biết cách kết hợp các số liệu tùy chỉnh vào một cuộc gọi lại bảng điều khiển để chúng có thể được theo dõi trong quá trình đào tạo không?
N.Kaiser
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.