日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

机器学习(八) 生成对抗网络(GAN)

發(fā)布時間:2024/3/26 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 机器学习(八) 生成对抗网络(GAN) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 前言
  • 1 GAN
    • 1.1 相關介紹
    • 1.2 原理
      • 1.2.1 網(wǎng)絡架構
      • 1.2.2 網(wǎng)絡訓練
    • 1.3 用GAN生成圖像
      • 1.3.1 判別器
      • 1.3.2 生成器
      • 1.3.3 訓練模型
  • 2 GAN變種
    • 2.1 CGAN
      • 2.1.1 原理
      • 2.1.2 PyTorch實現(xiàn)
    • 2.2 DCGAN
    • 2.3 CycleGAN
    • 2.4 WGAN
  • 3 訓練GAN的技巧

前言

??在生成對抗網(wǎng)絡(Generative Adversarial Network,簡稱 GAN)發(fā)明之前,變分自編碼器(VAE)被認為是理論完備,實現(xiàn)簡單,使用神經(jīng)網(wǎng)絡訓練起來很穩(wěn)定,生成的圖片逼近度也較高,但是人眼還是可以很輕易地分辨出真實圖片與機器生成的圖片。但在2014年GAN被提出之后,在之后的幾年里面里迅速發(fā)展,生成的圖片越來越逼真。

1 GAN

1.1 相關介紹

??GAN模型的核心思想就是博弈思想,是生成器(造假者)和判別器(鑒別者)之間的博弈,在提出GAN的原始論文中,作者舉了貨幣制造的例子。即像一臺驗鈔機和一臺制造假幣的機器之間的博弈,兩者不斷博弈,博弈的結果假幣越來越像真幣,直到驗鈔機無法識別一張貨幣是假幣還是真幣為止。

1.2 原理

1.2.1 網(wǎng)絡架構

??生成對抗網(wǎng)絡包含了兩個子網(wǎng)絡:生成網(wǎng)絡(Generator,簡稱 G)和判別網(wǎng)絡(Discriminator,簡稱 D),其中生成網(wǎng)絡 G 負責學習樣本的真實分布,判別網(wǎng)絡 D 負責將生成網(wǎng)絡采樣的樣本與真實樣本區(qū)分開來。
??生成網(wǎng)絡G(𝒛) :生成網(wǎng)絡 G 和自編碼器的 Decoder 功能類似,從先驗分布pzp_zpz?(?)采樣獲得潛在空間點向量,經(jīng)過網(wǎng)絡生成圖片樣本xˉ\bar{x}xˉ~𝑝𝑔(x∣z)𝑝_𝑔(x|z)pg?(xz)
??生成器的網(wǎng)絡(𝑝𝑔(x∣z)𝑝_𝑔(x|z)pg?(xz))可以由深度神經(jīng)網(wǎng)絡來參數(shù)化,如:卷積網(wǎng)絡和轉(zhuǎn)置卷積網(wǎng)絡。下圖中從均勻分布𝑝𝒛𝑝𝒛pz(?)中采樣出隱藏變量zzz,經(jīng)過多層轉(zhuǎn)置卷積層網(wǎng)絡參數(shù)化的𝑝𝑔(x∣z)𝑝_𝑔(x|z)pg?(xz)分布中采樣出樣本xfx_fxf?,從輸入輸出層面來看,生成器 G 的功能是將隱向量𝒛通過神經(jīng)網(wǎng)絡轉(zhuǎn)換為樣本向量xfx_fxf?,下標𝑓代表假樣本(Fake samples)。
??判別網(wǎng)絡D(𝒙):判別網(wǎng)絡和普通的二分類網(wǎng)絡功能類似,網(wǎng)絡的輸入數(shù)據(jù)集由采樣自真實數(shù)據(jù)分布p𝑟p_𝑟pr?(?)的樣本x𝑟x_𝑟xr? ~ 𝑝𝑟𝑝_𝑟pr?(?)和采樣自生成網(wǎng)絡的假樣本x𝑓x_𝑓xf? ~ 𝑝𝑔(x∣z)𝑝_𝑔(x|z)pg?(xz)組成。判別網(wǎng)絡輸出為xxx屬于真實樣本的概率𝑃(xxx為真|xxx),我們把所有真實樣本xrx_rxr?的標簽標注為真(1),所有生成網(wǎng)絡產(chǎn)生的樣本,所有生成網(wǎng)絡產(chǎn)生的樣本xfx_fxf?標注為假(0),通過最小化判別網(wǎng)絡 D 的預測值與標簽之間的誤差來優(yōu)化判別網(wǎng)絡參數(shù)。

