【实验代码】基础相关GAN实现

基础相关GAN实现

DCGAN的Pytorch实现

代码来源于Pytorch官方手册项目教程

copy
from __future__ import print_function #%matplotlib inline import argparse import os import random import torch import torch.nn as nn import torch.nn.parallel import torch.backends.cudnn as cudnn import torch.optim as optim import torch.utils.data import torchvision.datasets as dset import torchvision.transforms as transforms import torchvision.utils as vutils import numpy as np import matplotlib matplotlib.use('AGG')#或者PDF, SVG或PS import matplotlib.pyplot as plt import matplotlib.animation as animation from IPython.display import HTML # Set random seed for reproducibility manualSeed = 999 #manualSeed = random.randint(1, 10000) # use if you want new results print("Random Seed: ", manualSeed) random.seed(manualSeed) torch.manual_seed(manualSeed) # Root directory for dataset dataroot = "/home/disk_F/Public/apple2orange/dataset" # Number of workers for dataloader workers = 2 # Batch size during training batch_size = 128 # Spatial size of training images. All images will be resized to this # size using a transformer. image_size = 64 # Number of channels in the training images. For color images this is 3 nc = 3 # Size of z latent vector (i.e. size of generator input) nz = 100 # Size of feature maps in generator ngf = 64 # Size of feature maps in discriminator ndf = 64 # Number of training epochs num_epochs = 5 # Learning rate for optimizers lr = 0.0002 # Beta1 hyperparam for Adam optimizers beta1 = 0.5 # Number of GPUs available. Use 0 for CPU mode. ngpu = 1 # We can use an image folder dataset the way we have it setup. # Create the dataset dataset = dset.ImageFolder(root=dataroot, transform=transforms.Compose([ transforms.Resize(image_size), transforms.CenterCrop(image_size), transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)), ])) # Create the dataloader dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, shuffle=True, num_workers=workers) # Decide which device we want to run on device = torch.device("cuda:0" if (torch.cuda.is_available() and ngpu > 0) else "cpu") # Plot some training images real_batch = next(iter(dataloader)) plt.figure(figsize=(8,8)) plt.axis("off") plt.title("Training Images") plt.imshow(np.transpose(vutils.make_grid(real_batch[0].to(device)[:64], padding=2, normalize=True).cpu(),(1,2,0))) plt.savefig('input.jpg') plt.show() # custom weights initialization called on netG and netD def weights_init(m): classname = m.__class__.__name__ if classname.find('Conv') != -1: nn.init.normal_(m.weight.data, 0.0, 0.02) elif classname.find('BatchNorm') != -1: nn.init.normal_(m.weight.data, 1.0, 0.02) nn.init.constant_(m.bias.data, 0) # Generator Code class Generator(nn.Module): def __init__(self, ngpu): super(Generator, self).__init__() self.ngpu = ngpu self.main = nn.Sequential( # input is Z, going into a convolution nn.ConvTranspose2d( nz, ngf * 8, 4, 1, 0, bias=False), nn.BatchNorm2d(ngf * 8), nn.ReLU(True), # state size. (ngf*8) x 4 x 4 nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False), nn.BatchNorm2d(ngf * 4), nn.ReLU(True), # state size. (ngf*4) x 8 x 8 nn.ConvTranspose2d( ngf * 4, ngf * 2, 4, 2, 1, bias=False), nn.BatchNorm2d(ngf * 2), nn.ReLU(True), # state size. (ngf*2) x 16 x 16 nn.ConvTranspose2d( ngf * 2, ngf, 4, 2, 1, bias=False), nn.BatchNorm2d(ngf), nn.ReLU(True), # state size. (ngf) x 32 x 32 nn.ConvTranspose2d( ngf, nc, 4, 2, 1, bias=False), nn.Tanh() # state size. (nc) x 64 x 64 ) def forward(self, input): return self.main(input) # Create the generator netG = Generator(ngpu).to(device) # Handle multi-gpu if desired if (device.type == 'cuda') and (ngpu > 1): netG = nn.DataParallel(netG, list(range(ngpu))) # Apply the weights_init function to randomly initialize all weights # to mean=0, stdev=0.2. netG.apply(weights_init) # Print the model print(netG) class Discriminator(nn.Module): def __init__(self, ngpu): super(Discriminator, self).__init__() self.ngpu = ngpu self.main = nn.Sequential( # input is (nc) x 64 x 64 nn.Conv2d(nc, ndf, 4, 2, 1, bias=False), nn.LeakyReLU(0.2, inplace=True), # state size. (ndf) x 32 x 32 nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False), nn.BatchNorm2d(ndf * 2), nn.LeakyReLU(0.2, inplace=True), # state size. (ndf*2) x 16 x 16 nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False), nn.BatchNorm2d(ndf * 4), nn.LeakyReLU(0.2, inplace=True), # state size. (ndf*4) x 8 x 8 nn.Conv2d(ndf * 4, ndf * 8, 4, 2, 1, bias=False), nn.BatchNorm2d(ndf * 8), nn.LeakyReLU(0.2, inplace=True), # state size. (ndf*8) x 4 x 4 nn.Conv2d(ndf * 8, 1, 4, 1, 0, bias=False), nn.Sigmoid() ) def forward(self, input): return self.main(input) # Create the Discriminator netD = Discriminator(ngpu).to(device) # Handle multi-gpu if desired if (device.type == 'cuda') and (ngpu > 1): netD = nn.DataParallel(netD, list(range(ngpu))) # Apply the weights_init function to randomly initialize all weights # to mean=0, stdev=0.2. netD.apply(weights_init) # Print the model print(netD) # Initialize BCELoss function criterion = nn.BCELoss() # Create batch of latent vectors that we will use to visualize # the progression of the generator fixed_noise = torch.randn(64, nz, 1, 1, device=device) # Establish convention for real and fake labels during training real_label = 1. fake_label = 0. # Setup Adam optimizers for both G and D optimizerD = optim.Adam(netD.parameters(), lr=lr, betas=(beta1, 0.999)) optimizerG = optim.Adam(netG.parameters(), lr=lr, betas=(beta1, 0.999)) # Training Loop # Lists to keep track of progress img_list = [] G_losses = [] D_losses = [] iters = 0 print("Starting Training Loop...") # For each epoch for epoch in range(num_epochs): # For each batch in the dataloader for i, data in enumerate(dataloader, 0): ############################ # (1) Update D network: maximize log(D(x)) + log(1 - D(G(z))) ########################### ## Train with all-real batch netD.zero_grad() # Format batch real_cpu = data[0].to(device) b_size = real_cpu.size(0) label = torch.full((b_size,), real_label, dtype=torch.float, device=device) # Forward pass real batch through D output = netD(real_cpu).view(-1) # Calculate loss on all-real batch errD_real = criterion(output, label) # Calculate gradients for D in backward pass errD_real.backward() D_x = output.mean().item() ## Train with all-fake batch # Generate batch of latent vectors noise = torch.randn(b_size, nz, 1, 1, device=device) # Generate fake image batch with G fake = netG(noise) label.fill_(fake_label) # Classify all fake batch with D output = netD(fake.detach()).view(-1) # Calculate D's loss on the all-fake batch errD_fake = criterion(output, label) # Calculate the gradients for this batch, accumulated (summed) with previous gradients errD_fake.backward() D_G_z1 = output.mean().item() # Compute error of D as sum over the fake and the real batches errD = errD_real + errD_fake # Update D optimizerD.step() ############################ # (2) Update G network: maximize log(D(G(z))) ########################### netG.zero_grad() label.fill_(real_label) # fake labels are real for generator cost # Since we just updated D, perform another forward pass of all-fake batch through D output = netD(fake).view(-1) # Calculate G's loss based on this output errG = criterion(output, label) # Calculate gradients for G errG.backward() D_G_z2 = output.mean().item() # Update G optimizerG.step() # Output training stats if i % 50 == 0: print('[%d/%d][%d/%d]\tLoss_D: %.4f\tLoss_G: %.4f\tD(x): %.4f\tD(G(z)): %.4f / %.4f' % (epoch, num_epochs, i, len(dataloader), errD.item(), errG.item(), D_x, D_G_z1, D_G_z2)) # Save Losses for plotting later G_losses.append(errG.item()) D_losses.append(errD.item()) # Check how the generator is doing by saving G's output on fixed_noise if (iters % 500 == 0) or ((epoch == num_epochs-1) and (i == len(dataloader)-1)): with torch.no_grad(): fake = netG(fixed_noise).detach().cpu() img_list.append(vutils.make_grid(fake, padding=2, normalize=True)) iters += 1 plt.figure(figsize=(10,5)) plt.title("Generator and Discriminator Loss During Training") plt.plot(G_losses,label="G") plt.plot(D_losses,label="D") plt.xlabel("iterations") plt.ylabel("Loss") plt.legend() plt.savefig('loss_picture.jpg') plt.show() #%%capture #fig = plt.figure(figsize=(8,8)) #plt.axis("off") #ims = [[plt.plot(np.transpose(i,(1,2,0).numpy()), animated=True)] for i in img_list] #ani = animation.ArtistAnimation(fig, ims, interval=1000, repeat_delay=1000, blit=True) #HTML(ani.to_jshtml()) # Grab a batch of real images from the dataloader real_batch = next(iter(dataloader)) # Plot the real images plt.figure(figsize=(15,15)) plt.subplot(1,2,1) plt.axis("off") plt.title("Real Images") plt.imshow(np.transpose(vutils.make_grid(real_batch[0].to(device)[:64], padding=5, normalize=True).cpu(),(1,2,0))) # Plot the fake images from the last epoch plt.subplot(1,2,2) plt.axis("off") plt.title("Fake Images") plt.imshow(np.transpose(vutils.make_grid(img_list[-1].to(device)[:64], padding=5, normalize=True).cpu(),(1,2,0))) plt.savefig('myfig.jpg') plt.show()

实验记录

第一次实验

参数设置:

batch_size = 16

lr = 0.0002

beta1 = 0.5 #Beta1 hyperparam for Adam optimizers

实验结果

生成器和判别器的一直收敛不下去,好像出现了模式奔溃。而且生成的图片很恶心...

第二次实验

参数设置:

batch_size = 128




训练epoch 800轮

训练epoch 6000轮

GAN的Pytorch实现

copy
import torch import torch.nn as nn from torchvision import transforms, datasets from torch import optim as optim import matplotlib matplotlib.use('AGG')#或者PDF, SVG或PS import matplotlib.pyplot as plt import time device = torch.device("cuda" if torch.cuda.is_available() else "cpu") print(device) batch_size = 100 # MNIST dataset dataset = datasets.MNIST(root='./data/', train=True, transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize([0.5], [0.5])]), download=True) # Data loader dataloader = torch.utils.data.DataLoader(dataset=dataset, batch_size=batch_size, shuffle=True) print(f"Length of total dataset = {len(dataset)}, \nLength of dataloader with having batch_size of {batch_size} = {len(dataloader)}") dataiter = iter(dataloader) images,labels = dataiter.next() print(torch.min(images),torch.max(images)) class GeneratorModel(nn.Module): def __init__(self): super(GeneratorModel, self).__init__() input_dim = 100 output_dim = 784 # <----------D和G的非输出层激活函数都是LeakyReLU()函数---------> self.hidden_layer1 = nn.Sequential( nn.Linear(input_dim, 256), nn.LeakyReLU(0.2) ) self.hidden_layer2 = nn.Sequential( nn.Linear(256, 512), nn.LeakyReLU(0.2) ) self.hidden_layer3 = nn.Sequential( nn.Linear(512, 1024), nn.LeakyReLU(0.2) ) # <----------G的最后一层激活函数是Tanh()函数---------> self.hidden_layer4 = nn.Sequential( nn.Linear(1024, output_dim), nn.Tanh() ) def forward(self, x): output = self.hidden_layer1(x) output = self.hidden_layer2(output) output = self.hidden_layer3(output) output = self.hidden_layer4(output) return output.to(device) class DiscriminatorModel(nn.Module): def __init__(self): super(DiscriminatorModel, self).__init__() input_dim = 784 output_dim = 1 self.hidden_layer1 = nn.Sequential( nn.Linear(input_dim, 1024), nn.LeakyReLU(0.2), nn.Dropout(0.3) ) self.hidden_layer2 = nn.Sequential( nn.Linear(1024, 512), nn.LeakyReLU(0.2), nn.Dropout(0.3) ) self.hidden_layer3 = nn.Sequential( nn.Linear(512, 256), nn.LeakyReLU(0.2), nn.Dropout(0.3) ) # <----------D的最后一层激活函数是Sigmoid()函数---------> self.hidden_layer4 = nn.Sequential( nn.Linear(256, output_dim), nn.Sigmoid() ) def forward(self, x): output = self.hidden_layer1(x) output = self.hidden_layer2(output) output = self.hidden_layer3(output) output = self.hidden_layer4(output) return output.to(device) discriminator = DiscriminatorModel() generator = GeneratorModel() discriminator.to(device) generator.to(device) print(generator,"\n\n\n",discriminator) # <----------交叉熵损失函数----------> criterion = nn.BCELoss() # <----------Adam优化器----------> d_optimizer = torch.optim.Adam(discriminator.parameters(), lr=0.0002) g_optimizer = torch.optim.Adam(generator.parameters(), lr=0.0002) num_epochs = 100 batch = 100 outputs=[] # Losses & scores losses_g = [] losses_d = [] real_scores = [] fake_scores = [] for epoch_idx in range(num_epochs): start_time = time.time() for batch_idx, data_input in enumerate(dataloader): real = data_input[0].view(batch, 784).to(device) # batch_size X 784 batch_size = data_input[1] # batch_size noise = torch.randn(batch,100).to(device) fake = generator(noise) # batch_size X 784 disc_real = discriminator(real).view(-1) lossD_real = criterion(disc_real, torch.ones_like(disc_real)) disc_fake = discriminator(fake).view(-1) lossD_fake = criterion(disc_fake, torch.zeros_like(disc_fake)) # <----------D_loss是lossD_real+lossD_fake的和----------> lossD = (lossD_real + lossD_fake) / 2 real_score = torch.mean(disc_real).item() fake_score = torch.mean(disc_fake).item() d_optimizer.zero_grad() lossD.backward(retain_graph=True) d_optimizer.step() gen_fake = discriminator(fake).view(-1) # <----------G_loss是使向D输入fake_img,输出的值向1靠近---------> lossG = criterion(gen_fake, torch.ones_like(gen_fake)) g_optimizer.zero_grad() lossG.backward() g_optimizer.step() if ((batch_idx + 1)% 600 == 0 and (epoch_idx + 1)%10 == 0): print("Training Steps Completed: ", batch_idx) with torch.no_grad(): generated_data = fake.cpu().view(batch, 28, 28) real_data = real.cpu().view(batch, 28, 28) i = 0 j = 0 plt.figure(figsize=(10,2)) print("Real Images") for x in real_data: if(i>=10): break plt.subplot(2,10,i+1) plt.imshow(x.detach().numpy(), interpolation='nearest',cmap='gray') i = i+1 plt.title("on "+str((epoch_idx + 1))+ "th epoch") plt.show() print("Generated Images") plt.figure(figsize=(10,2)) for x in generated_data: if(j>=10): break plt.subplot(2,10,j+1) plt.imshow(x.detach().numpy(), interpolation='nearest',cmap='gray') j = j+1 plt.show() outputs.append((epoch_idx,real,fake)) losses_g.append(lossG) losses_d.append(lossD) real_scores.append(real_score) fake_scores.append(fake_score) print('Epochs [{}/{}] & Batch [{}/{}]: loss_d: {:.4f}, loss_g: {:.4f}, real_score: {:.4f}, fake_score: {:.4f}, took time: {:.0f}s'.format( (epoch_idx+1), num_epochs, batch_idx+1, len(dataloader),lossD,lossG,real_score,fake_score,time.time()-start_time)) if epoch_idx % 10 == 0: plt.plot(losses_d, '-') plt.plot(losses_g, '-') plt.xlabel('epoch') plt.ylabel('loss') plt.legend(['Discriminator', 'Generator']) plt.title('Losses') plt.savefig('Losses.jpg') plt.show() plt.close() plt.plot(real_scores, '-') plt.plot(fake_scores, '-') plt.xlabel('epoch') plt.ylabel('score') plt.legend(['Real', 'Fake']) plt.title('Scores') plt.savefig('Scores.jpg') plt.show() plt.close() # Save trained models torch.save(generator.state_dict(), 'generator.pth') torch.save(discriminator.state_dict(), 'discriminator.pth')



VAE的Pytorch实现

copy
import os import torch import torch.nn as nn import torch.nn.functional as F import torchvision from torchvision import transforms from torchvision.utils import save_image # 配置GPU或CPU设置 device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 创建目录保存生成的图片 sample_dir = 'samples' if not os.path.exists(sample_dir): os.makedirs(sample_dir) # 超参数设置 image_size = 784 # 图片大小 h_dim = 400 z_dim = 20 num_epochs = 15 # 15个循环 batch_size = 128 # 一批的数量 learning_rate = 1e-3 # 学习率 # 获取数据集 dataset = torchvision.datasets.MNIST(root='./resource', train=True, transform=transforms.ToTensor(), download=True) # 数据加载,按照batch_size大小加载,并随机打乱 data_loader = torch.utils.data.DataLoader(dataset=dataset, batch_size=batch_size, shuffle=True) # VAE模型 class VAE(nn.Module): def __init__(self, image_size=784, h_dim=400, z_dim=20): super(VAE, self).__init__() self.fc1 = nn.Linear(image_size, h_dim) self.fc2 = nn.Linear(h_dim, z_dim) self.fc3 = nn.Linear(h_dim, z_dim) self.fc4 = nn.Linear(z_dim, h_dim) self.fc5 = nn.Linear(h_dim, image_size) # 编码,学习高斯分布均值与方差 def encode(self, x): h = F.relu(self.fc1(x)) return self.fc2(h), self.fc3(h) # 将高斯分布均值与方差参数重表示,生成隐变量z 若x~N(mu, var*var)分布,则(x-mu)/var=z~N(0, 1)分布 def reparameterize(self, mu, log_var): std = torch.exp(log_var / 2) eps = torch.randn_like(std) return mu + eps * std # 解码隐变量z def decode(self, z): h = F.relu(self.fc4(z)) return F.sigmoid(self.fc5(h)) # 计算重构值和隐变量z的分布参数 def forward(self, x): mu, log_var = self.encode(x) # 从原始样本x中学习隐变量z的分布,即学习服从高斯分布均值与方差 z = self.reparameterize(mu, log_var) # 将高斯分布均值与方差参数重表示,生成隐变量z x_reconst = self.decode(z) # 解码隐变量z,生成重构x’ return x_reconst, mu, log_var # 返回重构值和隐变量的分布参数 # 构造VAE实例对象 model = VAE().to(device) print(model) """VAE( (fc1): Linear(in_features=784, out_features=400, bias=True) (fc2): Linear(in_features=400, out_features=20, bias=True) (fc3): Linear(in_features=400, out_features=20, bias=True) (fc4): Linear(in_features=20, out_features=400, bias=True) (fc5): Linear(in_features=400, out_features=784, bias=True) )""" # 选择优化器,并传入VAE模型参数和学习率 optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate) # 开始训练一共15个循环 for epoch in range(num_epochs): for i, (x, _) in enumerate(data_loader): # 前向传播 x = x.to(device).view(-1, image_size) # 将batch_size*1*28*28 ---->batch_size*image_size 其中,image_size=1*28*28=784 x_reconst, mu, log_var = model(x) # 将batch_size*748的x输入模型进行前向传播计算,重构值和服从高斯分布的隐变量z的分布参数(均值和方差) # 计算重构损失和KL散度 # 重构损失 reconst_loss = F.binary_cross_entropy(x_reconst, x, size_average=False) # KL散度 kl_div = - 0.5 * torch.sum(1 + log_var - mu.pow(2) - log_var.exp()) # 反向传播与优化 # 计算误差(重构误差和KL散度值) loss = reconst_loss + kl_div # 清空上一步的残余更新参数值 optimizer.zero_grad() # 误差反向传播, 计算参数更新值 loss.backward() # 将参数更新值施加到VAE model的parameters上 optimizer.step() # 每迭代一定步骤,打印结果值 if (i + 1) % 10 == 0: print("Epoch[{}/{}], Step [{}/{}], Reconst Loss: {:.4f}, KL Div: {:.4f}" .format(epoch + 1, num_epochs, i + 1, len(data_loader), reconst_loss.item(), kl_div.item())) with torch.no_grad(): # 保存采样值 # 生成随机数 z z = torch.randn(batch_size, z_dim).to(device) # z的大小为batch_size * z_dim = 128*20 # 对随机数 z 进行解码decode输出 out = model.decode(z).view(-1, 1, 28, 28) # 保存结果值 save_image(out, os.path.join(sample_dir, 'sampled-{}.png'.format(epoch + 1))) # 保存重构值 # 将batch_size*748的x输入模型进行前向传播计算,获取重构值out out, _, _ = model(x) # 将输入与输出拼接在一起输出保存 batch_size*1*28*(28+28)=batch_size*1*28*56 x_concat = torch.cat([x.view(-1, 1, 28, 28), out.view(-1, 1, 28, 28)], dim=3) save_image(x_concat, os.path.join(sample_dir, 'reconst-{}.png'.format(epoch + 1)))
posted @   梁君牧  阅读(357)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
🚀