通過DCGAN進行生成花朵
阿新 • • 發佈:2018-11-01
環境是你要安裝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以上,那麼就可以看到如下的效果: