搜狐技术产品

告别“脏数据”:我如何用Cleanlab将数据审核效率提升34倍?

摘要:在机器学习的世界里,“垃圾进,垃圾出”(Garbage In, Garbage Out)是铁律。数据质量决定了模型性能的天花板。本文将分享一个真实的文本分类项目案例,记录我们如何从一个令人绝望的数据质检困境——面对15,192条可疑数据束手无策,到最终利用cleanlab和其背后的“置信学习”理论,将待审核数据量锐减至438条,审核效率提升34倍的完整过程。这不只是一篇实战教程,更是一次对cleanlab底层技术原理的深度探索,希望能为你揭开数据质量管理的神秘面纱。

00

引子:一个令人头疼的开始

我们的项目目标是构建一个高效的文本分类模型,自动识别社交平台上的“灌水广告”。在收集并标注了近4万条数据后,我们用一个ERNIE模型完成了初步训练。然而,在进行数据质量审核时,我们遇到了巨大的麻烦。

我们采取了一个最“朴素”的方法:将所有模型预测结果与人工标注不一致的数据,都视为可疑数据,进行人工复核。

结果令人崩溃:在39,116条数据中,竟有15,192条被标记为“可疑”!这意味着要人工审核近40%的数据集,成本高昂且不现实。我们深知,这1.5万条数据中,绝大部分是“模型犯的错”,而非真正的“标注错误”。

如何从这片“噪音的海洋”中,精准地找到那些真正需要被修正的“金子”?答案就是我们今天要深入探讨的主角——cleanlab。

01

第一章:快车道 - 3个步骤搞定智能质检

为了快速进入核心,本章将以最精炼的方式展示如何利用cleanlab对我们的“灌水广告”数据集进行质量评估。

1.1 准备工作:环境、数据与模型

首先,安装必要的库:

pip install onnxruntime paddlenlp cleanlab pandas numpy tqdm scipy

我们的原始数据all.txt格式为文本\t标签,同时加载预训练好的ONNX模型和分词器。

# all.txt 文件内容示例

怎么说,你这边有空了解吗 正常
我关注你了,互关一下,详细介绍 灌水广告 \<-- 这是一个潜在的标注错误
你好有空帮服装商家点赞吗点赞两个作品奖励 五 元 正常 \<-- 这也是一个潜在的标注错误
...
1.2 获取模型预测概率(关键输入)

cleanlab工作的核心输入是模型对每条数据的预测概率向量pred_probs。为避免内存溢出,我们必须**分批处理(Batch Processing)**来生成这个结果。


import
 onnxruntime as ort
from
 paddlenlp.transformers import ErnieTokenizer
import
 numpy as np
from
 scipy.special import softmax
from
 tqdm import tqdm
import
 math

# 加载分词器和ONNX模型

print
("正在加载模型和分词器...")
tokenizer = ErnieTokenizer.from_pretrained('ernie-3.0-tiny-medium-v2-zh')
session = ort.InferenceSession("model-ad.onnx")  # 你的ONNX模型路径

# 定义类别标签与其ID的映射

class_labels = ['正常', '灌水广告']  # 保证ID顺序:0=正常, 1=灌水广告
label_to_id = {name: i for i, name in enumerate(class_labels)}


def
 load_data_from_file(filepath, label_map):
    """从'文本\t标签'格式的文件中加载数据"""

    texts = []
    given_label_names = []
    with
 open(filepath, 'r', encoding='utf-8') as f:
        for
 line in f:
            line = line.strip()
            if
 not line or '\t' not in line:
                continue

            text, label_name = line.split('\t', 1)
            if
 label_name in label_map:
                texts.append(text)
                given_label_names.append(label_name)

    # 将文本标签转换为数字ID

    given_labels_int = np.array([label_map[name] for name in given_label_names])
    print
(f"数据加载完成。共加载 {len(texts)} 条数据。")
    return
 texts, given_labels_int


# 执行加载

data_filepath = 'all.txt'
texts, given_labels = load_data_from_file(data_filepath, label_to_id)


def
 get_pred_probs_batched(texts_list, tokenizer, session, batch_size=64):
    """
    分批处理,为整个数据集生成预测概率,以节省内存。
    """

    print
(f"\n正在使用ONNX模型进行批量预测(分批处理,批大小={batch_size})...")
    num_samples = len(texts_list)
    num_batches = math.ceil(num_samples / batch_size)

    all_probabilities = []

    for
 i in tqdm(range(num_batches), desc="模型推理中"):
        start_index = i * batch_size
        end_index = min((i + 1) * batch_size, num_samples)
        batch_texts = texts_list[start_index:end_index]

        inputs = tokenizer(
            batch_texts, return_tensors="np", max_length=128,
            padding='max_length', truncation=True
        )
        input_ids = inputs['input_ids'].astype(np.int64)
        token_type_ids = inputs['token_type_ids'].astype(np.int64)

        logits = session.run(None, {
            "input_ids"
: input_ids,
            "token_type_ids"
: token_type_ids
        })[0]

        probabilities = softmax(logits, axis=1)
        all_probabilities.append(probabilities)

    # 将所有批次的结果合并成一个大的numpy数组

    final_probabilities = np.vstack(all_probabilities)
    print
("批量预测完成。")
    return
 final_probabilities


# 获取所有数据的预测概率

pred_probs = get_pred_probs_batched(texts, tokenizer, session, batch_size=64)
1.3 cleanlab登场:一键分析与报告

现在,万事俱备。我们有了原始文本texts、可能有问题的标注given_labels,以及模型给出的预测概率pred_probs。只需几行代码,cleanlab就能完成它的魔法。


from
 cleanlab import Datalab
import
 pandas as pd


print
("\n--- 使用 cleanlab.Datalab 查找标签问题 ---")

# cleanlab 推荐将数据包装在字典中,方便后续关联

data_for_lab = {"text": texts}

# 初始化 Datalab

lab = Datalab(data=data_for_lab, labels=given_labels)

# 核心步骤:传入预测概率,查找标签问题

# pred_probs 的形状应为 (n_samples, n_classes)

issue_indices_df = lab.find_label_issues(pred_probs=pred_probs)

print
(f"\nDatalab 分析完成,找到了 {len(issue_indices_df)} 个潜在的标签问题。")

if
 not issue_indices_df.empty:
    # 获取置信度阈值,后续会详细讲解

    confidence_thresholds = lab.thresholds

    review_list = []
    for
 idx, row in issue_indices_df.iterrows():
        # 获取模型对这个特定问题的预测标签

        model_pred_idx = np.argmax(pred_probs[idx])

        review_list.append({
            'original_index'
: idx,
            'text'
: texts[idx],
            'given_label'
: class_labels[given_labels[idx]],
            'model_suggestion'
: class_labels[model_pred_idx],
            'label_quality_score'
: row['label_quality_score'],
            'is_label_issue'
: row['is_label_issue']
        })

    # 转换为DataFrame并按质量分排序,最可疑的排在最前面

    review_df = pd.DataFrame(review_list).sort_values(by='label_quality_score', ascending=True)

    # 导出到CSV,使用'utf-8-sig'防止Excel打开乱码

    export_filename = 'label_issues_to_review.csv'
    review_df.to_csv(export_filename, encoding='utf-8-sig', index=False)

    print
(f"\n[成功] 已将 {len(review_df)} 条潜在问题数据导出到文件: {export_filename}")
    print
("\n置信度阈值:")
    for
 i, label_name in enumerate(class_labels):
        print
(f"  - 类别 '{label_name}': {confidence_thresholds[i]:.4f}")
else
:
    print
("恭喜!cleanlab 未在您的数据集中发现明显的标签错误。")

