深度学习自监督学习:从无标签数据中学习表示

张开发
2026/5/5 10:08:41 15 分钟阅读
深度学习自监督学习:从无标签数据中学习表示
深度学习自监督学习从无标签数据中学习表示1. 背景与意义自监督学习是深度学习领域的重要研究方向它通过利用数据本身的结构信息来学习有效的表示而无需人工标注。自监督学习的意义在于减少标注成本避免了昂贵的人工标注过程利用海量无标签数据充分利用互联网上的大量无标签数据提升模型泛化能力学习到的表示通常具有更好的泛化能力促进下游任务性能为下游任务提供更好的初始化参数在大数据时代自监督学习已成为深度学习的重要范式特别是在计算机视觉和自然语言处理领域。2. 核心概念与技术2.1 自监督学习的基本原理自监督学习通过设计 pretext任务pretext task来从无标签数据中学习表示。这些任务通常基于数据的内在结构无需人工标注。2.2 常见的自监督学习方法2.2.1 对比学习Contrastive Learning对比学习通过将相似样本拉近距离将不相似样本推开距离来学习表示。import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader class ContrastiveLoss(nn.Module): def __init__(self, temperature0.5): super(ContrastiveLoss, self).__init__() self.temperature temperature def forward(self, features, labels): # 计算特征之间的余弦相似度 similarity torch.matmul(features, features.T) / self.temperature # 创建标签掩码 mask labels.unsqueeze(0) labels.unsqueeze(1) # 排除自身相似度 mask mask.fill_diagonal_(False) # 计算正样本对的相似度 positive similarity[mask].view(labels.size(0), -1) # 计算负样本对的相似度 negative similarity[~mask].view(labels.size(0), -1) # 计算对比损失 logits torch.cat([positive, negative], dim1) labels torch.zeros(logits.size(0), dtypetorch.long, devicelogits.device) loss nn.CrossEntropyLoss()(logits, labels) return loss # 简单的对比学习模型 class ContrastiveModel(nn.Module): def __init__(self, input_dim, hidden_dim, output_dim): super(ContrastiveModel, self).__init__() self.encoder nn.Sequential( nn.Linear(input_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, output_dim), nn.LayerNorm(output_dim) ) def forward(self, x): return self.encoder(x) # 训练示例 def train_contrastive(model, dataloader, optimizer, criterion, epochs): model.train() for epoch in range(epochs): total_loss 0 for batch in dataloader: x, labels batch features model(x) # 标准化特征 features nn.functional.normalize(features, dim1) loss criterion(features, labels) optimizer.zero_grad() loss.backward() optimizer.step() total_loss loss.item() print(fEpoch {epoch1}, Loss: {total_loss/len(dataloader):.4f})2.2.2 掩码语言模型Masked Language Model掩码语言模型通过预测被掩码的单词来学习语言表示如BERT。from transformers import BertTokenizer, BertForMaskedLM import torch # 加载预训练模型和分词器 tokenizer BertTokenizer.from_pretrained(bert-base-uncased) model BertForMaskedLM.from_pretrained(bert-base-uncased) # 示例文本 text The cat sat on the [MASK]. # 分词 inputs tokenizer(text, return_tensorspt) # 预测被掩码的词 with torch.no_grad(): outputs model(**inputs) predictions outputs.logits # 获取掩码位置 mask_position (inputs.input_ids[0] tokenizer.mask_token_id).nonzero(as_tupleTrue)[0] # 获取预测的词 predicted_token_id torch.argmax(predictions[0, mask_position]).item() predicted_token tokenizer.decode(predicted_token_id) print(fOriginal text: {text}) print(fPredicted token: {predicted_token})2.2.3 图像自监督学习方法常见的图像自监督学习方法包括SimCLR通过数据增强和对比学习学习图像表示MoCo使用动量编码器和队列来存储负样本BYOL不需要负样本通过预测网络和目标网络的一致性学习表示import torch import torch.nn as nn import torchvision.transforms as transforms # SimCLR的数据增强 class SimCLRTransform: def __init__(self, size224): self.transform transforms.Compose([ transforms.RandomResizedCrop(size), transforms.RandomHorizontalFlip(), transforms.RandomApply([transforms.ColorJitter(0.8, 0.8, 0.8, 0.2)], p0.8), transforms.RandomGrayscale(p0.2), transforms.ToTensor(), transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)) ]) def __call__(self, x): # 生成两个不同的增强视图 return self.transform(x), self.transform(x) # SimCLR模型 class SimCLR(nn.Module): def __init__(self, base_encoder, projection_dim128): super(SimCLR, self).__init__() self.encoder base_encoder # 投影头 self.projector nn.Sequential( nn.Linear(512, 2048), nn.ReLU(), nn.Linear(2048, projection_dim) ) def forward(self, x1, x2): # 编码两个视图 h1 self.encoder(x1) h2 self.encoder(x2) # 投影 z1 self.projector(h1) z2 self.projector(h2) return z1, z23. 高级应用场景3.1 迁移学习自监督学习学习到的表示可以用于迁移学习提高下游任务的性能。import torch import torch.nn as nn import torchvision.models as models # 加载预训练的自监督模型 class TransferModel(nn.Module): def __init__(self, num_classes): super(TransferModel, self).__init__() # 加载SimCLR预训练的ResNet50 resnet models.resnet50(pretrainedFalse) # 替换分类头 self.encoder nn.Sequential(*list(resnet.children())[:-1]) self.classifier nn.Linear(2048, num_classes) def forward(self, x): features self.encoder(x).squeeze() logits self.classifier(features) return logits # 训练分类器 def train_classifier(model, dataloader, optimizer, criterion, epochs): model.train() for epoch in range(epochs): total_loss 0 correct 0 total 0 for batch in dataloader: x, labels batch logits model(x) loss criterion(logits, labels) optimizer.zero_grad() loss.backward() optimizer.step() total_loss loss.item() _, predicted torch.max(logits, 1) correct (predicted labels).sum().item() total labels.size(0) accuracy correct / total print(fEpoch {epoch1}, Loss: {total_loss/len(dataloader):.4f}, Accuracy: {accuracy:.4f})3.2 半监督学习自监督学习可以与半监督学习结合利用少量标签数据和大量无标签数据。import torch import torch.nn as nn class SemiSupervisedModel(nn.Module): def __init__(self, encoder, classifier): super(SemiSupervisedModel, self).__init__() self.encoder encoder self.classifier classifier def forward(self, x): features self.encoder(x) logits self.classifier(features) return logits # 半监督训练 def train_semi_supervised(model, labeled_dataloader, unlabeled_dataloader, optimizer, criterion, epochs): model.train() for epoch in range(epochs): total_loss 0 # 训练有标签数据 for batch in labeled_dataloader: x, labels batch logits model(x) loss criterion(logits, labels) optimizer.zero_grad() loss.backward() optimizer.step() total_loss loss.item() # 训练无标签数据使用一致性正则化 for batch in unlabeled_dataloader: x batch # 生成两个增强视图 x1, x2 SimCLRTransform()(x) logits1 model(x1) logits2 model(x2) # 一致性损失 consistency_loss nn.functional.mse_loss(logits1, logits2) optimizer.zero_grad() consistency_loss.backward() optimizer.step() total_loss consistency_loss.item() print(fEpoch {epoch1}, Loss: {total_loss/(len(labeled_dataloader)len(unlabeled_dataloader)):.4f})3.3 领域适应自监督学习可以帮助模型适应新的领域减少领域偏移的影响。import torch import torch.nn as nn class DomainAdaptationModel(nn.Module): def __init__(self, encoder, classifier, domain_discriminator): super(DomainAdaptationModel, self).__init__() self.encoder encoder self.classifier classifier self.domain_discriminator domain_discriminator def forward(self, x): features self.encoder(x) class_logits self.classifier(features) domain_logits self.domain_discriminator(features) return class_logits, domain_logits # 领域适应训练 def train_domain_adaptation(model, source_dataloader, target_dataloader, optimizer, class_criterion, domain_criterion, epochs): model.train() for epoch in range(epochs): total_loss 0 # 训练源域数据 for batch in source_dataloader: x, labels batch class_logits, domain_logits model(x) # 分类损失 class_loss class_criterion(class_logits, labels) # 域分类损失源域标签为0 domain_loss domain_criterion(domain_logits, torch.zeros(len(x), dtypetorch.long, devicex.device)) loss class_loss domain_loss optimizer.zero_grad() loss.backward() optimizer.step() total_loss loss.item() # 训练目标域数据 for batch in target_dataloader: x batch _, domain_logits model(x) # 域分类损失目标域标签为1 domain_loss domain_criterion(domain_logits, torch.ones(len(x), dtypetorch.long, devicex.device)) # 反转梯度 for param in model.domain_discriminator.parameters(): param.grad * -1 optimizer.zero_grad() domain_loss.backward() optimizer.step() total_loss domain_loss.item() print(fEpoch {epoch1}, Loss: {total_loss/(len(source_dataloader)len(target_dataloader)):.4f})4. 性能分析与比较4.1 自监督学习与有监督学习的对比方法数据集准确率训练时间标注成本有监督学习ImageNet76.5%100小时高SimCLRImageNet75.2%150小时无MoCo v2ImageNet76.7%120小时无BYOLImageNet74.9%130小时无4.2 自监督学习方法的性能比较import torch import torchvision.models as models import time # 加载不同的自监督预训练模型 def load_pretrained_models(): models_dict { SimCLR: models.resnet50(pretrainedFalse), MoCo: models.resnet50(pretrainedFalse), BYOL: models.resnet50(pretrainedFalse), Supervised: models.resnet50(pretrainedTrue) } # 这里假设我们已经下载了预训练权重 # 实际使用时需要加载对应的预训练权重 return models_dict # 测试模型性能 def test_model_performance(model, dataloader): model.eval() correct 0 total 0 start_time time.time() with torch.no_grad(): for batch in dataloader: x, labels batch outputs model(x) _, predicted torch.max(outputs, 1) correct (predicted labels).sum().item() total labels.size(0) end_time time.time() accuracy correct / total inference_time end_time - start_time return accuracy, inference_time # 比较不同模型 models_dict load_pretrained_models() results {} for name, model in models_dict.items(): accuracy, inference_time test_model_performance(model, test_dataloader) results[name] {accuracy: accuracy, inference_time: inference_time} print(f{name}: Accuracy {accuracy:.4f}, Inference time {inference_time:.2f} seconds)5. 代码质量与最佳实践5.1 数据增强策略多样性使用多种数据增强方法如随机裁剪、翻转、颜色变换等适度性避免过度增强导致数据失真领域相关性根据具体任务选择合适的数据增强方法5.2 模型设计编码器选择根据任务选择合适的编码器架构投影头设计使用适当的投影头来学习有效的表示损失函数选择根据任务选择合适的损失函数5.3 训练技巧批量大小使用较大的批量大小来增加负样本数量学习率调度使用余弦退火等学习率调度策略正则化使用dropout、权重衰减等正则化方法早停使用验证集进行早停避免过拟合6. 总结与展望自监督学习是深度学习的重要研究方向它通过利用数据本身的结构信息来学习有效的表示避免了昂贵的人工标注过程。随着研究的不断深入自监督学习方法的性能不断提升已经接近甚至超过有监督学习的性能。未来自监督学习的发展方向包括更有效的 pretext任务设计设计更适合特定领域的自监督任务多模态自监督学习结合多种模态的信息进行自监督学习自监督学习与强化学习的结合利用自监督学习来提升强化学习的性能自监督学习在小样本学习中的应用通过自监督学习来缓解小样本学习的挑战自监督学习已经成为深度学习的重要工具它将继续推动人工智能的发展为更多领域的应用提供支持。数据驱动严谨分析—— 从代码到架构每一步都有数据支撑—— lady_mumu一个在数据深渊里捞了十几年 Bug 的女码农

更多文章