自监督学习和对比学习举例讲解(附代码)

自监督学习与对比学习详解

自监督学习 (Self-Supervised Learning)

例子:图像旋转预测

自监督学习的一个简单例子是图像旋转预测任务。在这个任务中,我们对输入图像进行随机旋转,然后要求模型预测图像旋转的角度。这种方式不需要手动标注数据,因为旋转的角度是已知的。

代码示例

python 复制代码
import torch
import torch.nn as nn
import torchvision.transforms as transforms
from torch.utils.data import DataLoader, Dataset
from torchvision.datasets import CIFAR10
import random

# 创建自定义数据集
class RotatedCIFAR10(Dataset):
    def __init__(self, root, train=True, transform=None, download=False):
        self.dataset = CIFAR10(root=root, train=train, transform=transform, download=download)
        self.rotations = [0, 90, 180, 270]  # 定义旋转角度

    def __len__(self):
        return len(self.dataset)

    def __getitem__(self, index):
        img, _ = self.dataset[index]  # 忽略原始标签
        rotation = random.choice(self.rotations)  # 随机选择一个旋转角度
        rotated_img = transforms.functional.rotate(img, rotation)  # 对图像进行旋转
        return rotated_img, rotation // 90  # 返回旋转后的图像和旋转角度的标签(0, 1, 2, 3)

# 定义简单的CNN模型
class SimpleCNN(nn.Module):
    def __init__(self, num_classes=4):  # 旋转角度分类为4类
        super(SimpleCNN, self).__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(3, 32, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 64, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.fc = nn.Sequential(
            nn.Linear(64*8*8, 128),
            nn.ReLU(),
            nn.Linear(128, num_classes)
        )

    def forward(self, x):
        x = self.conv(x)
        x = x.view(x.size(0), -1)
        x = self.fc(x)
        return x

# 超参数和数据准备
batch_size = 64
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])
train_dataset = RotatedCIFAR10(root='./data', train=True, transform=transform, download=True)
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)

# 模型、损失函数和优化器
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = SimpleCNN().to(device)
criterion = nn.CrossEntropyLoss()  # 使用交叉熵损失函数进行分类
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

# 训练模型
num_epochs = 10
for epoch in range(num_epochs):
    for images, labels in train_loader:
        images, labels = images.to(device), labels.to(device)
        
        outputs = model(images)  # 前向传播
        loss = criterion(outputs, labels)  # 计算损失

        optimizer.zero_grad()
        loss.backward()  # 反向传播
        optimizer.step()  # 优化更新

    print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')

解释

  1. 自定义数据集:

    • RotatedCIFAR10类继承自Dataset,用于加载旋转后的CIFAR-10数据集。
    • __getitem__方法随机选择旋转角度并返回旋转后的图像和相应的标签。
    • 这种方式使得我们能够使用旋转角度作为标签进行训练,而不需要人工标注数据。这就是自监督学习的体现。
  2. 简单的CNN模型:

    • SimpleCNN类定义了一个简单的卷积神经网络,用于分类旋转后的图像。
    • forward方法实现前向传播。
  3. 训练过程:

    • 使用DataLoader加载数据。
    • 定义损失函数和优化器。
    • 在训练循环中进行前向传播、计算损失、反向传播和参数更新。

对比学习 (Contrastive Learning)

例子:Siamese Network

对比学习的一个常见例子是Siamese网络。该网络由两个共享权重的子网络组成,分别处理一对输入图像。目标是最小化相似图像之间的距离,最大化不同图像之间的距离。

代码示例

python 复制代码
import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision.transforms as transforms
from torch.utils.data import DataLoader, Dataset
from torchvision.datasets import CIFAR10
import random

# 创建自定义数据集
class SiameseCIFAR10(Dataset):
    def __init__(self, root, train=True, transform=None, download=False):
        self.dataset = CIFAR10(root=root, train=train, transform=transform, download=download)

    def __len__(self):
        return len(self.dataset)

    def __getitem__(self, index):
        img1, label1 = self.dataset[index]
        # 随机选择一个图像,可能是相同类也可能是不同类
        index2 = random.randint(0, len(self.dataset) - 1)
        img2, label2 = self.dataset[index2]
        label = torch.tensor(int(label1 == label2), dtype=torch.float32)  # 标签为1表示相同类,0表示不同类
        return img1, img2, label

