0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

PyTorch教程-20.2. 深度卷積生成對抗網(wǎng)絡

jf_pJlTbmA9 ? 來源:PyTorch ? 作者:PyTorch ? 2023-06-05 15:44 ? 次閱讀

20.1 節(jié)中,我們介紹了 GAN 工作原理背后的基本思想。我們展示了他們可以從一些簡單的、易于采樣的分布中抽取樣本,比如均勻分布或正態(tài)分布,并將它們轉(zhuǎn)換成看起來與某些數(shù)據(jù)集的分布相匹配的樣本。雖然我們匹配 2D 高斯分布的示例說明了要點,但它并不是特別令人興奮。

在本節(jié)中,我們將演示如何使用 GAN 生成逼真的圖像。我們的模型將基于 Radford等人介紹的深度卷積 GAN (DCGAN)。2015 年。我們將借用已經(jīng)證明在判別計算機視覺問題上非常成功的卷積架構(gòu),并展示如何通過 GAN 來利用它們來生成逼真的圖像。

import warnings
import torch
import torchvision
from torch import nn
from d2l import torch as d2l
from mxnet import gluon, init, np, npx
from mxnet.gluon import nn
from d2l import mxnet as d2l

npx.set_np()
import tensorflow as tf
from d2l import tensorflow as d2l

20.2.1。口袋妖怪數(shù)據(jù)集

我們將使用的數(shù)據(jù)集是從pokemondb獲得的 Pokemon 精靈的集合 。首先下載、提取和加載此數(shù)據(jù)集。

#@save
d2l.DATA_HUB['pokemon'] = (d2l.DATA_URL + 'pokemon.zip',
              'c065c0e2593b8b161a2d7873e42418bf6a21106c')

data_dir = d2l.download_extract('pokemon')
pokemon = torchvision.datasets.ImageFolder(data_dir)
Downloading ../data/pokemon.zip from http://d2l-data.s3-accelerate.amazonaws.com/pokemon.zip...
#@save
d2l.DATA_HUB['pokemon'] = (d2l.DATA_URL + 'pokemon.zip',
              'c065c0e2593b8b161a2d7873e42418bf6a21106c')

data_dir = d2l.download_extract('pokemon')
pokemon = gluon.data.vision.datasets.ImageFolderDataset(data_dir)
Downloading ../data/pokemon.zip from http://d2l-data.s3-accelerate.amazonaws.com/pokemon.zip...
#@save
d2l.DATA_HUB['pokemon'] = (d2l.DATA_URL + 'pokemon.zip',
              'c065c0e2593b8b161a2d7873e42418bf6a21106c')

data_dir = d2l.download_extract('pokemon')
batch_size = 256
pokemon = tf.keras.preprocessing.image_dataset_from_directory(
  data_dir, batch_size=batch_size, image_size=(64, 64))
Downloading ../data/pokemon.zip from http://d2l-data.s3-accelerate.amazonaws.com/pokemon.zip...
Found 40597 files belonging to 721 classes.

我們將每個圖像調(diào)整為64×64. 變換ToTensor 會將像素值投影到[0,1],而我們的生成器將使用 tanh 函數(shù)獲取輸出 [?1,1]. 因此我們用0.5意味著和0.5標準偏差以匹配值范圍。

batch_size = 256
transformer = torchvision.transforms.Compose([
  torchvision.transforms.Resize((64, 64)),
  torchvision.transforms.ToTensor(),
  torchvision.transforms.Normalize(0.5, 0.5)
])
pokemon.transform = transformer
data_iter = torch.utils.data.DataLoader(
  pokemon, batch_size=batch_size,
  shuffle=True, num_workers=d2l.get_dataloader_workers())
batch_size = 256
transformer = gluon.data.vision.transforms.Compose([
  gluon.data.vision.transforms.Resize(64),
  gluon.data.vision.transforms.ToTensor(),
  gluon.data.vision.transforms.Normalize(0.5, 0.5)
])
data_iter = gluon.data.DataLoader(
  pokemon.transform_first(transformer), batch_size=batch_size,
  shuffle=True, num_workers=d2l.get_dataloader_workers())
def transform_func(X):
  X = X / 255.
  X = (X - 0.5) / (0.5)
  return X

# For TF>=2.4 use `num_parallel_calls = tf.data.AUTOTUNE`
data_iter = pokemon.map(lambda x, y: (transform_func(x), y),
            num_parallel_calls=tf.data.experimental.AUTOTUNE)
