본문 바로가기

AI 인공지능

인공지능 수첩 ( Unconditional Generative Model / Conditional Generative Model / Subclassing / Pix2Pix / Encoder-Decoder / U-Net / PatchGAN / 판별 모델링 / 생성 모델링 / CycleGAN / Neural Style Transfer / GAN / DCGAN )

반응형

 

Unconditional Generative Model (조건 없는 생성모델)

- 다양한 노이즈를 계속 입력으로 넣어보고, 특정 이미지가 생성되기를 기다림.

- 원하는 종류의 이미지를 바로 생성해 내지 못함.

- 생성하고자 하는 데이터에 대해 제어하기 힘듦.

- Generator와 Discriminator의 두 신경망이 minimax game을 통해 서로 경쟁하며 발전함.

- z = 임의 노이즈 / D = Discriminator / G = Generator

- D(x)는 1이 되도록, D(G(z))는 0이 되도록 해야함.


Conditional Generative Model (조건 있는 생성모델)

- 우리가 원하는 이미지를 바로바로 생성해 냄.

- 원하는 이미지를 만들기 위한 특정 조건을 줌.

- GAN에 우변의 + 를 기준으로 양쪽 항에 라벨 정보인 y가 추가됨.

- 특정 조건 y가 함께 입력되므로 z를 어떠한 이미지로 만들어야 할지에 대한 방향을 제어할 수 있음.

- 노이즈레이블 정보를 함께 입력하며, fully-connected 레이어를 연속적으로 쌓아 만듦.

- L1손실과 GAN손실을 같이 사용하면 더욱 좋은 결과를 얻을 수 있음.


Subclassing

- tensorflow.keras.Model 을 상속받아 클래스를 만듦.

- __init__() 메서드 안에서 레이어 구성을 정의함.

- 구성된 레이어를 call() 메서드에서 사용해 forward propagation을 진행함.

# GAN Generator 구성하기

from tensorflow.keras import layers, Input, Model

class GeneratorGAN(Model):

def __init__(self):

super(GeneratorGAN, self).__init__()

self.dense_1 = layers.Dense(128, activation='relu')

self.dense_2 = layers.Dense(256, activation='relu')

self.dense_3 = layers.Dense(512, activation='relu')

self.dense_4 = layers.Dense(28*28*1, activation='tanh')

self.reshape = layers.Reshape((28, 28, 1))

def call(self, noise):

out = self.dense_1(noise)

out = self.dense_2(out)

out = self.dense_3(out)

out = self.dense_4(out)

return self.reshape(out)

# GAN Discriminator 구성하기

class DiscriminatorGAN(Model):

def __init__(self):

super(DiscriminatorGAN, self).__init__()

self.flatten = layers.Flatten()

 

self.blocks = []

for f in [512, 256, 128, 1]:

self.blocks.append(

layers.Dense(f, activation=None if f==1 else "relu")

)

 

def call(self, x):

x = self.flatten(x)

for block in self.blocks:

x = block(x)

return x

---------------------------------------------------------

# cGAN Generator 구성하기

class GeneratorCGAN(Model):

def __init__(self):

super(GeneratorCGAN, self).__init__()

 

self.dense_z = layers.Dense(256, activation='relu')

self.dense_y = layers.Dense(256, activation='relu')

self.combined_dense = layers.Dense(512, activation='relu')

self.final_dense = layers.Dense(28 * 28 * 1, activation='tanh')

self.reshape = layers.Reshape((28, 28, 1))

def call(self, noise, label):

noise = self.dense_z(noise)

label = self.dense_y(label)

out = self.combined_dense(tf.concat([noise, label], axis=-1))

out = self.final_dense(out)

return self.reshape(out)

 

# cGAN Discriminator 구성하기

class Maxout(layers.Layer):

def __init__(self, units, pieces):

super(Maxout, self).__init__()

self.dense = layers.Dense(units*pieces, activation="relu")

self.dropout = layers.Dropout(.5)

self.reshape = layers.Reshape((-1, pieces, units))

 

def call(self, x):

x = self.dense(x)

x = self.dropout(x)

x = self.reshape(x)

return tf.math.reduce_max(x, axis=2)

class DiscriminatorCGAN(Model):

def __init__(self):

super(DiscriminatorCGAN, self).__init__()

self.flatten = layers.Flatten()

 

self.image_block = Maxout(240, 5)

self.label_block = Maxout(50, 5)

self.combine_block = Maxout(240, 4)

self.dense = layers.Dense(1, activation=None)

 

def call(self, image, label):

image = self.flatten(image)

image = self.image_block(image)

label = self.label_block(label)

x = layers.Concatenate()([image, label])

x = self.combine_block(x)

return self.dense(x)

--------------------------------------------------

# loss function과 optimizer 정의

from tensorflow.keras import optimizers, losses

bce = losses.BinaryCrossentropy(from_logits=True)

def generator_loss(fake_output):

return bce(tf.ones_like(fake_output), fake_output)

