用大量的数据来训练有监督的机器学习模型可能是昂贵的、耗时的,而且常常是不必要的努力。如果你深思熟虑地决定对哪些数据点进行标注,就可以用较小的数据集达到相当的效果。有一类流行的技术被称为主动学习,用于决定标记哪些数据以训练出最佳模型。
主动学习利用已经训练好的模型来帮助你决定在固定的标签预算下,哪一批额外的数据最适合收集标签。为了在有限的数据标签下获得一个好的模型,我们在一个小的初始标签训练数据集上训练一个初始模型,然后迭代以下步骤:主动学习来决定哪些数据是最有信息量的,以便接下来进行标签(基于我们当前的模型),为这些数据收集标签并将它们添加到我们的训练数据集,在迄今为止所有标签的数据上重新训练我们的模型。
通过在多轮中选择信息量最大的样本进行标注,主动学习可以 提高模型的准确度,并减少训练一个达到特定准确度的模型所需的整体标注成本。
在这篇文章中,我将演示如何 使用开源的Python工具对任何图像分类数据集实施主动学习:一个来自亚马逊的名为AutoGluon的AutoML包,以及一个最近发布的名为ActiveLab的主动学习算法。如果你想直接跳到实现,可以在这里查看我的代码。
主动学习是如何工作的?
在主动学习中,一个模型是在一个小的、初始的标记数据子集上训练的。然后,训练好的模型被赋予所有未标记的数据点,从中主动选择哪些额外的数据点应该被添加到标记组中。然后在这些额外的标签上重新训练模型,这个过程不断重复,直到创建一个足够大的组。最终训练数据集的大小通常比随机选择这些额外的标签要小得多。
主动学习的单一迭代过程。原图改编自ActiveLab。
在主动学习过程中,一个模型可以使用不同的策略来选择额外的数据点进行标注。最基本的方法是直接随机选择下一个要标注的数据。另一种常见的方法是不确定性抽样,即选择模型最不确定或对其预测信心最低的例子。ActiveLab是这种不确定性抽样的一个高级变种,通过大量的基准测试,它被证明比其他流行的主动学习方法训练出更好的分类器。
AutoML与AutoGluon
AutoGluon是一个开源的自动机器学习库,由亚马逊开发,旨在简化构建机器学习模型的过程。它将机器学习管道的许多方面自动化,如转移学习、特征工程、模型选择和超参数调整,这些方面可能很耗时,需要高级的专业知识。AutoGluon和ActiveLab不仅可以用于图像,还可以用于其他数据模式,如文本或表格数据。因此,你可以使用这里展示的同一管道来有效地标记多种类型的数据!
实验
在我的实验中,我使用了Caltech256数据集,这是一个有256个不同类别的分类数据集,每个类别大约有80张图片和一个背景类别。我首先将数据分为训练-测试两部分,其中df_train 用于主动学习实验,df_test 作为保留数据,只用于在每轮主动学习后报告模型性能。
Load and split dataset into train and test (for reporting purposes).
dataset = ImageClassificationDataset.from_folder('./256_ObjectCategories/')
# get train-test split (use df_test only for reporting model performance after every active learning round)
df_train, df_test = train_test_split(dataset, test_size=0.33, random_state=123)
加载并将数据集分成训练和测试(用于报告)。
数据集对象可以是AutoGluon要求的任何格式的数据集labels, image_path ,只有当你试图报告性能结果时,才有必要进行训练-测试分割。
选择最初标记的数据集
选择一个小型的标记数据集开始,这个数据集可以代表你想要分类或预测的数据。在我的代码中,我选择从每个类别中随机选择8个样本开始。
df_labeled = df_train.groupby("label").sample(n=8, random_state=123)
labeled_index = list(df_labeled.index)
unlabeled_index = [i for i in range(len(dataset)) if i not in labeled_index]
df_unlabeled = dataset.iloc[unlabeled_index]
df_labeled = dataset.iloc[labeled_index]
从整个训练数据中选择初始的有标签和无标签的数据。
在有标签的数据上训练模型,并获得对无标签数据的预测类别概率。
然后,我在最初的标记数据集df_labeled 上训练AutoGluon模型,并让它对仍然未标记的训练数据进行预测,df_unlabeled 。
predictor = MultiModalPredictor(label="label",
problem_type="classification",
warn_if_exist=False)
predictor.fit(
train_data=df_labeled,
time_limit=60*60, # seconds
)
pred_probs_unlabeled = predictor.predict_proba(df_unlabeled)
在有标签的数据上训练模型,并使用拟合的分类器来获得对无标签数据的预测类概率。
该模型的完整训练代码可在此获得。
获得主动学习的分数
然后,我使用ActiveLab函数get_active_learning_scores (来自cleanlab库)作为我的主动学习策略,计算有标签和无标签数据的主动学习分数。
# compute active learning scores
_, active_learning_scores_unlabeled = get_active_learning_scores(
df_labeled['label'].to_numpy(), pred_probs_unlabeled=pred_probs_unlabeled
)
获取未标记的例子的主动学习分数的函数。
选择更多的样本进行标注。
然后我根据最低的模型置信度和我的批次大小选择一个未标记的数据子集,并将新标记的样本加入训练集,为下一轮做准备。
# get the indices of examples to collect more labels for
idx_to_label = get_idx_to_label(
active_learning_scores=active_learning_scores_unlabeled,
batch_size_to_label=batch_size_to_label,
)
df_labeled, df_unlabeled = setup_next_iter_data(df_labeled, df_unlabeled, relabel_idx_unlabeled)
设置主动学习循环的下一个迭代。
重复
我重复上面的过程,在扩展的标记数据上重新训练模型,直到达到所需的性能水平。最后的伪代码循环写在下面,或者查看完整的例子笔记本以获得更多的细节和完整的代码。
model_accuracy_arr = np.full(num_rounds, np.nan)
for i in range(num_rounds):
# train model on labeled data & predict labels for unlabeled data
predictor = train(df_labeled, out_folder=None, time_limit=60*60)
pred_probs_unlabeled = predictor.predict_proba(df_unlabeled)
# select more samples for labeling, first compute active learning score then select lowest conf subset
_, active_learning_scores_unlabeled = get_active_learning_scores(
df_labeled['label'].to_numpy(), pred_probs_unlabeled=pred_probs_unlabeled
)
relabel_idx_unlabeled = get_idx_to_label(
active_learning_scores_unlabeled=active_learning_scores_unlabeled,
batch_size_to_label=batch_size_to_label,
)
# add newely labeled samples to the training set
df_labeled, df_unlabeled = setup_next_iter_data(df_labeled, df_unlabeled, relabel_idx_unlabeled)
# evaluate model accuracy for the current round on held-out test data. This is an optional step
# for demonstration purposes, in practical applications you may not have ground truth labels
pred_labels = predictor.predict(data=df_test)
true_labels_test = np.array(df_test['label'].tolist())
model_accuracy_arr[i] = np.mean(pred_labels == true_labels_test)
多轮主动学习的伪代码循环
结果
在每一轮中,在选择新的样本后,在本轮的标记数据上训练一个模型,并在该轮的保留df_test 集上测量它的准确性。在这个例子中,上述步骤重复了10轮,每轮增加150个例子,准确率如下所示。
正如你所看到的,随着更多的数据被标记,模型的准确性在每一轮都有很好的提高。
在10轮主动学习中,模型在保留的测试数据上的准确性
资源
- 你可以用代码来复制本文的步骤,通过主动学习有效地标记任何图像分类数据集:https://colab.research.google.com/github/cleanlab/examples/blob/master/active_learning_single_annotator/active_learning_single_annotator.ipynb
- 关于在有多个数据注释者的情况下如何使用ActiveLab进行主动学习与数据重新标注的教程:https://github.com/cleanlab/examples/blob/master/active_learning_multiannotator/active_learning.ipynb
- 关于如何使用AutoGluon进行图像分类和其他监督学习任务的教程:https://auto.gluon.ai/