1.2.2 網(wǎng)絡訓練

??GAN 博弈學習的思想體現(xiàn)在在它的訓練方式上,由于生成器 G 和判別器 D 的優(yōu)化目標不一樣,不能和之前的網(wǎng)絡模型的訓練一樣,只采用一個損失函數(shù)。所以我們要分別對生成器和判別器進行訓練。
??判別網(wǎng)絡D(𝒙):它的目標是能夠很好地分辨出真樣本xrx_rxr?與假樣本xfx_fxf?。則其損失函數(shù)既要考慮識別真圖像能力,又要考慮識別假圖像能力,而不能只考慮一方面,故判別器的損失函數(shù)為兩者的和。因此 D 的分類問題是二分類問題,以圖片生成來說,交叉熵損失函數(shù)定義為:
因此判別網(wǎng)絡 D 的優(yōu)化目標是:

將最小化轉(zhuǎn)成最大化的問題并寫成期望的形式:

??具體代碼如下:D表示判別器、G為生成器、real_labels、fake_labels分別表示真圖像標簽、假圖像標簽。images是真圖像,z是從潛在空間隨機采樣的向量,通過生成器得到假圖像。

# 定義判斷器對真圖像的損失函數(shù) outputs = D(images) d_loss_real = criterion(outputs, real_labels) real_score = outputs # 定義判別器對假圖像(即由潛在空間點生成的圖像)的損失函數(shù) z = torch.randn(batch_size, latent_size).to(device) fake_images = G(z) outputs = D(fake_images) d_loss_fake = criterion(outputs, fake_labels) fake_score = outputs # 得到判別器總的損失函數(shù) d_loss = d_loss_real + d_loss_fake

??生成網(wǎng)絡G(𝒛) :我們希望xfx_fxf? = 𝐺(𝒛)能夠很好地騙過判別網(wǎng)絡 D,假樣本xfx_fxf?在判別網(wǎng)絡的輸出越接近真實的標簽越好。也就是說,在訓練生成網(wǎng)絡時,希望判別網(wǎng)絡的輸出𝐷(𝐺(𝒛))越逼近 1 越好,最小化𝐷(𝐺(𝒛))與 1 之間的交叉熵損失函數(shù):
將最小化轉(zhuǎn)成最大化的問題并寫成期望的形式:
等價成:

其中𝜙為生成網(wǎng)絡 G 的參數(shù)集,可以利用梯度下降算法來優(yōu)化參數(shù)𝜙。具體代碼如下:

z = torch.randn(batch_size, latent_size).to(device) fake_images = G(z) outputs = D(fake_images) g_loss = criterion(outputs, real_labels)

??通過對生成器和判別器的損失函數(shù)的求解,GAN的架構如下:

算法流程為:

1.3 用GAN生成圖像

??本次實驗為了方便,我使用的是 MNIST 手寫數(shù)字數(shù)據(jù)集,下面進行每部分的代碼實現(xiàn)。

1.3.1 判別器

??定義判別器網(wǎng)絡結構,這里使用LeakyReLU為激活函數(shù),輸出一個節(jié)點 并經(jīng)過Sigmoid后輸出,用于真假二分類。

class Discriminator(nn.Module) :def __init__(self) :super(Discriminator, self).__init__()self.D = nn.Sequential(nn.Linear(IMAGE_SIZE, HIDDEN_SIZE),nn.LeakyReLU(0.2),nn.Linear(HIDDEN_SIZE, HIDDEN_SIZE),nn.LeakyReLU(0.2),nn.Linear(HIDDEN_SIZE, 1),nn.Sigmoid())

1.3.2 生成器

??生成器與AVE的生成器類似,不同的地方是輸出為nn.tanh,使用nn.tanh 將使數(shù)據(jù)分布在[-1,1]之間。其輸入是潛在空間的向量z,輸出維度與真圖像相同。