运行完毕,我们得到了一个label_issues_to_review.csv文件,里面不多不少,正好是438条最值得怀疑的数据。审核工作量从1.5万锐减到4百多,效率提升了34倍!

实战部分到此结束。但作为一个有追求的技术人,我们不能只停留在“会用”的层面。接下来,让我们潜入水下,探索cleanlab冰山之下的巨大理论体系。

02

第二章:深度剖析 - cleanlab背后的置信学习(Confident Learning)

cleanlab的惊人效果,源于其坚实的理论基础——置信学习(Confident Learning, CL)。这是一个由MIT博士生Curtis Northcutt等人提出的,在噪声标签中进行学习的强大框架。

CL的核心思想,彻底摒弃了“预测与标签不符就是错误”的朴素想法。它认为:

在噪声数据中,我们不应该完全相信模型的预测,也不应该完全相信给定的标签。我们应该相信的,是模型在“极度自信”时所做的判断。

CL的整个框架可概括为三步:

  1. 估计标签噪声:估算出数据集中各类标签之间互相错标的概率。

  2. 找出错误标签:基于估算出的噪声,识别出每个具体的、可能错误的标签。

  3. 修正并学习:在修正或忽略错误标签的基础上进行模型训练。

2.1 核心前提:需要“样本外”的预测概率

为了避免模型对自己看过的样本产生“过拟合”的盲目自信,CL的所有计算都必须基于样本外(Out-of-Sample)的预测概率。实践中,这通常通过**交叉验证(Cross-Validation)**来实现。这是保证后续所有计算公正、可靠的基石。

注:cleanlab.Datalab类在内部已为我们优雅地处理了这一点。当我们传入pred_probs时,它假设这些概率已通过交叉验证得出。如果没传,它会自己用传入的模型进行交叉验证来生成。

2.2 第一步(核心):估计噪声矩阵 Q

CL最精妙的部分,在于它能在完全不知道真实标签(true labels)的情况下,估算出标签噪声的整体情况。它通过估算一个联合概率分布矩阵 Q 来实现。

1. 计算每个类别的“置信度阈值” t_j

这是CL的神来之笔。对于每个类别 j(如“灌水广告”),cleanlab会计算一个置信度阈值 t_j。这个阈值直观上代表了:“当我的模型敢于喊出‘这是j类’时,它通常有多大的把握?”

它的计算方式是:在所有被模型预测为类别 j 的样本中,其预测概率的平均值。

t_j = E[p_i[j] | argmax(p_i) = j]

在我们的项目中,计算出的阈值可能是:

• t_正常 = 0.92

• t_灌水广告 = 0.88

2. 统计“自信计数矩阵” C

有了阈值,我们就可以“自信地”计数了。我们创建一个 m x m 的计数矩阵 C (m是类别数)。遍历每个样本 x_i:

• 获取其给定标签 y_i。

• 获取其模型预测标签 y_hat_i 和对应的预测概率 p_hat_i。

• 关键判断:如果 p_hat_i >= t_{y_hat_i} (即,模型对这个预测的自信程度,达到了它平时的“平均自信水平”),我们就认为这次计数是可靠的。

• 将 C[y_i, y_hat_i] 的计数值加一。

通过这个过程,我们得到了一个计数矩阵 C。

C[i, j]

粗略代表了数据集中有多少个“给定标签是i,同时被模型自信地预测为j”的样本。

示例:自信计数矩阵 C
假设我们有10000个样本,最终得到的C矩阵可能如下所示:
| C | 预测为: 正常 | 预测为: 灌水广告 |
| :--- | :---: | :---: |
| 给定标签: 正常 | 7800 | 200 |
| 给定标签: 灌水广告 | 300 | 1600 |

这张表告诉我们:有大约300个被标注为“灌水广告”的样本,被模型非常自信地认为是“正常”内容——这正是噪声的重灾区。

3. 从 C 到 Q

