6.2.4 对比学习
对比学习(Contrastive Learning)通过构造正负样本对,让模型学习到不同模态之间的相似性和差异性。例如,在“图像-文本”匹配任务中,可以使用对比学习方法让模型区分匹配和不匹配的“图像-文本”对。请看下面的例子,演示了使用对比学习方法训练模型来学习“图像-文本”之间的相似性和差异性的过程。
实例6-4:使用对比学习方法训练模型(源码路径:codes/6/duixue.py)
实例文件duixue.py的具体实现代码如下所示。
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
# 定义对比学习模型
class ContrastiveModel(nn.Module):
def __init__(self, image_feature_dim, text_feature_dim, hidden_dim=512):
super(ContrastiveModel, self).__init__()
self.image_feature_dim = image_feature_dim
self.text_feature_dim = text_feature_dim
self.hidden_dim = hidden_dim
# 图像特征处理
self.image_linear = nn.Linear(image_feature_dim, hidden_dim)
self.image_norm = nn.LayerNorm(hidden_dim)
# 文本特征处理
self.text_linear = nn.Linear(text_feature_dim, hidden_dim)
self.text_norm = nn.LayerNorm(hidden_dim)
# 输出层
self.output_layer = nn.Linear(hidden_dim, 1)
def forward(self, image, text):
# 图像特征处理
image_features = F.normalize(self.image_linear(image), p=2, dim=1)
image_features = self.image_norm(image_features)
# 文本特征处理
text_features = F.normalize(self.text_linear(text), p=2, dim=1)
text_features = self.text_norm(text_features)
# 计算图像-文本之间的相似度得分
similarity_scores = torch.cosine_similarity(image_features, text_features, dim=1)
return similarity_scores
# 创建正负样本对
def create_contrastive_pairs(image_features, text_features, labels, margin=0.5):
# 计算正样本对的相似度得分
positive_scores = torch.cosine_similarity(image_features, text_features, dim=1)
# 打乱文本特征的顺序,构造负样本对
text_features_shuffled = text_features[torch.randperm(text_features.size(0))]
# 计算负样本对的相似度得分
negative_scores = torch.cosine_similarity(image_features, text_features_shuffled, dim=1)
# 计算对比损失
losses = F.relu(margin - positive_scores + negative_scores)
return losses.mean()
# 创建示例数据
image_feature_dim = 512
text_feature_dim = 512
batch_size = 4
# 随机生成图像特征和文本特征作为示例数据
image_features = torch.randn(batch_size, image_feature_dim, requires_grad=True) # 设置requires_grad为True
text_features = torch.randn(batch_size, text_feature_dim, requires_grad=True) # 设置requires_grad为True
labels = torch.randint(0, 2, (batch_size,)) # 随机生成标签,0表示不匹配,1表示匹配
# 创建对比学习模型实例
model = ContrastiveModel(image_feature_dim, text_feature_dim)
# 定义优化器
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 训练模型
num_epochs = 10
for epoch in range(num_epochs):
# 前向传播
similarity_scores = model(image_features, text_features)
# 计算对比损失
loss = create_contrastive_pairs(image_features, text_features, labels)
# 反向传播与优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}")
# 输出模型输出形状
print("Model outputs shape:", similarity_scores.shape)
上述代码的实现流程如下所示:
- 首先,定义了一个对比学习模型 ContrastiveModel,它接受图像特征和文本特征,并计算它们之间的相似度得分。
- 然后,编写了函数 create_contrastive_pairs,用于创建正负样本对,并计算对比损失。
- 接着,生成了示例数据,包括图像特征、文本特征和标签。
- 然后,创建了对比学习模型实例,并定义了优化器。
- 在训练循环中分别实现了模型的前向传播、计算损失、反向传播和优化步骤。
- 最后,打印输出了模型输出的形状,执行后会输出:
Epoch [1/10], Loss: 0.4508
Epoch [2/10], Loss: 0.5037
Epoch [3/10], Loss: 0.4508
Epoch [4/10], Loss: 0.4566
Epoch [5/10], Loss: 0.5000
Epoch [6/10], Loss: 0.4855
Epoch [7/10], Loss: 0.4998
Epoch [8/10], Loss: 0.5193
Epoch [9/10], Loss: 0.4597
Epoch [10/10], Loss: 0.5105
Model outputs shape: torch.Size([4])
上面的输出结果表明程序已经成功执行,并且模型输出的形状是torch.Size([4])。
6.2.5 数据增强
数据增强(Data Augmentation)对训练数据进行各种随机变换,以增加数据的多样性,提高模型的鲁棒性。对图像进行旋转、翻转、缩放等操作,对文本进行同义词替换、句子重排等操作。请看下面的代码,演示了使用PyTorch的 torchvision 库进行图像数据增强的过程。
from PIL import Image
import torchvision.transforms as transforms
# 示例数据增强函数,这里以图像数据增强为例
def image_augmentation(image_path):
# 加载图像
image = Image.open(image_path)
# 定义图像数据增强的变换
transform = transforms.Compose([
transforms.RandomHorizontalFlip(), # 水平翻转
transforms.RandomVerticalFlip(), # 垂直翻转
transforms.RandomRotation(30), # 随机旋转
transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1), # 随机颜色变换
transforms.RandomResizedCrop(224), # 随机裁剪和缩放
transforms.ToTensor(), # 转换为张量
])
# 应用变换
augmented_image = transform(image)
return augmented_image
# 示例代码
if __name__ == "__main__":
# 示例图像数据路径
sample_image_path = "sample_image.jpg"
# 图像数据增强示例
augmented_image = image_augmentation(sample_image_path)
print("Augmented Image Shape:", augmented_image.shape) # 打印增强后的图像形状
在上述代码中,首先加载指定的图像并定义了一系列图像数据增强的变换,包括随机水平翻转、垂直翻转、随机旋转、随机颜色变换和随机裁剪缩放等。然后,将这些变换组合成一个 transforms.Compose 对象,并应用于加载的图像,最后将增强后的图像转换为张量格式。
6.2.6 迁移学习
迁移学习(Transfer Learning)是指从一个任务或领域中学到的知识应用到另一个相关任务或领域。
例如,从自然图像分类任务中学到的特征可以迁移到医学图像分析任务中。请看下面的实例,演示了利用迁移学习在文生图模型训练中使用预训练的自然图像分类模型的过程。
实例6-5:利用迁移学习使用预训练的自然图像分类模型(源码路径:codes/6/qian.py)
实例文件qian.py的具体实现代码如下所示。
import torch
import torch.nn as nn
import torchvision
from torchvision import transforms, models
from torch.utils.data import DataLoader, Dataset
from PIL import Image
import numpy as np
# 加载自然图像分类预训练模型,这里以ResNet18为例
pretrained_model = models.resnet18(pretrained=True)
# 冻结预训练模型的参数
for param in pretrained_model.parameters():
param.requires_grad = False
# 替换预训练模型的最后一层,适应新的任务(医学图像分析),这里以二分类为例
num_ftrs = pretrained_model.fc.in_features
pretrained_model.fc = nn.Linear(num_ftrs, 2)
# 定义图像数据预处理
transform = transforms.Compose([
transforms.Resize((224, 224)), # 将图像大小调整为预训练模型的输入尺寸
transforms.ToTensor(), # 将图像转换为Tensor
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) # 标准化
])
# 假设这里有自然图像分类的数据集,用MedicalDataset代替
class MedicalDataset(Dataset):
def __init__(self, transform=None):
self.data = [] # 存放图像数据
self.targets = [] # 存放图像对应的标签
self.transform = transform
# 生成一些示例数据(随机生成)
for _ in range(100):
self.data.append(np.random.randint(0, 256, size=(224, 224, 3), dtype=np.uint8))
self.targets.append(np.random.randint(0, 2))
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
image = Image.fromarray(self.data[idx])
target = self.targets[idx]
if self.transform:
image = self.transform(image)
return image, target
# 创建自然图像分类数据集的 DataLoader,这里用MedicalDataset代替
medical_dataset = MedicalDataset(transform=transform)
medical_dataloader = DataLoader(medical_dataset, batch_size=32, shuffle=True)
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(pretrained_model.parameters(), lr=0.001, momentum=0.9)
# 训练模型
num_epochs = 5
for epoch in range(num_epochs):
running_loss = 0.0
for images, labels in medical_dataloader:
optimizer.zero_grad()
outputs = pretrained_model(images)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {running_loss/len(medical_dataloader):.4f}")
# 保存模型
torch.save(pretrained_model.state_dict(), 'medical_model.pth')
print("Model trained and saved.")
上述代码的实现流程如下所示:
- 首先,加载预训练的ResNet-18模型并替换最后一层以适应新的任务,这里的任务是二分类的医学图像分析。
- 然后,定义了一个简单的医学图像数据集类(这里使用随机生成的示例数据),进行数据预处理并创建数据加载器。
- 接着,分别定义损失函数和优化器,并进行模型训练。
- 最后,打印输出模型训练过程中的每个epoch的损失值,并保存训练好的模型。执行后会输出:
Epoch [1/5], Loss: 0.7988
Epoch [2/5], Loss: 0.7165
Epoch [3/5], Loss: 0.7389
Epoch [4/5], Loss: 0.6620
Epoch [5/5], Loss: 0.7141
Model trained and saved.
标签:dim,features,训练,文生,text,模型,self,图像,image
From: https://blog.csdn.net/asd343442/article/details/142356753