1. 程式人生 > >通過DCGAN進行生成花朵

通過DCGAN進行生成花朵

環境是你要安裝Keras和Tensorflow

先來個network.py,裡面定義了生成器網路和鑑別器網路:

 1 # -*- coding: UTF-8 -*-
 2 
 3 """
 4 DCGAN 深層卷積的生成對抗網路
 5 """
 6 
 7 import tensorflow as tf
 8 
 9 # Hyper parameter(超引數)
10 EPOCHS = 100
11 BATCH_SIZE = 128
12 LEARNING_RATE = 0.0002
13 BETA_1 = 0.5
14 
15 
16 # 定義判別器模型
17 def discriminator_model():
18 model = tf.keras.models.Sequential() 19 20 model.add(tf.keras.layers.Conv2D( 21 64, # 64 個過濾器,輸出的深度(depth)是 64 22 (5, 5), # 過濾器在二維的大小是(5 * 5) 23 padding='same', # same 表示輸出的大小不變,因此需要在外圍補零2圈 24 input_shape=(64, 64, 3) # 輸入形狀 [64, 64, 3]。3 表示 RGB 三原色 25 ))
26 model.add(tf.keras.layers.Activation("tanh")) # 新增 Tanh 啟用層 27 model.add(tf.keras.layers.MaxPool2D(pool_size=(2, 2))) # 池化層 28 model.add(tf.keras.layers.Conv2D(128, (5, 5))) 29 model.add(tf.keras.layers.Activation("tanh")) 30 model.add(tf.keras.layers.MaxPool2D(pool_size=(2, 2)))
31 model.add(tf.keras.layers.Conv2D(128, (5, 5))) 32 model.add(tf.keras.layers.Activation("tanh")) 33 model.add(tf.keras.layers.MaxPool2D(pool_size=(2, 2))) 34 model.add(tf.keras.layers.Flatten()) # 扁平化 35 model.add(tf.keras.layers.Dense(1024)) # 1024 個神經元的全連線層 36 model.add(tf.keras.layers.Activation("tanh")) 37 model.add(tf.keras.layers.Dense(1)) # 1 個神經元的全連線層 38 model.add(tf.keras.layers.Activation("sigmoid")) # 新增 Sigmoid 啟用層 39 40 return model 41 42 43 # 定義生成器模型 44 # 從隨機數來生成圖片 45 def generator_model(): 46 model = tf.keras.models.Sequential() 47 # 輸入的維度是 100, 輸出維度(神經元個數)是1024 的全連線層 48 model.add(tf.keras.layers.Dense(input_dim=100, units=1024)) 49 model.add(tf.keras.layers.Activation("tanh")) 50 model.add(tf.keras.layers.Dense(128 * 8 * 8)) # 8192 個神經元的全連線層 51 model.add(tf.keras.layers.BatchNormalization()) # 批標準化 52 model.add(tf.keras.layers.Activation("tanh")) 53 model.add(tf.keras.layers.Reshape((8, 8, 128), input_shape=(128 * 8 * 8, ))) # 8 x 8 畫素 54 model.add(tf.keras.layers.UpSampling2D(size=(2, 2))) # 16 x 16畫素 55 model.add(tf.keras.layers.Conv2D(128, (5, 5), padding="same")) 56 model.add(tf.keras.layers.Activation("tanh")) 57 model.add(tf.keras.layers.UpSampling2D(size=(2, 2))) # 32 x 32畫素 58 model.add(tf.keras.layers.Conv2D(128, (5, 5), padding="same")) 59 model.add(tf.keras.layers.Activation("tanh")) 60 model.add(tf.keras.layers.UpSampling2D(size=(2, 2))) # 64 x 64畫素 61 model.add(tf.keras.layers.Conv2D(3, (5, 5), padding="same")) 62 model.add(tf.keras.layers.Activation("tanh")) 63 64 return model 65 66 67 # 構造一個 Sequential 物件,包含一個 生成器 和一個 判別器 68 # 輸入 -> 生成器 -> 判別器 -> 輸出 69 def generator_containing_discriminator(generator, discriminator): 70 model = tf.keras.models.Sequential() 71 model.add(generator) 72 discriminator.trainable = False # 初始時 判別器 不可被訓練 73 model.add(discriminator) 74 return model

接著我們寫個訓練模型的檔案,train..py

 1 # -*- coding: UTF-8 -*-
 2 
 3 """
 4 訓練 DCGAN
 5 """
 6 
 7 import os
 8 import glob
 9 import numpy as np
10 from scipy import misc
11 import tensorflow as tf
12 
13 from network import *
14 
15 
16 def train():
17     # 確保包含所有圖片的 images 資料夾在所有 Python 檔案的同級目錄下
18     # 當然了,你也可以自定義資料夾名和路徑
19     if not os.path.exists("images"):
20         raise Exception("包含所有圖片的 images 資料夾不在此目錄下,請新增")
21 
22     # 獲取訓練資料
23     data = []
24     for image in glob.glob("images/*"):
25         image_data = misc.imread(image)  # imread 利用 PIL 來讀取圖片資料
26         data.append(image_data)
27     input_data = np.array(data)
28 
29     # 將資料標準化成 [-1, 1] 的取值, 這也是 Tanh 啟用函式的輸出範圍
30     input_data = (input_data.astype(np.float32) - 127.5) / 127.5
31 
32     # 構造 生成器 和 判別器
33     g = generator_model()
34     d = discriminator_model()
35 
36     # 構建 生成器 和 判別器 組成的網路模型
37     d_on_g = generator_containing_discriminator(g, d)
38 
39     # 優化器用 Adam Optimizer
40     g_optimizer = tf.keras.optimizers.Adam(lr=LEARNING_RATE, beta_1=BETA_1)
41     d_optimizer = tf.keras.optimizers.Adam(lr=LEARNING_RATE, beta_1=BETA_1)
42 
43     # 配置 生成器 和 判別器
44     g.compile(loss="binary_crossentropy", optimizer=g_optimizer)
45     d_on_g.compile(loss="binary_crossentropy", optimizer=g_optimizer)
46     d.trainable = True
47     d.compile(loss="binary_crossentropy", optimizer=d_optimizer)
48 
49     # 開始訓練
50     for epoch in range(EPOCHS):
51         for index in range(int(input_data.shape[0] / BATCH_SIZE)):
52             input_batch = input_data[index * BATCH_SIZE : (index + 1) * BATCH_SIZE]
53 
54             # 連續型均勻分佈的隨機資料(噪聲)
55             random_data = np.random.uniform(-1, 1, size=(BATCH_SIZE, 100))
56             # 生成器 生成的圖片資料
57             generated_images = g.predict(random_data, verbose=0)
58 
59             input_batch = np.concatenate((input_batch, generated_images))
60             output_batch = [1] * BATCH_SIZE + [0] * BATCH_SIZE
61 
62             # 訓練 判別器,讓它具備識別不合格生成圖片的能力
63             d_loss = d.train_on_batch(input_batch, output_batch)
64 
65             # 當訓練 生成器 時,讓 判別器 不可被訓練
66             d.trainable = False
67 
68             # 重新生成隨機資料。很關鍵
69             random_data = np.random.uniform(-1, 1, size=(BATCH_SIZE, 100))
70 
71             # 訓練 生成器,並通過不可被訓練的 判別器 去判別
72             g_loss = d_on_g.train_on_batch(random_data, [1] * BATCH_SIZE)
73 
74             # 恢復 判別器 可被訓練
75             d.trainable = True
76 
77             # 列印損失
78             print("Epoch {}, 第 {} 步, 生成器的損失: {:.3f}, 判別器的損失: {:.3f}".format(epoch, index, g_loss, d_loss))
79 
80         # 儲存 生成器 和 判別器 的引數
81         # 大家也可以設定儲存時名稱不同(比如後接 epoch 的數字),引數檔案就不會被覆蓋了
82         if epoch % 1 == 0:
83             g.save_weights("./generator_weight.h5", True)
84             d.save_weights("./discriminator_weight", True)
85 
86 
87 if __name__ == "__main__":
88     train()

執行這個檔案,就可以產生生成器網路的權重檔案  generator_weight.h5, 這裡我選擇每個訓練epoch都儲存一次權重檔案。你可以按你的喜好來。

  訓練好了之後,那麼我們就可以用generate.py檔案,從隨機資料生成好看的花朵了。

 1 # -*- coding: UTF-8 -*-
 2 
 3 """
 4 用 DCGAN 的生成器模型 和 訓練得到的生成器引數檔案 來生成圖片
 5 """
 6 
 7 import numpy as np
 8 from PIL import Image
 9 import tensorflow as tf
10 
11 from network import *
12 
13 
14 def generate():
15     # 構造生成器
16     g = generator_model()
17 
18     # 配置 生成器
19     g.compile(loss="binary_crossentropy", optimizer=tf.keras.optimizers.Adam(lr=LEARNING_RATE, beta_1=BETA_1))
20 
21     # 載入訓練好的 生成器 引數
22     g.load_weights("generator_weight.h5")
23 
24     # 連續型均勻分佈的隨機資料(噪聲)
25     random_data = np.random.uniform(-1, 1, size=(BATCH_SIZE, 100))
26 
27     # 用隨機資料作為輸入,生成器 生成圖片資料
28     images = g.predict(random_data, verbose=1)
29 
30     # 用生成的圖片資料生成 PNG 圖片
31     for i in range(BATCH_SIZE):
32         image = images[i] * 127.5 + 127.5
33         Image.fromarray(image.astype(np.uint8)).save("./generated_image/image-%s.png" % i)
34 
35 
36 if __name__ == "__main__":
37     generate()

附註1: 一些訓練過程

C:\ProgramData\Anaconda3\python.exe D:/threeTFproject/Case2_AI_Photoshop/train.py
C:\ProgramData\Anaconda3\lib\site-packages\h5py\__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
  from ._conv import register_converters as _register_converters
2018-11-01 09:29:35.205667: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
Epoch 0, 第 0 步, 生成器的損失: 0.169, 判別器的損失: 0.732
Epoch 0, 第 1 步, 生成器的損失: 0.258, 判別器的損失: 0.577
Epoch 0, 第 2 步, 生成器的損失: 0.680, 判別器的損失: 0.534
Epoch 0, 第 3 步, 生成器的損失: 1.493, 判別器的損失: 0.451
Epoch 0, 第 4 步, 生成器的損失: 1.484, 判別器的損失: 0.513
Epoch 0, 第 5 步, 生成器的損失: 2.465, 判別器的損失: 0.350
Epoch 0, 第 6 步, 生成器的損失: 4.008, 判別器的損失: 0.313
Epoch 0, 第 7 步, 生成器的損失: 2.139, 判別器的損失: 0.494
Epoch 0, 第 8 步, 生成器的損失: 2.939, 判別器的損失: 0.501
Epoch 0, 第 9 步, 生成器的損失: 3.805, 判別器的損失: 0.415
Epoch 0, 第 10 步, 生成器的損失: 3.413, 判別器的損失: 0.590
Epoch 0, 第 11 步, 生成器的損失: 2.520, 判別器的損失: 0.486
Epoch 0, 第 12 步, 生成器的損失: 2.286, 判別器的損失: 0.471
Epoch 0, 第 13 步, 生成器的損失: 1.228, 判別器的損失: 0.670
Epoch 0, 第 14 步, 生成器的損失: 0.561, 判別器的損失: 0.655
Epoch 0, 第 15 步, 生成器的損失: 0.560, 判別器的損失: 0.517
Epoch 0, 第 16 步, 生成器的損失: 0.643, 判別器的損失: 0.490
Epoch 0, 第 17 步, 生成器的損失: 0.727, 判別器的損失: 0.488
Epoch 0, 第 18 步, 生成器的損失: 1.003, 判別器的損失: 0.734
Epoch 0, 第 19 步, 生成器的損失: 1.235, 判別器的損失: 0.379
Epoch 0, 第 20 步, 生成器的損失: 1.869, 判別器的損失: 0.377
Epoch 0, 第 21 步, 生成器的損失: 2.073, 判別器的損失: 0.384
Epoch 0, 第 22 步, 生成器的損失: 1.185, 判別器的損失: 0.613
WARNING:tensorflow:This model was compiled with a Keras optimizer (<tensorflow.python.keras.optimizers.Adam object at 0x0000019D240A8BA8>) but is being saved in TensorFlow format with `save_weights`. The model's weights will be saved, but unlike with TensorFlow optimizers in the TensorFlow format the optimizer's state will not be saved.

Consider using a TensorFlow optimizer from `tf.train`.
Epoch 1, 第 0 步, 生成器的損失: 2.079, 判別器的損失: 0.590
Epoch 1, 第 1 步, 生成器的損失: 1.161, 判別器的損失: 0.506
Epoch 1, 第 2 步, 生成器的損失: 1.137, 判別器的損失: 0.451
Epoch 1, 第 3 步, 生成器的損失: 1.538, 判別器的損失: 0.346
Epoch 1, 第 4 步, 生成器的損失: 1.733, 判別器的損失: 0.362
Epoch 1, 第 5 步, 生成器的損失: 2.059, 判別器的損失: 0.275
Epoch 1, 第 6 步, 生成器的損失: 2.376, 判別器的損失: 0.243
Epoch 1, 第 7 步, 生成器的損失: 2.260, 判別器的損失: 0.300
Epoch 1, 第 8 步, 生成器的損失: 3.750, 判別器的損失: 0.240
Epoch 1, 第 9 步, 生成器的損失: 3.422, 判別器的損失: 0.222
Epoch 1, 第 10 步, 生成器的損失: 4.694, 判別器的損失: 0.275
Epoch 1, 第 11 步, 生成器的損失: 2.299, 判別器的損失: 0.411
Epoch 1, 第 12 步, 生成器的損失: 4.065, 判別器的損失: 0.547
Epoch 1, 第 13 步, 生成器的損失: 1.834, 判別器的損失: 0.470
Epoch 1, 第 14 步, 生成器的損失: 0.398, 判別器的損失: 1.344
Epoch 1, 第 15 步, 生成器的損失: 1.134, 判別器的損失: 0.973
Epoch 1, 第 16 步, 生成器的損失: 2.866, 判別器的損失: 0.374
Epoch 1, 第 17 步, 生成器的損失: 1.056, 判別器的損失: 0.767
Epoch 1, 第 18 步, 生成器的損失: 0.916, 判別器的損失: 0.603
Epoch 1, 第 19 步, 生成器的損失: 1.151, 判別器的損失: 0.645
Epoch 1, 第 20 步, 生成器的損失: 1.947, 判別器的損失: 0.411
Epoch 1, 第 21 步, 生成器的損失: 3.122, 判別器的損失: 0.314
Epoch 1, 第 22 步, 生成器的損失: 1.805, 判別器的損失: 0.642
WARNING:tensorflow:This model was compiled with a Keras optimizer (<tensorflow.python.keras.optimizers.Adam object at 0x0000019D240A8BA8>) but is being saved in TensorFlow format with `save_weights`. The model's weights will be saved, but unlike with TensorFlow optimizers in the TensorFlow format the optimizer's state will not be saved.

Consider using a TensorFlow optimizer from `tf.train`.
Epoch 2, 第 0 步, 生成器的損失: 1.240, 判別器的損失: 0.569
Epoch 2, 第 1 步, 生成器的損失: 1.151, 判別器的損失: 0.449
Epoch 2, 第 2 步, 生成器的損失: 1.395, 判別器的損失: 0.332
Epoch 2, 第 3 步, 生成器的損失: 1.649, 判別器的損失: 0.258
Epoch 2, 第 4 步, 生成器的損失: 1.777, 判別器的損失: 0.277
Epoch 2, 第 5 步, 生成器的損失: 1.562, 判別器的損失: 0.268
Epoch 2, 第 6 步, 生成器的損失: 2.229, 判別器的損失: 0.224
Epoch 2, 第 7 步, 生成器的損失: 2.432, 判別器的損失: 0.272
Epoch 2, 第 8 步, 生成器的損失: 4.502, 判別器的損失: 0.229
Epoch 2, 第 9 步, 生成器的損失: 4.549, 判別器的損失: 0.211
Epoch 2, 第 10 步, 生成器的損失: 4.481, 判別器的損失: 0.263
Epoch 2, 第 11 步, 生成器的損失: 3.766, 判別器的損失: 0.423
Epoch 2, 第 12 步, 生成器的損失: 2.195, 判別器的損失: 0.562
Epoch 2, 第 13 步, 生成器的損失: 1.682, 判別器的損失: 2.144
Epoch 2, 第 14 步, 生成器的損失: 0.911, 判別器的損失: 0.543
Epoch 2, 第 15 步, 生成器的損失: 0.301, 判別器的損失: 0.342
Epoch 2, 第 16 步, 生成器的損失: 0.159, 判別器的損失: 0.429
Epoch 2, 第 17 步, 生成器的損失: 0.208, 判別器的損失: 0.392
Epoch 2, 第 18 步, 生成器的損失: 0.241, 判別器的損失: 0.390
Epoch 2, 第 19 步, 生成器的損失: 0.826, 判別器的損失: 0.224
Epoch 2, 第 20 步, 生成器的損失: 1.065, 判別器的損失: 0.204
Epoch 2, 第 21 步, 生成器的損失: 0.824, 判別器的損失: 0.226
Epoch 2, 第 22 步, 生成器的損失: 4.178, 判別器的損失: 0.579
WARNING:tensorflow:This model was compiled with a Keras optimizer (<tensorflow.python.keras.optimizers.Adam object at 0x0000019D240A8BA8>) but is being saved in TensorFlow format with `save_weights`. The model's weights will be saved, but unlike with TensorFlow optimizers in the TensorFlow format the optimizer's state will not be saved.

Consider using a TensorFlow optimizer from `tf.train`.
Epoch 3, 第 0 步, 生成器的損失: 0.122, 判別器的損失: 0.613
Epoch 3, 第 1 步, 生成器的損失: 1.310, 判別器的損失: 0.799
Epoch 3, 第 2 步, 生成器的損失: 1.949, 判別器的損失: 0.168
Epoch 3, 第 3 步, 生成器的損失: 1.606, 判別器的損失: 0.167
Epoch 3, 第 4 步, 生成器的損失: 1.433, 判別器的損失: 0.281
Epoch 3, 第 5 步, 生成器的損失: 1.427, 判別器的損失: 0.323
Epoch 3, 第 6 步, 生成器的損失: 2.604, 判別器的損失: 0.292
Epoch 3, 第 7 步, 生成器的損失: 2.925, 判別器的損失: 0.377
Epoch 3, 第 8 步, 生成器的損失: 4.519, 判別器的損失: 0.292
Epoch 3, 第 9 步, 生成器的損失: 4.978, 判別器的損失: 0.415
Epoch 3, 第 10 步, 生成器的損失: 5.062, 判別器的損失: 0.506
Epoch 3, 第 11 步, 生成器的損失: 2.873, 判別器的損失: 0.648
Epoch 3, 第 12 步, 生成器的損失: 3.078, 判別器的損失: 0.610
Epoch 3, 第 13 步, 生成器的損失: 2.059, 判別器的損失: 0.783
Epoch 3, 第 14 步, 生成器的損失: 0.750, 判別器的損失: 1.088
Epoch 3, 第 15 步, 生成器的損失: 1.064, 判別器的損失: 0.898
Epoch 3, 第 16 步, 生成器的損失: 0.329, 判別器的損失: 0.714
Epoch 3, 第 17 步, 生成器的損失: 0.133, 判別器的損失: 0.446
Epoch 3, 第 18 步, 生成器的損失: 0.401, 判別器的損失: 0.476
Epoch 3, 第 19 步, 生成器的損失: 0.419, 判別器的損失: 0.374
Epoch 3, 第 20 步, 生成器的損失: 0.960, 判別器的損失: 0.225
Epoch 3, 第 21 步, 生成器的損失: 1.431, 判別器的損失: 0.203
Epoch 3, 第 22 步, 生成器的損失: 1.061, 判別器的損失: 0.717
WARNING:tensorflow:This model was compiled with a Keras optimizer (<tensorflow.python.keras.optimizers.Adam object at 0x0000019D240A8BA8>) but is being saved in TensorFlow format with `save_weights`. The model's weights will be saved, but unlike with TensorFlow optimizers in the TensorFlow format the optimizer's state will not be saved.

Consider using a TensorFlow optimizer from `tf.train`.
Epoch 4, 第 0 步, 生成器的損失: 2.778, 判別器的損失: 0.743
Epoch 4, 第 1 步, 生成器的損失: 0.179, 判別器的損失: 0.724
Epoch 4, 第 2 步, 生成器的損失: 2.880, 判別器的損失: 0.836
Epoch 4, 第 3 步, 生成器的損失: 2.585, 判別器的損失: 0.290
Epoch 4, 第 4 步, 生成器的損失: 2.781, 判別器的損失: 0.339
Epoch 4, 第 5 步, 生成器的損失: 2.925, 判別器的損失: 0.517
Epoch 4, 第 6 步, 生成器的損失: 5.254, 判別器的損失: 0.537

 

 

 

 附註2:這是train了一個epoch的generate_weight.ht拿來給generate.py生成花朵用的,效果如下:

用34 epoch的generate_weight.ht試試,效果如下:

如果你epoch到200以上,那麼就可以看到如下的效果: