欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

标注有错误?教你使用置信学习将样本错误标识出来!

程序员文章站 2024-03-20 11:12:22
...

前言

置信学习也叫信心学习(Confident Learning ,CL),它是一个新兴的、原则性的框架,用于识别标签错误、描述标签噪声。

网上对于这个置信学习描述也挺少的,主要有这一篇:《数据集中存在错误标注怎么办? 置信学习帮你解决》。它主要介绍了置信学习是什么,有什么用。总体来讲是翻译了国外的一个博客,这里大致讲述一下其内容,有很多晦涩难懂的。

首先抛出了一个惊人的事实,那就是我们常用的ImageNet 中可能至少有 10 万个标签有问题。这是令人吃惊的,因为我们都会认为标注的标签是正确的。但是,对于从事标注的人员来说,这应该是司空见惯的,因为标注本来就存在主观性,至少存在客观歧义性。要知道,目前ImageNet中总共有14197122幅图像,总共分为21841个类别。(私下认为,在2万多个类别情况下,做到了只有1%的错误,这才是应该吃惊的吧。)

不管怎么说,我们使用置信学习,就可以获得这10万个有问题的标签。并且附了下图来展示结果。
标注有错误?教你使用置信学习将样本错误标识出来!
上图显示了使用置信学习发现的 2012 ILSVRC ImageNet 训练集中的标签错误的例子。为了便于解释,我们将使用 CL 在 ImageNet 中发现的标签问题分为三类:

多标签图像(蓝色):在图像中有多个标签
本体论问题(绿色):包括“是”或 “有”两种关系,在这些情况下,数据集应该包含其中一类
标签错误(红色):数据集别的类的标签比给定的类标签更适合于某个示例

这样看起来确实很不错,通过置信学习,我们可以去识别出数据集中那些潜在的标注错误,对于进行数据清理和修改是一个非常不错的选择。最重要的是,这个框架适用于几乎所有的模型。(因为找到这些标注的问题完全是通过预测概率和真实标签获得的,与模型无关。)

而后,它给出了一个置信学习的流程图,帮助我们理解置信学习的过程,不过这里我不多赘述,可以直接看原文。
标注有错误?教你使用置信学习将样本错误标识出来!

最后讲了一些置信学习的优点和原理。

总的来说,置信学习主要有2个功能,一个功能是用于发现标注错误的标签,另一个功能则是增强模型的性能表现。但是原文没有特别注意如何实现,或者实现的具体内容,我这里重点讲一下如何发现标注错误的标签的具体代码,想看论文原文的同学可以点击《原文》,想看官方指南的可以点击《官方指南》。

如何发现标注错误标签

上面说了这么多好处,最终我们还是要落到实处啊。在官方介绍中,它声称1行代码就可以发现潜在的错误标签,如下所示。

# Compute psx (n x m matrix of predicted probabilities) 
#     in your favorite framework on your own first, with any classifier.
# Be sure to compute psx in an out-of-sample way (e.g. cross-validation)
# Label errors are ordered by likelihood of being an error.
#     First index in the output list is the most likely error.
from cleanlab.pruning import get_noise_indices

ordered_label_errors = get_noise_indices(
    s=numpy_array_of_noisy_labels,
    psx=numpy_array_of_predicted_probabilities,
    sorted_index_method='normalized_margin', # Orders label errors
 )

这就是一个被封装好的函数(对啊,不然怎么1行实现所有代码?),可以直接获得标注错误的索引。就是这么简单,你只需要准备好s和psx即可。

这里的S其实就是Y,只不过它为了说明标注中存在错误(Noisy Label),才使用S,这里的维度是(n,1),即标签的索引即可。而PSX则是使用自己的模型预测出的标签概率分布,它的维度理应是(n,k),其中k为类型数量,n为样本数量,不过要说明的是,在函数的注释里,建议使用3倍以上的交叉验证获得样本。

那我们需要做什么?只需要以下4步:

  1. 利用我们自己的模型,使用交叉验证的方式,记录下真实标签和模型预测的概率分布(即没有被argmax的预测结果)。
  2. 将交叉验证的所有结果拼接在一起,使用numpy.save保存为两个文件,如real.npypredict.npy
  3. 将两个文件使用Numpy.load读取,填充到numpy_array_of_noisy_labelsnumpy_array_of_predicted_probabilities中。
  4. 利用上面1行代码进行预测,获得的结果就是所有的可能错误的索引,其可能的正确标签就是概率分布中最大的那个。

这个置信学习的准确程度还是和你的模型性能好坏有关,它们在Imagenet和MNIST上出色的表现完全是因为它们原有模型的性能已经非常好了,例如在MNIST使用的是AlexNet,该模型可以跑出93%的准确性。而如果你使用的模型本身就不是非常厉害的话,那还是挺不可信的(尽管是信心学习)。

结语

嗯?这就完了?没错!好吧,还有个彩蛋,那就是介绍一下如何用它增强你的模型表现吧,只需要下面3行。

from cleanlab.classification import LearningWithNoisyLabels
from sklearn.linear_model import LogisticRegression

# Wrap around any classifier (scikit-learn, PyTorch, TensorFlow, FastText, etc.)
lnl = LearningWithNoisyLabels(clf=LogisticRegression()) 
lnl.fit(X=X_train_data, s=train_noisy_labels) 
# Estimate the predictions you would have gotten by training with *no* label errors.
predicted_test_labels = lnl.predict(X_test)

这里使用的是LogisticRegression()模型,你也可以使用任何你喜欢的模型,只需要实现下面4个方法即可。

from sklearn.base import BaseEstimator
class YourFavoriteModel(BaseEstimator): # Inherits scikit-learn base classifier
    '''Let's your model be used by LearningWithNoisyLabels'''
    def __init__(self, ):
        pass
    def fit(self, X, y, sample_weight = None):
        pass
    def predict(self, X):
        pass
    def predict_proba(self, X):
        pass
    def score(self, X, y, sample_weight = None):
        pass

# Now you can use `cleanlab.classification.LearningWithNoisyLabels` like this:
from cleanlab.classification import LearningWithNoisyLabels
lnl = LearningWithNoisyLabels(clf=YourFavoriteModel())
lnl.fit(train_data, train_labels_with_errors)

行了,今天的讲解就到这了!下期见!