CycleGAN(Cycle-Consistent Generative Adversarial Network)是一种用于图像到图像转换的深度学习模型。其主要目标是学习两个域之间的映射,例如将马的图像转换为斑马的图像,而无需配对的训练数据。以下是CycleGAN图像到图像转换的关键知识点总结:
1.生成对抗网络(GAN):
2.CycleGAN基于生成对抗网络结构,其中包含生成器(Generator)和判别器(Discriminator)。
3.生成器尝试生成逼真的目标域图像,而判别器则努力区分生成的图像和真实的目标域图像。
4.无监督学习:
5.CycleGAN是一种无监督学习方法,因为它不需要配对的训练数据,只需要在两个域中分别有大量的图像。
6.循环一致性损失:
7.循环一致性是CycleGAN的关键特性。它通过在图像从一个域到另一个域再返回时保持一致性来提高生成图像的质量。
8.通过引入循环一致性损失,确保从域A到域B再到域A的图像转换是相近的。
9.对抗性损失:
10.对抗性损失是通过生成器和判别器之间的对抗训练实现的。生成器努力生成以假乱真的图像,而判别器努力正确分类真实和生成的图像。
11.域自适应:
12.CycleGAN被设计用于域自适应,即在没有配对训练数据的情况下,将一个域的图像转换为另一个域的图像。
13.生成器和判别器的结构:
14.生成器和判别器的具体结构通常采用卷积神经网络(CNN)或残差网络(ResNet)的变种。
15.损失函数:
16.CycleGAN的总体损失函数包括生成器和判别器的对抗性损失,循环一致性损失,以及可能的身份映射损失。
17.训练策略:
18.CycleGAN的训练通常包括在生成器和判别器之间进行交替的优化,以及在循环一致性损失和对抗性损失之间的权衡。
19.实际应用:
20.CycleGAN在图像转换领域有许多实际应用,如风格迁移、季节转换等。
# 您将使用 PyTorch 的 DataLoader 类加载图像数据,以有效地从指定目录读取图像。
# 然后,您的任务是根据提供的规范定义 CycleGAN 架构。您将定义鉴别器和生成器模型。
# 您将通过计算生成器和判别器网络的对抗性和周期一致性损失并完成多个训练周期来完成训练周期。建议启用 GPU 使用率进行训练。
# 最后,您将通过查看随时间变化的损失并查看样本生成的图像来评估模型。
# 加载和可视化数据
import torch
from torch.utils.data import DataLoader
import torchvision
import torchvision.datasets as datasets
import torchvision.transforms as transforms
import os
# 设置环境变量以避免 OpenMP 问题
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
import matplotlib.pyplot as plt
import numpy as np
import warnings
warnings.filterwarnings('ignore')
# 数据加载器
# image_type:或存储 X 和 Y 图像的目录的名称summerwinter
# image_dir:主映像目录的名称,其中包含所有训练和测试映像
# image_size:调整大小的方形图像尺寸(所有图像都将调整为此暗淡)
# batch_size:一批数据中的图像数量
def get_data_loader(image_type, image_dir='summer2winter_yosemite',
image_size=128, batch_size=16, num_workers=0):
transform = transforms.Compose([transforms.Resize(image_size), # resize to 128x128
transforms.ToTensor()])
image_path = './' + image_dir
train_path = os.path.join(image_path, image_type)
test_path = os.path.join(image_path, 'test_{}'.format(image_type))
train_dataset = datasets.ImageFolder(train_path, transform)
test_dataset = datasets.ImageFolder(test_path, transform)
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True, num_workers=num_workers)
test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False, num_workers=num_workers)
return train_loader, test_loader
dataloader_X, test_dataloader_X = get_data_loader(image_type='summer')
dataloader_Y, test_dataloader_Y = get_data_loader(image_type='winter')
# 显示一些训练图像
def imshow(img):
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))
dataiter = iter(dataloader_X)
images, _ = next(dataiter)
fig = plt.figure(figsize=(12, 8))
imshow(torchvision.utils.make_grid(images))
dataiter = iter(dataloader_Y)
images, _ = next(dataiter)
fig = plt.figure(figsize=(12, 8))
imshow(torchvision.utils.make_grid(images))
plt.show()
# 预处理:从-1缩放到1
img=images[0]
print('Min:',img.min())
print('Max:',img.max())
def scale(x,feature_range=(-1,1)):
min,max=feature_range
x=x*(max-min)+min
return x
scale_img=scale(img)
print('Scaled min:',scale_img.min())
print('Scaled max:',scale_img.max())
# 定义模型
# CycleGAN 由两个鉴别器和两个生成器网络组成。
# 鉴别器
# 卷积辅助函数
import torch.nn as nn
import torch.nn.functional as F
# Helper conv function
def conv(in_channels, out_channels, kernel_size, stride=2, padding=1, batch_norm=True):
layers = []
conv_layer = nn.Conv2d(in_channels=in_channels, out_channels=out_channels,
kernel_size=kernel_size, stride=stride, padding=padding, bias=False)
layers.append(conv_layer)
if batch_norm:
layers.append(nn.BatchNorm2d(out_channels))
return nn.Sequential(*layers)
# Define the Discriminator architecture
class Discriminator(nn.Module):
def __init__(self, conv_dim=64):
super(Discriminator, self).__init__()
# Define the discriminator architecture here
# Example: simple convolutional neural network
self.model = nn.Sequential(
conv(3, conv_dim, 4, batch_norm=False),
nn.LeakyReLU(0.2, inplace=True),
# ...
nn.Conv2d(conv_dim, 1, kernel_size=4, stride=2, padding=1),
nn.Sigmoid()
)
def forward(self, x):
return self.model(x)
# Define the Residual Block
class ResidualBlock(nn.Module):
def __init__(self, conv_dim):
super(ResidualBlock, self).__init__()
# Define the residual block architecture here
# Example: Convolution -> BatchNorm -> ReLU -> Convolution -> BatchNorm
self.conv1 = conv(conv_dim, conv_dim, 3, stride=1, padding=1)
self.conv2 = conv(conv_dim, conv_dim, 3, stride=1, padding=1)
self.relu = nn.ReLU()
def forward(self, x):
out = self.conv1(x)
out = self.relu(out)
out = self.conv2(out)
return x + out
# Define the Generator architecture
class CycleGenerator(nn.Module):
def __init__(self, conv_dim=64, n_res_blocks=6):
super(CycleGenerator, self).__init__()
# Define the generator architecture here
# Example: Encoder -> Residual Blocks -> Decoder
self.encoder = conv(3, conv_dim, 4)
self.residual_blocks = nn.Sequential(
*[ResidualBlock(conv_dim) for _ in range(n_res_blocks)]
)
self.decoder = deconv(conv_dim, 3, 4, batch_norm=False)
def forward(self, x):
x = self.encoder(x)
x = self.residual_blocks(x)
x = self.decoder(x)
return x
# Transpose convolution helper function
def deconv(in_channels, out_channels, kernel_size, stride=2, padding=1, batch_norm=True):
layers = []
layers.append(nn.ConvTranspose2d(in_channels, out_channels, kernel_size, stride, padding, bias=False))
if batch_norm:
layers.append(nn.BatchNorm2d(out_channels))
return nn.Sequential(*layers)
# Create the complete model
def create_model(g_conv_dim=64, d_conv_dim=64, n_res_blocks=6):
G_XtoY = CycleGenerator(conv_dim=g_conv_dim, n_res_blocks=n_res_blocks)
G_YtoX = CycleGenerator(conv_dim=g_conv_dim, n_res_blocks=n_res_blocks)
D_X = Discriminator(conv_dim=d_conv_dim)
D_Y = Discriminator(conv_dim=d_conv_dim)
if torch.cuda.is_available():
device = torch.device("cuda:0")
G_XtoY.to(device)
G_YtoX.to(device)
D_X.to(device)
D_Y.to(device)
print('Models moved to GPU.')
else:
print('Only CPU available.')
return G_XtoY, G_YtoX, D_X, D_Y
G_XtoY, G_YtoX, D_X, D_Y = create_model()
def print_models(G_XtoY, G_YtoX, D_X, D_Y):
print(" G_XtoY ")
print("-----------------------------------------------")
print(G_XtoY)
print()
print(" G_YtoX ")
print("-----------------------------------------------")
print(G_YtoX)
print()
print(" D_X ")
print("-----------------------------------------------")
print(D_X)
print()
print(" D_Y ")
print("-----------------------------------------------")
print(D_Y)
print()
print_models(G_XtoY, G_YtoX, D_X, D_Y)