TensorFlow/Keras 使用特定类召回作为稀疏分类交叉熵的度量

2024-02-18

*更新在底部

我尝试使用 3 个类别中的 2 个类别的召回率作为指标,即 A、B、C 类中的 B 类和 C 类。

(其本质是我的模型在类别中高度不平衡[〜90%是A类],因此当我使用准确度时,每次预测A类时我都会得到〜90%的结果)

model.compile(
              loss='sparse_categorical_crossentropy', #or categorical_crossentropy
              optimizer=opt,
              metrics=[tf.keras.metrics.Recall(class_id=1, name='recall_1'),tf.keras.metrics.Recall(class_id=2, name='recall_2')]
              )

history = model.fit(train_x, train_y, batch_size=BATCH, epochs=EPOCHS, validation_data=(validation_x, validation_y), callbacks=[tensorboard, checkpoint])

这会抛出一个错误:

raise ValueError("Shapes %s and %s are incompatible" % (self, other))

ValueError: Shapes (None, 3) and (None, 1) are incompatible

模型总结为:

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
lstm (LSTM)                  (None, 120, 32)           19328
_________________________________________________________________
dropout (Dropout)            (None, 120, 32)           0
_________________________________________________________________
batch_normalization (BatchNo (None, 120, 32)           128
_________________________________________________________________
lstm_1 (LSTM)                (None, 120, 32)           8320
_________________________________________________________________
dropout_1 (Dropout)          (None, 120, 32)           0
_________________________________________________________________
batch_normalization_1 (Batch (None, 120, 32)           128
_________________________________________________________________
lstm_2 (LSTM)                (None, 32)                8320
_________________________________________________________________
dropout_2 (Dropout)          (None, 32)                0
_________________________________________________________________
batch_normalization_2 (Batch (None, 32)                128
_________________________________________________________________
dense (Dense)                (None, 32)                1056
_________________________________________________________________
dropout_3 (Dropout)          (None, 32)                0
_________________________________________________________________
dense_1 (Dense)              (None, 3)                 99
=================================================================
Total params: 37,507
Trainable params: 37,315
Non-trainable params: 192

请注意,如果使用以下命令,模型可以正常工作,不会出现错误:

metrics=['accuracy']

but this https://github.com/tensorflow/tensorflow/issues/37104 and this https://github.com/tensorflow/tensorflow/issues/42383让我觉得有些东西还没有按照 tf.metrics.SparseCategorical 的方式实现Recall()

from

tf.metrics.SparseCategoricalAccuracy()


因此,我转向了一个自定义指标,该指标陷入了其他问题的兔子洞,因为我在类和装饰器方面非常文盲。

我从一个自定义指标示例中把它搞砸了(我不知道如何使用sample_weight,所以我将其注释掉以便稍后再回来):

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

    def __init__(self, name="Relevant_Recall", **kwargs):
        super(RelevantRecall, self).__init__(name=name, **kwargs)
        self.joined_recall = self.add_weight(name="B/C Recall", initializer="zeros")

    def update_state(self, y_true, y_pred, sample_weight=None):
        y_pred = tf.argmax(y_pred, axis=1)
        report_dictionary = classification_report(y_true, y_pred, output_dict = True)

        # if sample_weight is not None:
        #     sample_weight = tf.cast(sample_weight, "float32")
        #     values = tf.multiply(values, sample_weight)
        # self.joined_recall.assign_add(tf.reduce_sum(values))

        self.joined_recall.assign_add((float(report_dictionary['1.0']['recall'])+float(report_dictionary['2.0']['recall']))/2)
 
    def result(self):
        return self.joined_recall

    def reset_states(self):
        # The state of the metric will be reset at the start of each epoch.
        self.joined_recall.assign(0.0)


model.compile(
              loss='sparse_categorical_crossentropy', #or categorical_crossentropy
              optimizer=opt,
              metrics=[RelevantRecall()]
              )


history = model.fit(train_x, train_y, batch_size=BATCH, epochs=EPOCHS, validation_data=(validation_x, validation_y), callbacks=[tensorboard, checkpoint])

这个目标是返回一个指标[recall(b)+recall(c)/2]。我想像这样分别返回两次召回metrics=[recall(b),recall(c)]会更好,但无论如何我都无法让前者工作。

我收到一个张量布尔错误:OperatorNotAllowedInGraphError: using a 'tf.Tensor' as a Python 'bool' is not allowed: AutoGraph did convert this function. This might indicate you are trying to use an unsupported feature.哪个谷歌搜索让我添加:@tf.function高于我的自定义指标类。

这导致了旧类类型与新类类型错误:

super(RelevantRecall, self).__init__(name=name, **kwargs)
TypeError: super() argument 1 must be type, not Function

由于班级有一个对象,我没有看到我是如何实现的?

正如我所说,我对这方面的各个方面都很陌生,因此任何关于如何使用仅选择预测类的度量来实现(以及如何最好地实现)的帮助将非常感激。

OR

如果我的想法完全错误,请告诉我/引导我找到正确的资源

理想情况下,我想采用以前的使用方法tf.keras.metrics.Recall(class_id=1....因为如果它有效的话,这似乎是最简洁的方法。

在模型的回调部分使用类似的函数时,我能够获得每个类的召回率,但这似乎更密集,因为我必须在每个时期结束时对 val/test 数据进行 model.predict。 还不清楚这是否告诉模型专注于改进所选的类(即在度量与回调中实现它的差异)


回调代码:

class MetricsCallback(Callback):
    def __init__(self, test_data, y_true):
        # Should be the label encoding of your classes
        self.y_true = y_true
        self.test_data = test_data

    def on_epoch_end(self, epoch, logs=None):
        # Here we get the probabilities - longer process
        y_pred = self.model.predict(self.test_data)

        # Here we get the actual classes
        y_pred = tf.argmax(y_pred,axis=1)
        report_dictionary = classification_report(self.y_true, y_pred, output_dict = True)
        print ("\n")
  
        print (f"Accuracy: {report_dictionary['accuracy']} - Holds: {report_dictionary['0.0']['recall']} - Sells: {report_dictionary['1.0']['recall']} - Buys: {report_dictionary['2.0']['recall']}")
        self._data = (float(report_dictionary['1.0']['recall'])+float(report_dictionary['2.0']['recall']))/2
        return

metrics_callback = MetricsCallback(test_data = validation_x, y_true = validation_y)

history = model.fit(train_x, train_y, batch_size=BATCH, epochs=EPOCHS, validation_data=(validation_x, validation_y), callbacks=[tensorboard, checkpoint, metrics_callback) 

更新 19/07/2021

  • 我已经求助于使用categorical_crossentropy for loss代替sparse_categorical_crossentropy.
  • 对我的类/目标数组进行单热编码。
  • 使用 tf 召回:[tf.keras.metrics.Recall(class_id=1, name='recall_1')

我现在使用下面的代码。

train_y = tf.one_hot(train_y, 3)
validation_y = tf.one_hot(validation_y, 3)
test_y = tf.one_hot(test_y, 3)

model.compile(
    loss='categorical_crossentropy',
    optimizer=opt,
    metrics=[tf.keras.metrics.Recall(class_id=1, name='No'),tf.keras.metrics.Recall(class_id=2, name='Yes')]
    ) #tf.keras.metrics.Recall(class_id=0, name='Wait')

history = model.fit(train_x, train_y, batch_size=BATCH, epochs=EPOCHS, validation_data=(validation_x, validation_y), callbacks=[tensorboard, checkpoint])

谢谢阿布舍克·普拉贾帕特

这实现了相同的总体目标,并且由于少量的互斥类,可能对性能有非常小的差异/影响,

but在存在大量互斥类的情况下,我仍然没有解决方案来实现与上述相同的目标sparse_categorical_crossentropy


你的问题很简单。我为你整理了一个例子:

import tensorflow as tf
from sklearn.datasets import make_classification

data = make_classification(n_samples=1000, n_features=20, n_classes=3, n_clusters_per_class=1)

model = tf.keras.Sequential([
    tf.keras.layers.InputLayer(input_shape=(20)),
    tf.keras.layers.Dense(3, activation='softmax')
])

model.compile(
              loss=tf.keras.losses.CategoricalCrossentropy(), #or categorical_crossentropy
              optimizer='adam',
              metrics = [tf.keras.metrics.Recall(class_id=1)]
              )

y = tf.keras.utils.to_categorical(data[1], num_classes=3)

dataset = tf.data.Dataset.from_tensor_slices((data[0], y))
dataset = dataset.batch(10)

model.fit(dataset, epochs=10)

现在你可以看到,当你使用metrics.Recall如果使用特定的类 ID,那么您的输入 y 应该是 one-hot 编码的。因此,如果我们有 3 个类,那么对于 0 来说,它应该是 -> [1, 0, 0] ,依此类推 1 -> [0, 1, 0] 和 2 -> [0, 0, 1]。

不使用额外内存

import tensorflow as tf
from sklearn.datasets import make_classification

data = make_classification(n_samples=1000, n_features=20, n_classes=3, n_clusters_per_class=1)

model = tf.keras.Sequential([
    tf.keras.layers.InputLayer(input_shape=(20)),
    tf.keras.layers.Dense(3, activation='softmax')
])

model.compile(
              loss=tf.keras.losses.CategoricalCrossentropy(), #or categorical_crossentropy
              optimizer='adam',
              metrics = [tf.keras.metrics.Recall(class_id=1)]
              )

def encode(x, y):
    y = tf.one_hot(y, 3) # Here 3 is the number of classes
    return x, y

dataset = tf.data.Dataset.from_tensor_slices((data[0], data[1]))
dataset = dataset.map(encode)
dataset = dataset.batch(10)

model.fit(dataset, epochs=10)

新的例子-

import numpy as np
import tensorflow as tf
from sklearn.datasets import make_classification

data = make_classification(n_samples=1000, n_features=20, n_classes=3, n_clusters_per_class=1)

model = tf.keras.Sequential([
    tf.keras.layers.InputLayer(input_shape=(20)),
    tf.keras.layers.Dense(3, activation='softmax')
])

def encode(x, y):
    y = tf.one_hot(y, 3)
    return x, y

dataset = tf.data.Dataset.from_tensor_slices((data[0], data[1]))
dataset = dataset.map(encode)
dataset = dataset.batch(10)

m1 = tf.keras.metrics.Recall()
m2 = tf.keras.metrics.Recall()

def my_recall(y_true, y_pred):
    
    actual_a = y_true[:, 1]
    pred_a = y_pred[:, 1]
    
    actual_b = y_true[:, 2]
    pred_b = y_pred[:, 2]
    
    m1.update_state(actual_a, pred_a)
    m2.update_state(actual_b, pred_b)
    
    return (m1.result() + m2.result())/2

model.compile(
              loss=tf.keras.losses.CategoricalCrossentropy(), #or categorical_crossentropy
              optimizer='adam',
              metrics = [my_recall]
              )

model.fit(dataset, epochs=10)

对于您更新的问题 -

import numpy as np
import tensorflow as tf
from sklearn.datasets import make_classification

data = make_classification(n_samples=1000, n_features=20, n_classes=3, n_clusters_per_class=1)

model = tf.keras.Sequential([
    tf.keras.layers.InputLayer(input_shape=(20)),
    tf.keras.layers.Dense(3, activation='softmax')
])

dataset = tf.data.Dataset.from_tensor_slices((data[0], data[1]))
dataset = dataset.batch(10)

m1 = tf.keras.metrics.Recall()
m2 = tf.keras.metrics.Recall()

def my_recall(y_true, y_pred):
    y_true = tf.cast(y_true, dtype=tf.int32)
    actual_onehot = tf.one_hot(y_true, 3)
    actual_a = actual_onehot[1]
    pred_a = tf.reshape(y_pred[1], (1,3))
    actual_b = actual_onehot[2]
    pred_b = tf.reshape(y_pred[2], (1,3))  
    m1.update_state(actual_a, pred_a)
    m2.update_state(actual_b, pred_b)   
    return (m1.result() + m2.result())/2

model.compile(
              loss=tf.keras.losses.SparseCategoricalCrossentropy(),
              optimizer='adam',          
              metrics = [my_recall]
              )

model.fit(dataset, epochs=10)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TensorFlow/Keras 使用特定类召回作为稀疏分类交叉熵的度量 的相关文章

随机推荐

  • Bootstrap .popover()“显示”和“销毁”无法正常工作

    当我在 手动 模式下使用引导弹出窗口时 销毁 和 隐藏 无法正常工作 当我使用隐藏和销毁时 弹出窗口不透明度更改为 0 但它没有将显示更改为无 这导致弹出窗口容器覆盖其下方的内容 否则 如果我使用 toogle 模式 它可以正常工作 My
  • 当我们实例化一个对象时,是否会创建超类的实例?

    当我们在java中实例化一个特定的类时 是否会创建超类的实例 如果是这种情况 那么实例化所有超类将会产生大量开销 我尝试了以下代码 public class AClass public AClass System out println C
  • 倾斜阴影,而不是内容

    考虑 div class my class AAA div 我只想倾斜阴影 但不倾斜内容div将阴影放入伪元素中 my class height 5rem width 10rem before content box shadow 0 2e
  • 从用户代理检测设备(移动设备)是什么的php脚本?

    我尝试编写一个 php 脚本 从标头中的用户代理返回设备 我看到的问题并不是简单地执行正则表达式 因为设备之间存在差异 我错了吗 所以我想要根据用户代理更新的移动设备列表 我找到了这个清单 手机用户代理列表 http en wikipedi
  • 避免跨线程操作错误的最简洁和正确的方法?

    我不太擅长代表 也不明白幕后发生的事情 我得到了cross thread operation从不同线程访问 UI 项目时出错 我想做的是在 a 中编写一个通用函数Utility类 以便我可以将任何方法 代码块传递给该函数 我可以通过多种方式
  • 具有不规则节点的分层 data.frame 到 JSON

    我有这个嵌套数据集 grandparent parent child grandchild age Grandma 100 Grandma John 72 Grandma John Jessica 41 Grandma John Joann
  • XmlSerializer 更改编码

    我正在使用这段代码Serialize XML to String XmlWriterSettings xmlWriterSettings new XmlWriterSettings indent true Encoding Encoding
  • emacs 创建键修饰符

    我在 mac 操作系统上使用 emacs 我想将修饰符 Meta Control 映射到一个简单的键 基本上这就是我需要的 global set key kbd a hyper 这里 a 只是 a 键 没有 Control a 或其他什么
  • 用C解析CSV文件[关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 有没有一个库可以用来解析 C 中的 CSV 文件 我在 Linux 系统上 我知道关于this http
  • 我需要为 NSObject 调用 [super init] 或 [super initWithCoder] 等

    通常当我从UIclass I 将调用感兴趣的超类初始值设定项 但是 我不确定实施细节NSObject 似乎在成员变量方面没有太多进展 所以我想知道 我需要打电话吗 super init 如果我的子类扩展NSObject 从技术上来说 不 这
  • 如何捕获 Python Unittest 测试用例失败的屏幕截图

    我使用 Python 3 6 5 和以下库 Appium Python 客户端 0 26 单元测试2 1 1 0 硒 3 5 0 pytest 3 6 3 现在我需要截图以防测试失败 所以我故意做了一个错误的陈述self driver fi
  • 无法理解使用 Eclipse 的 Maven pom 文件

    I am very new to Maven and i am creating my first maven project of maven archetype quickstart 然后它会生成错误消息 但在我的项目资源管理器中 我无
  • SICP中的图片语言如何使用框架?

    我似乎无法理解 SICP 中框架的实现 书中指出 我们将使用单位正方形中的坐标 0 图像如何表示为坐标 我能想到的唯一解释是 所有图像 都是线条 只能映射到一个框架 该框架的边界不能超过单位正方形的边界 但我对此表示怀疑 因为书中的下一行解
  • 如何在 Objective C 中打印出 bool

    我在 NSUserDefault 中为关键 TCshow 设置了一个 bool 值 我想运行 nslog 测试密钥是否已保存 并且我正在尝试打印布尔值 这是我的代码 但它不起作用 有什么建议吗 IBAction acceptAction i
  • 创建 T4 生成类型的泛型 List

    我使用 T4 技术创建了简单的类 lt template debug false hostspecific false language C gt lt output extension cs gt using System lt var
  • 我可以在 Android 应用程序类中创建自定义全局方法吗?

    我目前有一个具有许多活动的应用程序 需要有一种方法来维护这些活动之间的状态 我使用 Application 类来执行此操作 声明全局变量并使用 getter 和 setter 与我的活动进行交互 我希望在那里放置一些自定义方法 以便当我想要
  • 如何将文件路径变量传递给 mex 命令?

    目前正在尝试创建脚本化 mex 文件生成的最小示例 我有一个 MATLAB m 脚本 正在运行它来生成 mex 文件 我想将所有参数作为变量传递 以便在给定文件名 路径列表时自动构建一堆 mex 文件 1 unknown argument
  • AngularJs:ng-if 内的表单无法从控制器访问

    我里面有一个表格ng if指示 我想使用检查控制器中的表单验证 valid div div
  • Android 错误跟踪器在哪里? (Android Google Code 项目除外)

    为了解决 Android 上的问题 我已经到达这个差异 https android googlesource com platform frameworks base ed4f28b492da3ff140bbaabbbda798a08c40
  • TensorFlow/Keras 使用特定类召回作为稀疏分类交叉熵的度量

    更新在底部 我尝试使用 3 个类别中的 2 个类别的召回率作为指标 即 A B C 类中的 B 类和 C 类 其本质是我的模型在类别中高度不平衡 90 是A类 因此当我使用准确度时 每次预测A类时我都会得到 90 的结果 model com