生成性對抗網絡技術實現

生成性對抗網絡技術實現

Generative Adversarial Networks

以某種形式,使用深度神經網絡學習從數據點到標籤的映射。這種學習被稱爲區別性學習,因爲希望能夠區分貓和狗的照片。量詞和迴歸詞都是區別學習的例子。而由反向傳播訓練的神經網絡顛覆了認爲在大型複雜數據集上進行區分學習的一切。在僅僅5-6年的時間裏,高分辨率圖像的分類精度已經從無用的提高到了人類的水平(有一些警告)。將爲提供另一個關於所有其區分性任務的細節,在這些任務中,深層神經網絡做得非常好。

但是機器學習不僅僅是解決有區別的任務。例如,給定一個沒有任何標籤的大型數據集,可能需要學習一個簡潔地捕捉這些數據特徵的模型。給定這樣一個模型,就可以抽取與訓練數據分佈相似的合成數據點。例如,給定大量的人臉照片,可能希望能夠生成一個新的照片級真實感圖像,看起來似乎似乎來自同一個數據集。這種學習被稱爲生成性建模。

直到最近,還沒有一種方法可以合成新的真實感圖像。但是,深度神經網絡在區分學習中的成功開闢了新的可能性。在過去三年中,一個大趨勢是應用有區別的深層網絡來克服通常不認爲是有監督學習問題的問題的挑戰。遞歸神經網絡語言模型是一個使用判別網絡(訓練以預測下一個字符)的一個例子,一旦訓練,就可以作爲一個生成模型。 2014年,一篇突破性的論文介紹了生成性對抗性網絡(GAN)[Goodfello等人,2014],這是一種巧妙的新方法,可以利用區分模型的能力來獲得良好的生成模型。GANs的核心思想是,如果不能區分假數據和真實數據,那麼數據生成器是好的。在統計學中,這被稱爲兩個樣本測試-一個用來回答是否有數據集的測試

X={x1,…,xn} and X′={x′1,…,x′n}

來自同一分佈。大多數統計論文與GAN的主要區別在於後者以建設性的方式運用了這一觀點。換句話說,不只是訓練一個模型說“嘿,這兩個數據集看起來不像來自同一個分佈”,而是使用兩個樣本測試爲生成模型提供訓練信號。這允許改進數據生成器,直到生成與實際數據相似的內容。至少,需要愚弄分類器。即使分類器是最先進的深層神經網絡。
在這裏插入圖片描述
Fig. 1 Generative Adversarial Networks

GAN架構如圖1所示。正如所看到的,在GAN架構中有兩個部分-首先,需要一個設備(比如說,一個深度網絡,但實際上可以是任何東西,比如遊戲渲染引擎),可能有可能生成看起來像真實的數據。如果要處理圖像,就需要生成圖像。如果在處理語音,需要生成音頻序列,等等。稱之爲發啓generator網絡。第二部分是鑑別器網絡。試圖區分假數據和真數據。這兩個網絡互相競爭。生成器網絡試圖欺騙鑑別器discriminator網絡。此時,鑑別器discriminator網絡適應新的假數據。這些信息,反過來又被用來改進generator網絡,等等。
在這裏插入圖片描述
在這裏插入圖片描述
%matplotlib inline

from d2l import mxnet as d2l

from mxnet import autograd, gluon, init, np, npx

from mxnet.gluon import nn

npx.set_np()

  1. Generate some “real” data

由於這將是世界上最蹩腳的例子,只需從高斯函數中生成數據。

X = np.random.normal(size=(1000, 2))

A = np.array([[1, 2], [-0.1, 0.5]])

b = np.array([1, 2])

data = X.dot(A) + b

讓看看得到了什麼。這應該是高斯位移,平均值b,以某種相當任意的方式平均協方差矩陣ATA。

d2l.set_figsize((3.5, 2.5))

d2l.plt.scatter(data[:100, 0].asnumpy(), data[:100, 1].asnumpy());

print(“The covariance matrix is\n%s” % np.dot(A.T, A))

The covariance matrix is

[[1.01 1.95]

[1.95 4.25]]
在這裏插入圖片描述
batch_size = 8

data_iter = d2l.load_array((data,), batch_size)

  1. Generator

發啓Generator網絡將是最簡單的網絡-單層線性模型。這是因爲將用高斯數據Generator驅動線性網絡。因此,實際上只需要學習參數就可以完美地僞造東西。

net_G = nn.Sequential()

net_G.add(nn.Dense(2))

  1. Discriminator

對於鑑別器Discriminator,將更具鑑別力:將使用一個3層的MLP使事情變得更有趣。

net_D = nn.Sequential()

net_D.add(nn.Dense(5, activation=‘tanh’),

      nn.Dense(3, activation='tanh'),

      nn.Dense(1))
  1. Training

首先定義了一個函數來更新鑑別器discriminator。

#@save

def update_D(X, Z, net_D, net_G, loss, trainer_D):

"""Update discriminator."""

batch_size = X.shape[0]

ones = np.ones((batch_size,), ctx=X.ctx)

zeros = np.zeros((batch_size,), ctx=X.ctx)

with autograd.record():

    real_Y = net_D(X)

    fake_X = net_G(Z)

    # Do not need to compute gradient for net_G, detach it from

    # computing gradients.

    fake_Y = net_D(fake_X.detach())

    loss_D = (loss(real_Y, ones) + loss(fake_Y, zeros)) / 2

loss_D.backward()

trainer_D.step(batch_size)

return float(loss_D.sum())

生成器也同樣更新。但是從這裏的重複使用熵的標籤改變了假數據0到 1。

#@save

def update_G(Z, net_D, net_G, loss, trainer_G): # saved in d2l

"""Update generator."""

batch_size = Z.shape[0]

ones = np.ones((batch_size,), ctx=Z.ctx)

with autograd.record():

    # We could reuse fake_X from update_D to save computation.

    fake_X = net_G(Z)

    # Recomputing fake_Y is needed since net_D is changed.

    fake_Y = net_D(fake_X)

    loss_G = loss(fake_Y, ones)

loss_G.backward()

trainer_G.step(batch_size)

return float(loss_G.sum())

鑑別器Discriminator和產生器Generator都執行帶有交叉熵損失的二元邏輯迴歸。用Adam來平滑訓練過程。在每次迭代中,首先更新鑑別器Discriminator,然後更新生成器Generator。將損失和產生的例子都形象化。

def train(net_D, net_G, data_iter, num_epochs, lr_D, lr_G, latent_dim, data):

loss = gluon.loss.SigmoidBCELoss()

net_D.initialize(init=init.Normal(0.02), force_reinit=True)

net_G.initialize(init=init.Normal(0.02), force_reinit=True)

trainer_D = gluon.Trainer(net_D.collect_params(),

                          'adam', {'learning_rate': lr_D})

trainer_G = gluon.Trainer(net_G.collect_params(),

                          'adam', {'learning_rate': lr_G})

animator = d2l.Animator(xlabel='epoch', ylabel='loss',

                        xlim=[1, num_epochs], nrows=2, figsize=(5, 5),

                        legend=['generator', 'discriminator'])

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))

        metric.add(update_D(X, Z, net_D, net_G, loss, trainer_D),

                   update_G(Z, net_D, net_G, loss, trainer_G),

                   batch_size)

    # Visualize generated examples

    Z = np.random.normal(0, 1, size=(100, latent_dim))

    fake_X = net_G(Z).asnumpy()

    animator.axes[1].cla()

    animator.axes[1].scatter(data[:, 0], data[:, 1])

    animator.axes[1].scatter(fake_X[:, 0], fake_X[:, 1])

    animator.axes[1].legend(['real', 'generated'])

    # Show the losses

    loss_D, loss_G = metric[0]/metric[2], metric[1]/metric[2]

    animator.add(epoch, (loss_D, loss_G))

print('loss_D %.3f, loss_G %.3f, %d examples/sec' % (

    loss_D, loss_G, metric[2]/timer.stop()))

現在指定超參數來擬合高斯分佈。

lr_D, lr_G, latent_dim, num_epochs = 0.05, 0.005, 2, 20

train(net_D, net_G, data_iter, num_epochs, lr_D, lr_G,

  latent_dim, data[:100].asnumpy())

loss_D 0.693, loss_G 0.693, 577 examples/sec
在這裏插入圖片描述
5. Summary

Generative adversarial networks (GANs) composes of two deep networks, the generator and the discriminator.
The generator generates the image as much closer to the true image as possible to fool the discriminator, via maximizing the cross-entropy loss, i.e., maxlog(D(x′))maxlog⁡(D(x′)).
The discriminator tries to distinguish the generated images from the true images, via minimizing the cross-entropy loss, i.e., min−ylogD(x)−(1−y)log(1−D(x))

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章