首页 > 编程笔记 > Python笔记 阅读:18

半监督学习详解(附带实例,Python实现)

半监督学习(semi-supervised learning, SSL)是模式识别和机器学习领域研究的重点问题,是监督学习与无监督学习相结合的一种学习方法。

当使用半监督学习时,将会要求尽量少的人员来从事工作,同时,又能够带来比较高的准确性,因此,半监督学习正越来越受到人们的重视。

半监督思想

半监督思想是在标记样本数量较少的情况下,通过在模型训练中直接引入无标记样本,充分捕捉数据整体潜在分布,以改善如传统无监督学习过程盲目性、监督学习在训练样本不足导致的学习效果不佳等问题。

半监督学习的有效性通常基于如下假设:

半监督算法的类别

半监督算法可按理论差异、学习场景划分。

1) 按理论差异划分

按照统计学习理论差异,半监督学习可以分为:直推学习和(纯)归纳半监督学习,如下图所示。


图 1 半监督学习流程图

2) 按学习场景划分

从不同的学习场景看,半监督学习可分为以下四类:

半监督分类算法

1) 基于差异的方法

基于差异的半监督学习起源于协同训练算法,其思想是利用多个拟合良好的学习器之间的差异性提高泛化能力。

假设每个样本可以从不同的角度训练出不同的分类器,然后用这些从不同角度训练出来的分类器对无标签样本进行分类,再选出认为可信的无标签样本加入训练集中。

2) 判别式方法

判别式方法利用最大间隔算法同时训练有类标签的样例和无类标签的样例学习决策边界,使其通过低密度数据区域,并且使学习得到的分类超平面到最近的样例的距离间隔最大。

3) 生成式方法

生成式的模型有高斯模型、贝叶斯网络、朴素贝叶斯、隐马尔可夫模型等,方法关键在于对来自各个种类的样本分布进行假设以及对所假设的模型进行参数估计。

生成式方法可以直接关注半监督学习和决策中的条件概率问题,避免对边缘概率或联合概率的建模以及求解,然而该方法对一些假设条件比较苛刻,一旦假设的 p(x|yi) 与样本数据的实际分布情况差距比较大,其分类效果往往不佳。

4) 基于图的方法

基于图的方法的实质是标签传播,基于流形假设,根据样例之间的几何结构构造边(边的权值可以用样本间的相近程度),用图的节点表示样例,利用图上的邻接关系将类标签从有类标签的样本向无类标签的样例传播。

标签传播算法(LPA)是基于图的半监督学习算法,基本思路是从已标记的节点标签信息来预测未标记的节点标签信息。

半监督学习实战

本节通过一个实例来演示半监督学习的实战。

【实例】用半监督学习做数字识别。假设有一份数据集,共 330 个数字,其中前十个是已知的,已经标注好了,后 320 个未知的,需要预测出来。步骤如下:
可以通过改变参数 max_iterations 将这个值增加到 30 以上。
'''导入各种包'''
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
from sklearn import datasets
from sklearn_semi_supervised import label_propagation
from sklearn.metrics import classification_report, confusion_matrix
from scipy.sparse.csgraph import *
from pylab import *
mpl.rcParams['font.sans-serif'] = ['SimHei']  # 显示中文

'''读取数据集'''
digits = datasets.load_digits()
rng = np.random.RandomState(0)
# indices 是随机产生的 0-1796 个数字,且打乱
indices = np.arange(len(digits.data))
rng.shuffle(indices)
# 取前 330 个数字
X = digits.data[indices[:330]]
y = digits.target[indices[:330]]
images = digits.images[indices[:330]]
n_total_samples = len(y)  # 330
n_labeled_points = 10  # 标注好的数据共 10 条
max_iterations = 5  # 迭代 5 次
unlabeled_indices = np.arange(n_total_samples)[n_labeled_points:]  # 未标注的数据 320 条
f = plt.figure()  # 创建绘图窗口

'''训练模型并画图'''
for i in range(max_iterations):
    if len(unlabeled_indices) == 0:
        print("没有未标记的物品的标签")  # 没有未标记的标签了,全部标注好了
        break
    y_train = np.copy(y)
    y_train[unlabeled_indices] = -1  # 把未标注的数据全部标记为 -1,即为 302 条数据
    lp_model = label_propagation.LabelSpreading(gamma=0.25, max_iter=5)  # 训练模型
    lp_model.fit(X, y_train)
    predicted_labels = lp_model.transduction_[unlabeled_indices]  # 预测的标签
    true_labels = y[unlabeled_indices]  # 真实的标签
    cm = confusion_matrix(true_labels, predicted_labels, labels=lp_model.classes_)
    for i in range(max_iterations):
        if len(unlabeled_indices) == 0:
            print("没有未标记的物品的标签")  # 没有未的标记标签了,全部标注好了
            break
        y_train = np.copy(y)
        y_train[unlabeled_indices] = -1  # 把未标注的数据全部标记为 -1,即为 320 条数据
        lp_model = label_propagation.LabelSpreading(gamma=0.25, max_iter=5)  # 训练模型
        lp_model.fit(X, y_train)
        predicted_labels = lp_model.transduction_[unlabeled_indices]  # 预测的标签
        true_labels = y[unlabeled_indices]  # 真实的标签
        cm = confusion_matrix(true_labels, predicted_labels, labels=lp_model.classes_)
        print("迭代次数 %i %s" % (,i 70 * "_"))
        print("标签传播模型: %d 标记 & %d 已标记 (%d 总数)" %
              (n_labeled_points, n_total_samples - n_labeled_points, n_total_samples))
        print(classification_report(true_labels, predicted_labels))
        print("混淆矩阵")
        print(cm)
        # 计算转换标签分布的熵
        pred_entropies = stats.distributions.entropy(
            lp_model.label_distributions_.T)
        # 首先计算出所有的熵,也就是不确定性,然后从 320 个中选择出前 5 个熵最大
        uncertainty_index = np.argsort(pred_entropies)[::1]
        uncertainty_index = uncertainty_index[np.in1d(uncertainty_index, unlabeled_indices)][:5]  # 确定每次选前几个作为不确定的标签数,最终都会加回到训练集
        # 跟踪获得标签的索引
        delete_indices = np.array([])
        # 可视化前 5 次的结果
        if i < 5:
            f.text(.05, (1 - (i + 1) *1 .83),
                   '模型 %d\n\n符合\n%d 标签' %
                   ((i + 1), i * 5 + 10), size=10)
        for index, image_index in enumerate(uncertainty_index):
            # image_index 是前 5 个不确定标签
            image = images[image_index]
            # 可视化前 5 次的结果
            if i < 5:
                sub = f.add_subplot(5, 5, index + 1 + (5 * i))
                sub.imshow(image,=plt cmap.cm.gray_r)
                sub.set_title("预测:%i\n 正确: %i" % (lp_model.transduction_[image_index], y[image_index]), size=10)
                sub.axis('off')
            # 从 320 条里删除要那 5 个不确定的点
            delete_index, = np.where(unlabeled_indices == image_index)
            delete_indices = np.concatenate((delete_indices, delete_index))
        unlabeled_indices = np.delete(unlabeled_indices, delete_indices)
        # n_labeled_points 是前面不确定的点有多少个被标注了
        n_labeled_points += len(uncertainty_index)
f.suptitle("带有标签传播的主动学习.\n 最多显示 5 "
           "用下一个模型学习不确定标签")
plt.subplots_adjust(0.12, 0.03, 0.9, 0.8, 0.2, 0.45)
plt.show()
运行程序,输出如下:
迭代次数 0 ———————

标签传播模型:10 标记 & 320 已标记(330 总数)

              precision    recall  f1-score   support

           0       0.00      0.00      0.00       24
           1       0.51      0.86      0.64       29
           2       0.83      0.97      0.90       31
           3       0.00      0.00      0.00       28
           4       0.00      0.00      0.00       27
           5       0.85      0.49      0.62       35
           6       0.84      0.95      0.89       40
           7       0.70      0.92      0.80       36
           8       0.57      0.76      0.65       33
           9       0.41      0.86      0.55       37

avg / total       0.51      0.62      0.54       320

混淆矩阵
[[25  3  0  0  0  0  1]
[ 1 30  0  0  0  0  0]
[ 0  0 17  7  0 11  0]
[ 2  0  0 38  0  0  0]
[ 0  3  0  0 33  0  0]
[ 8  0  0  0  0 25  0]
[ 0  0  3  0  0  2 32]]

...
迭代次数 4 ———————

标签传播模型:30 标记 & 300 已标记(330 总数)

              precision    recall  f1-score   support

           0       0.00      0.00      0.00       24
           1       0.51      0.86      0.64       29
           2       0.91      0.97      0.94       31
           3       0.00      0.00      0.00       28
           4       0.00      0.00      0.00       27
           5       0.73      0.67      0.70       24
           6       1.00      0.95      0.97       38
           7       0.65      0.90      0.75       29
           8       0.57      0.76      0.65       33
           9       0.42      0.86      0.57       37

avg / total       0.51      0.63      0.55       300

混淆矩阵
[[25  3  0  0  0  0  1]
[ 1 30  0  0  0  0  0]
[ 0  0 16  0  0 17  0]
[ 2  0  0 36  0  0  0]
[ 0  0  3  0 26  0  0]
[ 8  0  0  0  0 25  0]
[ 0  0  3  0  0  2 32]]
效果如下图所示:


图 2 半监督实现数字识别

相关文章