NeuroWhAI의 잡블로그

[TensorFlow] DCGAN으로 MNIST 이미지 생성하기 (최종) 본문

개발 및 공부/라이브러리&프레임워크

[TensorFlow] DCGAN으로 MNIST 이미지 생성하기 (최종)

NeuroWhAI 2018. 3. 15. 11:25


지식 부족으로 계속 실패했었는데 그럭저럭 완성됬습니다.
인터넷 블로그의 글들과 GitHub의 소스코드들을 참고해서 만들었습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#-*- coding: utf-8 -*-
 
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
 
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("./mnist/data/", one_hot=True)
 
total_epoch = 100
batch_size = 100
n_noise = 100
 
D_global_step = tf.Variable(0, trainable=False, name='D_global_step')
G_global_step = tf.Variable(0, trainable=False, name='G_global_step')
 
= tf.placeholder(tf.float32, [None, 28281])
= tf.placeholder(tf.float32, [None, n_noise])
is_training = tf.placeholder(tf.bool)
 
def leaky_relu(x, leak=0.2):
    return tf.maximum(x, x * leak)
 
def generator(noise):
    with tf.variable_scope('generator'):
        output = tf.layers.dense(noise, 128*7*7)
        output = tf.reshape(output, [-177128])
        output = tf.nn.relu(tf.layers.batch_normalization(output, training=is_training))
        output = tf.layers.conv2d_transpose(output, 64, [55], strides=(22), padding='SAME')
        output = tf.nn.relu(tf.layers.batch_normalization(output, training=is_training))
        output = tf.layers.conv2d_transpose(output, 32, [55], strides=(22), padding='SAME')
        output = tf.nn.relu(tf.layers.batch_normalization(output, training=is_training))
        output = tf.layers.conv2d_transpose(output, 1, [55], strides=(11), padding='SAME')
        output = tf.tanh(output)
    return output
 
def discriminator(inputs, reuse=None):
    with tf.variable_scope('discriminator') as scope:
        if reuse:
            scope.reuse_variables()
        output = tf.layers.conv2d(inputs, 32, [55], strides=(22), padding='SAME')
        output = leaky_relu(output)
        output = tf.layers.conv2d(output, 64, [55], strides=(22), padding='SAME')
        output = leaky_relu(tf.layers.batch_normalization(output, training=is_training))
        output = tf.layers.conv2d(output, 128, [55], strides=(22), padding='SAME')
        output = leaky_relu(tf.layers.batch_normalization(output, training=is_training))
        flat = tf.contrib.layers.flatten(output)
        output = tf.layers.dense(flat, 1, activation=None)
    return output
 
def get_noise(batch_size, n_noise):
    return np.random.uniform(-1.01.0, size=[batch_size, n_noise])
 
def get_moving_noise(batch_size, n_noise):
    assert batch_size > 0
 
    noise_list = []
    base_noise = np.random.uniform(-1.01.0, size=[n_noise])
    end_noise = np.random.uniform(-1.01.0, size=[n_noise])
 
    step = (end_noise - base_noise) / batch_size
    noise = np.copy(base_noise)
    for _ in range(batch_size - 1):
        noise_list.append(noise)
        noise = noise + step
    noise_list.append(end_noise)
    
    return noise_list
 
= generator(Z)
D_real = discriminator(X)
D_gene = discriminator(G, True)
 
loss_D_real = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(
    logits=D_real, labels=tf.ones_like(D_real)
))
loss_D_gene = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(
    logits=D_gene, labels=tf.zeros_like(D_gene)
))
 
loss_D = loss_D_real + loss_D_gene
loss_G = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(
    logits=D_gene, labels=tf.ones_like(D_gene)
))
 
vars_D = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES,
    scope='discriminator')
vars_G = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES,
    scope='generator')
 
update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
with tf.control_dependencies(update_ops):
    train_D = tf.train.AdamOptimizer().minimize(loss_D,
        var_list=vars_D, global_step=D_global_step)
    train_G = tf.train.AdamOptimizer().minimize(loss_G,
        var_list=vars_G, global_step=G_global_step)
 
tf.summary.scalar('loss_D', loss_D)
tf.summary.scalar('loss_G', loss_G)
 
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
 
    merged = tf.summary.merge_all()
    writer = tf.summary.FileWriter('./logs', sess.graph)
 
    total_batch = int(mnist.train.num_examples / batch_size)
 
    for epoch in range(total_epoch):
        loss_val_D, loss_val_G = 00
 
        batch_xs, batch_ys = None, None
        noise = None
 
        for i in range(total_batch):
            batch_xs, batch_ys = mnist.train.next_batch(batch_size)
            batch_xs = batch_xs.reshape(-128281)
            noise = get_noise(batch_size, n_noise)
 
            _, loss_val_D = sess.run([train_D, loss_D],
                feed_dict={X: batch_xs, Z: noise, is_training: True})
            _, loss_val_G = sess.run([train_G, loss_G],
                feed_dict={X: batch_xs, Z: noise, is_training: True})
 
        summary = sess.run(merged,
            feed_dict={X: batch_xs, Z: noise, is_training: True})
        writer.add_summary(summary, global_step=sess.run(G_global_step))
 
        print('Epoch:''%04d' % epoch,
            'D loss: {:.4}'.format(loss_val_D),
            'G loss: {:.4}'.format(loss_val_G))
 
        if epoch == 0 or (epoch + 1) % 5 == 0:
            sample_size = 10
            noise = get_noise(sample_size, n_noise)
            samples = sess.run(G, feed_dict={Z: noise, is_training: False})
            test_noise = get_moving_noise(sample_size, n_noise)
            test_samples = sess.run(G, feed_dict={Z: test_noise, is_training: False})
 
            fig, ax = plt.subplots(2, sample_size, figsize=(sample_size, 2))
 
            for i in range(sample_size):
                ax[0][i].set_axis_off()
                ax[1][i].set_axis_off()
                ax[0][i].imshow(np.reshape(samples[i], (2828)))
                ax[1][i].imshow(np.reshape(test_samples[i], (2828)))
 
            plt.savefig('{}.png'.format(str(epoch).zfill(3)),
                bbox_inches='tight')
            
            plt.close(fig)
 
cs

결과:


아래는 생성한 결과 이미지 입니다.
첫째줄은 단순하게 랜덤 노이즈로 생성한 결과물이고
둘째줄은 노이즈를 두개(a, b) 만들고 자연스럽게 a에서 b로 노이즈 값을 변화시키면서 만든 결과물 입니다.
DCGAN의 장점 중 하나가 입력에 대해 오버피팅되지 않는다는 거라서
학습이 잘 되었다면 노이즈를 변화시키면 결과물도 자연스럽게 바뀐다고 하니 그걸 보려고 두번째 줄을 만들었습니다.
학습 초기의 결과는 뺐습니다.








GPU는 GTX 960M을 사용했는데 100 epochs에 4시간 걸렸네요. ㅠㅠ
왜 고성능 GPU가 딸린 ML 전용 클라우드 서비스를 쓰는지 알 것 같습니다....

아무튼 만족스러운 결과입니다!
딥러닝을 배우고는 있지만 정작 실용적인 무언가를 아직 못만들어봐서 이렇게라도 만족하고 있습니다.
언젠가 노하우가 늘고 창의적인 아이디어가 떠오른다면 열정을 불태워서 진행해보고 싶습니다.




Comments