环境是你要安装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:ProgramDataAnaconda3python.exe D:/threeTFproject/Case2_AI_Photoshop/train.py C:ProgramDataAnaconda3libsite-packagesh5py__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以上,那么就可以看到如下的效果: