Keras的ADR和FAR自定义度量标准

时间:2017-01-23 16:09:57

标签: tensorflow keras

我需要在keras中使用张量流后端定义自定义指标,以获取ADR和FAR指标,其中:

  • ADR是第1类中正确检测到的元素数与第1类中元素总数之间的比率。

  • FAR是错误分类为Class 1元素的Class 0元素数与Class 0元素总数之间的比率。

目前,我已经能够计算每个类的元素总数:

def false_rates(y_true, y_pred):
    total_1 = K.sum(tf.cast(tf.equal(y_true, 1), 'int32'))
    total_0 = K.sum(tf.cast(tf.equal(y_true, 0), 'int32'))
    # [...]

现在,对于张量中的每个索引i,我需要计算多少:

  • y_true[i] == 1 and y_pred[i] == 1 ADR
  • y_true[i] == 0 and y_pred[i] == 1代表FAR

但我不知道如何使用tensorflow操作,我得到的最接近的是:

adr = K.sum(
        tf.cast(
            tf.equal(
                tf.add(
                    tf.cast(tf.equal(y_true, 1), 'int32'),
                    tf.cast(tf.equal(y_pred, 1), 'int32')), 2), 'int32'))

# far = ...?

但它似乎没有返回任何东西而不是0。

谢谢你的帮助!

编辑以包含完整代码:

# coding: utf-8
import csv
import numpy as np
import os

os.environ["KERAS_BACKEND"] = "tensorflow"

from keras import backend as K
from keras.callbacks import ModelCheckpoint, EarlyStopping, TensorBoard
from keras.layers import Convolution2D
from keras.models import Sequential
from keras.optimizers import RMSprop, SGD
from keras.layers.core import Dense, Dropout
from keras.layers.recurrent import LSTM
from keras.layers.embeddings import Embedding
from keras.preprocessing.sequence import pad_sequences
from keras.preprocessing.text import one_hot

def build_model(input_shape, n1, dropout_p, n_symbols, n_sequence):
    model = Sequential()
    model.add(Embedding(n_symbols+1,
                        output_dim=n1,
                        input_length=n_sequence))
    model.add(LSTM(n1))
    model.add(Dropout(dropout_p))
    model.add(Dense(1))
    return model

def load_sequences(path):
    X, y = [], []
    with open(path,'r') as file:
        reader = csv.reader(file)
        for line in reader:
                X.append(line[0])
                y.append(int(line[1]))
    return np.array(X), np.array(y)

def adr_and_far(y_true, y_pred):
    total_adr = K.sum(K.tf.cast(K.tf.equal(y_true, 1), 'int32'))
    total_far = K.sum(K.tf.cast(K.tf.equal(y_true, 0), 'int32'))

    adr_idx = K.tf.equal(y_true, 1) & K.tf.equal(y_pred, 1)
    adr_idx = K.tf.reshape(K.tf.where(adr_idx), [-1])

    far_idx = K.tf.equal(y_true, 0) & K.tf.equal(y_pred, 1)
    far_idx = K.tf.reshape(K.tf.where(far_idx), [-1])

    num_adr = K.tf.shape(adr_idx)[0]  # 3
    num_far = K.tf.shape(far_idx)[0]  # 2

    return { 'total_adr': total_adr,
             'adr': num_adr / total_adr,
             'total_far': total_far,
             'far': num_far / total_far
           }

simbols = ['1','a','A','r','2','b','B','s','3','c','C','t','4','d','D','u','5','e','E','v','6','f','F','w','7','g','G','x','8','h','H','y','9','i','I','z', ',', '.', '*', '+', '0']
n_symbols = len(simbols) # dimensionality of your word vectors

max_len_sequence = 20
input_shape = (max_len_sequence, n_symbols)
n1 = 128 # From Paper
dropout_p = 0.1
loss_method = 'binary_crossentropy'

optimizer = 'adam'
model = build_model(input_shape, n1, dropout_p, n_symbols, max_len_sequence)
model.compile(loss=loss_method, optimizer=optimizer, metrics=['accuracy', adr_and_far])

错误:

 Using TensorFlow backend.
Traceback (most recent call last):
  File "1%29+Training+RNN+Single+Model.py", line 68, in <module>
    model.compile(loss=loss_method, optimizer=optimizer, metrics=['accuracy', adr_and_far])
  File "/usr/local/lib/python2.7/site-packages/keras/models.py", line 594, in compile
    **kwargs)
  File "/usr/local/lib/python2.7/site-packages/keras/engine/training.py", line 716, in compile
    metric_result = metric_fn(y_true, y_pred)
  File "1%29+Training+RNN+Single+Model.py", line 43, in adr_and_far
    adr_idx = K.tf.reshape(K.tf.where(adr_idx), [-1])
TypeError: select() takes at least 3 arguments (1 given)

1 个答案:

答案 0 :(得分:1)

你需要数数吗?

y_true = tf.constant([1, 1, 1, 0, 0, 0, 1, 1, 1])
y_pred = tf.constant([1, 1, 0, 1, 1, 0, 1, 0, 0])

adr_idx = tf.equal(y_true, y_pred) & tf.equal(y_true, 1)
adr_idx = tf.reshape(tf.where(adr_idx), [-1]) # [0, 1, 6]

far_idx = tf.equal(y_true, 0) & tf.equal(y_pred, 1) 
far_idx = tf.reshape(tf.where(far_idx), [-1])  # [3, 4]

num_adr = tf.shape(adr_idx)[0]  # 3
num_far = tf.shape(far_idx)[0]  # 2

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    a, b = sess.run([num_adr, num_far])

使用keras 1.2.1和tensorflow版本0.11
我认为原因是形状不同 y_true的形状为(?, ?),y_pred的形状为(?, 1)

def adr_and_far(y_true, y_pred):
    total_adr = K.sum(K.tf.cast(K.tf.equal(y_true, 1), 'int32'))
    total_far = K.sum(K.tf.cast(K.tf.equal(y_true, 0), 'int32'))

    adr_idx = K.tf.equal(y_true, 1) & K.tf.equal(y_pred, 1)
    adr_idx = K.sum(K.tf.cast(K.reshape(adr_idx, [-1]), 'int32'))

    far_idx = K.tf.equal(y_true, 0) & K.tf.equal(y_pred, 1)
    far_idx = K.sum(K.tf.cast(K.reshape(far_idx, [-1]), 'int32'))


    return { 'total_adr': total_adr,
             'adr': adr_idx / total_adr,
             'total_far': total_far,
             'far': far_idx / total_far
           }