class Generator(nn.Module) :def __init__(self):super(Generator, self).__init__()self.G = nn.Sequential(nn.Linear(Z_SIZE, HIDDEN_SIZE),nn.ReLU(),nn.Linear(HIDDEN_SIZE, HIDDEN_SIZE),nn.ReLU(),nn.Linear(HIDDEN_SIZE, IMAGE_SIZE),nn.Tanh())def forward(self, z) :return self.G(z)

1.3.3 訓練模型

for epoch in range(MAX_EPOCH) :for i, (images, labels) in enumerate(Dataloader) :images = images.reshape(BATCH_SIZE, -1).cuda()#真樣本與生成樣本的標簽設置real_labels = torch.ones(BATCH_SIZE, 1).cuda()fake_labels = torch.zeros(BATCH_SIZE, 1).cuda()#訓練判別器d_optimizer.zero_grad()g_optimizer.zero_grad()out = D(images)real_score = outd_loss_real = criterion(out, real_labels)z = torch.randn(BATCH_SIZE, Z_SIZE).cuda()fake_images = G(z)out = D(fake_images)fake_score = outd_loss_fake = criterion(out, fake_labels)d_loss = d_loss_fake + d_loss_reald_loss.backward()d_optimizer.step()#訓練生成器d_optimizer.zero_grad()g_optimizer.zero_grad()z = torch.randn(BATCH_SIZE, Z_SIZE).cuda()fake_images = G(z)out = D(fake_images)g_loss = criterion(out, real_labels)g_loss.backward()g_optimizer.step()if (i + 1) % 200 == 0:print('Epoch [{}/{}], Step [{}/{}], d_loss: {:.4f}, g_loss: {:.4f}, D(x): {:.2f}, D(G(z)): {:.2f}'.format(epoch, MAX_EPOCH, i + 1, len(Dataloader), d_loss.item(), g_loss.item(),real_score.mean().item(), fake_score.mean().item()))# 保存真圖片if (epoch + 1) == 1:images = images.reshape(images.size(0), 1, 28, 28)save_image(denorm(images), os.path.join(sample_dir, 'real_images.png'))# 保存假圖片fake_images = fake_images.reshape(fake_images.size(0), 1, 28, 28)save_image(denorm(fake_images), os.path.join(sample_dir, 'fake_images-{}.png'.format(epoch + 1)))# 保存模型torch.save(G.state_dict(), 'G.ckpt')torch.save(D.state_dict(), 'D.ckpt')

??效果,分別展示epoch為1、100、200時生成的圖片,其中當epoch為200時噪聲就已經(jīng)很少了,但是對數(shù)字的分布結構并不能很好的描述出來。

2 GAN變種

2.1 CGAN

??AVE和GAN都能基于潛在空間的隨機向量z生成新圖片,GAN生成的圖 像比AVE的更清晰,質(zhì)量更好些。不過它們生成的都是隨機的,無法預先控制你要生成的哪類或哪個數(shù)。我們希望 生成某個數(shù)字,生成某個主題或類別的圖像,實現(xiàn)按需生成的目的,這樣的應用應該非常廣泛。CGAN正是針對這類問題而提出的。

2.1.1 原理

??在GAN這種完全無監(jiān)督的方式加上一個標簽或一點監(jiān)督信息,使整個網(wǎng)絡就可看成半監(jiān)督模型。其基本架構與GAN類似,只要添加一個條件y即可,y就是加入的監(jiān)督信息,比如說MNIST數(shù)據(jù)集可以提供某個數(shù)字的標簽 信息,人臉生成可以提供性別、是否微笑、年齡等信息,帶某個主題的圖像 等標簽信息。

??對生成器輸入一個從潛在空間隨機采樣的一個向量z及一個條件y,生成 一個符合該條件的圖像G(z/y)。對判別器來說,輸入一張圖像x和條件y,輸 出該圖像在該條件下的概率D(x/y)。

2.1.2 PyTorch實現(xiàn)

??CGAN實現(xiàn)采用的數(shù)據(jù)集依然是 MNIST 手寫數(shù)字數(shù)據(jù)集,其實現(xiàn)過程與原始的GAN的相差不大,主要差異時是標注信息的添加。

import torch import torch.nn as nn import torch.optim as optim import os import matplotlib.pyplot as plt import torchvision.transforms as transforms from torchvision import datasets from torch.utils.data import DataLoader from torchvision.utils import save_image from torch.utils.tensorboard import SummaryWriter from torchvision.utils import make_grid#設置超參數(shù) MAX_EPOCH = 50 LR_RATE = 0.0001 BATCH_SIZE = 100writer = SummaryWriter(log_dir = 'logs') sample_dir = 'samples_CGAN' os.makedirs(sample_dir, exist_ok = True)Dataset = datasets.MNIST(root = 'data',download = False,train = True,transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize([0.5], [0.5])]))Dataloader = DataLoader(Dataset, batch_size = BATCH_SIZE, shuffle = True, drop_last = True)#生成器 class Generator(nn.Module) :def __init__(self):super(Generator, self).__init__()self.embedding = nn.Embedding(10, 10)self.G = nn.Sequential(nn.Linear(110, 256),nn.LeakyReLU(0.2),nn.Linear(256, 512),nn.LeakyReLU(0.2),nn.Linear(512, 1024),nn.LeakyReLU(0.2),nn.Linear(1024, 784),nn.Tanh())def forward(self, z, labels) :y = self.embedding(labels)x = torch.cat([z, y], dim = 1)out = self.G(x)return out.view(z.size(0), 28, 28)#判別器 class Discriminator(nn.Module) :def __init__(self) :super(Discriminator, self).__init__()self.embedding = nn.Embedding(10, 10)self.D = nn.Sequential(nn.Linear(794, 1024),nn.LeakyReLU(0.2),nn.Dropout(0.4),nn.Linear(1024, 512),nn.LeakyReLU(0.2),nn.Dropout(0.4),nn.Linear(512, 256),nn.LeakyReLU(0.2),nn.Dropout(0.4),nn.Linear(256, 1),nn.Sigmoid())def forward(self, x, labels):x = x.view(x.size(0), -1)y = self.embedding(labels)x = torch.cat([x, y], dim = 1)out = self.D(x)return out#Clamp函數(shù)x限制在區(qū)間[min, max]內(nèi) def denorm(x):out = (x + 1) / 2return out.clamp(0, 1)D = Discriminator().cuda() G = Generator().cuda() d_optimizer = optim.Adam(D.parameters(), lr = LR_RATE) g_optimizer = optim.Adam(G.parameters(), lr = LR_RATE) criterion = nn.BCELoss()#訓練 for epoch in range(MAX_EPOCH) :for i, (images, labels) in enumerate(Dataloader) :step = epoch * len(Dataloader) + i + 1images, labels = images.reshape(BATCH_SIZE, -1).cuda(), labels.cuda()real_labels = torch.ones(BATCH_SIZE, 1).cuda()d_optimizer.zero_grad()g_optimizer.zero_grad()out = D(images, labels)real_score = outd_loss_real = criterion(out, real_labels)z = torch.randn(BATCH_SIZE, 100).cuda()fake_labels = torch.randint(0, 10, (BATCH_SIZE, )).cuda()fake_images = G(z, fake_labels)out = D(fake_images, fake_labels)fake_score = outd_loss_fake = criterion(out, torch.zeros(BATCH_SIZE, 1).cuda())d_loss = d_loss_fake + d_loss_reald_loss.backward()d_optimizer.step()d_optimizer.zero_grad()g_optimizer.zero_grad()z = torch.randn(BATCH_SIZE, 100).cuda()fake_images = G(z, fake_labels)out = D(fake_images, fake_labels)g_loss = criterion(out, real_labels)g_loss.backward()g_optimizer.step()if (i + 1) % 200 == 0:print('Epoch [{}/{}], Step [{}/{}], d_loss: {:.4f}, g_loss: {:.4f}, D(x): {:.2f}, D(G(z)): {:.2f}'.format(epoch, MAX_EPOCH, i + 1, len(Dataloader), d_loss.item(), g_loss.item(),real_score.mean().item(), fake_score.mean().item()))# 保存真圖片if (epoch + 1) == 1:images = images.reshape(images.size(0), 1, 28, 28)save_image(denorm(images), os.path.join(sample_dir, 'real_images.png'))# 保存假圖片fake_images = fake_images.reshape(fake_images.size(0), 1, 28, 28)save_image(denorm(fake_images), os.path.join(sample_dir, 'fake_images-{}.png'.format(epoch + 1)))# 可視化損失值writer.add_scalars('scalars', {'d_loss': d_loss.item(), 'g_loss': g_loss.item()}, step)# 保存模型torch.save(G.state_dict(), 'G.ckpt')torch.save(D.state_dict(), 'D.ckpt')#利用網(wǎng)格(10×10)的形式顯示指定條件下生成的圖像。 z = torch.randn(100, 100).cuda() labels = torch.LongTensor([i for i in range(10) for _ in range(10)]).cuda() images = G(z, labels).unsqueeze(1) grid = make_grid(images, nrow = 10, normalize = True) fig, ax = plt.subplots(figsize = (10, 10)) ax.imshow(grid.permute(1, 2, 0).detach().cpu().numpy(), cmap = 'binary') ax.axis('off') plt.show()#可視化指定單個數(shù)字條件下生成的數(shù)字 def generate_digit(generator, digit) :z = torch.randn(1, 100).cuda()label = torch.LongTensor([digit]).cuda()img = generator(z, label).detach().cpu()img = 0.5 * img + 0.5return transforms.ToPILImage()(img) generate_digit(G, 8)

