第12.1节 Self-training自训练算法
各位朋友大家好,欢迎来到月来客栈,我是掌柜空字符。
本期推送内容目录如下,如果本期内容对你有所帮助,欢迎点赞、转发支持掌柜!
12.1 Self-training自训练算法 12.1.1 算法思想 12.1.2 算法原理 12.1.3 Self-Training示例代码 12.1.4 从零实现Self-Training 12.1.5 小结 引用
12.1 Self-training自训练算法
经过前面几个章节的介绍,相信大家对于有监督学习和无监督学习这两类机器学习算法有了清晰地认识。在接下来的这篇文章中,笔者将会开始介绍机器学习领域中的第3类学习算法——半监督学习(Semi-supervised learning )。那什么是半监督学习方法呢?
当大家在谈论到分类或者回归任务时,绕不开的一个话题就是标注数据。在有监督的学习任务中,通常都需要大量的标注数据才能有效地使得模型学习到输入到输出之间的映射关系。然而,在实际情况中这一条件却很难满足,因为数据标注既耗费时间同时成本又高昂,并且在很多场景下还需要引入领域专家来对数据进行标注。因此,在这样的情境下半监督学习方式就应运而生了。
所谓半监督学习指的是通过少量有标签的数据和大量无标签的数据来完成整个模型训练的过程,它是介于无监督学习和有监督学习之间的一种学习方式。下面,先来介绍半监督学习中最简单的一个算法——Self-Training模型。
12.1.1 算法思想
Self-Training算得上是几种半监督学习方法中最简单易懂的一种,其核心思想是先通过少量的标注数据来训练一个弱的分类器,然后再通过这个弱分类器来对无标签的样本进行标注,当满足一定条件时(例如预测概率大于某个阈值)则将预测的结果作为该样本的真实标签,接着再次以当前已有的标注数据来训练模型并对无标签的样本进行标注并反复迭代,最后直到达到停止条件时结束。整个Self-Training算法的迭代过程可以通过图12-1来进行表示。
如图12-1所示,第一步先通过少量的标注数据来训练一个弱的分类器;第二步再用这个弱分类器来对无标签的数据样本进行预测,并按某种策略将预测得到的部分标签作为样本的真实标签;第三步则是利用当前所有有标签的样本(包括第二步处理后的样本)来训练分类器,如果达到停止条件则进入第四步,否则继续进入第二步对无标签的样本进行预测;第四步是利用第三步训练得到的分类器在测试集上进行评估。
12.1.2 算法原理
根据Self-Training算法的思想可知,Self-Training本质上还可以看做是一种模型的训练策略,因为它并不涉及对于分类算法本身的改变,此时模型将会作为一个可变的参数来供Self-Training使用。在这个过程中,唯一需要确定的便是第二步中对于预测结果的筛选。通常来讲,可以设定一个概率阈值来决定其最终所属的分类类别。
例如对于一个三分类任务来说,模型在样本上对于每个类别的预测概率为,同时设定概率阈值为。如果是按照分类算法一般的处理流程,那么样本将会被确定为第个类别。但是在Self-Training中还会根据设定的概率阈值来进行筛选,如果预测概率小于概率阈值,即那么样本将会继续被归为无标签样本;如果预测概率大于概率阈值,即那么样本才会被确定为第个类别。这一点详见12.1.4的代码实现。
因此,Self-Training算法的一个最大优点就是它能够快速地直接运用于已有的有监督学习算法进行半监督建模学习。
12.1.3 Self-Training示例代码
在介绍完Self-Training算法的思想及原理后,下面来介绍在sklearn中如何使用Self-Training模块。在sklearn中,我们可以通过sklearn.semi_supervised
中的SelfTrainingClassifier
模块来使用Self-Training算法。使用示例如下所示:
1 def load_data():
2 x, y = load_iris(return_X_y=True)
3 x_train, x_test, y_train, y_test = \
4 train_test_split(x, y, test_size=0.3, random_state=2022)
5 rng = np.random.RandomState(20)
6 random_unlabeled_points = rng.rand(y_train.shape[0]) < 0.3
7 y_mixed = deepcopy(y_train)
8 y_mixed[random_unlabeled_points] = -1
9 return x_train, x_test, y_train, y_test, y_mixed
在上述代码中,第2~4行分别是读取数据集并划分成训练集和测试集两个部分;第5~8行是确定的样本,并将其原始的正确标签置为-1,即没有标签的样本;第9行则是返回最后处理完成的结果。
进一步,Self-Training的建模过程如下:
1 def test_self_training():
2 x_train, x_test, y_train, y_test, y_mixed = load_data()
3 svm = SVC(probability=True)
4 print(f"一共有{np.sum(y_mixed == -1)}个样本无标签.")
5 model = SelfTrainingClassifier(svm, threshold=0.6)
6 model.fit(x_train, y_mixed)
7 y_pred = model.predict(x_test)
8 print(f"模型在测试集上的准确率为: {accuracy_score(y_pred, y_test)}")
9
10 if __name__ == '__main__':
11 test_self_training()
在上述代码中,第3行则是定义一个分类模型(这里是以SVM为例,并通过参数probability
指定需要返回每个样本的预测概率);第5~6行则是先实例化了一个SelfTrainingClassifier
类对象,并指定了分类器和概率阈值;第7~8行则是在测试集上对训练好的模型进行评估。
上述代码运行结束后便会输出类似如下所示的结果:
1 一共有27个样本无标签.
2 模型在测试集上的准确率为: 0.9778
以上完整代码参见Book/Chapter12/C01_self_training.py
文件。
12.1.4 从零实现Self-Training
在介绍完如何通过sklearn来完成Self-Training算法的建模过程后我们再来看如何从零实现Self-Training算法。根据第12.1.2节介绍可知,分类器需要返回每个样本的预测概率,这里将以之前介绍的支持向量机为基础来进行代码实现。
为你认可的知识付费,欢迎订阅本专栏阅读更多优质内容!
1. 类初始化实现