오토인코더, GAN, 확산 모델
적대적 생성 신경망(GAN)
GAN은 생성자, 판별자라는 신경망 두 개로 구성된다.
- 생성자: 랜덤한 분포(일반적으로 가우스 분포)를 입력으로 받고 이미지와 같은 데이터를 출력한다. 랜덤한 입력은 생성할 이미지의 잠재 표현(코딩)으로 생각할 수 있다. 생성자는 변이형 오토인코더의 디코더와 같은 기능을 제공하여 동일한 방식으로 새로운 이미지를 생성할 수 있다. (가우스 잡음 주입하여 새로운 이미지 출력) 그러나 훈련 방식이 매우 다르다.
- 판별자: 생성자에서 얻은 가짜 이미지나 훈련 세트에서 추출한 진짜 이미지를 입력으로 받아 입력된 이미지가 진짜인지 가짜인지 구분한다.
▶ 훈련하는 동안 생성자와 판별자의 목표는 반대로, 판별자는 진짜 이미지와 가짜 이미지를 구분하고 생성자는 판별자를 속일 만큼 진짜 같은 이미지를 만든다. GAN은 다른 목표를 가진 두 개의 네트워크로 구성되기 때문에 일반적인 신경망처럼 훈련할 수 없다.
각 훈련 반복은 두 단계로 이루어진다.
- 먼저 판별자를 훈련한다. 훈련 세트에서 실제 이미지 배치를 샘플링하고 생성자에서 생성한 동일한 수의 가짜 이미지를 합친다. 가짜 이미지의 레이블은 0으로, 진짜 이미지는 1로 설정한다. 판별자는 이진 크로스 엔트로피를 사용해 한 스텝 동안 이렇게 레이블된 배치로 훈련된다. 이 단계에서 역전파는 판별자의 가중치만 최적화한다.
- 생성자를 훈련한다. 먼저 생성자를 사용해 다른 가짜 이미지 배치를 만들고, 다시 판별자를 사용해 이미지의 진위 여부를 판별한다. 이번에는 배치에 진짜 이미지를 추가하지 않고 레이블을 모두 1(진짜)로 설정한다. 이 단계 동안에는 판별자의 가중치를 동결하는 것이 중요하므로, 역전파는 생성자의 가중치에만 영향을 미친다.
◆ 패션 MNIST 데이터셋으로 간단한 GAN 생성하기
- 생성자와 판별자를 만든다.
생성자는 오토인코더의 디코더와 비슷하고, 판별자는 일반적인 이진 분류기이다. 각 훈련 반복의 두 번째 단계에서 생성자와 판별자가 연결된 전체 GAN 모델이 필요하다.
tf.random.set_seed(42)
codings_size = 30
Dense = tf.keras.layers.Dense
generator = tf.keras.Sequential([
Dense(100, activation='relu', kernel_initializer='he_normal', input_shape=(codings_size,)),
Dense(150, activation='relu', kernel_initializer='he_normal'),
Dense(28 *28, activation='sigmoid'),
tf.keras.layers.Reshape([28, 28])
])
discriminator = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=[28, 28]),
Dense(150, activation='relu', kernel_initializer='he_normal'),
Dense(100, activation='relu', kernel_initializer='he_normal'),
Dense(1, activation='sigmoid')
])
gan = tf.keras.Sequential([generator, discriminator])
- 이 모델을 컴파일한다.
판별자는 이진 분류기이므로 자연스럽게 이진 크로스엔트로피 손실을 사용하고, gan 모델도 이진 분류기이므로 이진 크로스 엔트로피 손실을 사용한다. 그러나 생성자는 gan 모델을 통해서만 훈련되기 때문에 따로 컴파일할 필요가 없다. 따라서 gan 모델을 컴파일하기 전에 판별자가 훈련되지 않도록 설정해야 한다.
discriminator.compile(loss='binary_crossentropy', optimizer='rmsprop')
discriminator.trainable = False
gan.compile(loss='binary_crossentropy', optimizer='rmsprop')
- 훈련 (사용자 정의 훈련 반복문)
훈련이 일반적인 반복이 아니기 때문에 fit() 메서드를 사용할 수 없어 대신 사용할 사용자 정의 훈련 반복문을 만든다. 이를 위해 먼저 이미지를 순회하는 Dataset을 만든다.
batch_size = 32
dataset = tf.data.Dataset.from_tensor_slices(X_train).shuffle(buffer_size=1000)
dataset = dataset.batch(batch_size, drop_remainder=True).prefetch(1)
- 훈련 반복을 train_gan() 함수로 감싼다.
def train_gan(gan, dataset, batch_size, codings_size, n_epochs):
generator, discriminator = gan.layers
for epoch in range(n_epochs):
for X_batch in dataset:
# 단계 1 - 판별자 훈련
noise = tf.random.normal(shape=[batch_size, codings_size])
generated_images = generator(noise)
X_fake_and_real = tf.concat([generated_images, X_batch], axis=0)
y1 = tf.constant([[0.]] * batch_size + [[1.]] * batch_size)
discriminator.train_on_batch(X_fake_and_real, y1)
# 단계 2 - 생성자 훈련
noise = tf.random.normal(shape=[batch_size, codings_size])
y2 = tf.constant([[1.]] * batch_size)
gan.train_on_batch(noise, y2)
train_gan(gan, dataset, batch_size, codings_size, n_epochs=5) # 메모리 부족을 피하기 위해 50 > 5
훈련이 끝난 후에 가우스 분포에서 랜덤하게 코딩을 샘플링하여 생성자에 주입하면 새로운 이미지를 얻을 수 있고, 생성된 이미지를 출력하면 첫 번째 에포크가 끝난 시점에서 이미 잡음이 많기는 하나, 패션 MNIST 이미지처럼 보이기 시작한다.
(해당 코드를 실행하면 시간이 꽤 오래 걸리므로, GPU 사용을 할 수 있는 코랩으로 변경하여 수행하였다.)
※ 주피터노트북 파일(.ipynb) 코랩에서 여는 방법.
켜져 있는 주피터노트북을 저장 및 종료한 뒤,
코랩을 들어간 다음, 파일 > 노트 업로드 > 업로드 > 해당 파일 클릭하면 됨.
※ 코랩에서 GPU를 사용하려면, 런타임 > 런타임 유형 변경 에서 GPU를 선택하면 된다.
참고로, (에포크를 5로 낮췄음에도 불구하고) 해당 코드는 코랩에서 GPU를 사용해서 수행해도 오랜 시간이 걸린다
GAN 훈련의 어려움
1. 내시 균형 (Nash Equilibrium)
내시 균형은 게임 이론에서 각 플레이어가 자신의 최선의 전략을 선택했을 때 어떤 플레이어도 전략을 변경할 동기가 없는 상태를 의미한다. GAN에서는 생성자 (Generator)와 판별자 (Discriminator)가 일종의 게임을 하고 있다.
- 생성자: 가능한 한 실제 데이터를 잘 흉내내는 샘플을 생성하려고 한다.
- 판별자: 생성된 샘플이 가짜인지 진짜인지 구분하려고 한다.
생성자와 판별자가 동시에 최적화되며 내시 균형점에 도달해야 하나, 이 균형 상태를 찾는 것이 매우 어려울 수 있다. 양쪽 네트워크가 균형을 이루지 못하면 다음과 같은 문제가 발생할 수 있다:
- 판별자가 너무 강할 때: 생성자는 판별자를 속일 수 없으므로 학습이 제대로 되지 않는다.
- 생성자가 너무 강할 때: 판별자는 거의 모든 샘플을 진짜로 분류하여 유의미한 피드백을 생성자에게 전달하지 못한다.
2. 모드 붕괴 (Mode Collapse)
모드 붕괴는 생성자가 다양한 출력을 생성하지 못하고 특정 몇 가지 패턴만 반복해서 생성하는 문제이다. 이는 아래와 같은 문제를 초래합니다:
- 생성자가 훈련 데이터의 모든 분포를 학습하지 못하고 일부 모드(특정 패턴이나 유형)만 학습하게 된다.
- 생성자가 다양한 샘플을 생성하지 못함으로써 원래 데이터 분포를 제대로 반영하지 못한다.
모드 붕괴를 방지하기 위해 다양한 기술이 제안되고 있지만 여전히 완벽한 해결책은 없다.
3. 경험 재생 (Experience Replay)
경험 재생은 원래 강화 학습에서 사용되는 기법으로, 이전의 경험을 저장해 두었다가 나중에 다시 사용하는 방법이다. GAN에서도 이를 응용할 수 있지만, 여러 도전 과제가 있다
- 판별자와 생성자의 공동 학습: 두 네트워크가 동시에 학습하다 보니 시간에 따라 학습 데이터의 분포가 변화한다. 판별자가 실제 데이터를 더 잘 구분하게 되는데, 이는 경험 재생을 통해 가짜 데이터를 다시 학습시키면 효과가 떨어지기도 한다.
- 메모리 리소스: 많은 학습 데이터를 저장하기 위해 필요한 메모리가 매우 클 수 있다.
결과적으로 GAN의 훈련은 근본적으로 구조적 상호작용 때문에 어려운 점이 많다. 위에서 설명드린 요소들을 고려하여 훈련 과정을 설계할 필요가 있으며, 이를 통해 보다 효율적인 결과를 얻을 수 있다.
4. 미니배치 판별 (Mini-batch Discrimination)
미니배치 판별(Mini-batch Discrimination)은 GAN 훈련에서 발생할 수 있는 모드 붕괴(Mode Collapse)를 완화하기 위한 기술 중 하나이다. 이 방법은 생성자가 보다 다양한 샘플을 생성하도록 돕는 역할을 한다.
미니배치 판별은 생성자가 모드 붕괴를 방지하고 다양한 데이터를 생성하도록 돕기 위해 판별자가 개별 샘플 대신 미니배치(batch) 단위로 샘플의 다양성을 평가하는 기법이다. 이 기법은 다음과 같은 방식으로 작동한다:
- 미니배치의 개념: 한 번에 하나의 샘플이 아닌 여러 샘플(미니배치)을 판별기 입력으로 사용하여 평가한다.
- 특성 간 거리 계산: 미니배치 내의 샘플들은 고유한 특성 벡터(Feature Vector)를 가진다. 판별자는 각 샘플 간의 거리를 계산하여 샘플들이 얼마나 서로 다른지 평가한다.
- 다양성 측정: 미니배치 내 샘플 간의 거리가 멀면 멀수록(즉, 샘플들이 서로 더 다르면) 판별자는 그 미니배치가 다양한 데이터를 포함하고 있다고 판단한다.
심층 합성곱 GAN(DCGAN)
심층 합성곱 생성적 적대 신경망(Deep Convolutional Generative Adversarial Network, DCGAN)은 GAN의 한 형태로, 합성곱 신경망(Convolutional Neural Networks, CNN)을 사용하여 더 안정적이고 효율적인 이미지 생성을 목표로 한다.
- DCGAN의 주요 구성 요소
DCGAN은 기본적으로 두 가지 주요 구성 요소(생성자와 판별자)로 이루어져 있다. 이 두 네트워크는 모두 합성곱 계층을 사용하여 이미지를 생성하고 판별한다.
- 생성자(Generator)
- 랜덤 노이즈 벡터를 입력으로 받아 점차적으로 해상도가 높은 이미지를 생성한다.
- 전치 합성곱 층(Transposed Convolutions, 흔히 Deconvolutions라고도 함)이 사용되어 공간 해상도를 업샘플링하고 이미지의 크기를 점차 증가시킨다.
- 배치 정규화(Batch Normalization)와 활성화 함수(ReLU 및 Tanh)를 사용하여 학습이 더 안정적이도록 한다.
- 판별자(Discriminator)
- 이미지(실제 이미지 및 생성된 이미지)를 입력으로 받아 이미지가 실제인지 가짜인지를 판별한다.
- 합성곱 층을 통해 입력 이미지를 점차적으로 다운샘플링 한다.
- 배치 정규화와 LeakyReLU 활성화 함수를 사용하여 학습이 더 원활히 진행되도록 한다.
- 안정적인 합성곱 GAN을 구축하기 위해 제안한 주요 가이드
- 판별자에 있는 풀링 층을 스트라이드 합성곱으로 바꾸고 생성자에 있는 풀링 층은 전치 합성곱으로 바꾼다.
- 생성자와 판별자에 배치 정규화를 사용한다. 생성자의 출력 층과 판별자의 입력 층은 제외한다.
- 층을 깊게 쌓기 위해 완전 연결 은닉 층을 제거한다.
- tanh 함수를 사용해야 하는 출력 층을 제외하고 생성자의 모든 층은 ReLU 활성화 함수를 사용한다.
- 판별자의 모든 층은 LeakyReLU 활성화 함수를 사용한다.
▶ 이 가이드라인은 항상 맞는 것은 아니므로, 여전히 여러 가지 하아퍼파라마티로 실험해봐야 한다.
아래 코드는 패션 MNIST에서 잘 작동하는 작은 DCGAN 모델이다.
tf.random.set_seed(42)
codings_size = 100
layers = tf.keras.layers
generator = tf.keras.Sequential([
layers.Dense(7 * 7 * 128), input_shape=(codings_size,)),
layers.Reshape([7, 7, 128]),
layers.BatchNormalization(),
layers.Conv2DTranspose(64, kernel_size=5, strides=2,
padding='same', activation='relu'),
layers.BatchhNormalization(),
layers.Conv2DTranspose(1, kernel_size=5, strides=2,
padding='same', activation='tanh'),
])
discriminator = tf.keras.Sequential([
layers.Conv2D(64, kernel_size=5, strides=2, padding='same',
activation=layers.LeakyReLU(0.2)),
layers.Dropout(0.4),
layers.Conv2D(128, kernel_size=5, strides=2, padding='same',
activation=layers.LeakyReLU(0.2)),
layers.Dropout(0.4),
layers.Flatten(),
layers.Dense(1, activation='sigmoid')
])
gan = tf.keras.Sequential([generator, discriminator])
[코드 설명]
생성자는 크기가 100인 코딩을 받아 7*7*128 차원(6,272)으로 투영하고 이 결과를 7*7*128 크기의 텐서로 바꾼다.
이 텐서는 배치 정규화를 거쳐 스트라이드가 2인 전치 합성곱 층에 주입된다. (7*7에서 14*14로 업샘플링 되고 깊이는 128에서 64로 감소한다)
이 결과는 다시 배치 정규화 층을 지나서 스트라이드가 2인 다른 전치 합성곱 층에 주입된다. (여기서는 14*14에서 28*28로 업샘플링되고 깊이는 64에서 1로 감소한다) 이 층은 tanh 활성화 함수를 사용하므로 출력 범위 -1에서 1사이 이다.
따라서 GAN을 훈련하기 전에 훈련 세트를 동일한 범위로 스케일을 조정하고, 크기를 바꾸고 채널 차원을 추가해야 한다.
X_train_dcgan = X_train.reshape(-1, 28, 28, 1) * 2. - 1. # 크기 변경 및 스케일 조정
마지막으로 데이터셋을 만들고 모델을 컴파일 및 훈련하기 위한 코드를 사용한다.
batch_size = 32
dataset = tf.data.Dataset.from_tensor_slices(X_train_dcgan)
dataset = dataset.shuffle(1000)
dataset = dataset.batch(batch_size, drop_remainder=True).prefetch(1)
# 메모리 부족 에러를 피하기 위해 n_epochs를 50에서 10으로 바꿈.
train_gan(gan, dataset, batch_size, codings_size, n_epochs=10)
훈련 에포크 후에 생성자는 아래와 같은 이미지를 생성한다.
하지만 DCGAN은 완벽하지 않은데, 예를 들어 DCGAN으로 매우 큰 이미지를 생성하면 국부적으로는 특징이 구분되지만 전반적으로는 일관성 없는 이미지를 얻을 가능성이 높다.
ProGAN과 StyleGAN
Pro GAN과 Style GAN은 GAN(Generative Adversarial Networks)의 발전된 형태로, 특히 고해상도 이미지 생성을 목표로 설계된 네트워크들이다.
1. Progressive Growing of GANs (Pro GAN)
Pro GAN은 Karras et al.이 제안한 아키텍처로, 점진적 생성 과정을 통해 고해상도 이미지를 생성하는 기법이다. 이 방식은 GAN이 고해상도 이미지를 더 안정적으로 학습할 수 있도록 도와준다.
- 주요 특징
- 점진적 해상도 증가: 훈련 초기에 저해상도 이미지(예: 4x4)로 시작하여, 점점 더 높은 해상도로 증가시킨다. 이 과정에서 새로운 계층이 점차적으로 추가된다.
- 미니배치 표준 편차 층: 판별자의 마지막 층 근처에 추가한다. 입력에 있는 모든 위치에 대해 모든 채널과 배치의 모든 샘플에 걸쳐 표준 편차를 계산한다.
- 동일한 학습 속도: He 초기화 대신 평균이 0이고 표준 편차가 1인 가우스 분포를 사용해 모든 가중치를 초기화한다.
- 픽셀별 정규화 층: 생성자의 합성곱 층 뒤에 추가한다. 이 층은 동일한 이미지의 동일 위치에 있는 모든 활성화를 채널에 대해 정규화를 수행한다.
- 학습 안정성 개선: 생성 및 판별 네트워크의 복잡도가 점차 증가하기 때문에, 초기 학습이 더 안정적으로 이루어진다.
- 고해상도 이미지 생성: 이 방법을 통해 매우 높은 해상도의 이미지를 성공적으로 생성할 수 있다(예: 1024x1024).
- Pro GAN 아키텍처의 동작 방식
- 저해상도에서 시작: 첫 단계에서는 저해상도 이미지를 생성하고 판별한다(예: 4x4).
- 해상도 증가: 훈련 과정에서 해상도를 증가시키는 계층을 추가한다. 예를 들어, 8x8, 16x16, 32x32 등의 해상도로 점차 늘려간다.
- 페이딩(Fading): 네트워크가 새 해상도에 적응하도록, 기존 네트워크와 새 계층의 출력을 혼합하여 사용한다. 새로운 해상도로 완전히 전환되면 섞은 단계를 끝내고 새 계층만 남긴다.
2. Style GAN
Style GAN은 Pro GAN의 발전된 형태로, 스타일 변환 기법을 도입하여 더 다양한 고해상도 이미지를 생성할 수 있는 모델이다. Karras et al.이 제안한 이 모델은 특히 이미지 생성 과정에서 스타일 효과를 더 디테일하게 조절할 수 있다는 점에서 주목받고 있다.
- 주요 특징
- 스타일 매핑 네트워크: 이 네트워크는 입력된 잠재 벡터를 공간 내의 스타일 벡터로 매핑한다. 이 스타일 벡터는 생성 네트워크의 각 계층에 전달되어, 다양한 스타일 속성을 제어할 수 있다.
- AdaIN (Adaptive Instance Normalization, 적응적 인스턴스 정규화): 스타일 벡터는 AdaIN을 통해 각 계층의 활성화를 조절한다. 이 기법을 통해 다양한 스타일을 효과적으로 적용할 수 있다.
- 복합적 스타일 제어: 여러 스타일을 혼합하여 다양한 이미지 속성을 세밀하게 제어할 수 있으며, 한 이미지 내에서 다른 해상도 수준에서 서로 다른 스타일을 부여할 수 있다.
- Style GAN 아키텍처의 동작 방식
- 스타일 매핑 (Style Mapping): 기본적인 잠재 공간 벡터를 새로운 스타일 벡터인 (\mathbf{w})로 변환한다.
- 스타일 모듈 (Style Module): 생성 네트워크의 여러 계층에 스타일 벡터 (\mathbf{w})를 적용한다. AdaIN을 사용하여 계층의 특성을 조절한다.
- 노이즈 적용: 랜덤 노이즈를 추가하여 더 세밀한 디테일을 추가한다.
- 합성 네트워크 (Synthesis Network): 최종 출력을 생성하기 위해 여러 계층에서 스타일 벡터를 사용하며, 이미지 생성을 책임진다. 이 네트워크는 일정하게 학습된 입력을 받는다.
- 스타일 믹싱(Style Mixing): 일정 비율의 이미지를 두 개의 다른 코딩으로 생성한다.
3.ProGAN - StyleGAN 비교
- Pro GAN: 점진적인 학습을 통해 고해상도 이미지 생성을 더 안정화시켰다.
- Style GAN: 스타일 매핑과 Adaptive Instance Normalization을 통해 생성된 이미지의 세밀한 스타일 제어를 가능하게 했다.
둘 다 고해상도 이미지 생성에서 탁월한 성능을 보이며, Style GAN은 특히 더 다양한 스타일과 디테일을 추가하는 데 강점을 지닌다.
다음 내용
[출처]
핸즈 온 머신러닝
'[파이썬 Projects] > <파이썬 딥러닝, 신경망>' 카테고리의 다른 글
[딥러닝] 강화 학습(Reinforcement Learning) - 1 (3) | 2024.12.04 |
---|---|
[딥러닝] 비지도 학습: 확산 모델 (3) | 2024.12.04 |
[딥러닝] 비지도 학습: 오토인코더 (1) | 2024.12.03 |
[딥러닝] 비지도 학습: 오토인코더, GAN, 확산 모델 (0) | 2024.12.03 |
[딥러닝] RNN을 사용한 자연어 처리 (1) | 2024.12.02 |