def discriminator_loss(real_output, fake_output):

return bce(tf.ones_like(real_output), real_output) + bce(tf.zeros_like(fake_output), fake_output)

gene_opt = optimizers.Adam(1e-4)

disc_opt = optimizers.Adam(1e-4)

-----------------------------------------------

# GAN으로 MNIST 학습

gan_generator = GeneratorGAN()

gan_discriminator = DiscriminatorGAN()

@tf.function()

def gan_step(real_images):

noise = tf.random.normal([real_images.shape[0], 100])

 

with tf.GradientTape(persistent=True) as tape:

# Generator를 이용해 가짜 이미지 생성

fake_images = gan_generator(noise)

# Discriminator를 이용해 진짜 및 가짜이미지를 각각 판별

real_out = gan_discriminator(real_images)

fake_out = gan_discriminator(fake_images)

# 각 손실(loss)을 계산

gene_loss = generator_loss(fake_out)

disc_loss = discriminator_loss(real_out, fake_out)

# gradient 계산

gene_grad = tape.gradient(gene_loss, gan_generator.trainable_variables)

disc_grad = tape.gradient(disc_loss, gan_discriminator.trainable_variables)

# 모델 학습

gene_opt.apply_gradients(zip(gene_grad, gan_generator.trainable_variables))

disc_opt.apply_gradients(zip(disc_grad, gan_discriminator.trainable_variables))

return gene_loss, disc_loss

EPOCHS = 10

for epoch in range(1, EPOCHS+1):

for i, images in enumerate(gan_datasets):

gene_loss, disc_loss = gan_step(images)

if (i+1) % 100 == 0:

print(f"[{epoch}/{EPOCHS} EPOCHS, {i+1} ITER] G:{gene_loss}, D:{disc_loss}")

import numpy as np

noise = tf.random.normal([10, 100])

output = gan_generator(noise)

output = np.squeeze(output.numpy())

plt.figure(figsize=(15,6))

for i in range(1, 11):

plt.subplot(2,5,i)

plt.imshow(output[i-1])

import os

weight_path = os.getenv('HOME')+'/aiffel/conditional_generation/gan/GAN_500'

noise = tf.random.normal([10, 100])

gan_generator = GeneratorGAN()

gan_generator.load_weights(weight_path)

output = gan_generator(noise)

output = np.squeeze(output.numpy())

plt.figure(figsize=(15,6))

for i in range(1, 11):

plt.subplot(2,5,i)

plt.imshow(output[i-1])

--------------------------------------------------

# cGAN으로 MNIST 학습하기

cgan_generator = GeneratorCGAN()

cgan_discriminator = DiscriminatorCGAN()

@tf.function()

def cgan_step(real_images, labels):

noise = tf.random.normal([real_images.shape[0], 100])

 

with tf.GradientTape(persistent=True) as tape:

fake_images = cgan_generator(noise, labels)

 

real_out = cgan_discriminator(real_images, labels)

fake_out = cgan_discriminator(fake_images, labels)

 

gene_loss = generator_loss(fake_out)

disc_loss = discriminator_loss(real_out, fake_out)

 

gene_grad = tape.gradient(gene_loss, cgan_generator.trainable_variables)

disc_grad = tape.gradient(disc_loss, cgan_discriminator.trainable_variables)

 

gene_opt.apply_gradients(zip(gene_grad, cgan_generator.trainable_variables))

disc_opt.apply_gradients(zip(disc_grad, cgan_discriminator.trainable_variables))

return gene_loss, disc_loss

EPOCHS = 1

for epoch in range(1, EPOCHS+1):

 

for i, (images, labels) in enumerate(cgan_datasets):

gene_loss, disc_loss = cgan_step(images, labels)

 

if (i+1) % 100 == 0:

print(f"[{epoch}/{EPOCHS} EPOCHS, {i} ITER] G:{gene_loss}, D:{disc_loss}")

number = 3 # 생성하길 원하는 숫자

weight_path = os.getenv('HOME')+'/aiffel/conditional_generation/cgan/CGAN_500'

noise = tf.random.normal([10, 100])

label = tf.one_hot(number, 10)

label = tf.expand_dims(label, axis=0)

label = tf.repeat(label, 10, axis=0)

generator = GeneratorCGAN()

generator.load_weights(weight_path)

output = generator(noise, label)

output = np.squeeze(output.numpy())

plt.figure(figsize=(15,6))

for i in range(1, 11):

plt.subplot(2,5,i)

plt.imshow(output[i-1])


Pix2Pix

- 이미지를 입력으로 하여 원하는 다른 형태의 이미지로 변환시킬 수 있는 모델

- 원하는 이미지를 얻기 위해 이미지를 조건으로 줌.

- Conditional Adversarial Networks로 Image-to-Image Translation을 수행함.

- 이미지의 픽셀에서 다른 이미지의 픽셀로(pixel to pixel)변환한다는 뜻에서 Pix2Pix라는 이름으로 불림.

