1.생성적 적대 신경망(GAN, Generative Adversarial Networks)
- 딥러닝의 원리를 활용해 가상의 이미지를 생성하는 알고리즘
- 예를 들어 얼굴을 만든다면, 이미지 픽셀들이 어떻게 조합되어야 우리가 생각하는 얼굴의 형상이 되는지를 딥러닝 알고리즘이 예측한 결과가 나옴

- 적대적(adversarial)
- 진짜 같은 가짜를 만들기 위해 GAN 알고리즘 내부에서 적대적 경합을 진행
- 생성자(Generator)
- 가짜를 만들어 내는 파트
- 판별자(Discriminator)
- 진위를 가려내는 파트
- DCGAN(Deep Convolutional GAN)
- 페이스북의 AI 연구팀이 만든 GAN 알고리즘으로, 초기의 GAN을 보완한 알고리즘
2. 생성자
- 가상의 이미지를 생성
- 처음엔 랜덤한 픽셀 값으로 채워진 가짜 이미지로 시작
- 판별자의 판별 결과에 따라 지속적으로 업데이트하며 점차 원하는 이미지를 생성
- 패딩(Padding)
- 생성자가 만들어내는 이미지를 판별자가 비교한 진짜와 같은 크기가 되게 만들어줌

- 배치 정규화(Batch Normalization)
- 입력 데이터의 평균이 0, 분산이 1이 되도록 재배치하는 것
- 다음 층으로 입력될 값을 일정하게 재배치
Code) 생성자 모델
generator = Sequential()
generator.add(Dense(128*7*7, input_dim=100, activation=LeakyReLU(0.2))) #활성화 함수로 LeakyReLU
generator.add(BatchNormalization()) #배치 정규화
generator.add(Reshape((7, 7, 128)))
generator.add(UpSampling2D()) #가로,세로 2배씩 증가
generator.add(Conv2D(64, kernel_size=5, padding='same')) #컨볼루션
generator.add(BatchNormalization()) #배치 정규화
generator.add(Activation(LeakyReLU(0.2))) #활성화 함수로 LeakyReLU
generator.add(UpSampling2D()) #가로,세로 2배씩 증가
generator.add(Conv2D(1, kernel_size=5, padding='same', activation='tanh')) #활성화 함수로 tanh
- LeakyReLU()
- GAN에서 ReLU()를 쓸 경우 학습이 불안정해 지는 경우가 발생
- x값이 음수이면 무조건 0이 되어 뉴런들이 일찍 소실되는 단점
- LeakyReLU()를 사용하면 0이하에서도 작은 값을 갖게 만들어 단점을 보완
- 예제의 경우, 0보다 작을 때 0.2를 곱해줌
- GAN에서 ReLU()를 쓸 경우 학습이 불안정해 지는 경우가 발생
3. 판별자
- 생성자에서 넘어온 이미지가 가짜인지 진짜인지를 판별해주는 장치
- 컨볼루션 신경망의 구조를 그대로 차용
- 컨볼루션 신경망이 구별하는 데에 최적화된 알고리즘이기 때문
4. 적대적 신경망 실행하기

