第二十八周:文献阅读笔记(弱监督学习)+ pytorch学习

发布时间:2024年01月14日

摘要

弱监督学习是一种机器学习方法,其训练过程中使用的标签信息相对不完整或不精确。与传统的监督学习不同,弱监督学习可以利用不完全的标记信息来进行模型训练,这些信息可能是不精确的、嘈杂的或者只有部分标注的数据。本文将通过 A brief introduction to weakly supervised learning 这篇文献,了解弱监督学习。

Abstract

Weakly supervised learning is a machine learning method that uses relatively incomplete or imprecise labeling information during training. Unlike traditional supervised learning, weakly supervised learning can utilize incomplete labeling information for model training, which may be imprecise, noisy, or only partially labeled data. In this paper, we will learn about weakly supervised learning through A brief introduction to weakly supervised learning this literature.

1. 弱监督学习

文献链接:A brief introduction to weakly supervised learning

1.1. 文献摘要

监督学习技术通过从大量训练示例中学习来构建预测模型,其中每个训练示例都有一个指示其真实输出的标签。尽管当前技术取得了巨大成功,但值得注意的是,在许多任务中,由于数据标记过程的成本高昂,很难获得像完全真实标签这样的强监督信息。因此,机器学习技术需要在弱监督下工作。本文回顾了弱监督学习的一些研究进展,重点讨论了三种典型的弱监督类型:不完全监督,仅给训练数据的子集加上标签;不精确的监督,训练数据仅带有粗粒度的标签;以及不准确的监督,给定的标签并不总是真实的。

1.2. 引言

机器学习在各种任务中取得了巨大的成功,特别是在分类和回归等监督学习任务中。通常,预测模型是从包含大量训练示例的训练数据集中学习的,每个训练示例对应一个事件/对象。训练示例由两部分组成:描述事件/对象的特征向量(或实例),以及指示真实输出的标签。

在分类中,标签表示训练样例所属的类,在回归中,标签是与示例相对应的实值响应。大多数成功的技术,例如深度学习 ,都需要为大型训练数据集提供真实标签。然而,在许多任务中,由于数据标记过程的成本高昂,很难获得强有力的监督信息。因此,机器学习技术需要能够在弱监督下工作。

通常,弱监督分为三种类型。分别如下:

  1. 不完整监督:只有训练数据的一个(通常很小)子集带有标签,而其他数据保持未标记。这种情况在各种任务中都会发生。例如,在图像分类中,真实标签是由人类注释者给出的;从互联网上很容易获得大量图像,但由于人力成本,只能对一小部分图像进行注释。
  2. 不精确的监督:只给出粗粒度的标签。再次考虑图像分类任务。最好对图像中的每个对象进行注释;然而,通常我们只有图像级标签而不是对象级标签。
  3. 不准确的监督:给定的标签并不总是真实的。这种情况就会发生,例如当图像注释者粗心或疲倦,或者某些图像难以分类时。

弱监督学习是一个涵盖各种研究的总称,这些研究试图通过弱监督学习来构建预测模型。在本文中,作者讨论了这方面研究的一些进展,重点关注不完整、不精确和不准确监督下的学习。为了简单起见,在本文中,作者考虑关于两个可交换类 Y Y Y N N N 的二元分类。

形式上,具有强监督学习的任务是从训练数据集 D = { ( x 1 , y 1 ) , . . . , ( x m , y m ) ) } D=\left \{ (x_{1},y_{1}),... ,(x_{m},y_{m})) \right \} D={(x1?,y1?,...,(xm?,ym?))} 中学习 f : X ~ Y f:X \sim Y fXY,其中 X X X 是特征空间, Y = { Y , N } Y=\left \{ Y,N \right \} Y={Y,N} x i ? X x_{i}\epsilon X xi??X y i ? Y y_{i}\epsilon Y yi??Y,作者假设 ( x i , y i ) (x_i , y_i ) (xi?,yi?) 根据未知的相同且独立的分布 D D D 生成;换句话说, ( x i , y i ) (x_i , y_i ) (xi?,yi?) 是独立同分布的samples。图 1 展示了我们将在本文中讨论的三种弱监督类型。
在这里插入图片描述

1.3. 不完全监督

不完全监督涉及这样的情况:给我们少量的标记数据,不足以训练一个好的学习器,而有大量的未标记数据可用。形式上,任务从训练数据集 D = ( x 1 , y 1 ) , . . . , ( x l , y l ) , x l + 1 , . . . , x m D ={(x_1, y_1),..., (x_l , y_l ), x_{l+1},..., x_m} D=(x1?,y1?),...,(xl?,yl?),xl+1?,...,xm? 学习 f : X → Y f : X → Y f:XY,其中有 l l l 个标记训练示例(即用 y i y_{i} yi? 给出的示例)和 u = m ? l u = m ? l u=m?l 未标记实例的数量;其他条件与强监督的监督学习相同,如引言末尾所定义。为了方便讨论,作者将 l l l 个标记实例称为“标记数据”,将 u u u 个未标记实例称为“未标记数据”。

1.3.1. 主动学习与半监督学习

主动学习假设存在一个“预言机”,例如人类专家,可以查询该“预言机”以获得所选未标记实例的真实标签。相比之下,半监督学习尝试自动利用除了标记数据之外的未标记数据来提高学习性能,而无需人工干预。有一种特殊的半监督学习称为传导式学习。这种学习和(纯)半监督学习之间的主要区别在于它们对测试数据(即由训练模型预测的数据)的不同假设。传导式学习持有“封闭世界”假设,即测试数据是提前给出的,目标是优化测试数据上的性能;换句话说,未标记的数据正是测试数据。纯半监督学习持有“开放世界”假设,即测试数据未知,未标记的数据不一定是测试数据。图2直观地展示了主动学习、(纯)半监督学习和转导学习之间的区别。
在这里插入图片描述

1.3.2. 通过人工干预

主动学习假设可以从预言机中查询未标记实例的真实标签。为简单起见,假设标记成本仅取决于查询数量。因此,主动学习的目标是最小化查询数量,从而最小化训练好的模型的标记成本。给定一小组标记数据和大量未标记数据,主动学习尝试选择最有价值的未标记实例进行查询。有两个广泛使用的选择标准,即信息性和代表性。

信息性衡量未标记实例有助于减少统计模型的不确定性的程度,而代表性衡量实例有助于表示输入模式结构的程度。

基于信息量的方法的主要弱点在于,它们严重依赖标记数据来构建初始模型来选择查询实例,并且当只有少数标记示例可用时,性能通常不稳定。基于代表性的方法的主要弱点在于,性能很大程度上取决于未标记数据主导的聚类结果,尤其是当只有少数标记示例时。因此,最近的几种主动学习方法试图利用信息性和代表性。

1.3.3. 无需人工干预

半监督学习尝试在人工不干预的情况下利用未标记的数据。人们可能会好奇为什么没有标签的数据可以帮助构建预测模型。为了简单解释,假设数据来自具有 n 个混合分量的高斯混合模型,即在这里插入图片描述
其中 α i \alpha_{i} αi? 是混合系数, ∑ i = 1 n α i = 1 {\textstyle \sum_{i=1}^{n}}\alpha_i=1 i=1n?αi?=1 Θ = { θ } \Theta=\left \{ \theta \right \} Θ={θ} 是模型参数,在这种情况下,标签 y i y_i yi? 可以被认为是一个随机变量,其分布 P ( y i ∣ x i , g i ) P (y_i |x_i , g_i ) P(yi?xi?,gi?) 由混合分量 g i g_i gi? 和特征向量 x i x_i xi? 确定。根据最大后验准则,我们有模型在这里插入图片描述
其中在这里插入图片描述
该目标是通过根据训练数据估计项 P ( y i = c ∣ g i = j , x i ) P (y_{i} = c |g_{i} = j, x_{i} ) P(yi?=cgi?=j,xi?) P ( g i = j ∣ x i ) P (g_{i} = j |x_{i} ) P(gi?=jxi?) 来实现的。显然,只有第一个术语需要标签信息。因此,未标记的数据可用于帮助改进第二项的估计,从而提高学习模型的性能。图 3 提供了直观的解释。如果我们必须基于唯一的正点和负点进行预测,我们所能做的只是随机猜测,因为测试数据点恰好位于两个标记数据点之间;如果允许我们观察一些未标记的数据点(如图中的灰色部分),我们可以以高置信度将测试数据点预测为正值。在这里,虽然未标记的数据点没有显式地具有标签信息,但它们隐式地传达了一些有关数据分布的信息,这有助于预测建模。
在这里插入图片描述
实际上,半监督学习有两个基本假设,即 聚类假设流形假设 ;两者都与数据分布有关。前者假设数据具有固有的簇结构,因此落入同一簇的实例具有相同的类标签。后者假设数据位于流形上,因此附近的实例具有相似的预测。这两个假设的本质在于相信相似的数据点应该具有相似的输出,而未标记的数据有助于揭示哪些数据点相似。

半监督学习方法主要有四大类,即生成方法、基于图的方法、低密度分离方法和基于分歧的方法。

  1. 生成方法:生成方法假设标记数据和未标记数据都是从相同的固有模型生成的。因此,未标记实例的标签可以视为模型参数的缺失值,并通过 EM(期望最大化)算法等方法进行估计。这些方法的不同之处在于使用不同的生成模型拟合数据。为了获得良好的性能,通常需要领域知识来确定适当的生成模型。也有人尝试结合生成方法和判别方法的优点。
  2. 基于图的方法:基于图的方法构造一个图,其中节点对应于训练实例,边对应于实例之间的关系(通常是某种相似性或距离),然后根据某些标准在图上传播标签信息;例如标签可以在由最小切割分隔的不同子图中传播。显然,性能在很大程度上取决于图的构建方式。请注意,对于 m 个数据点,此类方法通常需要大约 O ( m 2 ) O(m^2) O(m2) 存储和几乎 O ( m 3 ) O(m^3) O(m3) 计算复杂度。因此,它们严重受到可扩展性的影响;此外,它们本质上是传导性的,因为在没有图形重建的情况下很难容纳新实例。
  3. 低密度分离方法:低密度分离方法强制分类边界穿过输入空间中的密度较低的区域。最著名的代表是S3VM(半监督支持向量机)。图 4 展示了传统监督 SVM 和 S3VM 之间的差异。显然,S3VM 试图识别穿过密度较低区域的分类边界,同时保持标记数据的正确分类。这样的目标可以通过以不同的方式尝试对未标记的数据点进行不同的标签分配来实现,从而导致复杂的优化问题。因此,这方面的研究工作主要集中在有效的优化方法上。
  4. 基于分歧的方法:基于分歧的方法生成多个学习者,并让他们协作利用未标记的数据,其中学习者之间的分歧对于让学习过程继续进行至关重要。最著名的代表是 协同训练它通过训练来自两个不同特征集(或两个视图)的两个学习器来工作。在每次迭代中,每个学习器都会选择其最有信心预测的未标记实例,并将其预测分配为伪标签以训练其同伴学习器。通过将学习者组合为一个整体,可以进一步增强这种方法。请注意,基于分歧的方法提供了一种将半监督学习与主动学习结合起来的自然方式:除了让学习者互相教学之外,还可以选择一些学习者都没有信心或高度自信但矛盾的未标记实例进行查询。

1.4. 不确切的监督

不确切的监督是指给出了一些监督信息,但没有达到预期的精确程度。典型的情况是只有粗粒度的标签信息可用。

例如,在药物活性预测问题中,目标是通过学习一组已知分子来建立一个模型来预测新分子是否有资格制造特殊药物。一个分子可以有多种低能形状,该分子能否用来制造药物取决于该分子是否具有某些特殊的形状。然而,即使对于已知的分子,人类专家也只知道分子是否合格,而不知道哪些特殊形状具有决定性。

形式上,任务是从训练数据集 D = ( X 1 , y 1 ) , . . . , ( X m , y m ) D={(X_1, y_1), ..., (X_m, y_m)} D=(X1?,y1?),...,(Xm?,ym?) 学习 f : X → Y f : X → Y f:XY,其中 X i = x i 1 , . . . , x i , m i ? X X_i ={x_{i 1},..., x_{i, mi} }? X Xi?=xi1?,...,xi,mi??X 称为包, x i j ∈ X ( j ∈ 1 , . . . , m i ) x_{ij} ∈ X (j ∈ {1, ..., m_i}) xij?X(j1,...,mi?) 是实例, m i m_i mi? X i X_i Xi? 中实例的数量, y i ∈ Y = { Y , N } y_i ∈ Y =\left \{ Y,N \right \} yi?Y={Y,N} X i X_{i} Xi? 是正包,即 y i = Y y_{i} =Y yi?=Y,如果存在 x i p x_{ip} xip? 为正,而 p ∈ 1 , . . . , m i p ∈ {1, ..., m_i} p1,...,mi? 未知。目标是预测未见过的袋子的标签。这称为多实例学习

人们已经为多实例学习开发了许多有效的算法。实际上,几乎所有监督学习算法都有其多实例同行。大多数算法试图将单实例监督学习算法适应多实例表示,主要是将重点从对实例的区分转移到对包的区分;其他一些算法试图通过表示转换使多实例表示适应单实例算法。还有一种分类,将算法分组为实例空间范式,其中实例级响应被聚合;袋子空间范式,其中袋子被视为一个整体;以及嵌入式空间范式,其中学习是在嵌入式特征空间中进行的。实例通常被视为独立同分布的samples。