- PatchGAN을 활용하며, 크게는 Generator와 Discriminator 두 가지 구성 요소로 이루어짐.

- 이미지를 다루는데 효율적인 convolution 레이어를 활용함.

- Encoder-Decoder구조와 U-Net 구조가 있음.

- 간단한 이미지를 입력할 경우 실제 사진처럼 보이도록 바꿔줌.

- 단순화된 이미지(Input Image)와 실제 이미지(Ground Truth)가 쌍을 이루는 데이터셋으로 학습을 진행함.

- 한 방향으로의 변환만 가능함.

 

 

 


Encoder-Decoder

- Encoder에서 입력 이미지x를 받으면 단계적으로 이미지를 down-sampling하면서 입력 이미지의 중요한 representation을 학습함.

- Decoder에서는 이를 이용해 반대로 다시 이미지를 up-sampling하여 입력 이미지와 동일한 크기의 변환된 이미지y를 생성해냄.

- Encoder의 최종 출력은 그림 중간에 위치한 가장 작은 사각형이며, bottleneck이라고도 불림.

=> 입력 이미지(x)의 가장 중요한 특징만을 담고 있음.


 

U-Net

- U-Net은 각 레이어마다 Encoder와 Decoder가 연결(skip connection)되어 있음.

- Decoder가 변환된 이미지를 더 잘 생성하도록 Encoder로부터 더 많은 추가 정보를 이용함.

- 단순한 Encoder-Decoder구조를 사용한 결과에 비해 선명한 결과를 얻을 수 있음.


 

PatchGAN

- 하나의 이미지가 Discriminator의 입력으로 들어오면, convolution 레이어를 거쳐 확률 값을 나타내는 최종 결과를 생성하는데, 그 결과는 여러 개의 값을 가짐.

- 서로 다른 영역에 대해 진짜/가짜를 나타내는 여러 개의 확률 값을 계산할 수 있으며, 이 값을 평균하여 최종 Discriminator의 출력을 생성함.

- 이미지의 일부 영역(patch)을 이용함.

- 이미지에서 거리가 먼 두 픽셀은 서로 연관성이 거의 없으므로, 특정 크기를 가진 일부 영역에 대해 세부적으로 진짜/가짜를 판별하는 것


 

판별 모델링 (Discriminative Modeling)

- 직접 데이터셋을 만들고, 각 이미지를 알맞은 카테고리로 분류할 수 있도록 학습시키는 모델

- 입력받은 데이터를 어떤 기준에 대해 판별하는 것이 목표인 모델링

- 입력된 데이터셋을 특정 기준에 따라 분류하거나, 특정 값을 맞히는 모델


생성 모델링 (Generative Modeling)

- 학습한 데이터셋과 비슷하면서도 기존에는 없던 새로운 데이터셋을 생성하는 모델

- 데이터와 모델로부터 도출할 수 있는 여러 확률 분포베이즈 이론을 이용해 데이터의 실제 분포를 간접적으로 모델링함.

생성 모델을 학습시킬 때는 두 확률 분포의 차이를 나타내는 지표인 쿨백-라이블러 발산이 사용됨.


CycleGAN

- 한 이미지와 다른 이미지를 번갈아가며 변형시킴.

- 데이터가 쌍을 이루지 않더라도, 사진 각각의 데이터셋만 있다면 학습시킬 수 있음.

- 양방향으로의 이미지 변환이 가능함. (실사 이미지를 그림으로 바꾸는 것과 그림을 실사 이미지로 바꾸는 것 모두 가능)


 

Neural Style Transfer

- 전체 이미지의 구성을 유지하고 싶은 Base Image와 입히고 싶은 스타일이 담긴 Style Image 두 장을 활용해 새로운 이미지를 만들어 냄.

- Base Image에서는 Content(내용)만, Style Image에서는 Style(스타일)만 추출해서 합침.


GAN (Generative Adversarial Network)

- GAN에는 생성자(Generator)판별자(Discriminator) 두 가지 네트워크가 있음.

- 생성자: 아무 의미 없는 랜덤 노이즈로부터 신경망 연산을 통해 이미지 형상의 벡터를 생성해냄.

- 판별자: 기존에 있던 진짜 이미지와 생성자가 만들어낸 이미지를 입력받아 각 이미지가 진짜(Real)인지, 가짜 (Fake)인지에 대한 판단 정도를 실숫값으로 출력함.

- 생성자와 판별자 서로 간의 경쟁이 둘 모두를 성장하게 하며, 결국 진짜와 구분될 수 없는 위조를 만들어 냄.

- 손실함수로 교차 엔트로피(Cross Entropy)​를 사용함.


DCGAN (Deep Convolutional GAN)

- GAN 중 특히 Convolutional Layer으로 이루어진 딥러닝 모델

- GAN을 더욱 발전시켜서 훨씬 그럴듯한 고화질 이미지 생성해냄.

반응형