人工智能之核心基础 机器学习 第十三章 自监督学习

34 阅读8分钟

人工智能之核心基础 机器学习

第十三章 自监督学习


13.1 自监督学习概述

📌 定义:从无标签数据中自动生成监督信号

  • 输入:只有大量无标签数据 x1,x2,,xnx_1, x_2, \dots, x_n
  • 关键操作:人为设计一个前置任务(Pretext Task),从原始数据中“挖掉一部分”或“打乱结构”,让模型去预测被挖掉的部分
  • 输出:训练好的编码器(Encoder),可提取通用特征用于下游任务

通俗比喻: 就像玩拼图——你把一张完整图片撕成碎片(制造任务),然后训练自己把碎片拼回去(学习特征)。 拼图能力练好了,看一眼新图片就能理解其结构!


🔍 与无监督学习的区别

维度无监督学习自监督学习
目标发现数据结构(聚类/降维)学习可迁移的特征表示
是否有任务❌ 无明确预测任务✅ 有精心设计的前置任务
输出形式簇标签、低维坐标、异常分数特征向量(可用于分类/检测等)
评估方式内部指标(轮廓系数等)下游任务性能(如分类准确率)

💡 一句话总结自监督 = 无监督数据 + 监督式训练方式


13.2 自监督学习的核心:前置任务设计

“任务设计决定特征质量”

以下是三种入门级前置任务:

1️⃣ 掩码填充(Masked Input Reconstruction)

  • 操作:随机遮盖输入的一部分(如图像块、文本词)
  • 任务:预测被遮盖的内容
  • 代表模型:BERT(文本)、MAE(图像)

🖼️ 图像示例: 原图 → 随机盖住30%方块 → 模型猜被盖住的像素

2️⃣ 对比学习(Contrastive Learning)

  • 操作:对同一张图做两种不同增强(裁剪、颜色抖动等),得到两个“视角”
  • 任务:让这两个视角的特征相似,与其他样本的特征不相似
  • 代表模型:SimCLR, MoCo, SimSiam

🧠 核心思想:“同一事物的不同照片应有相似表示”

3️⃣ 时序预测(Temporal Prediction)

  • 操作:给定视频前几帧 / 时间序列前几步
  • 任务:预测下一帧 / 下一时刻
  • 适用:视频、语音、传感器数据

13.3 入门级自监督算法

算法1:自编码器(Autoencoder)——最经典的重构型自监督

  • 结构
    • 编码器(Encoder):xzx \rightarrow z(压缩到低维)
    • 解码器(Decoder):zx^z \rightarrow \hat{x}(重建原始输入)
  • 损失函数L=xx^2\mathcal{L} = \|x - \hat{x}\|^2
  • 用途:降噪、降维、特征提取

✅ 优点:结构简单,训练稳定 ❌ 缺点:可能学不到高级语义(只记像素)


算法2:简化版 SimSiam(无负样本对比学习)

  • 核心创新:不需要负样本对,也能学好特征!
  • 结构
    • 一个编码器 ff
    • 一个投影头 gg(MLP)
    • 一个停止梯度(stop-gradient)操作
  • 损失:对称的余弦相似度损失

💡 适合入门:避免复杂负采样,效果却很好


算法3:掩码自编码器(MAE)基础思路

  • 编码器:只处理未被掩码的图像块(高效!)
  • 解码器:用轻量网络重建所有块(包括被掩码的)
  • 关键:高比例掩码(如75%),迫使模型学全局语义

🌟 优势:训练快、特征强,已成为视觉预训练主流


13.4 自监督学习的核心价值

✅ 三大核心优势

  1. 学习通用特征表示

    • 无需领域标签,学到的特征适用于多种任务(分类、检测、分割)
  2. 大幅降低下游标注需求

    • 在1%标签数据上微调,效果接近全监督
  3. 利用海量无标签数据

    • 互联网图像、网页文本、用户行为日志 → 全是免费训练数据!

📊 现实案例

  • BERT:用全部维基百科+图书语料预训练 → 各NLP任务SOTA
  • MAE:用ImageNet无标签版预训练 → 分类准确率提升5%+

13.5 优缺点与适用场景