- 생성자 G()에 입력값 input을 넣은 결과는 G(input)
- 이것을 판별자에 입력하면 결과는 D(G(input))
- 판별자는 실제 데이터인 x로 만든 D(x)만을 참으로 여김
- 학습이 진행될수록 D(G(input))와 D(x)를 구별하기 어려움
- 정확도가 0.5에 가까워질 때, 생성자 종료
Code)
from tensorflow.keras.datasets import mnist
from tensorflow.keras.layers import Input, Dense, Reshape, Flatten, Dropout
from tensorflow.keras.layers import BatchNormalization, Activation, LeakyReLU, UpSampling2D, Conv2D
from tensorflow.keras.models import Sequential, Model
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
import matplotlib.pyplot as plt
#이미지가 저장될 폴더가 없다면 만듭니다.
import os
if not os.path.exists("./gan_images"):
os.makedirs("./gan_images")
np.random.seed(3)
tf.random.set_seed(3)
#생성자 모델을 만듭니다.
generator = Sequential()
generator.add(Dense(128*7*7, input_dim=100, activation=LeakyReLU(0.2)))
generator.add(BatchNormalization())
generator.add(Reshape((7, 7, 128)))
generator.add(UpSampling2D())
generator.add(Conv2D(64, kernel_size=5, padding='same'))
generator.add(BatchNormalization())
generator.add(Activation(LeakyReLU(0.2)))
generator.add(UpSampling2D())
generator.add(Conv2D(1, kernel_size=5, padding='same', activation='tanh'))
#판별자 모델을 만듭니다.
discriminator = Sequential()
discriminator.add(Conv2D(64, kernel_size=5, strides=2, input_shape=(28,28,1), padding="same"))
discriminator.add(Activation(LeakyReLU(0.2)))
discriminator.add(Dropout(0.3))
discriminator.add(Conv2D(128, kernel_size=5, strides=2, padding="same"))
discriminator.add(Activation(LeakyReLU(0.2)))
discriminator.add(Dropout(0.3))
discriminator.add(Flatten())
discriminator.add(Dense(1, activation='sigmoid'))
discriminator.compile(loss='binary_crossentropy', optimizer='adam')
discriminator.trainable = False
#생성자와 판별자 모델을 연결시키는 gan 모델을 만듭니다.
ginput = Input(shape=(100,))
dis_output = discriminator(generator(ginput))
gan = Model(ginput, dis_output)
gan.compile(loss='binary_crossentropy', optimizer='adam')
gan.summary()
#신경망을 실행시키는 함수를 만듭니다.
def gan_train(epoch, batch_size, saving_interval):
# MNIST 데이터 불러오기
(X_train, _), (_, _) = mnist.load_data() # 앞서 불러온 적 있는 MNIST를 다시 이용합니다. 단, 테스트과정은 필요없고 이미지만 사용할 것이기 때문에 X_train만 불러왔습니다.
X_train = X_train.reshape(X_train.shape[0], 28, 28, 1).astype('float32')
X_train = (X_train - 127.5) / 127.5 # 픽셀값은 0에서 255사이의 값입니다. 이전에 255로 나누어 줄때는 이를 0~1사이의 값으로 바꾸었던 것인데, 여기서는 127.5를 빼준 뒤 127.5로 나누어 줌으로 인해 -1에서 1사이의 값으로 바뀌게 됩니다.
#X_train.shape, Y_train.shape, X_test.shape, Y_test.shape
true = np.ones((batch_size, 1))
fake = np.zeros((batch_size, 1))
for i in range(epoch):
# 실제 데이터를 판별자에 입력하는 부분입니다.
idx = np.random.randint(0, X_train.shape[0], batch_size)
imgs = X_train[idx]
d_loss_real = discriminator.train_on_batch(imgs, true)
#가상 이미지를 판별자에 입력하는 부분입니다.
noise = np.random.normal(0, 1, (batch_size, 100))
gen_imgs = generator.predict(noise)
d_loss_fake = discriminator.train_on_batch(gen_imgs, fake)
#판별자와 생성자의 오차를 계산합니다.
d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)
g_loss = gan.train_on_batch(noise, true)
print('epoch:%d' % i, ' d_loss:%.4f' % d_loss, ' g_loss:%.4f' % g_loss)
# 이부분은 중간 과정을 이미지로 저장해 주는 부분입니다.
# 만들어진 이미지들은 gan_images 폴더에 저장됩니다.
if i % saving_interval == 0:
#r, c = 5, 5
noise = np.random.normal(0, 1, (25, 100))
gen_imgs = generator.predict(noise)
# Rescale images 0 - 1
gen_imgs = 0.5 * gen_imgs + 0.5
fig, axs = plt.subplots(5, 5)
count = 0
for j in range(5):
for k in range(5):
axs[j, k].imshow(gen_imgs[count, :, :, 0], cmap='gray')
axs[j, k].axis('off')
count += 1
fig.savefig("gan_images/gan_mnist_%d.png" % i)
gan_train(4001, 32, 200) #4000번 반복되고(+1을 해 주는 것에 주의), 배치 사이즈는 32, 200번 마다 결과가 저장되게 하였습니다.


에포크를 반복할 수록 점점 숫자에 가까운 형태가 만들어짐
'ML > 모두의 딥러닝' 카테고리의 다른 글
18장) 시퀀스 배열로 다루는 순환 신경망(RNN) (0) | 2023.07.19 |
---|---|
17장) 딥러닝을 이용한 자연어 처리 (0) | 2023.07.18 |
16장) 이미지 인식의 꽃, CNN 익히기 (0) | 2023.07.17 |
15장) 선형 회귀 적용하기 (0) | 2023.07.14 |
14장) 베스트 모델 만들기 (0) | 2023.07.13 |