tensorflow中的自定义f1_分数度量

tensorflow中的自定义f1_分数度量,tensorflow,machine-learning,keras,metrics,Tensorflow,Machine Learning,Keras,Metrics,我想为tf.keras实现f1_分数指标 from tensorflow.keras.models import Model, Sequential from tensorflow.keras.layers import Dense from tensorflow.keras.optimizers import Adam from tensorflow.keras.losses import binary_crossentropy from tensorflow.keras.metrics im

我想为tf.keras实现f1_分数指标

from tensorflow.keras.models import Model, Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.losses import binary_crossentropy
from tensorflow.keras.metrics import Accuracy, BinaryAccuracy
from sklearn.metrics import accuracy_score
import numpy as np
import tensorflow as tf

class F1_Score(tf.keras.metrics.Metric):

    def __init__(self, name='f1_score', **kwargs):
        super().__init__(name=name, **kwargs)
        self.f1 = self.add_weight(name='f1', initializer='zeros')

    def update_state(self, y_true, y_pred, sample_weight=None):
        p = Precision(thresholds=0.5)(y_true, y_pred)
        r = Recall(thresholds=0.5)(y_true, y_pred)
        self.f1 = 2 * ((p * r) / (p + r + 1e-6))

    def result(self):
        return self.f1

    def reset_states(self):
        self.f1.assign(0)
        
model = Sequential([
  Dense(64, activation='relu', input_shape=(784,)),
  Dense(64, activation='relu'),
  Dense(4, activation='sigmoid'),
])
x = np.random.normal(size=(10, 784))
y = np.random.choice(2, size=(10, 4))
model.compile(optimizer=Adam(0.001), loss='binary_crossentropy',
                  metrics=['accuracy', , F1_Score()])
model.fit(x[:1], y[:1], batch_size=1, epochs=1, verbose=1)
我有一个错误:

ValueError:tf.function-decorated函数试图创建变量 非首次通话


出现此错误是因为您希望在update_state函数期间实例化一些
tf.Variable
s。当从类Precision和Recall实例化对象时,您正在创建一些
tf.Variable
s

实例化构造函数中的对象,并在update_state函数中调用它们:

F1级分数(tf.keras.metrics.Metric):
定义初始值(self,name='f1\u score',**kwargs):
super()
self.f1=self.add_weight(name='f1',initializer='zeros')
self.precision\u fn=精度(阈值=0.5)
自我回忆\u fn=回忆(阈值=0.5)
def更新状态(自身、y_真、y_pred、样本重量=无):
p=自精度fn(y\u真,y\u pred)
r=自我回忆(y_真,y_前)
#因为f1是一个变量,所以我们使用赋值
自我分配(2*((p*r)/(p+r+1e-6)))
def结果(自我):
返回self.f1
def复位_状态(自身):
#我们还需要重置精度和召回对象的状态
自精度重置状态()
自我回忆(fn)复位(states)
self.f1.assign(0)

行为说明:

Tensorflow仅允许在第一次调用
tf.函数时创建变量,请参见:

函数仅允许在第一次调用时创建新的tf.Variable对象

Keras度量被包装在tf.function中,以允许与tensorflow v1兼容。您可以在

如果
update\u state
不在eager/tf.function中且不是来自 内置公制,将其包装在
tf.function
中。这是为了方便用户编写 v1中的自定义指标不需要担心控件依赖关系和 返回操作


您的类中还有另一个错误,即您重写了您在计算f1分数时创建的
f1 tf.Variable
。要更新变量的值,需要使用
assign
。我们一定不要忘记重置使用中的精度和召回度量对象的状态

您可以使用
tensorflow插件
,它有一个用于F1分数的内置方法。(别忘了
pip安装tensorflow插件

看看下面:

  model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.00001),
                  loss=tf.keras.losses.CategoricalCrossentropy(),
                  metrics=[tf.keras.metrics.CategoricalAccuracy(),
                           tfa.metrics.F1Score(num_classes=n_classes, average='macro'),
                           tfa.metrics.FBetaScore(beta=2.0, num_classes=n_classes, average='macro')])
如果确实存在多标签分类问题,可以将其更改为:

  model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.00001),
                      loss=tf.keras.losses.BinaryCrossentropy(),
                      metrics=[tf.keras.metrics.BinaryAccuracy(),
                               tfa.metrics.F1Score(num_classes=1, average='macro',threshold=0.5),
                               tfa.metrics.FBetaScore(beta=2.0, num_classes=1, average='macro',threshold=0.5)])

这是我对Tensorflow 2.0的代码评分f1:

class F1Score(tf.keras.metrics.Metric):
  def __init__(self, name='F1Score', **kwargs):
    super(F1Score, self).__init__(name=name, **kwargs)
    self.f1score = self.add_weight(name='F1Score', initializer='zeros')
    self.count = self.add_weight(name='F1ScoreCount', initializer='zeros')

  def update_state(self, y_true, y_pred, sample_weight=None):
    y_true = tf.cast(y_true, tf.bool)
    y_pred = tf.cast(y_pred, tf.bool)

    true_positives = tf.logical_and(tf.equal(y_true, True), tf.equal(y_pred, True))
    true_positives = tf.cast(true_positives, self.dtype)
    count_true_positives = tf.reduce_sum(true_positives)

    possible_positives = tf.cast(y_true, self.dtype)
    count_possible_positives = tf.reduce_sum(possible_positives)

    predicted_positives = tf.cast(y_pred, self.dtype)
    count_predicted_positives = tf.reduce_sum(predicted_positives)

    precision = count_true_positives / (count_predicted_positives + K.epsilon())
    recall = count_true_positives / (count_possible_positives + K.epsilon())
    f1_cal = 2*(precision*recall)/(precision + recall + K.epsilon())

    self.count.assign_add(1)
    a = 1.0 / self.count
    b = 1.0 - a
    self.f1score.assign(a*f1_cal+b*self.f1score)

  def result(self):
    return self.f1score

顺便说一句,您是否尝试过使用内置指标来了解它们的工作原理?这些指标适用于二进制/多类/多标签分类。tfa.metrics.F1Score
FBetaScore
之间的区别是什么?F1分数是FBetaScore的一种特殊情况,其中Beta==1。谢谢,你能看一下这个问题吗?我得到一个错误
AttributeError:'Tensor'对象在reset_states()中没有属性'assign
!!我还使用了
tf.compat.v1.assign
,得到了相同的结果error@BetterEnglish查看我的更新。我在你的代码中遗漏了一些错误。欢迎使用SO!请阅读,然后