✅ 适用场景

  • 大规模无标签数据可用(如爬取的网页、监控视频)
  • 下游任务标注成本高(医疗、工业质检)
  • 需要通用特征平台(公司级AI中台)

❌ 局限性

  • 前置任务设计依赖经验:任务不好 → 特征没用
  • 计算资源要求高:通常需GPU集群预训练
  • 小数据场景收益有限:预训练需足够数据多样性

⚠️ 重要提醒: 自监督不是“万能药”——如果下游任务与预训练数据分布差异大(如用自然图像预训练做X光分类),效果可能不佳。


13.6 实战案例 + 代码实现(PyTorch + Scikit-learn)

💡 为便于理解,以下使用简化模型和小数据集


案例1:自编码器实现数据降维与重构

import torch
import torch.nn as nn
import torchvision.transforms as transforms
from torchvision.datasets import MNIST
import matplotlib.pyplot as plt

# 自编码器定义
class Autoencoder(nn.Module):
    def __init__(self, latent_dim=32):
        super().__init__()
        # 编码器
        self.encoder = nn.Sequential(
            nn.Linear(28*28, 128),
            nn.ReLU(),
            nn.Linear(128, 64),
            nn.ReLU(),
            nn.Linear(64, latent_dim)
        )
        # 解码器
        self.decoder = nn.Sequential(
            nn.Linear(latent_dim, 64),
            nn.ReLU(),
            nn.Linear(64, 128),
            nn.ReLU(),
            nn.Linear(128, 28*28),
            nn.Sigmoid()  # 输出0~1
        )
    
    def forward(self, x):
        x = x.view(x.size(0), -1)
        z = self.encoder(x)
        recon = self.decoder(z)
        return recon, z

# 训练
device = 'cuda' if torch.cuda.is_available() else 'cpu'
model = Autoencoder(latent_dim=32).to(device)
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)

# 加载MNIST(仅用图像,不用标签)
transform = transforms.Compose([transforms.ToTensor()])
train_set = MNIST(root='./data', train=True, download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(train_set, batch_size=256, shuffle=True)

# 训练循环(简化)
for epoch in range(10):
    for data, _ in train_loader:
        data = data.to(device)
        recon, _ = model(data)
        loss = criterion(recon, data.view(data.size(0), -1))
        
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    print(f"Epoch {epoch}, Loss: {loss.item():.4f}")

# 可视化重构效果
model.eval()
with torch.no_grad():
    sample, _ = next(iter(train_loader))
    sample = sample[:8].to(device)
    recon, _ = model(sample)
    
    fig, axes = plt.subplots(2, 8, figsize=(12, 3))
    for i in range(8):
        axes[0, i].imshow(sample[i].cpu().squeeze(), cmap='gray')
        axes[1, i].imshow(recon[i].cpu().view(28,28), cmap='gray')
        axes[0, i].axis('off')
        axes[1, i].axis('off')
    axes[0, 0].set_title("原始")
    axes[1, 0].set_title("重构")
    plt.show()

🔍 观察:即使只用32维,也能较好重构手写数字!


案例2:简单对比学习(SimSiam简化版) + 下游分类

# 数据增强(两个视角)
def augment(x):
    return transforms.Compose([
        transforms.RandomResizedCrop(28, scale=(0.8, 1.0)),
        transforms.RandomApply([transforms.ColorJitter(0.2, 0.2, 0.2, 0.1)], p=0.8),
        transforms.RandomGrayscale(p=0.2),
        transforms.ToTensor()
    ])(x)

# SimSiam简化模型
class SimSiam(nn.Module):
    def __init__(self, backbone, proj_dim=64):
        super().__init__()
        self.backbone = backbone  # 如ResNet
        self.projector = nn.Sequential(
            nn.Linear(backbone.out_features, proj_dim),
            nn.BatchNorm1d(proj_dim),
            nn.ReLU(),
            nn.Linear(proj_dim, proj_dim)
        )
        self.predictor = nn.Sequential(
            nn.Linear(proj_dim, proj_dim//2),
            nn.ReLU(),
            nn.Linear(proj_dim//2, proj_dim)
        )
    
    def forward(self, x1, x2):
        z1 = self.projector(self.backbone(x1))
        z2 = self.projector(self.backbone(x2))
        p1 = self.predictor(z1)
        p2 = self.predictor(z2)
        return p1, p2, z1.detach(), z2.detach()

# 损失函数(对称余弦相似度)
def simsiam_loss(p1, p2, z1, z2):
    def cos_loss(a, b):
        a = nn.functional.normalize(a, dim=1)
        b = nn.functional.normalize(b, dim=1)
        return -(a * b).sum(dim=1).mean()
    return (cos_loss(p1, z2) + cos_loss(p2, z1)) / 2

# 注意:完整实现较复杂,此处展示思路
# 预训练后,冻结backbone,接分类头微调

💡 下游任务: 预训练后,取 backbone 作为特征提取器,接一个线性分类器,在少量标签数据上训练。


案例3:文本掩码填充预训练 + 情感分析微调(使用Hugging Face)

from transformers import BertTokenizer, BertForMaskedLM, BertForSequenceClassification
from transformers import LineByLineTextDataset, DataCollatorForLanguageModeling
from transformers import Trainer, TrainingArguments

# 1. 准备无标签文本(如大量影评)
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')

# 2. 构建MLM数据集
dataset = LineByLineTextDataset(
    tokenizer=tokenizer,
    file_path="unlabeled_reviews.txt",
    block_size=128
)
data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm_probability=0.15)

# 3. 加载预训练BERT(继续预训练)
model_mlm = BertForMaskedLM.from_pretrained('bert-base-uncased')

training_args = TrainingArguments(
    output_dir='./mlm_model',
    num_train_epochs=3,
    per_device_train_batch_size=16,
    save_steps=1000,
)

trainer = Trainer(
    model=model_mlm,
    args=training_args,
    data_collator=data_collator,
    train_dataset=dataset,
)

trainer.train()

# 4. 微调情感分析(二分类)
model_clf = BertForSequenceClassification.from_pretrained('./mlm_model', num_labels=2)
# ... 此处加载少量标注情感数据,标准Trainer微调 ...

# 结果:在100条标注数据上,准确率可达85%+(远超从零训练)

🌐 现实意义: 用公司内部客服对话预训练BERT,再微调做意图识别,效果远超通用BERT!


🎯 本章总结

方法前置任务特点适用模态
自编码器重构原始输入简单、稳定图像、表格
对比学习区分正负样本对学高级语义图像、音频
掩码重建预测被遮盖部分利用上下文文本、图像

💡 建议:

  1. 入门:自编码器(理解重构思想)
  2. 进阶:SimSiam(掌握对比学习)
  3. 实战:Hugging Face + MAE(工业级应用)

📘 未来方向

  • 多模态自监督(图文对齐:CLIP)
  • 生成式自监督(扩散模型、LLM)
  • 自监督 + 强化学习(智能体自主探索)

🌟 记住自监督学习的本质,是教会机器“自学成才”的能力 —— 这正是通往通用人工智能的关键一步!

资料关注

公众号:咚咚王 gitee:gitee.com/wy185850518…

《Python编程:从入门到实践》 《利用Python进行数据分析》 《算法导论中文第三版》 《概率论与数理统计(第四版) (盛骤) 》 《程序员的数学》 《线性代数应该这样学第3版》 《微积分和数学分析引论》 《(西瓜书)周志华-机器学习》 《TensorFlow机器学习实战指南》 《Sklearn与TensorFlow机器学习实用指南》 《模式识别(第四版)》 《深度学习 deep learning》伊恩·古德费洛著 花书 《Python深度学习第二版(中文版)【纯文本】 (登封大数据 (Francois Choliet)) (Z-Library)》 《深入浅出神经网络与深度学习+(迈克尔·尼尔森(Michael+Nielsen)》 《自然语言处理综论 第2版》 《Natural-Language-Processing-with-PyTorch》 《计算机视觉-算法与应用(中文版)》 《Learning OpenCV 4》 《AIGC:智能创作时代》杜雨+&+张孜铭 《AIGC原理与实践:零基础学大语言模型、扩散模型和多模态模型》 《从零构建大语言模型(中文版)》 《实战AI大模型》 《AI 3.0》