利用網(wǎng)格(10×10)的形式顯示指定條件下生成的圖像:

可視化指定單個數(shù)字條件下生成的數(shù)字:

可視化生成器和判別器損失值如下 :

由上圖可知,CGAN的訓練過程不像一般神經(jīng)網(wǎng)絡的過程,它是判別 器和生成器互相競爭的過程,最后兩者達成一個平衡。

2.2 DCGAN

??在前面中無論是原始的GAN還是CGAN我們建立的網(wǎng)絡都是基于全連接網(wǎng)絡構建的,這樣的網(wǎng)絡由于圖片的維度較高,網(wǎng)絡參數(shù)量巨大,不能很好地學習到圖片地特征,導致訓練效果不佳。DCGAN提出了使用轉(zhuǎn)置卷積層實現(xiàn)的生成網(wǎng)絡,普通卷積層來實現(xiàn)的判別網(wǎng)絡,大大地降低了網(wǎng)絡參數(shù)量,同時圖片的生成效果也大幅提升,展現(xiàn)了 GAN 模型在圖片生成效果上超越 VAE 模型的潛質(zhì)。注:雖然使用卷積網(wǎng)絡會大大降低參數(shù)量,但是所需要的樣本數(shù)要更多一些。

2.3 CycleGAN

CycleGAN 是一種無監(jiān)督方式,主要用于圖片風格相互轉(zhuǎn)換的。CycleGAN 基本的思想是,如果由圖片 A 轉(zhuǎn)換到圖片 B,再從圖片 B 轉(zhuǎn)換到A′,那么A′應該和 A 是同一張圖片。因此除了設立標準的 GAN 損失項外,CycleGAN 還增設了循環(huán)一致性損失(Cycle Consistency Loss),來保證A′盡可能與 A 逼近。

2.4 WGAN

??GAN 的訓練問題一直被詬病,很容易出現(xiàn)訓練不收斂和模式崩塌的現(xiàn)象。WGAN 從理論層面分析了原始的 GAN 使用 JS 散度存在的缺陷,并提出了可以使用 Wasserstein 距 離來解決這個問題。在 WGAN-GP 中,作者提出了通過添加梯度懲罰項,從工程層面很好的實現(xiàn)了 WGAN 算法,并且實驗性證實了 WGAN 訓練穩(wěn)定的優(yōu)點。

3 訓練GAN的技巧

  • 批量加載和批規(guī)范化,有利于提升訓練過程中博弈的穩(wěn)定性。
  • 使用tanh激活函數(shù)作為生成器最后一層,將圖像數(shù)據(jù)規(guī)范在-1和1之間,一般不用sigmoid。
  • 選用Leaky ReLU作為生成器和判別器的激活函數(shù),有利于改善梯度的稀疏性,稀疏的梯度會妨礙GAN的訓練。
  • 使用卷積層時,考慮卷積核的大小能被步幅整除,否則,可能導致生成的圖像中存在棋盤狀偽影。

全部代碼可以參考此處
參考

  • 《Python深度學習基于PyTorch》
  • 《TensorFlow深度學習》

總結

以上是生活随笔為你收集整理的机器学习(八) 生成对抗网络(GAN)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。