多实例学习已成功应用于各种任务,例如图像分类/检索/注释、文本分类、垃圾邮件检测、医学诊断、人脸/物体检测 ,对象类发现,对象跟踪等。

在这些任务中,很自然地将真实对象(例如图像或文本文档)视为一个包;然而,与药物活性预测相反,在药物活性预测中,袋子中存在自然形成的实例(即分子的形状),需要为每个袋子生成实例。包生成器指定如何生成实例来构成包。通常,可以从图像中提取许多小块作为其实例,而章节/段落甚至句子可以用作文本文档的实例。

多实例学习的最初目标是预测未见过的袋子的标签;然而,有研究试图确定使阳性袋子呈阳性的关键实例。这对于在没有细粒度标记训练数据的情况下定位图像中感兴趣区域等任务非常有帮助。值得注意的是,标准多实例学习假设每个正袋必须包含一个关键实例,而有研究假设没有关键实例并且每个实例都对袋标签有贡献,或者甚至假设有多个概念,并且只有当包包含满足每个概念的实例时,包才是正的。更多变体可以在中找到。

1.5. 不准确的监督

监督不准确是指监督信息不真实的情况;换句话说,某些标签信息可能会出现错误。该公式与引言末尾所示的几乎相同,只是训练数据集中的 y i y_i yi? 可能不正确。

一个典型的场景是使用标签噪声进行学习。有很多理论研究,其中大多数假设随机分类噪声,即标签受到随机噪声的影响。在实践中,一个基本的想法是识别可能被错误标记的示例,然后尝试进行一些纠正。例如,数据编辑方法构建了一个相对邻域图,其中每个节点对应于一个训练示例,连接具有不同标签的两个节点的边称为切割边。然后,测量切边权重统计数据,直觉上认为如果实例与许多切边相关联,则该实例是可疑的。可疑实例可以被删除或重新标记,如图6所示。值得一提的是,这种方法通常依赖于咨询邻域信息,因此,它们在高维特征空间中不太可靠,因为邻域的识别通常不太可靠。
在这里插入图片描述

1.6. 弱监督学习的创新点

当存在强大的监督信息(例如带有真实标签的大量训练示例)时,监督学习技术取得了巨大的成功。然而,在实际任务中,收集监督信息需要成本,因此,通常希望能够进行弱监督学习。

弱监督学习的创新点在于,利用只有部分标记或不完全准确的标记数据进行训练,并尝试从中学习出准确的模型。与传统的监督学习不同,其中要求全部数据都有准确的标签,弱监督学习通过利用标记不完全的数据集进行训练,克服了大量标记数据的获取和标注的困难,从而实现了更高的效率和可扩展性。

弱监督学习具有以下几个创新点:

  1. 使用部分标记数据:弱监督学习尝试使用仅有部分数据标注的数据集进行训练,有效减少了标记数据的需求量和标记成本。
  2. 探索数据的隐含信息:通过挖掘数据中的隐含信息,如数据的分布特征、数据之间的相关性等,来提高模型的性能和泛化能力。
  3. 模型学习标签的生成:弱监督学习方法尝试学习出能够自动生成标签或标签的潜在分布的模型,而不仅仅依赖于人工标注的标签。

2. pytorch学习

在这里插入图片描述

import torch
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.tensorboard import SummaryWriter


class Test_module(nn.Module):
    def __init__(self):
        super(Test_module, self).__init__()
        self.module1 = Sequential(
            Conv2d(3, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )

    def forward(self, x):
        x = self.module1(x)
        return x

Test_module = Test_module()
print(Test_module)
input = torch.ones((64, 3, 32, 32))
writer = SummaryWriter("./logs_seq")
writer.add_graph(Test_module, input)
writer.close()

运行结果:
在这里插入图片描述
在这里插入图片描述

2.1. 对现有模型进行修改

# 对现有的模型进行修改

import torchvision
from torch import nn
vgg16_true = torchvision.models.vgg16(pretrained=True)
print(vgg16_true)

train_data = torchvision.datasets.CIFAR10('./data', train=True, transform=torchvision.transforms.ToTensor(),
                                          download=True)
vgg16_true.classifier.add_module('add_Linear', nn.Linear(1000, 10))
print(vgg16_true)

运行结果:
在这里插入图片描述

2.2. 优化器的使用

import torch
import torchvision.datasets
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linear

from torch.utils.data import DataLoader

dataset = torchvision.datasets.CIFAR10("./data", train=False, transform=torchvision.transforms.ToTensor(),download=True)
dataloader = DataLoader(dataset, batch_size=1)

class Test_module(nn.Module):
    def __init__(self):
        super(Test_module, self).__init__()
        self.module1 = Sequential(
            Conv2d(3, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )

    def forward(self, x):
        x = self.module1(x)
        return x
loss = nn.CrossEntropyLoss()
Test_module = Test_module()
optim = torch.optim.SGD(Test_module.parameters(), lr=0.01)
for epoch in range(20):
    running_loss = 0.0
    for data in dataloader:
        imgs, targets = data
        outputs = Test_module(imgs)
        result_loss = loss(outputs, targets)
        optim.zero_grad()
        result_loss.backward()
        optim.step()
        running_loss = running_loss + result_loss
    print(running_loss)

运行结果:
一共20轮训练,控制台打印出的是每轮训练的总损失。

在这里插入图片描述

2.3. 完整的模型训练套路

网络架构
在这里插入图片描述
文件结构:
在这里插入图片描述
神经网络:model.py

# 搭建神经网络
import torch
from torch import nn


class Test_module(nn.Module):
    def __init__(self):
        super(Test_module, self).__init__()
        self.model = nn.Sequential(
            nn.Conv2d(3, 32, 5, 1, 2),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 32, 5, 1, 2),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 64, 5, 1, 2),
            nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(64*4*4, 64),
            nn.Linear(64, 10)
        )
    def forward(self, x):
        x = self.model(x)
        return x

if __name__ == '__main__':
    Test_module = Test_module()
    input = torch.ones(64, 3, 32, 32)
    output = Test_module(input)
    print(output.shape)

整体模型训练:


import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

from model import *

# 准备数据集
train_data = torchvision.datasets.CIFAR10(root="./train_data", train=True, transform=torchvision.transforms.ToTensor(), download=True)
test_data = torchvision.datasets.CIFAR10(root="./test_data", train=False,
                                         transform=torchvision.transforms.ToTensor(),
                                         download=True)
train_data_size = len(train_data)
test_data_size = len(test_data)
print("训练数据集的长度为:{}".format(train_data_size))
print("测试数据集的长度为:{}".format(test_data_size))

# 利用 DataLoader 来加载数据集
train_dataloader = DataLoader(train_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)

# 创建网络模型
Test_module = Test_module()

# 创建损失函数
loss_fn = nn.CrossEntropyLoss()

# 优化器
learning_rate = 0.01
optimizer = torch.optim.SGD(Test_module.parameters(), lr=learning_rate)

# 设置训练网络的一些参数
# 记录训练的次数
total_train_step = 0
# 记录测试的次数
total_test_step = 0
# 训练的轮数
epoch = 10

# 添加tensorboard
writer = SummaryWriter("./logs_train")
for i in range(epoch):
    print("------第 {} 轮训练开始------".format(i+1))
    for data in train_dataloader:
        # 训练步骤开始
        imgs, targets = data
        outputs = Test_module(imgs)
        loss = loss_fn(outputs, targets)
        # 优化器优化模型
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        total_train_step += 1
        if total_train_step % 100 == 0:
            print("训练次数:{}, loss:{}".format(total_train_step, loss.item()))
            writer.add_scalar("train_loss", loss.item(), total_test_step)
    # 测试步骤开始
    total_test_loss = 0
    # 整体的正确率
    total_accuracy = 0
    with torch.no_grad():
        for data in test_dataloader:
            imgs, targets = data
            outputs = Test_module(imgs)
            loss = loss_fn(outputs, targets)
            total_test_loss = total_test_loss + loss.item()
            accuracy = (outputs.argmax(1) == targets).sum()
            total_accuracy = total_accuracy + accuracy
    print("整体测试集上的Loss:{}".format(total_test_loss))
    print("整体测试集上的正确率:{}".format(total_accuracy/test_data_size))
    writer.add_scalar("test_loss", total_test_loss, total_test_step)
    writer.add_scalar("test_accuracy", total_accuracy/test_data_size, total_test_step)
    total_test_step += 1

    # 保存训练的模型
    torch.save(Test_module, "Test_module_{}.pth".format(i))
    print("模型已保存")

writer.close()

运行结果:

在这里插入图片描述
tensorboard图示:
在这里插入图片描述

总结

这周了解了弱监督学习,同时也针对一个神经网络,用pytorch进行了代码实现和模型训练,整体来说收获还是很大的,下周将继续阅读文献,同时将之前学习过的神经网络逐个实现,加油~

文章来源:https://blog.csdn.net/weixin_45409613/article/details/135503433
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。