# 定义Siamese Network
class SiameseNetwork(nn.Module):
    def __init__(self):
        super(SiameseNetwork, self).__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(3, 32, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 64, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.fc = nn.Sequential(
            nn.Linear(64*8*8, 128),
            nn.ReLU(),
            nn.Linear(128, 128)
        )

    def forward_once(self, x):
        x = self.conv(x)
        x = x.view(x.size(0), -1)
        x = self.fc(x)
        return x

    def forward(self, x1, x2):
        out1 = self.forward_once(x1)
        out2 = self.forward_once(x2)
        return out1, out2

# 对比损失函数
class ContrastiveLoss(nn.Module):
    def __init__(self, margin=1.0):
        super(ContrastiveLoss, self).__init__()
        self.margin = margin

    def forward(self, output1, output2, label):
        euclidean_distance = F.pairwise_distance(output1, output2)
        loss_contrastive = torch.mean((1 - label) * torch.pow(euclidean_distance, 2) +
                                      label * torch.pow(torch.clamp(self.margin - euclidean_distance, min=0.0), 2))
        return loss_contrastive

# 超参数和数据准备
batch_size = 64
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])
train_dataset = SiameseCIFAR10(root='./data', train=True, transform=transform, download=True)
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)

# 模型、损失函数和优化器
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = SiameseNetwork().to(device)
criterion = ContrastiveLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

# 训练模型
num_epochs = 10
for epoch in range(num_epochs):
    for img1, img2, labels in train_loader:
        img1, img2, labels = img1.to(device), img2.to(device), labels.to(device)
        
        output1, output2 = model(img1, img2)
        loss = criterion(output1, output2, labels)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

    print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')

解释

  1. 自定义数据集:

    • SiameseCIFAR10类继承自Dataset,用于加载图像对。
    • __getitem__方法返回图像对及其相似性标签。
  2. Siamese网络:

    • SiameseNetwork类定义了一个共享权重的卷积神经网络,用于处理图像对。
    • forward_once方法处理单个图像,forward方法处理图像对。
  3. 对比损失函数:

    • ContrastiveLoss类定义了对比损

失函数。

  • forward方法计算两个输出之间的欧氏距离,并根据相似性标签计算损失。
  1. 训练过程 :
    • 使用DataLoader加载数据。
    • 定义损失函数和优化器。
    • 在训练循环中进行前向传播、计算损失、反向传播和参数更新。

总结

自监督学习和对比学习都是利用无标签数据进行训练的方法。自监督学习通过设计预训练任务生成标签,而对比学习通过最小化相似样本之间的距离和最大化不同样本之间的距离来学习有用的特征。上面的例子详细展示了如何实现这两种学习方法,希望能帮助各位更好的理解。

相关推荐
测开小菜鸟4 分钟前
使用python向钉钉群聊发送消息
java·python·钉钉
Power202466625 分钟前
NLP论文速读|LongReward:基于AI反馈来提升长上下文大语言模型
人工智能·深度学习·机器学习·自然语言处理·nlp
YRr YRr1 小时前
深度学习:循环神经网络(RNN)详解
人工智能·rnn·深度学习
sp_fyf_20241 小时前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-01
人工智能·深度学习·神经网络·算法·机器学习·语言模型·数据挖掘
红客5971 小时前
Transformer和BERT的区别
深度学习·bert·transformer
多吃轻食1 小时前
大模型微调技术 --> 脉络
人工智能·深度学习·神经网络·自然语言处理·embedding
萧鼎1 小时前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
学地理的小胖砸1 小时前
【一些关于Python的信息和帮助】
开发语言·python
疯一样的码农1 小时前
Python 继承、多态、封装、抽象
开发语言·python
charles_vaez2 小时前
开源模型应用落地-glm模型小试-glm-4-9b-chat-快速体验(一)
深度学习·语言模型·自然语言处理