data_iter = data_iter.cache().shuffle(buffer_size=1000).prefetch(
  buffer_size=tf.data.experimental.AUTOTUNE)
WARNING:tensorflow:From /home/d2l-worker/miniconda3/envs/d2l-en-release-1/lib/python3.9/site-packages/tensorflow/python/autograph/pyct/static_analysis/liveness.py:83: Analyzer.lamba_check (from tensorflow.python.autograph.pyct.static_analysis.liveness) is deprecated and will be removed after 2023-09-23.
Instructions for updating:
Lambda fuctions will be no more assumed to be used in the statement where they are used, or at least in the same block. https://github.com/tensorflow/tensorflow/issues/56089

讓我們想象一下前 20 張圖像。

warnings.filterwarnings('ignore')
d2l.set_figsize((4, 4))
for X, y in data_iter:
  imgs = X[:20,:,:,:].permute(0, 2, 3, 1)/2+0.5
  d2l.show_images(imgs, num_rows=4, num_cols=5)
  break
https://file.elecfans.com/web2/M00/A9/CE/poYBAGR9PgeAcQuvAAUFYoaPyj0359.svg
d2l.set_figsize((4, 4))
for X, y in data_iter:
  imgs = X[:20,:,:,:].transpose(0, 2, 3, 1)/2+0.5
  d2l.show_images(imgs, num_rows=4, num_cols=5)
  break
https://file.elecfans.com/web2/M00/AA/49/pYYBAGR9PgqAFv1VAAWC4qBkgJs206.svg
d2l.set_figsize(figsize=(4, 4))
for X, y in data_iter.take(1):
  imgs = X[:20, :, :, :] / 2 + 0.5
  d2l.show_images(imgs, num_rows=4, num_cols=5)
https://file.elecfans.com/web2/M00/A9/CE/poYBAGR9Pg6AP2sgAAWKkkbhRrg987.svg

20.2.2。發(fā)電機

生成器需要映射噪聲變量 z∈Rd, 長度-d向量,到具有寬度和高度的 RGB 圖像64×64. 14.11 節(jié)中我們介紹了全卷積網(wǎng)絡,它使用轉(zhuǎn)置卷積層(參考 14.10 節(jié))來擴大輸入尺寸。生成器的基本塊包含一個轉(zhuǎn)置卷積層,然后是批量歸一化和 ReLU 激活。

class G_block(nn.Module):
  def __init__(self, out_channels, in_channels=3, kernel_size=4, strides=2,
         padding=1, **kwargs):
    super(G_block, self).__init__(**kwargs)
    self.conv2d_trans = nn.ConvTranspose2d(in_channels, out_channels,
                kernel_size, strides, padding, bias=False)
    self.batch_norm = nn.BatchNorm2d(out_channels)
    self.activation = nn.ReLU()

  def forward(self, X):
    return self.activation(self.batch_norm(self.conv2d_trans(X)))
class G_block(nn.Block):
  def __init__(self, channels, kernel_size=4,
         strides=2, padding=1, **kwargs):
    super(G_block, self).__init__(**kwargs)
    self.conv2d_trans = nn.Conv2DTranspose(
      channels, kernel_size, strides, padding, use_bias=False)
    self.batch_norm = nn.BatchNorm()
    self.activation = nn.Activation('relu')

  def forward(self, X):
    return self.activation(self.batch_norm(self.conv2d_trans(X)))
class G_block(tf.keras.layers.Layer):
  def __init__(self, out_channels, kernel_size=4, strides=2, padding="same",
         **kwargs):
    super().__init__(**kwargs)
    self.conv2d_trans = tf.keras.layers.Conv2DTranspose(
      out_channels, kernel_size, strides, padding, use_bias=False)
    self.batch_norm = tf.keras.layers.BatchNormalization()
    self.activation = tf.keras.layers.ReLU()

  def call(self, X):
    return self.activation(self.batch_norm(self.conv2d_trans(X)))

默認情況下,轉(zhuǎn)置卷積層使用 kh=kw=4內(nèi)核,一個sh=sw=2大步前進,一個 ph=pw=1填充。輸入形狀為 nh′×nw′=16×16,生成器塊將使輸入的寬度和高度加倍。

(20.2.1)nh′×nw′=[(nhkh?(nh?1)(kh?sh)?2ph]×[(nwkw?(nw?1)(kw?sw)?2pw]=[(kh+sh(nh?1)?2ph]×[(kw+sw(nw?1)?2pw]=[(4+2×(16?1)?2×1]×[(4+2×(16?1)?2×1]=32×32.
x = torch.zeros((2, 3, 16, 16))
g_blk = G_block(20)
g_blk(x).shape
torch.Size([2, 20, 32, 32])
x = np.zeros((2, 3, 16, 16))
g_blk = G_block(20)
g_blk.initialize()
g_blk(x).shape
(2, 20, 32, 32)
x = tf.zeros((2, 16, 16, 3)) # Channel last convention
g_blk = G_block(20)
g_blk(x).shape
TensorShape([2, 32, 32, 20])

如果將轉(zhuǎn)置卷積層更改為4×4 核心,1×1步幅和零填充。輸入大小為 1×1,輸出的寬度和高度將分別增加 3。

x = torch.zeros((2, 3, 1, 1))
g_blk = G_block(20, strides=1, padding=0)
g_blk(x).shape
torch.Size([2, 20, 4, 4])
x = np.zeros((2, 3, 1, 1))
g_blk = G_block(20, strides=1, padding=0)
g_blk.initialize()
g_blk(x).shape
(2, 20, 4, 4)
x = tf.zeros((2, 1, 1, 3))
# `padding="valid"` corresponds to no padding
g_blk = G_block(20, strides=1, padding="valid")
g_blk(x).shape
TensorShape([2, 4, 4, 20])

生成器由四個基本塊組成,將輸入的寬度和高度從 1 增加到 32。同時,它首先將潛在變量投影到64×8通道,然后每次將通道減半。最后,使用轉(zhuǎn)置卷積層生成輸出。它進一步加倍寬度和高度以匹配所需的64×64形狀,并將通道尺寸減小到 3. tanh 激活函數(shù)用于將輸出值投影到(?1,1)范圍。

n_G = 64
net_G = nn.Sequential(
  G_block(in_channels=100, out_channels=n_G*8,
      strides=1, padding=0),         # Output: (64 * 8, 4, 4)
  G_block(in_channels=n_G*8, out_channels=n_G*4), # Output: (64 * 4, 8, 8)
  G_block(in_channels=n_G*4, out_channels=n_G*2), # Output: (64 * 2, 16, 16)
  G_block(in_channels=n_G*2, out_channels=n_G),  # Output: (64, 32, 32)
  nn.ConvTranspose2d(in_channels=n_G, out_channels=3,
            kernel_size=4, stride=2, padding=1, bias=False),
  nn.Tanh()) # Output: (3, 64, 64)
n_G = 64
net_G = nn.Sequential()
net_G.add(G_block(n_G*8, strides=1, padding=0), # Output: (64 * 8, 4, 4)
     G_block(n_G*4), # Output: (64 * 4, 8, 8)
     G_block(n_G*2), # Output: (64 * 2, 16, 16)
     G_block(n_G),  # Output: (64, 32, 32)
     nn.Conv2DTranspose(
       3, kernel_size=4, strides=2, padding=1, use_bias=False,
       activation='tanh')) # Output: (3, 64, 64)
n_G = 64
net_G = tf.keras.Sequential([
  # Output: (4, 4, 64 * 8)
  G_block(out_channels=n_G*8, strides=1, padding="valid"),
  G_block(out_channels=n_G*4), # Output: (8, 8, 64 * 4)
  G_block(out_channels=n_G*2), # Output: (16, 16, 64 * 2)
  G_block(out_channels=n_G), # Output: (32, 32, 64)
  # Output: (64, 64, 3)
  tf.keras.layers.Conv2DTranspose(
    3, kernel_size=4, strides=2, padding="same", use_bias=False,
    activation="tanh")
])

生成一個 100 維的潛在變量來驗證生成器的輸出形狀。

x = torch.zeros((1, 100, 1, 1))
net_G(x).shape
torch.Size([1, 3, 64, 64])
x = np.zeros((1, 100, 1, 1))
net_G.initialize()
net_G(x).shape
(1, 3, 64, 64)
x = tf.zeros((1, 1, 1, 100))
net_G(x).shape
TensorShape([1, 64, 64, 3])

20.2.3。判別器

判別器是一個普通的卷積網(wǎng)絡,除了它使用一個 leaky ReLU 作為它的激活函數(shù)。鑒于 α∈[0,1], 它的定義是

(20.2.2)leaky ReLU(x)={xifx>0αxotherwise.

可以看出,如果α=0,以及一個身份函數(shù),如果α=1. 為了α∈(0,1),leaky ReLU 是一個非線性函數(shù),它為負輸入提供非零輸出。它旨在解決“垂死的 ReLU”問題,即神經(jīng)元可能始終輸出負值,因此無法取得任何進展,因為 ReLU 的梯度為 0。

alphas = [0, .2, .4, .6, .8, 1]
x = torch.arange(-2, 1, 0.1)
Y = [nn.LeakyReLU(alpha)(x).detach().numpy() for alpha in alphas]
d2l.plot(x.detach().numpy(), Y, 'x', 'y', alphas)
https://file.elecfans.com/web2/M00/A9/CE/poYBAGR9PhKAAphBAACN8Sd5kmw122.svg
alphas = [0, .2, .4, .6, .8, 1]
x = np.arange(-2, 1, 0.1)
Y = [nn.LeakyReLU(alpha)(x).asnumpy() for alpha in alphas]
d2l.plot(x.asnumpy(), Y, 'x', 'y', alphas)
https://file.elecfans.com/web2/M00/A9/CE/poYBAGR9PhSAVJfHAACN_mMaeFE528.svg
alphas = [0, .2, .4, .6, .8, 1]
x = tf.range(-2, 1, 0.1)
Y = [tf.keras.layers.LeakyReLU(alpha)(x).numpy() for alpha in alphas]
d2l.plot(x.numpy(), Y, 'x', 'y', alphas)
https://file.elecfans.com/web2/M00/A9/CE/poYBAGR9PhaAZDDrAACPk58eqYI298.svg

判別器的基本塊是一個卷積層,然后是一個批量歸一化層和一個 leaky ReLU 激活。卷積層的超參數(shù)類似于生成器塊中的轉(zhuǎn)置卷積層。

class D_block(nn.Module):
  def __init__(self, out_channels, in_channels=3, kernel_size=4, strides=2,
        padding=1, alpha=0.2, **kwargs):
    super(D_block, self).__init__(**kwargs)
    self.conv2d = nn.Conv2d(in_channels, out_channels, kernel_size,
                strides, padding, bias=False)
    self.batch_norm = nn.BatchNorm2d(out_channels)
    self.activation = nn.LeakyReLU(alpha, inplace=True)

  def forward(self, X):
    return self.activation(self.batch_norm(self.conv2d(X)))
class D_block(nn.Block):
  def __init__(self, channels, kernel_size=4, strides=2,
         padding=1, alpha=0.2, **kwargs):
    super(D_block, self).__init__(**kwargs)
    self.conv2d = nn.Conv2D(
      channels, kernel_size, strides, padding, use_bias=False)
    self.batch_norm = nn.BatchNorm()
    self.activation = nn.LeakyReLU(alpha)

  def forward(self, X):
    return self.activation(self.batch_norm(self.conv2d(X)))
class D_block(tf.keras.layers.Layer):
  def __init__(self, out_channels, kernel_size=4, strides=2, padding="same",
         alpha=0.2, **kwargs):
    super().__init__(**kwargs)
    self.conv2d = tf.keras.layers.Conv2D(out_channels, kernel_size,
                       strides, padding, use_bias=False)
    self.batch_norm = tf.keras.layers.BatchNormalization()
    self.activation = tf.keras.layers.LeakyReLU(alpha)

  def call(self, X):
    return self.activation(self.batch_norm(self.conv2d(X)))

正如我們在第 7.3 節(jié)中演示的那樣,具有默認設置的基本塊會將輸入的寬度和高度減半。例如,給定一個輸入形狀nh=nw=16, 具有內(nèi)核形狀 kh=kw=4, 步幅sh=sw=2和填充形狀ph=pw=1,輸出形狀將是:

(20.2.3)nh′×nw′=?(nh?kh+2ph+sh)/sh?×?(nw?kw+2pw+sw)/sw?=?(16?4+2×1+2)/2?×?(16?4+2×1+2)/2?=8×8.
x = torch.zeros((2, 3, 16, 16))
d_blk = D_block(20)
d_blk(x).shape
torch.Size([2, 20, 8, 8])
x = np.zeros((2, 3, 16, 16))
d_blk = D_block(20)
d_blk.initialize()
d_blk(x).shape
(2, 20, 8, 8)
x = tf.zeros((2, 16, 16, 3))
d_blk = D_block(20)
d_blk(x).shape
TensorShape([2, 8, 8, 20])

鑒別器是生成器的鏡像。

n_D = 64
net_D = nn.Sequential(
  D_block(n_D), # Output: (64, 32, 32)
  D_block(in_channels=n_D, out_channels=n_D*2), # Output: (64 * 2, 16, 16)
  D_block(in_channels=n_D*2, out_channels=n_D*4), # Output: (64 * 4, 8, 8)
  D_block(in_channels=n_D*4, out_channels=n_D*8), # Output: (64 * 8, 4, 4)
  nn.Conv2d(in_channels=n_D*8, out_channels=1,
       kernel_size=4, bias=False)) # Output: (1, 1, 1)
n_D = 64
net_D = nn.Sequential()
net_D.add(D_block(n_D),  # Output: (64, 32, 32)
     D_block(n_D*2), # Output: (64 * 2, 16, 16)
     D_block(n_D*4), # Output: (64 * 4, 8, 8)
     D_block(n_D*8), # Output: (64 * 8, 4, 4)
     nn.Conv2D(1, kernel_size=4, use_bias=False)) # Output: (1, 1, 1)
n_D = 64
net_D = tf.keras.Sequential([
  D_block(n_D), # Output: (32, 32, 64)
  D_block(out_channels=n_D*2), # Output: (16, 16, 64 * 2)
  D_block(out_channels=n_D*4), # Output: (8, 8, 64 * 4)
  D_block(out_channels=n_D*8), # Outupt: (4, 4, 64 * 64)
  # Output: (1, 1, 1)
  tf.keras.layers.Conv2D(1, kernel_size=4, use_bias=False)
])

它使用帶有輸出通道的卷積層1作為獲得單個預測值的最后一層。

x = torch.zeros((1, 3, 64, 64))
net_D(x).shape
torch.Size([1, 1, 1, 1])
x = np.zeros((1, 3, 64, 64))
net_D.initialize()
net_D(x).shape
(1, 1, 1, 1)
x = tf.zeros((1, 64, 64, 3))
net_D(x).shape
TensorShape([1, 1, 1, 1])

20.2.4。訓練

第 20.1 節(jié)中的基本 GAN 相比,我們對生成器和鑒別器使用相同的學習率,因為它們彼此相似。此外,我們改變β1在 Adam 中(第 12.10 節(jié))來自0.90.5. 它降低了動量的平滑度,即過去梯度的指數(shù)加權(quán)移動平均值,以處理快速變化的梯度,因為生成器和鑒別器相互爭斗。此外,隨機生成的噪聲Z是一個 4-D 張量,我們正在使用 GPU加速計算。

def train(net_D, net_G, data_iter, num_epochs, lr, latent_dim,
     device=d2l.try_gpu()):
  loss = nn.BCEWithLogitsLoss(reduction='sum')
  for w in net_D.parameters():
    nn.init.normal_(w, 0, 0.02)
  for w in net_G.parameters():
    nn.init.normal_(w, 0, 0.02)
  net_D, net_G = net_D.to(device), net_G.to(device)
  trainer_hp = {'lr': lr, 'betas': [0.5,0.999]}
  trainer_D = torch.optim.Adam(net_D.parameters(), **trainer_hp)
  trainer_G = torch.optim.Adam(net_G.parameters(), **trainer_hp)
  animator = d2l.Animator(xlabel='epoch', ylabel='loss',
              xlim=[1, num_epochs], nrows=2, figsize=(5, 5),
              legend=['discriminator', 'generator'])
  animator.fig.subplots_adjust(hspace=0.3)
  for epoch in range(1, num_epochs + 1):
    # Train one epoch
    timer = d2l.Timer()
    metric = d2l.Accumulator(3) # loss_D, loss_G, num_examples
    for X, _ in data_iter:
      batch_size = X.shape[0]
      Z = torch.normal(0, 1, size=(batch_size, latent_dim, 1, 1))
      X, Z = X.to(device), Z.to(device)
      metric.add(d2l.update_D(X, Z, net_D, net_G, loss, trainer_D),
            d2l.update_G(Z, net_D, net_G, loss, trainer_G),
            batch_size)
    # Show generated examples
    Z = torch.normal(0, 1, size=(21, latent_dim, 1, 1), device=device)
    # Normalize the synthetic data to N(0, 1)
    fake_x = net_G(Z).permute(0, 2, 3, 1) / 2 + 0.5
    imgs = torch.cat(
      [torch.cat([
        fake_x[i * 7 + j].cpu().detach() for j in range(7)], dim=1)
       for i in range(len(fake_x)//7)], dim=0)
    animator.axes[1].cla()
    animator.axes[1].imshow(imgs)
    # Show the losses
    loss_D, loss_G = metric[0] / metric[2], metric[1] / metric[2]
    animator.add(epoch, (loss_D, loss_G))
  print(f'loss_D {loss_D:.3f}, loss_G {loss_G:.3f}, '
     f'{metric[2] / timer.stop():.1f} examples/sec on {str(device)}')
def train(net_D, net_G, data_iter, num_epochs, lr, latent_dim,
     device=d2l.try_gpu()):
  loss = gluon.loss.SigmoidBCELoss()
  net_D.initialize(init=init.Normal(0.02), force_reinit=True, ctx=device)
  net_G.initialize(init=init.Normal(0.02), force_reinit=True, ctx=device)
  trainer_hp = {'learning_rate': lr, 'beta1': 0.5}
  trainer_D = gluon.Trainer(net_D.collect_params(), 'adam', trainer_hp)
  trainer_G = gluon.Trainer(net_G.collect_params(), 'adam', trainer_hp)
  animator = d2l.Animator(xlabel='epoch', ylabel='loss',
              xlim=[1, num_epochs], nrows=2, figsize=(5, 5),
              legend=['discriminator', 'generator'])
  animator.fig.subplots_adjust(hspace=0.3)
  for epoch in range(1, num_epochs + 1):
    # Train one epoch
    timer = d2l.Timer()
    metric = d2l.Accumulator(3) # loss_D, loss_G, num_examples
    for X, _ in data_iter:
      batch_size = X.shape[0]
      Z = np.random.normal(0, 1, size=(batch_size, latent_dim, 1, 1))
      X, Z = X.as_in_ctx(device), Z.as_in_ctx(device),
      metric.add(d2l.update_D(X, Z, net_D, net_G, loss, trainer_D),
            d2l.update_G(Z, net_D, net_G, loss, trainer_G),
            batch_size)
    # Show generated examples
    Z = np.random.normal(0, 1, size=(21, latent_dim, 1, 1), ctx=device)
    # Normalize the synthetic data to N(0, 1)
    fake_x = net_G(Z).transpose(0, 2, 3, 1) / 2 + 0.5
    imgs = np.concatenate(
      [np.concatenate([fake_x[i * 7 + j] for j in range(7)], axis=1)
       for i in range(len(fake_x)//7)], axis=0)
    animator.axes[1].cla()
    animator.axes[1].imshow(imgs.asnumpy())
    # Show the losses
    loss_D, loss_G = metric[0] / metric[2], metric[1] / metric[2]
    animator.add(epoch, (loss_D, loss_G))
  print(f'loss_D {loss_D:.3f}, loss_G {loss_G:.3f}, '
     f'{metric[2] / timer.stop():.1f} examples/sec on {str(device)}')
def train(net_D, net_G, data_iter, num_epochs, lr, latent_dim,
     device=d2l.try_gpu()):
  loss = tf.keras.losses.BinaryCrossentropy(
    from_logits=True, reduction=tf.keras.losses.Reduction.SUM)

  for w in net_D.trainable_variables:
    w.assign(tf.random.normal(mean=0, stddev=0.02, shape=w.shape))
  for w in net_G.trainable_variables:
    w.assign(tf.random.normal(mean=0, stddev=0.02, shape=w.shape))

  optimizer_hp = {"lr": lr, "beta_1": 0.5, "beta_2": 0.999}
  optimizer_D = tf.keras.optimizers.Adam(**optimizer_hp)
  optimizer_G = tf.keras.optimizers.Adam(**optimizer_hp)

  animator = d2l.Animator(xlabel='epoch', ylabel='loss',
              xlim=[1, num_epochs], nrows=2, figsize=(5, 5),
              legend=['discriminator', 'generator'])
  animator.fig.subplots_adjust(hspace=0.3)

  for epoch in range(1, num_epochs + 1):
    # Train one epoch
    timer = d2l.Timer()
    metric = d2l.Accumulator(3) # loss_D, loss_G, num_examples
    for X, _ in data_iter:
      batch_size = X.shape[0]
      Z = tf.random.normal(mean=0, stddev=1,
                 shape=(batch_size, 1, 1, latent_dim))
      metric.add(d2l.update_D(X, Z, net_D, net_G, loss, optimizer_D),
            d2l.update_G(Z, net_D, net_G, loss, optimizer_G),
            batch_size)

    # Show generated examples
    Z = tf.random.normal(mean=0, stddev=1, shape=(21, 1, 1, latent_dim))
    # Normalize the synthetic data to N(0, 1)
    fake_x = net_G(Z) / 2 + 0.5
    imgs = tf.concat([tf.concat([fake_x[i * 7 + j] for j in range(7)],
                  axis=1)
             for i in range(len(fake_x) // 7)], axis=0)
    animator.axes[1].cla()
    animator.axes[1].imshow(imgs)
    # Show the losses
    loss_D, loss_G = metric[0] / metric[2], metric[1] / metric[2]
    animator.add(epoch, (loss_D, loss_G))
  print(f'loss_D {loss_D:.3f}, loss_G {loss_G:.3f}, '
     f'{metric[2] / timer.stop():.1f} examples/sec on {str(device._device_name)}')

我們用少量的 epochs 訓練模型只是為了演示。為了獲得更好的性能,可以將變量num_epochs設置為更大的數(shù)字。

latent_dim, lr, num_epochs = 100, 0.005, 20
train(net_D, net_G, data_iter, num_epochs, lr, latent_dim)
loss_D 0.030, loss_G 7.203, 1026.4 examples/sec on cuda:0
https://file.elecfans.com/web2/M00/AA/49/pYYBAGR9PhmAKNvvAAQ_akulsoA525.svg
latent_dim, lr, num_epochs = 100, 0.005, 20
train(net_D, net_G, data_iter, num_epochs, lr, latent_dim)
loss_D 0.224, loss_G 6.386, 2260.7 examples/sec on gpu(0)
https://file.elecfans.com/web2/M00/A9/CE/poYBAGR9PhyANJTuAAQWXCMFF5g049.svg
latent_dim, lr, num_epochs = 100, 0.0005, 40
train(net_D, net_G, data_iter, num_epochs, lr, latent_dim)
loss_D 0.112, loss_G 4.952, 1968.2 examples/sec on /GPU:0
https://file.elecfans.com/web2/M00/AA/49/pYYBAGR9Ph6ANe_HAAP3DIt7UTs347.svg

20.2.5。概括

  • DCGAN 架構(gòu)有四個用于鑒別器的卷積層和四個用于生成器的“分數(shù)步”卷積層。

  • 鑒別器是一個 4 層跨步卷積,具有批量歸一化(除了它的輸入層)和 leaky ReLU 激活。

  • Leaky ReLU 是一種非線性函數(shù),可為負輸入提供非零輸出。它旨在解決“垂死的 ReLU”問題,并幫助梯度更容易地通過架構(gòu)。

20.2.6. 練習

  1. 如果我們使用標準 ReLU 激活而不是 leaky ReLU 會發(fā)生什么?

  2. 在 Fashion-MNIST 上應用 DCGAN,看看哪個類別效果好,哪個效果不好。


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • pytorch
    +關注

    關注

    2

    文章

    794

    瀏覽量

    13010
收藏 人收藏

    評論

    相關推薦

    圖像生成對抗生成網(wǎng)絡gan_GAN生成汽車圖像 精選資料推薦

    圖像生成對抗生成網(wǎng)絡ganHello there! This is my story of making a GAN that would generate images of cars
    發(fā)表于 08-31 06:48

    圖像生成對抗生成網(wǎng)絡

    圖像生成對抗生成網(wǎng)絡ganby Thalles Silva 由Thalles Silva暖身 (Warm up)Let’s say there’s a very cool party going
    發(fā)表于 09-15 09:29

    生成對抗網(wǎng)絡模型綜述

    ,開創(chuàng)性地提出了生成對抗網(wǎng)絡( GAN)。生成對抗網(wǎng)絡包含一個生成模型和一個判別模型。其中,生成
    發(fā)表于 04-03 10:48 ?1次下載
    <b class='flag-5'>生成對抗</b><b class='flag-5'>網(wǎng)絡</b>模型綜述

    生成對抗網(wǎng)絡GAN,正在成為新的“深度學習”

    生成對抗網(wǎng)絡由一個生成網(wǎng)絡(Generator)與一個判別網(wǎng)絡(Discriminator)組成。生成
    的頭像 發(fā)表于 06-11 16:04 ?4685次閱讀
    <b class='flag-5'>生成對抗</b><b class='flag-5'>網(wǎng)絡</b>GAN,正在成為新的“<b class='flag-5'>深度</b>學習”

    如何使用生成對抗網(wǎng)絡進行信息隱藏方案資料說明

    針對信息隱藏中含密栽體會留有修改痕跡,從根本上難以抵抗基于統(tǒng)計的隱寫分析算法檢測的問題,提出一種基于生成對抗網(wǎng)絡( GAN)的信息隱藏方案。該方案首先利用生成對抗網(wǎng)絡中的
    發(fā)表于 12-12 16:57 ?6次下載
    如何使用<b class='flag-5'>生成對抗</b><b class='flag-5'>網(wǎng)絡</b>進行信息隱藏方案資料說明

    如何使用深度殘差生成對抗網(wǎng)絡設計醫(yī)學影像超分辨率算法

    針對醫(yī)學影像超分辨率重建過程中細節(jié)丟失導致的模糊問題,提出了一種基于深度殘差生成對抗網(wǎng)絡( GAN)的醫(yī)學影像超分辨率算法。首先,算法包括生成網(wǎng)絡
    發(fā)表于 01-02 16:59 ?5次下載
    如何使用<b class='flag-5'>深度</b>殘差<b class='flag-5'>生成對抗</b><b class='flag-5'>網(wǎng)絡</b>設計醫(yī)學影像超分辨率算法

    基于譜歸一化條件生成對抗網(wǎng)絡的圖像修復算法

    基于生成對抗網(wǎng)絡的圖像修復算法在修復大尺寸缺失圖像時,存在圖像失真較多與判別網(wǎng)絡性能不可控等問題,基于譜歸一化條件生成對抗網(wǎng)絡,提出一種新的
    發(fā)表于 03-12 10:22 ?14次下載
    基于譜歸一化條件<b class='flag-5'>生成對抗</b><b class='flag-5'>網(wǎng)絡</b>的圖像修復算法

    基于生成對抗網(wǎng)絡深度偽造視頻綜述

    深度偽造的濫用,給囯家、社會和個人帶來了潛在威脅。首先,介紹了深度偽造的概念和當前發(fā)展趨勢,分析了基于生成對抗網(wǎng)絡深度偽造視頻的
    發(fā)表于 05-10 15:39 ?11次下載

    基于密集卷積生成對抗網(wǎng)絡的圖像修復方法

    差等問題。針對上述問題,文中提出了一種基于密集卷積生成對抗網(wǎng)絡的圖像修復算法。該算法采用生成對抗網(wǎng)絡作為圖像修復的基本框架。首先,利用密集
    發(fā)表于 05-13 14:39 ?15次下載

    注塑瓶檢測的半監(jiān)督深度卷積生成對抗網(wǎng)絡模型

    ( Semi-supervised)深度卷積生成對抗網(wǎng)絡( Deep Convolutional Generative Adversarial Network, DCGAN)模型。該模
    發(fā)表于 05-18 14:24 ?2次下載

    基于深度卷積生成對抗網(wǎng)絡的花朵圖像識別分類

    為了提高花朵圖像識別與分類的準確率,采用基于深度卷積生成對抗網(wǎng)絡的算法來完成花朵圖像的識別與分類。為了保證花朵圖像在卷積過程中的特征完整性,
    發(fā)表于 05-28 16:51 ?5次下載

    基于像素級生成對抗網(wǎng)絡的圖像彩色化模型

    基于像素級生成對抗網(wǎng)絡的圖像彩色化模型
    發(fā)表于 06-27 11:02 ?4次下載

    PyTorch教程8.1之深度卷積神經(jīng)網(wǎng)絡(AlexNet)

    電子發(fā)燒友網(wǎng)站提供《PyTorch教程8.1之深度卷積神經(jīng)網(wǎng)絡(AlexNet).pdf》資料免費下載
    發(fā)表于 06-05 10:09 ?0次下載
    <b class='flag-5'>PyTorch</b>教程8.1之<b class='flag-5'>深度</b><b class='flag-5'>卷積</b>神經(jīng)<b class='flag-5'>網(wǎng)絡</b>(AlexNet)

    PyTorch教程20.2深度卷積生成對抗網(wǎng)絡

    電子發(fā)燒友網(wǎng)站提供《PyTorch教程20.2深度卷積生成對抗網(wǎng)絡.pdf》資料免費下載
    發(fā)表于 06-05 10:21 ?2次下載
    <b class='flag-5'>PyTorch</b>教程<b class='flag-5'>20.2</b>之<b class='flag-5'>深度</b><b class='flag-5'>卷積</b><b class='flag-5'>生成對抗</b><b class='flag-5'>網(wǎng)絡</b>

    生成對抗網(wǎng)絡(GANs)的原理與應用案例

    生成對抗網(wǎng)絡(Generative Adversarial Networks,GANs)是一種由蒙特利爾大學的Ian Goodfellow等人在2014年提出的深度學習算法。GANs通過構(gòu)建兩個
    的頭像 發(fā)表于 07-09 11:34 ?450次閱讀