最后,将计数矩阵 C 除以总样本数 N 进行归一化,就得到了我们想要的联合概率分布矩阵 Q。

示例:联合概率分布矩阵 Q (= C / 10000)
| Q | 预测为: 正常 | 预测为: 灌水广告 |
| :--- | :---: | :---: |
| 真实标签(估计): 正常 | 0.78 | 0.02 |
| 真实标签(估计): 灌水广告| 0.03 | 0.16 |

Q[i, j]

揭示了类别 i 有多大概率被错标且被模型自信地识别为 j。

2.3 第二步:识别具体的错误标签

有了宏观的噪声矩阵 Q,我们就可以深入到微观,找出每个可能错误的样本了。cleanlab最常用的算法是Prune by Confidence (PBC)。

PBC的逻辑非常简单,但威力巨大:

对于一个样本,如果模型对它“给定标签”的预测概率,低于这个标签类别的“置信度阈值”,那么它就是一个潜在的标签错误。

判断流程示例:

  1. 样本 A:

    • 文本: "我关注你了,互关一下..."

    • 给定标签: 灌水广告

    • 模型预测概率: {正常: 0.98, 灌水广告: 0.02}

    • 置信度阈值: t_灌水广告 = 0.88

    • 判断: 模型对“灌水广告”这个标签的置信度(0.02) 远低于 该类别的平均自信水平(0.88)。

    • 结论: 标记为“标签问题”。

  2. 样本 B:

    • 文本: "这个产品效果真的太棒了,强烈推荐给大家..."

    • 给定标签: 正常

    • 模型预测概率: {正常: 0.95, 灌水广告: 0.05}

    • 置信度阈值: t_正常 = 0.92

    • 判断: 模型对“正常”这个标签的置信度(0.95) 高于 该类别的平均自信水平(0.92)。

    • 结论: 标签可信,通过。

现在,您应该也完全理解了导出报告中 label_quality_score 这一列的含义了。它就是模型对该样本“给定标签”的预测概率。这个分数越低,意味着模型对人工标注的越“不认同”,该标注是错误的可能性就越大。

2.4 第三步(进阶):修正并学习

cleanlab的能力不止于此。它还提供了一个CleanLearning类,可以包裹任何分类器模型。在训练时,它会自动根据计算出的噪声信息,修正损失函数或对样本重加权,从而主动减轻噪声标签的负面影响,实现端到端的自动化数据质量优化。

03

第三章:价值与反思

通过引入cleanlab,我们获得了远超技术本身的商业价值:

  1. 降本增效:将数周的人工审核压缩到几天,直接节约了巨大的人力成本,并缩短了模型迭代周期。

  2. 提升模型性能:用“更干净”的数据训练,有效提高了模型的性能天花板和鲁棒性,降低了线上业务风险。

  3. 建立可量化的数据质量标准:我们拥有了一套科学、可复现的数据质量评估体系,为未来项目提供了坚实的数据基础。

反思与注意事项:

• 依赖于一个“还不错的”模型:如果模型性能比随机猜测还差,其“自信”判断毫无意义,cleanlab也无法工作。

• 处理数据漂移:当数据分布或模型发生重大变化时,需要重新运行评估流程。

04

结语:拥抱Data-Centric AI的时代

吴恩达教授近年来一直在倡导“以数据为中心的AI”(Data-Centric AI)。他认为,在模型架构趋同的今天,高质量的数据是构建卓越AI系统的核心竞争力。

我们这次的实践,正是Data-Centric AI理念的一次成功落地。从15,192到438,这不只是一次数字的变化,更是一种思维模式的转变——从被动、繁重的人工审核,到主动、高效的智能定位。希望本文的分享,能为您在未来的AI项目中,提供一把披荆斩棘的利器。

参考资料:

• Cleanlab GitHub: https://github.com/cleanlab/cleanlab

• Confident Learning 原始论文: Confident Learning: Estimating Uncertainty in Dataset Labels