├── readme.md ├── .gitignore ├── gan.py ├── WGAN.py ├── CGAN_WGANGP.py └── code.ipynb /readme.md: -------------------------------------------------------------------------------- 1 | #简介 2 | 3 | 学习GAN系列的代码记录和分享 4 | 5 | - code.ipynb GAN的入门版代码,[参考文章](https://zhuanlan.zhihu.com/p/26523982) 6 | - gan 三层MLP原始GAN 7 | - WGAN GAN的进化版,修改了GAN在训练上的一些问题。 8 | - CGAN 网络结构是采用CGAN,但在训练方式上采用了WGAN-GP的训练方法。可以通过修改代码改回单纯的WGAN-GP -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | -------------------------------------------------------------------------------- /gan.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | import tensorflow as tf 4 | import cv2 5 | from tensorflow.examples.tutorials.mnist import input_data 6 | 7 | os.environ["TF_CPP_MIN_LOG_LEVEL"] = '3' 8 | Mnist = input_data.read_data_sets('MNIST_data/', one_hot=False) 9 | 10 | image_size = 28 * 28 11 | z_size = 100 12 | batch_size = 64 13 | max_iter = 10000 14 | log_i = 10 15 | save_i = 1000 16 | verbose = True 17 | resotre = True 18 | model_path = "my_net/GAN_net.ckpt" 19 | 20 | 21 | def lrelu(x, leak=0.2): 22 | return tf.maximum(x, leak * x) 23 | 24 | 25 | def combine(image): 26 | if len(image) > 9: 27 | image = image[:9] 28 | rows = [] 29 | for i in range(3): 30 | cols = [] 31 | for j in range(3): 32 | index = i * 3 + j 33 | img = image[index].reshape(28, 28) 34 | cols.append(img) 35 | row = np.concatenate(tuple(cols), axis=0) 36 | rows.append(row) 37 | new_image = np.concatenate(tuple(rows), axis=1) 38 | return new_image 39 | 40 | 41 | def G(z, reuse=False): 42 | with tf.variable_scope("G", reuse=reuse): 43 | layer1 = tf.layers.dense(z, 512, activation=tf.nn.relu) 44 | layer2 = tf.layers.dense(layer1, 512, activation=tf.nn.relu) 45 | layer3 = tf.layers.dense(layer2, image_size, activation=tf.nn.tanh) 46 | return layer3 47 | 48 | 49 | def D(x, reuse=False): 50 | with tf.variable_scope("D", reuse=reuse): 51 | layer1 = tf.layers.dense(x, 512, activation=tf.nn.relu) 52 | layer2 = tf.layers.dense(layer1, 512, activation=tf.nn.relu) 53 | layer3 = tf.layers.dense(layer2, 1) 54 | return layer3 55 | 56 | 57 | x = tf.placeholder(tf.float32, shape=[None, image_size], name="image") 58 | z = tf.placeholder(tf.float32, shape=[None, z_size], name="z") 59 | g_net = G(z) 60 | d_net_real = D(x) 61 | d_net_fake = D(g_net, reuse=True) 62 | 63 | vars = tf.trainable_variables() 64 | 65 | D_PARAMS = [var for var in vars if var.name.startswith("D")] 66 | G_PARAMS = [var for var in vars if var.name.startswith("G")] 67 | # d_clip = [tf.assign(var, tf.clip_by_value(var, -0.01, 0.01)) for var in D_PARAMS] 68 | # d_clip = tf.group(*d_clip) # 限制参数 69 | d_loss = tf.reduce_mean( 70 | tf.nn.sigmoid_cross_entropy_with_logits(logits=d_net_fake, labels=tf.zeros_like(d_net_fake))) + tf.reduce_mean( 71 | tf.nn.sigmoid_cross_entropy_with_logits(logits=d_net_real, labels=tf.ones_like(d_net_real))) 72 | # d_loss = tf.reduce_mean(d_net_fake) - tf.reduce_mean(d_net_real) 73 | 74 | d_opt = tf.train.RMSPropOptimizer(1e-4).minimize( 75 | d_loss, 76 | global_step=tf.Variable(0), 77 | var_list=D_PARAMS 78 | ) 79 | 80 | g_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=d_net_fake, labels=tf.ones_like(d_net_fake))) 81 | # g_loss = tf.reduce_mean(-d_net_fake) 82 | g_opt = tf.train.RMSPropOptimizer(1e-4).minimize( 83 | g_loss, 84 | global_step=tf.Variable(0), 85 | var_list=G_PARAMS 86 | ) 87 | 88 | sess = tf.Session() 89 | saver = tf.train.Saver() 90 | sess.run(tf.global_variables_initializer()) 91 | if resotre: 92 | print("Load Model ...") 93 | saver.restore(sess,model_path) 94 | for it in range(max_iter): 95 | X = Mnist.train.next_batch(batch_size)[0] 96 | image = (X - 0.5) / 0.5 97 | noise = np.random.normal(size=[batch_size, z_size]) 98 | for _ in range(1): 99 | _, d_loss_value = sess.run([d_opt,d_loss], feed_dict={ 100 | x: image, 101 | z: noise 102 | }) 103 | for _ in range(2): 104 | _, g_loss_value = sess.run([g_opt, g_loss], feed_dict={ 105 | z: noise 106 | }) 107 | if it == 0 or (it + 1) % log_i == 0: 108 | print("[{}/{}] d_loss:{:.5f} g_loss:{:.5f}".format(it + 1, max_iter, d_loss_value, g_loss_value)) 109 | if verbose: 110 | noise = np.random.normal(size=[batch_size, z_size]) 111 | fake_image = sess.run([g_net], feed_dict={ 112 | z: noise 113 | })[0] 114 | if len(fake_image) >= 9: 115 | new_image = combine(fake_image) 116 | # print("new image max:{} min:{}".format(new_image.max(),new_image.min())) 117 | new_image = np.clip(new_image * 0.5 + 0.5, 0, 1) # cv2.imshow 需要0-1浮点,或0~255int 118 | w, h = new_image.shape 119 | new_image = cv2.resize(new_image, (int(h * 3), int(w * 3))) 120 | cv2.imshow("mnist example", new_image) 121 | cv2.waitKey(1) 122 | if (it + 1) % save_i == 0: 123 | cv2.imwrite("mnist_example.jpg", new_image) 124 | 125 | save_path = saver.save(sess,model_path ) 126 | print("Model save in %s" % save_path) 127 | else: 128 | print("image too less") 129 | -------------------------------------------------------------------------------- /WGAN.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | """ 3 | WGAN 4 | - D的最后一层取消sigmoid 5 | - 损失函数取消log 6 | - D的w 取值限制在[-c,c]区间内 7 | - 使用RMSProp或SGD并以较低的学习率进行优化 8 | - WD 理论上可以衡量WGAN的训练效果 (实验情况多次打脸) 9 | 项目文件: 10 | MINIST_data minst数据,第一次运行该代码会自动从网络上下载 11 | image 用于保存训练过程中生成的图片,自行创建或改代码路径 12 | my_net 用于保存训练后的模型,自行创建或改代码路径 13 | """ 14 | 15 | import numpy as np 16 | import tensorflow as tf 17 | from PIL import Image 18 | from tensorflow.examples.tutorials.mnist import input_data 19 | 20 | mnist = input_data.read_data_sets('MNIST_data', one_hot=True) 21 | 22 | 23 | def combine(image): 24 | assert len(image) == 64 25 | rows = [] 26 | for i in range(8): 27 | cols = [] 28 | for j in range(8): 29 | index = i * 8 + j 30 | img = image[index].reshape(28, 28) 31 | cols.append(img) 32 | row = np.concatenate(tuple(cols), axis=0) 33 | rows.append(row) 34 | new_image = np.concatenate(tuple(rows), axis=1) 35 | return new_image.astype("uint8") 36 | 37 | 38 | 39 | 40 | 41 | def dense(inputs, shape, name, bn=False, act_fun=None): 42 | W = tf.get_variable(name + ".w", initializer=tf.random_normal(shape=shape)) 43 | b = tf.get_variable(name + ".b", initializer=(tf.zeros((1, shape[-1])) + 0.1)) 44 | y = tf.add(tf.matmul(inputs, W), b) 45 | 46 | def batch_normalization(inputs, out_size, name, axes=0): 47 | mean, var = tf.nn.moments(inputs, axes=[axes]) 48 | scale = tf.get_variable(name=name + ".scale", initializer=tf.ones([out_size])) 49 | offset = tf.get_variable(name=name + ".shift", initializer=tf.zeros([out_size])) 50 | epsilon = 0.001 51 | return tf.nn.batch_normalization(inputs, mean, var, offset, scale, epsilon, name=name + ".bn") 52 | 53 | if bn: 54 | y = batch_normalization(y, shape[1], name=name + ".bn") 55 | if act_fun: 56 | y = act_fun(y) 57 | return y 58 | 59 | 60 | def D(inputs, name, reuse=False): 61 | with tf.variable_scope(name, reuse=reuse): 62 | l1 = dense(inputs, [784, 512], name="relu1", act_fun=tf.nn.relu) 63 | l2 = dense(l1, [512, 512], name="relu2", act_fun=tf.nn.relu) 64 | l3 = dense(l2, [512, 512], name="relu3", act_fun=tf.nn.relu) 65 | y = dense(l3, [512, 1], name="output") 66 | return y 67 | 68 | 69 | def G(inputs, name, reuse=False): 70 | with tf.variable_scope(name, reuse=reuse): 71 | l1 = dense(inputs, [100, 512], name="relu1", act_fun=tf.nn.relu) 72 | l2 = dense(l1, [512, 512], name="relu2", act_fun=tf.nn.relu) 73 | l3 = dense(l2, [512, 512], name="relu3", act_fun=tf.nn.relu) 74 | y = dense(l3, [512, 784], name="output", bn=True, act_fun=tf.nn.sigmoid) 75 | return y 76 | 77 | 78 | z = tf.placeholder(tf.float32, [None, 100], name="noise") # 100 79 | x = tf.placeholder(tf.float32, [None, 784], name="image") # 28*28 80 | 81 | real_out = D(x, "D") 82 | gen = G(z, "G") 83 | fake_out = D(gen, "D", reuse=True) 84 | 85 | vars = tf.trainable_variables() 86 | 87 | D_PARAMS = [var for var in vars if var.name.startswith("D")] 88 | G_PARAMS = [var for var in vars if var.name.startswith("G")] 89 | 90 | d_clip = [tf.assign(var, tf.clip_by_value(var, -0.01, 0.01)) for var in D_PARAMS] 91 | d_clip = tf.group(*d_clip) # 限制参数 92 | 93 | wd = tf.reduce_mean(real_out) - tf.reduce_mean(fake_out) 94 | d_loss = tf.reduce_mean(fake_out) - tf.reduce_mean(real_out) 95 | g_loss = tf.reduce_mean(-fake_out) 96 | 97 | d_opt = tf.train.RMSPropOptimizer(1e-3).minimize( 98 | d_loss, 99 | global_step=tf.Variable(0), 100 | var_list=D_PARAMS 101 | ) 102 | 103 | g_opt = tf.train.RMSPropOptimizer(1e-3).minimize( 104 | g_loss, 105 | global_step=tf.Variable(0), 106 | var_list=G_PARAMS 107 | ) 108 | is_restore = False 109 | # is_restore = True # 是否第一次训练(不需要载入模型) 110 | 111 | sess = tf.Session() 112 | sess.run(tf.global_variables_initializer()) 113 | 114 | if is_restore: 115 | saver = tf.train.Saver() 116 | # 提取变量 117 | saver.restore(sess, "my_net/GAN_net.ckpt") 118 | print("Model restore...") 119 | 120 | 121 | CRITICAL_NUM = 5 122 | for step in range(100 * 1000): 123 | if step < 25 or step % 500 == 0: 124 | critical_num = 100 125 | else: 126 | critical_num = CRITICAL_NUM 127 | for ep in range(critical_num): 128 | noise = np.random.normal(size=(64, 100)) 129 | batch_xs = mnist.train.next_batch(64)[0] 130 | _, d_loss_v, _ = sess.run([d_opt, d_loss, d_clip], feed_dict={ 131 | x: batch_xs, 132 | z: noise 133 | }) 134 | 135 | 136 | for ep in range(1): 137 | noise = np.random.normal(size=(64, 100)) 138 | _, g_loss_v = sess.run([g_opt, g_loss], feed_dict={ 139 | z: noise 140 | }) 141 | print("Step:%d D-loss:%.4f G-loss:%.4f" % (step + 1, d_loss_v, g_loss_v)) 142 | if step % 1000 == 999: 143 | batch_xs = mnist.train.next_batch(64)[0] 144 | # batch_xs = pre(batch_xs) 145 | noise = np.random.normal(size=(64, 100)) 146 | mpl_v = sess.run(wd, feed_dict={ 147 | x: batch_xs, 148 | z: noise 149 | }) 150 | print("################## Step %d WD:%.4f ###############" % (step + 1, mpl_v)) 151 | generate = sess.run(gen, feed_dict={ 152 | z: noise 153 | }) 154 | 155 | generate *= 255 156 | generate = np.clip(generate, 0, 255) 157 | image = combine(generate) 158 | Image.fromarray(image).save("image/Step_%d.jpg" % (step + 1)) 159 | saver = tf.train.Saver() 160 | save_path = saver.save(sess, "my_net/GAN_net.ckpt") 161 | print("Model save in %s" % save_path) 162 | sess.close() 163 | -------------------------------------------------------------------------------- /CGAN_WGANGP.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | 3 | import numpy as np 4 | import tensorflow as tf 5 | import time 6 | from sklearn.preprocessing import PolynomialFeatures 7 | from PIL import Image 8 | from tensorflow.examples.tutorials.mnist import input_data 9 | 10 | W = 28 11 | H = 28 12 | chanel = 1 13 | 14 | BATCH_SIZE = 16 15 | K = 1.0 16 | LAMBDA = 10 # 梯度norm在目标函数中的权重,大概训练过程是先将D满足梯度norm的目标,这个参数会影响达到这个目标的时间 17 | Mnist = input_data.read_data_sets('MNIST_data/', one_hot=True) 18 | 19 | is_restore = True 20 | 21 | 22 | def preprocess(x): 23 | return x 24 | 25 | def deprocess(x): 26 | image = x* 255 27 | return image.reshape([9,W,H,chanel]).astype("uint8") 28 | 29 | def combine(image): 30 | assert len(image) >= 9 31 | if len(image) > 9: 32 | image = image[:9] 33 | rows = [] 34 | for i in range(3): 35 | cols = [] 36 | for j in range(3): 37 | index = i * 3 + j 38 | img = image[index].reshape(H, W) 39 | cols.append(img) 40 | row = np.concatenate(tuple(cols), axis=0) 41 | rows.append(row) 42 | new_image = np.concatenate(tuple(rows), axis=1) 43 | return new_image.astype("uint8") 44 | 45 | 46 | def leakyRelu(x, alpha=0.2): 47 | output = tf.maximum(alpha * x, x) 48 | return output 49 | 50 | 51 | def selu(x): 52 | alpha = 1.6732632423543772848170429916717 53 | scale = 1.0507009873554804934193349852946 54 | return scale * tf.where(x >= 0.0, x, alpha * tf.nn.elu(x)) 55 | 56 | 57 | def flatten(inputs): 58 | dim = tf.reduce_prod(tf.shape(inputs)[1:]) 59 | return tf.reshape(inputs, [-1, dim]) 60 | 61 | 62 | def conv2d(inputs, filter_shape, name, stride=(1, 1), padding="SAME", baies=True, act_fun=None): 63 | filter_w = tf.get_variable(name + ".w", shape=filter_shape, 64 | initializer=tf.truncated_normal_initializer(stddev=0.02)) 65 | if baies: 66 | filter_b = tf.get_variable(name + ".b", initializer=tf.zeros((1, filter_shape[-1])) + 0.1) 67 | feature_map = tf.nn.conv2d(inputs, filter_w, strides=[1, stride[0], stride[1], 1], padding=padding) + filter_b 68 | else: 69 | feature_map = tf.nn.conv2d(inputs, filter_w, strides=[1, stride[0], stride[1], 1], padding=padding) 70 | if act_fun: 71 | feature_map = act_fun(feature_map) 72 | return feature_map 73 | 74 | 75 | def decov2d(inputs, filter_shape, output_shape, name, stride=(1, 1), 76 | padding="SAME", bn=False, baies=True, act_fun=None): 77 | def batch_normalization(inputs, out_size, name, axes=0): 78 | mean, var = tf.nn.moments(inputs, axes=[axes]) 79 | scale = tf.get_variable(name=name + ".scale", initializer=tf.ones([out_size])) 80 | offset = tf.get_variable(name=name + ".shift", initializer=tf.zeros([out_size])) 81 | epsilon = 0.001 82 | return tf.nn.batch_normalization(inputs, mean, var, offset, scale, epsilon, name=name + ".bn") 83 | 84 | w = tf.get_variable(name + ".w", shape=[filter_shape[0], filter_shape[1], output_shape[-1], inputs.get_shape()[-1]], 85 | initializer=tf.truncated_normal_initializer(stddev=0.02)) 86 | if baies: 87 | b = tf.get_variable(name + ".b", [output_shape[-1]], initializer=tf.constant_initializer(0.01)) 88 | convt = tf.nn.conv2d_transpose(inputs, w, output_shape=output_shape, 89 | strides=[1, stride[0], stride[1], 1], padding=padding) + b 90 | else: 91 | convt = tf.nn.conv2d_transpose(inputs, w, output_shape=output_shape, 92 | strides=[1, stride[0], stride[1], 1], padding=padding) 93 | if bn: 94 | convt = batch_normalization(flatten(convt), output_shape[1] * output_shape[2] * output_shape[3], 95 | name=name + ".bn") 96 | convt = tf.reshape(convt, [-1] + output_shape[1:]) 97 | if act_fun: 98 | convt = act_fun(convt) 99 | return convt 100 | 101 | 102 | def dense(inputs, shape, name, bn=False, act_fun=None): 103 | W = tf.get_variable(name + ".w", initializer=tf.random_normal(shape=shape) / np.sqrt(shape[0] / 2)) 104 | b = tf.get_variable(name + ".b", initializer=(tf.zeros((1, shape[-1])) + 0.1)) 105 | y = tf.add(tf.matmul(inputs, W), b) 106 | 107 | def batch_normalization(inputs, out_size, name): 108 | mean, var = tf.nn.moments(inputs, axes=[0]) 109 | scale = tf.get_variable(name=name + ".scale", initializer=tf.ones([out_size])) 110 | offset = tf.get_variable(name=name + ".shift", initializer=tf.zeros([out_size])) 111 | epsilon = 0.001 112 | return tf.nn.batch_normalization(inputs, mean, var, offset, scale, epsilon, name=name + ".bn") 113 | 114 | if bn: 115 | y = batch_normalization(y, shape[1], name=name + ".bn") 116 | if act_fun: 117 | y = act_fun(y) 118 | return y 119 | 120 | 121 | def max_pooling(inputs, ksize=(2, 2), stride=(2, 2), padding="SAME"): 122 | return tf.nn.max_pool(inputs, 123 | ksize=[1, ksize[0], ksize[1], 1], 124 | strides=[1, stride[0], stride[1], 1], padding=padding) 125 | 126 | hidden = 16 127 | 128 | def D(inputs, condition,name, reuse=False): 129 | with tf.variable_scope(name, reuse=reuse): 130 | # l1 = conv2d(tf.reshape(inputs, [-1, W, H, chanel]), [5, 5, chanel, hidden], name="cov1", 131 | # act_fun=leakyRelu) 132 | # l2 = conv2d(l1, [5, 5, hidden,int(hidden/2)], name="cov2", 133 | # act_fun=leakyRelu) 134 | # # l3 = conv2d(l2, [5, 5, int(hidden/2), int(hidden/4)], name="cov3", 135 | # # act_fun=leakyRelu) # W/8 H/8 HIDDEN*4 136 | # l3 = flatten(l2) 137 | # l4 = dense(l3, [int(W)*int(H)*int(hidden/2) ,128], name="feature") 138 | # l5 = tf.concat([l4,condition], axis=1) 139 | # l6 = dense(l5, [128+10 ,64], name="feature2") 140 | # y = dense(l6, [64, 1], name="output") 141 | inputs = tf.concat([inputs,condition], axis=1) 142 | l1 = dense(inputs, [W*H*chanel+10, 256], name="ly1",act_fun=leakyRelu) 143 | l1 = dense(l1, [256,128], name="ly2",act_fun=leakyRelu) 144 | l1 = dense(l1, [128,64], name="ly3",act_fun=leakyRelu) 145 | y = dense(l1, [64,1], name="output") 146 | return y 147 | 148 | 149 | def G(inputs,condition,name, reuse=False): 150 | with tf.variable_scope(name, reuse=reuse): 151 | inputs = tf.concat([inputs,condition], axis=1) 152 | l1 = dense(inputs, [100+10, 128], name="ly1",act_fun=tf.nn.relu) 153 | l1 = dense(l1, [128,512], name="ly2",act_fun=tf.nn.relu) 154 | l1 = dense(l1, [512,1024], name="ly3",act_fun=tf.nn.relu) 155 | y = dense(l1, [1024,W*H*chanel], name="output",act_fun=tf.nn.sigmoid) 156 | # inputs = tf.concat([inputs,condition], axis=1) 157 | # l1 = dense(inputs, [100+9, W* H * hidden], name="linear", bn=True,act_fun=tf.nn.relu) 158 | # l2 = decov2d(tf.reshape(l1, [-1, W, H, hidden]), filter_shape=[5, 5], output_shape=[BATCH_SIZE, W, H, hidden], 159 | # name="decov", bn=True,act_fun=tf.nn.relu) 160 | # l3 = decov2d(tf.reshape(l2, [-1, W, H, hidden]), filter_shape=[5, 5], output_shape=[BATCH_SIZE, W, H, hidden], 161 | # name="decov2",bn=True,act_fun=tf.nn.relu) 162 | # y = decov2d(tf.reshape(l3, [-1, W, H, hidden]), filter_shape=[5, 5], output_shape=[BATCH_SIZE, W, H, chanel], 163 | # name="decov3",act_fun=tf.nn.sigmoid) 164 | # y = flatten(y) 165 | return y 166 | 167 | 168 | z = tf.placeholder(tf.float32, [None, 100], name="noise") # 100 169 | x = tf.placeholder(tf.float32, [None, W * H * chanel], name="image") # 36*36*3 170 | c = tf.placeholder(tf.float32, [None, 10], name="condition") # 36*36*3 171 | 172 | real_out = D(x, c,"D") 173 | gen = G(z,c,"G") 174 | fake_out = D(gen,c,"D", reuse=True) 175 | 176 | vars = tf.trainable_variables() 177 | 178 | D_PARAMS = [var for var in vars if var.name.startswith("D")] 179 | G_PARAMS = [var for var in vars if var.name.startswith("G")] 180 | 181 | wd = tf.reduce_mean(real_out) - tf.reduce_mean(fake_out) 182 | alpha = tf.random_uniform( 183 | shape=[BATCH_SIZE, 1], 184 | minval=0., 185 | maxval=1. 186 | ) # 采样 187 | d_loss = tf.reduce_mean(fake_out) - tf.reduce_mean(real_out) 188 | 189 | # 插值 190 | insert_value = gen - alpha * (x - gen) 191 | 192 | gradients = tf.gradients(D(insert_value,c,name="D", reuse=True), [insert_value])[0] 193 | slopes = tf.sqrt(tf.reduce_sum(tf.square(gradients), reduction_indices=[1])) # 求范数 194 | gradient_penalty = tf.reduce_mean((slopes - K) ** 2) # 最少化这个会使梯度集中在K值附近 195 | 196 | 197 | l1_loss = tf.reduce_mean(tf.abs(gen-x)) 198 | 199 | 200 | d_loss += LAMBDA * gradient_penalty 201 | g_loss = tf.reduce_mean(-fake_out) 202 | 203 | d_opt = tf.train.AdamOptimizer(1e-4, beta1=0.4, beta2=0.9).minimize( 204 | d_loss, 205 | global_step=tf.Variable(0), 206 | var_list=D_PARAMS 207 | ) 208 | 209 | g_opt = tf.train.AdamOptimizer(1e-4, beta1=0.4, beta2=0.9).minimize( 210 | g_loss, 211 | global_step=tf.Variable(0), 212 | var_list=G_PARAMS 213 | ) 214 | 215 | 216 | 217 | model_path = "my_net2/GAN_net.ckpt" 218 | 219 | b = 0 220 | e = 100 * 1000 221 | sess = tf.Session() 222 | sess.run(tf.global_variables_initializer()) 223 | 224 | if is_restore: 225 | saver = tf.train.Saver() 226 | # 提取变量 227 | saver.restore(sess, model_path) 228 | print("Model restore...") 229 | 230 | 231 | print("Training……") 232 | CRITICAL_NUM = 5 233 | epoch = 100 234 | length = Mnist.train.num_examples 235 | for ep in range(epoch): 236 | bt = time.time() 237 | step = 0 238 | while step < length: 239 | critical_num = CRITICAL_NUM 240 | for _ in range(critical_num): 241 | noise = np.random.normal(size=(BATCH_SIZE, 100)) 242 | batch_xs,batch_ys= Mnist.train.next_batch(BATCH_SIZE) 243 | batch_xs = preprocess(batch_xs) 244 | _, d_loss_v,wd_v = sess.run([d_opt, d_loss,wd], feed_dict={ 245 | x: batch_xs, 246 | c: batch_ys, 247 | z: noise, 248 | }) 249 | step += BATCH_SIZE 250 | print("\rep: %d/%d batch: %d/%d loss:%.7f "%(ep+1,epoch,step,length,wd_v),end="") 251 | 252 | for _ in range(1): 253 | noise = np.random.normal(size=(BATCH_SIZE, 100)) 254 | batch_xs,batch_ys = Mnist.train.next_batch(BATCH_SIZE) 255 | batch_xs = preprocess(batch_xs) 256 | _, g_loss_v = sess.run([g_opt, g_loss], feed_dict={ 257 | x: batch_xs, 258 | c:batch_ys, 259 | z: noise, 260 | }) 261 | step += BATCH_SIZE 262 | print("\rep: %d/%d batch: %d/%d loss:%.7f "%(ep+1,epoch,step,length,wd_v),end="") 263 | 264 | 265 | print() 266 | et = time.time() 267 | noise = np.random.normal(size=(9, 100)) 268 | noise_y = np.array([ 269 | [0,0,0,0,0,0,0,0,0,1], 270 | [0,0,0,0,0,0,0,0,1,0], 271 | [0,0,0,0,0,0,0,1,0,0], 272 | [0,0,0,0,0,0,1,0,0,0], 273 | [0,0,0,0,0,1,0,0,0,0], 274 | [0,0,0,0,1,0,0,0,0,0], 275 | [0,0,0,1,0,0,0,0,0,0], 276 | [0,0,1,0,0,0,0,0,0,0], 277 | [0,1,0,0,0,0,0,0,0,0], 278 | ]) 279 | generate = sess.run(gen, feed_dict={ 280 | z: noise, 281 | c:noise_y 282 | }) 283 | generate = deprocess(generate) 284 | image = combine(generate) 285 | Image.fromarray(image).save("image2/ep_%d.jpg" % (ep + 1)) 286 | saver = tf.train.Saver() 287 | save_path = saver.save(sess, model_path) 288 | print("Model save in %s" % save_path) 289 | print("Cost time: %d s"%(et-bt)) 290 | print("-----------------------------") 291 | -------------------------------------------------------------------------------- /code.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 2, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import matplotlib.pyplot as plt\n", 12 | "import numpy as np\n", 13 | "import tensorflow as tf\n", 14 | "%matplotlib inline" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 78, 20 | "metadata": { 21 | "collapsed": true 22 | }, 23 | "outputs": [], 24 | "source": [ 25 | "LENGTH = 1000 # 每一个样本由1000个\n", 26 | "\n", 27 | "def sample_data(size, length=100):\n", 28 | " \"\"\"\n", 29 | " 生成值得均值和方差的数据\n", 30 | " :param size:\n", 31 | " :param length:\n", 32 | " :return:\n", 33 | " \"\"\"\n", 34 | " data = []\n", 35 | " for _ in range(size):\n", 36 | " data.append(sorted(np.random.normal(4, 1.5, length)))\n", 37 | " return np.array(data)\n", 38 | "\n", 39 | "\n", 40 | "def random_data(size, length=100):\n", 41 | " \"\"\"\n", 42 | " 随机生成数据\n", 43 | " :param size:\n", 44 | " :param length:\n", 45 | " :return:\n", 46 | " \"\"\"\n", 47 | " data = []\n", 48 | " for _ in range(size):\n", 49 | " x = np.random.random(length) \n", 50 | " data.append(x)\n", 51 | " return np.array(data)\n", 52 | "\n", 53 | "\n", 54 | "def preprocess_data(x):\n", 55 | " \"\"\"\n", 56 | " 计算每一组数据平均值和方差\n", 57 | " :param x:\n", 58 | " :return:\n", 59 | " \"\"\"\n", 60 | " return [[np.mean(data), np.std(data)] for data in x]" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": 79, 66 | "metadata": { 67 | "collapsed": true 68 | }, 69 | "outputs": [], 70 | "source": [ 71 | "x = tf.placeholder(tf.float32, shape=[None, 2], name=\"feature\") # [mean,std] -》 D\n", 72 | "y = tf.placeholder(tf.float32, shape=[None, 1], name=\"label\")\n", 73 | "in_size = LENGTH\n", 74 | "out_size = LENGTH\n", 75 | "\n", 76 | "###################################### G 网络结构\n", 77 | "# 第一层\n", 78 | "z = tf.placeholder(tf.float32, shape=[None, LENGTH], name=\"noise\") # 随机值噪音\n", 79 | "Weights = tf.Variable(tf.random_normal([in_size, 32]))\n", 80 | "biases = tf.Variable(tf.zeros([1, 32]) + 0.1)\n", 81 | "G_output = tf.matmul(z, Weights) + biases\n", 82 | "G_output = tf.nn.relu(G_output)\n", 83 | "# 第二层\n", 84 | "Weights2 = tf.Variable(tf.random_normal([32, 32]))\n", 85 | "biases2 = tf.Variable(tf.zeros([1, 32]) + 0.1)\n", 86 | "G_output2 = tf.matmul(G_output, Weights2) + biases2\n", 87 | "G_output2 = tf.nn.sigmoid(G_output2)\n", 88 | "# 第三层\n", 89 | "Weights3 = tf.Variable(tf.random_normal([32, out_size]))\n", 90 | "biases3 = tf.Variable(tf.zeros([1, out_size]) + 0.1)\n", 91 | "G_output3 = tf.matmul(G_output2, Weights3) + biases3\n", 92 | "\n", 93 | "G_PARAMS = [Weights, biases, Weights2, biases2, Weights3, biases3] # G的参数\n", 94 | "\n", 95 | "###################################### D 网络结构(预训练的D)\n", 96 | "# 第一层\n", 97 | "\n", 98 | "dWeights = tf.Variable(tf.random_normal([2, 32]), name=\"D_W\")\n", 99 | "dbiases = tf.Variable(tf.zeros([1, 32]) + 0.1, name=\"D_b\")\n", 100 | "D_output = tf.matmul(x, dWeights) + dbiases\n", 101 | "D_output = tf.nn.relu(D_output)\n", 102 | "# 第二层\n", 103 | "dWeights2 = tf.Variable(tf.random_normal([32, 32]), name=\"D_W2\")\n", 104 | "dbiases2 = tf.Variable(tf.zeros([1, 32]) + 0.1, name=\"D_b2\")\n", 105 | "D_output2 = tf.matmul(D_output, dWeights2) + dbiases2\n", 106 | "D_output2 = tf.nn.sigmoid(D_output2)\n", 107 | "\n", 108 | "# 第三层\n", 109 | "dWeights3 = tf.Variable(tf.random_normal([32, 1]), name=\"D_W3\")\n", 110 | "dbiases3 = tf.Variable(tf.zeros([1, 1]) + 0.1, name=\"D_b3\")\n", 111 | "D_output3_ = tf.matmul(D_output2, dWeights3) + dbiases3\n", 112 | "D_output3 = tf.nn.sigmoid(D_output3_)\n", 113 | "\n", 114 | "D_PARAMS = [dWeights, dbiases,\n", 115 | " dWeights2, dbiases2,\n", 116 | " dWeights3, dbiases3]\n", 117 | "\n", 118 | "##################################### GAN的结构\n", 119 | "\n", 120 | "# 先求出G_output3的各行平均值和方差\n", 121 | "MEAN = tf.reduce_mean(G_output3, 1) # 行向量\n", 122 | "MEAN_T = tf.transpose(tf.expand_dims(MEAN, 0)) # 转置\n", 123 | "STD = tf.sqrt(tf.reduce_mean(tf.square(G_output3 - MEAN_T), 1))\n", 124 | "DATA = tf.concat(1, [MEAN_T,\n", 125 | " tf.transpose(tf.expand_dims(STD, 0))])\n", 126 | "\n", 127 | "# GAN中的D\n", 128 | "GAN_Weights = tf.Variable(tf.random_normal([2, 32]), name=\"GAN_W\")\n", 129 | "GAN_biases = tf.Variable(tf.zeros([1, 32]) + 0.1, name=\"GAN_b\")\n", 130 | "GAN_output = tf.matmul(DATA, GAN_Weights) + GAN_biases\n", 131 | "GAN_output = tf.nn.relu(GAN_output)\n", 132 | "# 第二层\n", 133 | "GAN_Weights2 = tf.Variable(tf.random_normal([32, 32]), name=\"GAN_W2\")\n", 134 | "GAN_biases2 = tf.Variable(tf.zeros([1, 32]) + 0.1, name=\"GAN_b2\")\n", 135 | "GAN_output2 = tf.matmul(GAN_output, GAN_Weights2) + GAN_biases2\n", 136 | "GAN_output2 = tf.nn.sigmoid(GAN_output2)\n", 137 | "\n", 138 | "# 第三层\n", 139 | "GAN_Weights3 = tf.Variable(tf.random_normal([32, 1]), name=\"GAN_W3\")\n", 140 | "GAN_biases3 = tf.Variable(tf.zeros([1, 1]) + 0.1, name=\"GAN_b3\")\n", 141 | "GAN_output3_ = tf.matmul(GAN_output2, GAN_Weights3) + GAN_biases3\n", 142 | "GAN_output3 = tf.nn.sigmoid(GAN_output3_)\n", 143 | "\n", 144 | "GAN_D_PARAMS = [GAN_Weights, GAN_biases,\n", 145 | " GAN_Weights2, GAN_biases2,\n", 146 | " GAN_Weights3, GAN_biases3]" 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": 80, 152 | "metadata": { 153 | "collapsed": true 154 | }, 155 | "outputs": [], 156 | "source": [ 157 | "##################################### 定义损失函数\n", 158 | "d_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(D_output3_, y)) # 二分类交叉熵\n", 159 | "g_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(GAN_output3_, y)) # GAN二分类交叉熵" 160 | ] 161 | }, 162 | { 163 | "cell_type": "code", 164 | "execution_count": 81, 165 | "metadata": { 166 | "collapsed": true 167 | }, 168 | "outputs": [], 169 | "source": [ 170 | "#################################### 定义优化器\n", 171 | "d_optimizer = tf.train.GradientDescentOptimizer(0.01).minimize(\n", 172 | " d_loss,\n", 173 | " global_step=tf.Variable(0),\n", 174 | " var_list=D_PARAMS\n", 175 | ")\n", 176 | "\n", 177 | "g_optimizer = tf.train.GradientDescentOptimizer(0.05).minimize(\n", 178 | " g_loss,\n", 179 | " global_step=tf.Variable(0),\n", 180 | " var_list=G_PARAMS\n", 181 | ")" 182 | ] 183 | }, 184 | { 185 | "cell_type": "code", 186 | "execution_count": 82, 187 | "metadata": { 188 | "collapsed": false 189 | }, 190 | "outputs": [], 191 | "source": [ 192 | "d_loss_history = []\n", 193 | "g_loss_history = []\n", 194 | "epoch = 200\n", 195 | "with tf.Session() as sess:\n", 196 | " sess.run(tf.global_variables_initializer())\n", 197 | " # GAN博弈开始\n", 198 | " print('train GAN....')\n", 199 | " for step in range(epoch):\n", 200 | " # 先进行GAN中的D的训练,即对生成样本的判断\n", 201 | " for _ in range(100):\n", 202 | " # 使用G生成一批样本:\n", 203 | " real = sample_data(100,length=LENGTH)\n", 204 | " noise = random_data(100,length=LENGTH)\n", 205 | " generate = sess.run(G_output3, feed_dict={\n", 206 | " z: noise\n", 207 | " }) # 生成样本\n", 208 | " X = list(real) + list(generate) \n", 209 | " X = preprocess_data(X)\n", 210 | " Y = [[1] for _ in range(len(real))] + [[0] for _ in range(len(generate))]\n", 211 | " d_loss_value, _ = sess.run([d_loss, d_optimizer], feed_dict={\n", 212 | " x: X,\n", 213 | " y: Y\n", 214 | " }) # 训练判别网络\n", 215 | " d_loss_history.append(d_loss_value)\n", 216 | " # 将参数移动过去GAN中的判别网络\n", 217 | " dp_value = sess.run(D_PARAMS)\n", 218 | " for i, v in enumerate(GAN_D_PARAMS):\n", 219 | " sess.run(v.assign(dp_value[i]))\n", 220 | "\n", 221 | " for _ in range(100):\n", 222 | " noise = random_data(100,length=LENGTH)\n", 223 | " g_loss_value, _ = sess.run([g_loss, g_optimizer], feed_dict={\n", 224 | " z: noise,\n", 225 | " y: [[1] for _ in range(len(noise))] # 混肴为目标,不需要加入x,我们只是借助G,并不需要训练G\n", 226 | " }) # 调整G,让GAN的误差减少\n", 227 | " g_loss_history.append(g_loss_value)\n", 228 | " if step % 20 == 0 or step+1 == epoch:\n", 229 | " noise = random_data(1,length=LENGTH)\n", 230 | " generate = sess.run(G_output3, feed_dict={\n", 231 | " z: noise\n", 232 | " })\n", 233 | " print(\"[%4d] GAN-d-loss: %.12f GAN-g-loss: %.12f generate-mean: %.4f generate-std: %.4f\" % (step,\n", 234 | " d_loss_value, g_loss_value,generate.mean() ,generate.std() ))\n", 235 | " \n", 236 | " \n", 237 | " print(\"train finish...\")" 238 | ] 239 | }, 240 | { 241 | "cell_type": "code", 242 | "execution_count": 83, 243 | "metadata": { 244 | "collapsed": false 245 | }, 246 | "outputs": [ 247 | { 248 | "data": { 249 | "text/plain": [ 250 | "[]" 251 | ] 252 | }, 253 | "execution_count": 83, 254 | "metadata": {}, 255 | "output_type": "execute_result" 256 | }, 257 | { 258 | "data": { 259 | "image/png": "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\n", 260 | "text/plain": [ 261 | "" 262 | ] 263 | }, 264 | "metadata": {}, 265 | "output_type": "display_data" 266 | } 267 | ], 268 | "source": [ 269 | "plt.subplot(211)\n", 270 | "plt.plot(d_loss_history)\n", 271 | "a = plt.subplot(212)\n", 272 | "plt.plot(g_loss_history,c=\"g\")" 273 | ] 274 | }, 275 | { 276 | "cell_type": "code", 277 | "execution_count": 84, 278 | "metadata": { 279 | "collapsed": false 280 | }, 281 | "outputs": [ 282 | { 283 | "data": { 284 | "text/plain": [ 285 | "[]" 286 | ] 287 | }, 288 | "execution_count": 84, 289 | "metadata": {}, 290 | "output_type": "execute_result" 291 | }, 292 | { 293 | "data": { 294 | "image/png": "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\n", 295 | "text/plain": [ 296 | "" 297 | ] 298 | }, 299 | "metadata": {}, 300 | "output_type": "display_data" 301 | } 302 | ], 303 | "source": [ 304 | "real = sample_data(1,length=LENGTH)\n", 305 | "(data, bins) = np.histogram(real[0])\n", 306 | "plt.plot(bins[:-1], data, c=\"g\")\n", 307 | "\n", 308 | "\n", 309 | "(data, bins) = np.histogram(noise[0])\n", 310 | "plt.plot(bins[:-1], data, c=\"b\")\n", 311 | "\n", 312 | "# with tf.Session() as sess:\n", 313 | "# sess.run(tf.global_variables_initializer())\n", 314 | "# generate = sess.run(G_output3, feed_dict={\n", 315 | "# z: noise\n", 316 | "# })\n", 317 | "(data, bins) = np.histogram(generate[0])\n", 318 | "plt.plot(bins[:-1], data, c=\"r\")" 319 | ] 320 | }, 321 | { 322 | "cell_type": "code", 323 | "execution_count": 76, 324 | "metadata": { 325 | "collapsed": false 326 | }, 327 | "outputs": [ 328 | { 329 | "data": { 330 | "text/plain": [ 331 | "array([ 1.31326169, 0.69314718])" 332 | ] 333 | }, 334 | "execution_count": 76, 335 | "metadata": {}, 336 | "output_type": "execute_result" 337 | } 338 | ], 339 | "source": [ 340 | "#x - x * z + log(1 + exp(-x))\n", 341 | "\n", 342 | "pre = np.array([1,0])\n", 343 | "real = np.array([0,1])\n", 344 | "\n", 345 | "pre-pre*real + np.log(1+np.exp(-pre))" 346 | ] 347 | }, 348 | { 349 | "cell_type": "code", 350 | "execution_count": null, 351 | "metadata": { 352 | "collapsed": true 353 | }, 354 | "outputs": [], 355 | "source": [ 356 | "" 357 | ] 358 | }, 359 | { 360 | "cell_type": "code", 361 | "execution_count": null, 362 | "metadata": { 363 | "collapsed": true 364 | }, 365 | "outputs": [], 366 | "source": [ 367 | "" 368 | ] 369 | } 370 | ], 371 | "metadata": { 372 | "kernelspec": { 373 | "display_name": "Python 3", 374 | "language": "python", 375 | "name": "python3" 376 | }, 377 | "language_info": { 378 | "codemirror_mode": { 379 | "name": "ipython", 380 | "version": 3.0 381 | }, 382 | "file_extension": ".py", 383 | "mimetype": "text/x-python", 384 | "name": "python", 385 | "nbconvert_exporter": "python", 386 | "pygments_lexer": "ipython3", 387 | "version": "3.5.1" 388 | } 389 | }, 390 | "nbformat": 4, 391 | "nbformat_minor": 0 392 | } --------------------------------------------------------------------------------