手把手教你搭建一個GAN(生成對抗網絡)模型


手把手教你搭建一個GAN(生成對抗網絡)模型

This blog is out of date. Check out my new blog holder: sonictl.github.io

本網站上的博文已經停止維護/更新了。 請移步到新的博客空間:sonictl.github.io

這個教程用 Keras 實現一個簡單的GAN (生成對抗網絡)模型. 基於這個:mnistGAN項目,我們將用到Keras 這個python 庫。

將用到的python packages:

  • keras: 神經網絡模型相關
  • matplotlib: 畫圖
  • tensorflow: keras運行基礎
  • tqdm: 進度條

Talk is cheap, show me the code.

1. 導入包:

import os
import numpy as np
import matplotlib.pyplot as plt
from tqdm import tqdm

from keras.layers import Input  # input layer  
from keras.models import Model, Sequential
from keras.layers.core import Dense, Dropout
from keras.layers.advanced_activations import LeakyReLU
from keras.datasets import mnist
from keras.optimizers import Adam
from keras import initializers

2. 定義幾個變量:

# Let Keras know that we are using tensorflow as our backend engine
os.environ["KERAS_BACKEND"] = "tensorflow"

# To make sure that we can reproduce the experiment and get the same results by same random output
np.random.seed(10)

# The dimension of our random noise vector. this code is from: sonictl_at_cnblogs.net
random_dim = 100

3. 准備數據:

這里要用到手寫阿拉伯數字(MNIST)數據集。MNIST 數據集已經是一個被”嚼爛”了的數據集, 很多教程都會對它”下手”, 幾乎成為一個 “典范”. 介紹一下:

MNIST 數據集來自美國國家標准與技術研究所, National Institute of Standards and Technology (NIST). 訓練集 (training set) 由來自 250 個不同人手寫的數字構成, 其中 50% 是高中學生, 50% 來自人口普查局 (the Census Bureau) 的工作人員. 測試集(test set) 也是同樣比例的手寫數字數據.

MNIST 數據集可在 http://yann.lecun.com/exdb/mnist/ 獲取, 它包含了四個部分:

  • Training set images(包含 60,000 個樣本)
  • Training set labels(包含 60,000 個標簽)
  • Test set images(10,000 個樣本)
  • Test set labels(包含 10,000 個標簽)
    在 MNIST 數據集中的每張圖片由 28 x 28 個像素點構成, 每個像素點用一個灰度值表示. labels包含了相應的目標變量, 也就是手寫數字的類標簽(整數 0-9).
    如圖:
    MNIST 數據集中的圖

代碼:

def load_minst_data():
    # load the data
    (x_train, y_train), (x_test, y_test) = mnist.load_data()    # y is the set of labels, mnist.load_data() is part of Keras and allows you to easily import the MNIST dataset
    # normalize our inputs to be in the range[-1, 1]
    x_train = (x_train.astype(np.float32) - 127.5)/127.5
    # convert x_train with a shape of (60000, 28, 28) to (60000, 784) so we have
    # 784 columns per row
    x_train = x_train.reshape(60000, 784)
    return (x_train, y_train, x_test, y_test)

4. 生成器和判別器

現在要建立生成器和判別器,我們要用Adam 優化器來優化這2個網絡。對於生成器和判別器中的神經網絡,我們都用3個隱藏層,並用Leaky Relu函數來作為激活函數。這里還有個技巧,為了提升判別器在它沒見過的數據上的魯棒性,在里面加了一個DropOut 層

# You will use the Adam optimizer
def get_optimizer():
    return Adam(lr=0.0002, beta_1=0.5)

def get_generator(optimizer):
    generator = Sequential()
    generator.add(Dense(256, input_dim=random_dim, kernel_initializer=initializers.RandomNormal(stddev=0.02)))
    generator.add(LeakyReLU(0.2))

    generator.add(Dense(512))
    generator.add(LeakyReLU(0.2))

    generator.add(Dense(1024))
    generator.add(LeakyReLU(0.2))

    generator.add(Dense(784, activation='tanh'))
    generator.compile(loss='binary_crossentropy', optimizer=optimizer)
    return generator

def get_discriminator(optimizer):
    discriminator = Sequential()
    discriminator.add(Dense(1024, input_dim=784, kernel_initializer=initializers.RandomNormal(stddev=0.02)))
    discriminator.add(LeakyReLU(0.2))
    discriminator.add(Dropout(0.3))

    discriminator.add(Dense(512))
    discriminator.add(LeakyReLU(0.2))
    discriminator.add(Dropout(0.3))

    discriminator.add(Dense(256))
    discriminator.add(LeakyReLU(0.2))
    discriminator.add(Dropout(0.3))

    discriminator.add(Dense(1, activation='sigmoid'))
    discriminator.compile(loss='binary_crossentropy', optimizer=optimizer)
    return discriminator

一個流程的代碼

有關的注釋都已經寫了。一行行弄懂基本就懂了。

import os
import numpy as np
import matplotlib.pyplot as plt
from tqdm import tqdm


from keras.layers import Input
from keras.models import Model, Sequential
from keras.layers.core import Dense, Dropout
from keras.layers.advanced_activations import LeakyReLU
from keras.datasets import mnist
from keras.optimizers import Adam
from keras import initializers

# fix the multiple OpenMP runtime linked error:
os.environ['KMP_DUPLICATE_LIB_OK']='True'

# Let Keras know that we are using tensorflow as our backend engine
os.environ["KERAS_BACKEND"] = "tensorflow"

# To make sure that we can reproduce the experiment and get the same results
np.random.seed(10)

# The dimension of our random noise vector. This vector is the most initial input of the gan Model.
random_dim = 100

# size of each batch
batch_size = 128

# load the data:
(x_train, y_train), (x_test, y_test) = mnist.load_data('mnist.npz')
x_train = (x_train.astype(np.float32) - 127.5)/127.5   # x_train_i is from 0 to 255, 255 = 127.5*2
# convert x_train with a shape of (60000, 28, 28) to (60000, 784) so we have
# 784 columns per row
x_train = x_train.reshape(60000, 784)

# Split the training data into batches of size 128
batch_count = x_train.shape[0] / batch_size
batch_count = int(round(batch_count))
print('batch_count:', batch_count)

#
# ==== build the GAN ====
adam = Adam(lr=0.0002, beta_1=0.5)

# -- generator building: --
generator = Sequential()   # keras Sequential model, model of sequential stack of layers
generator.add(Dense(256, input_dim=random_dim, kernel_initializer=initializers.RandomNormal(stddev=0.02)))
# layer: (256, input_dim=random_dim, kernel_initializer=initializers.RandomNormal(stddev=0.02))
generator.add(LeakyReLU(0.2))
generator.add(Dense(512))     # second layer
generator.add(LeakyReLU(0.2))
generator.add(Dense(1024))    # third layer
generator.add(LeakyReLU(0.2))
generator.add(Dense(28*28, activation='tanh'))    # output layer, 784 = 28*28
generator.compile(loss='binary_crossentropy', optimizer=adam)    # compile Before training a model,
# you need to configure the learning process, which is done via the compile method.

# -- discriminator building: --
discriminator = Sequential()

discriminator.add(Dense(1024, input_dim=784, kernel_initializer=initializers.RandomNormal(stddev=0.02)))
discriminator.add(LeakyReLU(0.2))
discriminator.add(Dropout(0.3))

discriminator.add(Dense(512))
discriminator.add(LeakyReLU(0.2))
discriminator.add(Dropout(0.3))

discriminator.add(Dense(256))
discriminator.add(LeakyReLU(0.2))
discriminator.add(Dropout(0.3))

discriminator.add(Dense(1, activation='sigmoid'))
discriminator.compile(loss='binary_crossentropy', optimizer=adam)

# -- gan building with generator&discriminator: --
discriminator.trainable = False  # frozen discriminator first. Train either the generator or discriminator at a time
gan_input = Input(shape=(random_dim,))   # keras.layers.input, type: tensor.
# gan input (noise) will be 100-dimensional vectors

x = generator(gan_input)  # gan_input -> generator(a Sequential()) -> x , x is the input of discriminator, x is an image
gan_output = discriminator(x) # x -> discriminator -> gan_output. gan_output is a probability: if the image is real
gan = Model(inputs=gan_input, outputs=gan_output) # gan_input ->[GAN]-> gan_output. The Model takes the head and tail as
# its arguments of inputs and outputs.

gan.compile(loss='binary_crossentropy', optimizer=adam) # gan: <keras.engine.training.Model object at 0x647626d68>

# ==== one epoch of training: =====
e = 1
print( '-'*15, 'Epoch %d' % e, '-'*15)
for _ in tqdm(range(batch_count)):  # each batch in batch_count, Note: operations on each batch of 128 samples.
    # Get a random set of input noise and images
    noise = np.random.normal(0, 1, size=[batch_size, random_dim])   # batch_size = 128, one batch of noise.
    temp_idx = np.random.randint(0, x_train.shape[0], size=batch_size)  # pick 128 rand int numbers from [0, 60000]
    image_batch = x_train[temp_idx]  # shape=(128,784)

    generated_images = generator.predict(noise)  # Generate fake MNIST images: shape=(128,784)
    num_fake_img = len(generated_images)
    X = np.concatenate([image_batch, generated_images])  # concatenate the True image batch and Fake image  (256,784)

    # Labels for generated and real data
    y_dis = np.zeros(2*batch_size)
    y_dis[:batch_size] = 0.9   # One-sided label smoothing
    # read more: https://towardsdatascience.com/gan-ways-to-improve-gan-performance-acf37f9f59b?gi=ddcc9670e7bd

    # Train discriminator
    discriminator.trainable = True
    discriminator.train_on_batch(X, y_dis)   # The training of discriminator is as same as general neural networks

    # Train generator
    discriminator.trainable = False
    noise = np.random.normal(0, 1, size=[batch_size, random_dim])
    y_gen = np.ones(batch_size)
    gan.train_on_batch(noise, y_gen)

You can read more content in the link below:
Read more:

.
.
.
.
.
.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM