13. 생성모델¶
13.1 생성 모델이란¶
생성 모델(generative model)은 주어진 데이터를 학습하여 데이터 분포를 따르는 유사한 데이터를 생성하는 모델
13.1.1 생성 모델 개념¶
기존 합성곱 신경망에서 다룬 이미지 분류, 이미지 검출 등은 input image x가 있을 때 그에 대한 정답 y를 찾는 것이였다. 이와 같이 이미지를 분류하는 것을 '판별(자) 모델(discriminator model)'이라 한다.
판별자 모델에서 추출한 특성들의 조합을 이용해 새로운 이미지를 생성할 수 있는데 이것을 '생성(자) 모델(generative model)'이라고 한다.
즉, 생성 모델은 input image에 대한 데이터 분포 p(x)를 학습해 새로운 이미지(새로운 이미지이면서 기존 이미지에서 특성을 추출했기 때문에 최대한 입력 이미지와 유사한 이미지)를 생성하는 것을 목표로 한다.
13.1.2 생성 모델의 유형¶
생성모델의 유형에는 모델의 확률 변수를 구하는 '변형 오토인코더 모델'과 확률 변수를 이용하지 않는 'GAN 모델'이 존재
변형 오토인코더는 확률 변수 p(x)를 정의해 사용하며 이미지의 잠재 공간(latent space)에서 샘플링하여 완전히 새로운 이미지나 기존 이미지를 변형하는 방식으로 학습을 진행
GAN은 생성자와 판별자가 서로 경쟁하면서 가짜 이미지를 진짜 이미지와 최대한 비슷하게 만들도록 학습을 진행
13.2 변형 오토인코더¶
변형 오토인코더는 오토인코더의 확장장
13.2.1 오토인코더란¶
- 오토인코더는 입력을 출력으로 복사하는 신경망으로 은닉층(혹은 병목층)의 노드 수가 입력 값보다 적은 것이 특징
- 오토인코더의 병목층은 입력과 출력의 뉴런보다 훨씬 적다. 즉, 적은 수의 병목층 뉴런으로 데이터를 가장 잘 표현할 수 있는 방법
오토인코더의 네 가지 주요 부분
- 인코더: 인지 네트워크(recognition network)라고도 하며, 특성에 대한 학습을 수행하는 부분
- 병목층(은닉층): 모델의 뉴런 개수가 최소인 계층. 차원이 가장 낮은 입력 데이터의 압축 표현이 포함
- 디코더: 생성 네트워크(generative network)라고도 하며, 병목층에서 압축된 데이터를 원래대로 재구성(recontruction)하는 역할
- 손실 재구성: 오토인코더는 입력층과 출력층의 뉴런 개수가 동일하다는 것만 제외하면 일반적인 다층 퍼셉트론(Multi-Layer Perceptron, MLP)과 구조가 동일. 오토인코더는 압축된 입력을 출력층에서 재구성하며, 손실 함수는 입력과 출력의 차이를 가지고 계산
오토인코더가 중요한 이유
- 데이터 압축: 메모리 측면에서 상당한 장점인데 오토인코더를 이용하여 이미지나 음성 파일의 중요 특성만 압축하면 용량도 작고 품질도 더 좋아진다.
- 차원의 저주(curse of dimensionality) 예방: 차원의 저주 문제를 예방할 수 있다. 오토인코더는 특성 개수를 줄여 주기 때문에 데이터 차원이 감소하여 차원의 저주를 피할 수 있다.
- 특성 추출: 오토인코더는 비지도 학습으로 자동으로 중요한 특성을 찾는다.
오토인코더 예제¶
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
import matplotlib.pylab as plt
import torchvision.datasets as datasets
import torchvision.transforms as transforms
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device
device(type='cuda')
transform = transforms.Compose([transforms.ToTensor()]) # image to tensor
train_dataset = datasets.MNIST( # mnist train dataset
root="/content/drive/MyDrive/deep_learning_pytorch_book/deep learning pytorch book/13장/data", train=True, transform=transform, download=True)
test_dataset = datasets.MNIST( # mnist test dataset
root="/content/drive/MyDrive/deep_learning_pytorch_book/deep learning pytorch book/13장/data", train=False, transform=transform, download=True)
train_loader = DataLoader(
train_dataset, batch_size=128, shuffle=True, num_workers=4, pin_memory=False) # pin_memory = True일 경우 GPU에 미리 train dataset을 불러와 학습시키기 때문에 학습 속도가 향상된다.
test_loader = DataLoader(
test_dataset, batch_size=32, shuffle=False, num_workers=4)
class Encoder(nn.Module): # encoder class
def __init__(self, encoded_space_dim,fc2_input_dim):
super().__init__()
self.encoder_cnn = nn.Sequential(
nn.Conv2d(1, 8, 3, stride=2, padding=1),
nn.ReLU(True),
nn.Conv2d(8, 16, 3, stride=2, padding=1),
nn.BatchNorm2d(16),
nn.ReLU(True),
nn.Conv2d(16, 32, 3, stride=2, padding=0),
nn.ReLU(True)
)
self.flatten = nn.Flatten(start_dim=1)
self.encoder_lin = nn.Sequential(
nn.Linear(3 * 3 * 32, 128),
nn.ReLU(True),
nn.Linear(128, encoded_space_dim)
)
def forward(self, x):
x = self.encoder_cnn(x)
x = self.flatten(x)
x = self.encoder_lin(x)
return x
class Decoder(nn.Module): # decoder class
def __init__(self, encoded_space_dim,fc2_input_dim):
super().__init__()
self.decoder_lin = nn.Sequential(
nn.Linear(encoded_space_dim, 128),
nn.ReLU(True),
nn.Linear(128, 3 * 3 * 32),
nn.ReLU(True)
)
self.unflatten = nn.Unflatten(dim=1,
unflattened_size=(32, 3, 3))
self.decoder_conv = nn.Sequential(
nn.ConvTranspose2d(32, 16, 3,
stride=2, output_padding=0),
nn.BatchNorm2d(16),
nn.ReLU(True),
nn.ConvTranspose2d(16, 8, 3, stride=2,
padding=1, output_padding=1),
nn.BatchNorm2d(8),
nn.ReLU(True),
nn.ConvTranspose2d(8, 1, 3, stride=2,
padding=1, output_padding=1)
)
def forward(self, x):
x = self.decoder_lin(x)
x = self.unflatten(x)
x = self.decoder_conv(x)
x = torch.sigmoid(x)
return x
encoder = Encoder(encoded_space_dim=4,fc2_input_dim=128)
decoder = Decoder(encoded_space_dim=4,fc2_input_dim=128)
encoder.to(device)
decoder.to(device)
params_to_optimize = [
{'params': encoder.parameters()}, # encoder, decoder parameter를 따로 지정
{'params': decoder.parameters()}
]
optim = torch.optim.Adam(params_to_optimize, lr=0.001, weight_decay=1e-05)
loss_fn = torch.nn.MSELoss()
def train_epoch(encoder, decoder, device, dataloader, loss_fn, optimizer,noise_factor=0.3):
encoder.train() # encoder train
decoder.train() # decoder train
train_loss = []
for image_batch, _ in dataloader: # data의 label은 사용 x
image_noisy = add_noise(image_batch,noise_factor)
image_noisy = image_noisy.to(device)
encoded_data = encoder(image_noisy) # image_noisy를 encoder에 적용
decoded_data = decoder(encoded_data) # encoder에서 나온 값을 decoder에 적용해 새로운 image 생성
loss = loss_fn(decoded_data, image_noisy) # 생성된 이미지와 image_noisy의 오차 게산
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss.append(loss.detach().cpu().numpy())
return np.mean(train_loss)
def test_epoch(encoder, decoder, device, dataloader, loss_fn,noise_factor=0.3):
encoder.eval()
decoder.eval()
with torch.no_grad():
conc_out = [] # 각 배치에 대한 출력을 저장하기 위해 리스트 형식의 변수 정의
conc_label = []
for image_batch, _ in dataloader:
image_batch = image_batch.to(device)
encoded_data = encoder(image_batch)
decoded_data = decoder(encoded_data)
conc_out.append(decoded_data.cpu())
conc_label.append(image_batch.cpu())
conc_out = torch.cat(conc_out) # 리스트 형식으로 저장된 모든 값을 하나의 텐서로 생성
conc_label = torch.cat(conc_label)
val_loss = loss_fn(conc_out, conc_label) # 손실 함수를 이용해 오차 계산
return val_loss.data
def add_noise(inputs,noise_factor=0.3): # original image에 noise 추가 & 값을 0 ~ 1 사이로 clip
noisy = inputs+torch.randn_like(inputs) * noise_factor
noisy = torch.clip(noisy,0.,1.)
return noisy
from matplotlib import font_manager # 한글 깨짐 방지. colab version x
font_fname = 'C:/Windows/Fonts/malgun.ttf'
font_family = font_manager.FontProperties(fname=font_fname).get_name()
plt.rcParams["font.family"] = font_family
def plot_ae_outputs(encoder,decoder,n=5,noise_factor=0.3):
plt.figure(figsize=(10,4.5))
for i in range(n):
ax = plt.subplot(3,n,i+1)
img = test_dataset[i][0].unsqueeze(0)
image_noisy = add_noise(img,noise_factor)
image_noisy = image_noisy.to(device)
encoder.eval()
decoder.eval()
with torch.no_grad():
rec_img = decoder(encoder(image_noisy))
plt.imshow(img.cpu().squeeze().numpy(), cmap='gist_gray')
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
if i == n//2:
ax.set_title('original image')
ax = plt.subplot(3, n, i + 1 + n)
plt.imshow(image_noisy.cpu().squeeze().numpy(), cmap='gist_gray')
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
if i == n//2:
ax.set_title('iamge with noise')
ax = plt.subplot(3, n, i + 1 + n + n)
plt.imshow(rec_img.cpu().squeeze().numpy(), cmap='gist_gray')
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
if i == n//2:
ax.set_title('generative image')
plt.subplots_adjust(left=0.1, # subplots_adjust는 subplot들이 겹치지 않도록 최소한의 여백을 만들어줌
bottom=0.1,
right=0.7,
top=0.9,
wspace=0.3,
hspace=0.3)
plt.show()
import numpy as np
num_epochs = 30
history_da={'train_loss':[],'val_loss':[]}
loss_fn = torch.nn.MSELoss()
for epoch in range(num_epochs):
train_loss=train_epoch(
encoder=encoder,
decoder=decoder,
device=device,
dataloader=train_loader,
loss_fn=loss_fn,
optimizer=optim, noise_factor=0.3)
val_loss = test_epoch(
encoder=encoder,
decoder=decoder,
device=device,
dataloader=test_loader,
loss_fn=loss_fn, noise_factor=0.3)
history_da['train_loss'].append(train_loss)
history_da['val_loss'].append(val_loss)
print('\n EPOCH {}/{} \t train loss {:.3f} \t val loss {:.3f}'.format(epoch + 1, num_epochs,train_loss,val_loss))
plot_ae_outputs(encoder,decoder,noise_factor=0.3)
Output hidden; open in https://colab.research.google.com to view.
13.2.2 변형 오토인코더(variational autoencoder)¶
오토인코더는 차원을 줄이는 것이 목표이기 때문에 새롭게 생성된 데이터의 확률 분포에는 관심이 없다. 하지만 변형 오토인코더는 표준편차와 평균을 이용해 확률 분포를 만들고, 거기에서 샘플링해 디코더를 통과시킨 후 새로운 데이터를 만들어 낸다.
즉, 변형 오토인코더는 입력 데이터와 조금 다른 출력 데이터를 만들어 내는데, 이때 z라는 가우시안 분포를 이용(z를 잠재 백터(latent vector)라 함). 중요한 특성의 parameter를 담고 있는 z 분포에서 벡터를 랜덤하게 샘플링하고 이 분포의 오차를 이용해 입력 데이터와 유사한 다양한 데이터를 만들어 내는 것이 변형 오토인코더
오토인코더는 데이터 벡터에 대한 차원을 축소하여 실제 이미지와 동일한 이미지를 출력하는 것이 목적이었다면, 변형 오토인코더는 데이터가 만들어지는 확률 분포를 찾아 비슷한 데이터를 생성하는 것이 목적
학습은 backpropagation을 이용해 L의 값이 높아지는 방향으로 기울기를 업데이트하는데, 즉 likelihood가 증가하는 방향으로 파라미터 Φ, θ를 업데이트한다.
!pip install tensorboardX
# tensorboardX는 학습 과정을 시각적으로 확인하고자 할 때 사용
Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/ Collecting tensorboardX Downloading tensorboardX-2.5.1-py2.py3-none-any.whl (125 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 125.4/125.4 KB 6.8 MB/s eta 0:00:00 Requirement already satisfied: protobuf<=3.20.1,>=3.8.0 in /usr/local/lib/python3.8/dist-packages (from tensorboardX) (3.19.6) Requirement already satisfied: numpy in /usr/local/lib/python3.8/dist-packages (from tensorboardX) (1.21.6) Installing collected packages: tensorboardX Successfully installed tensorboardX-2.5.1
import datetime
import os
from tensorboardX import SummaryWriter
import torch
import torchvision
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
import matplotlib.pylab as plt
import torchvision.datasets as datasets
import torchvision.transforms as transforms
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device
device(type='cuda')
transform = transforms.Compose([transforms.ToTensor()])
train_dataset = datasets.MNIST(
root="/content/drive/MyDrive/deep_learning_pytorch_book/deep learning pytorch book/13장/data", train=True, transform=transform, download=True)
test_dataset = datasets.MNIST(
root="/content/drive/MyDrive/deep_learning_pytorch_book/deep learning pytorch book/13장/data", train=False, transform=transform, download=True)
train_loader = DataLoader(
train_dataset, batch_size=100, shuffle=True, num_workers=4, pin_memory=False)
test_loader = DataLoader(
test_dataset, batch_size=100, shuffle=False, num_workers=4)
/usr/local/lib/python3.8/dist-packages/torch/utils/data/dataloader.py:554: UserWarning: This DataLoader will create 4 worker processes in total. Our suggested max number of worker in current system is 2, which is smaller than what this DataLoader is going to create. Please be aware that excessive worker creation might get DataLoader running slow or even freeze, lower the worker number to avoid potential slowness/freeze if necessary. warnings.warn(_create_warning_msg(
class Encoder(nn.Module): # 데이터 x가 주어졌을 때 디코더가 원래 데이터로 잘 복원할 수 있는 이상적인 확률 분포 p(z|x)를 찾는 것이 목표
def __init__(self, input_dim, hidden_dim, latent_dim):
super(Encoder, self).__init__()
self.input1 = nn.Linear(input_dim, hidden_dim)
self.input2 = nn.Linear(hidden_dim, hidden_dim)
self.mean = nn.Linear(hidden_dim, latent_dim)
self.var = nn.Linear (hidden_dim, latent_dim)
self.LeakyReLU = nn.LeakyReLU(0.2)
self.training = True
def forward(self, x):
h_ = self.LeakyReLU(self.input1(x))
h_ = self.LeakyReLU(self.input2(h_))
mean = self.mean(h_)
log_var = self.var(h_)
return mean, log_var # encoder network에서 평균과 분산을 return
class Decoder(nn.Module): # 추출한 샘플을 입력으로 받아 다시 원본으로 재구축하는 역할을 수행
def __init__(self, latent_dim, hidden_dim, output_dim):
super(Decoder, self).__init__()
self.hidden1 = nn.Linear(latent_dim, hidden_dim)
self.hidden2 = nn.Linear(hidden_dim, hidden_dim)
self.output = nn.Linear(hidden_dim, output_dim)
self.LeakyReLU = nn.LeakyReLU(0.2)
def forward(self, x):
h = self.LeakyReLU(self.hidden1(x))
h = self.LeakyReLU(self.hidden2(h))
x_hat = torch.sigmoid(self.output(h)) # sigmoid를 거치기 때문에 x_hat은 0 ~ 1 사이의 값을 갖는다.
return x_hat
class Model(nn.Module):
def __init__(self, Encoder, Decoder):
super(Model, self).__init__()
self.Encoder = Encoder
self.Decoder = Decoder
def reparameterization(self, mean, var): # z vector를 샘플링하기 위한 함수, z는 가우시안 분포라고 가정했기 때문에 encoder에서 받은 평균과 표준편차를 이용해 z를 생성
epsilon = torch.randn_like(var).to(device)
z = mean + var*epsilon
return z
def forward(self, x):
mean, log_var = self.Encoder(x)
z = self.reparameterization(mean, torch.exp(0.5 * log_var))
x_hat = self.Decoder(z)
return x_hat, mean, log_var
x_dim = 784
hidden_dim = 400
latent_dim = 200
epochs = 30
batch_size = 100
encoder = Encoder(input_dim=x_dim, hidden_dim=hidden_dim, latent_dim=latent_dim)
decoder = Decoder(latent_dim=latent_dim, hidden_dim = hidden_dim, output_dim = x_dim)
model = Model(Encoder=encoder, Decoder=decoder).to(device)
def loss_function(x, x_hat, mean, log_var): # 변분추론으로 p(z|x)와 q(z) 사이의 쿨백-라이블러 발산(KLD)을 계산
reproduction_loss = nn.functional.binary_cross_entropy(x_hat, x, reduction='sum')
KLD = - 0.5 * torch.sum(1+ log_var - mean.pow(2) - log_var.exp())
return reproduction_loss, KLD
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
saved_loc = 'scalar/' # tensorboard에서 사용할 경로
writer = SummaryWriter(saved_loc)
model.train()
def train(epoch, model, train_loader, optimizer):
train_loss = 0
for batch_idx, (x, _) in enumerate(train_loader):
x = x.view(batch_size, x_dim)
x = x.to(device)
optimizer.zero_grad()
x_hat, mean, log_var = model(x)
BCE, KLD = loss_function(x, x_hat, mean, log_var)
loss = BCE + KLD
# tensorboard에 주요 측정 항목의 결과를 출력할 때 사용하는 함수가 add_scalar
# 첫 번째 parameter는 tag로 어떤 값을 기록할지에 대한 구분자로 그래프 제목
# 두 번째 parameter는 확인하고자 하는 값으로 그래프 y축에 해당
# 세 번째 parameter는 그래프 x축을 의미
writer.add_scalar("Train/Reconstruction Error", BCE.item(), batch_idx + epoch * (len(train_loader.dataset)/batch_size) )
writer.add_scalar("Train/KL-Divergence", KLD.item(), batch_idx + epoch * (len(train_loader.dataset)/batch_size) )
writer.add_scalar("Train/Total Loss" , loss.item(), batch_idx + epoch * (len(train_loader.dataset)/batch_size) )
train_loss += loss.item()
loss.backward()
optimizer.step()
if batch_idx % 100 == 0:
print('Train Epoch: {} [{}/{} ({:.0f}%)]\t Loss: {:.6f}'.format(
epoch, batch_idx * len(x), len(train_loader.dataset),
100. * batch_idx / len(train_loader),
loss.item() / len(x)))
print("======> Epoch: {} Average loss: {:.4f}".format(
epoch, train_loss / len(train_loader.dataset)))
def test(epoch, model, test_loader):
model.eval()
test_loss = 0
with torch.no_grad():
for batch_idx, (x, _) in enumerate(test_loader):
x = x.view(batch_size, x_dim)
x = x.to(device)
x_hat, mean, log_var = model(x)
BCE, KLD = loss_function(x, x_hat, mean, log_var)
loss = BCE + KLD
# test dataset에 대해서도 loss를 log에 저장
writer.add_scalar("Test/Reconstruction Error", BCE.item(), batch_idx + epoch * (len(test_loader.dataset)/batch_size) )
writer.add_scalar("Test/KL-Divergence", KLD.item(), batch_idx + epoch * (len(test_loader.dataset)/batch_size) )
writer.add_scalar("Test/Total Loss" , loss.item(), batch_idx + epoch * (len(test_loader.dataset)/batch_size) )
test_loss += loss.item()
if batch_idx == 0:
n = min(x.size(0), 8)
comparison = torch.cat([x[:n], x_hat.view(batch_size, x_dim)[:n]])
grid = torchvision.utils.make_grid(comparison.cpu())
writer.add_image("Test image - Above: Real data, below: reconstruction data", grid, epoch)
from tqdm.auto import tqdm
for epoch in tqdm(range(0, epochs)):
train(epoch, model, train_loader, optimizer)
test(epoch, model, test_loader)
print("\n")
writer.close() # close를 하지 않으면 loss 값이 저장되지 않는다.
0%| | 0/30 [00:00<?, ?it/s]
Train Epoch: 0 [0/60000 (0%)] Loss: 544.537656 Train Epoch: 0 [10000/60000 (17%)] Loss: 190.182871 Train Epoch: 0 [20000/60000 (33%)] Loss: 180.157637 Train Epoch: 0 [30000/60000 (50%)] Loss: 158.603066 Train Epoch: 0 [40000/60000 (67%)] Loss: 155.330898 Train Epoch: 0 [50000/60000 (83%)] Loss: 151.759043 ======> Epoch: 0 Average loss: 173.8391 Train Epoch: 1 [0/60000 (0%)] Loss: 138.110645 Train Epoch: 1 [10000/60000 (17%)] Loss: 135.611035 Train Epoch: 1 [20000/60000 (33%)] Loss: 132.408105 Train Epoch: 1 [30000/60000 (50%)] Loss: 126.979238 Train Epoch: 1 [40000/60000 (67%)] Loss: 129.650957 Train Epoch: 1 [50000/60000 (83%)] Loss: 125.553311 ======> Epoch: 1 Average loss: 128.9631 Train Epoch: 2 [0/60000 (0%)] Loss: 120.913398 Train Epoch: 2 [10000/60000 (17%)] Loss: 119.039092 Train Epoch: 2 [20000/60000 (33%)] Loss: 116.582383 Train Epoch: 2 [30000/60000 (50%)] Loss: 117.202568 Train Epoch: 2 [40000/60000 (67%)] Loss: 107.897197 Train Epoch: 2 [50000/60000 (83%)] Loss: 118.597539 ======> Epoch: 2 Average loss: 117.1255 Train Epoch: 3 [0/60000 (0%)] Loss: 113.717031 Train Epoch: 3 [10000/60000 (17%)] Loss: 114.700615 Train Epoch: 3 [20000/60000 (33%)] Loss: 111.574512 Train Epoch: 3 [30000/60000 (50%)] Loss: 118.784863 Train Epoch: 3 [40000/60000 (67%)] Loss: 113.443779 Train Epoch: 3 [50000/60000 (83%)] Loss: 116.037607 ======> Epoch: 3 Average loss: 113.2442 Train Epoch: 4 [0/60000 (0%)] Loss: 112.188555 Train Epoch: 4 [10000/60000 (17%)] Loss: 112.550918 Train Epoch: 4 [20000/60000 (33%)] Loss: 112.769326 Train Epoch: 4 [30000/60000 (50%)] Loss: 111.140605 Train Epoch: 4 [40000/60000 (67%)] Loss: 109.773564 Train Epoch: 4 [50000/60000 (83%)] Loss: 110.510937 ======> Epoch: 4 Average loss: 110.1732 Train Epoch: 5 [0/60000 (0%)] Loss: 109.846514 Train Epoch: 5 [10000/60000 (17%)] Loss: 106.050537 Train Epoch: 5 [20000/60000 (33%)] Loss: 107.689990 Train Epoch: 5 [30000/60000 (50%)] Loss: 106.740830 Train Epoch: 5 [40000/60000 (67%)] Loss: 110.121113 Train Epoch: 5 [50000/60000 (83%)] Loss: 109.342314 ======> Epoch: 5 Average loss: 108.2614 Train Epoch: 6 [0/60000 (0%)] Loss: 107.407773 Train Epoch: 6 [10000/60000 (17%)] Loss: 102.529990 Train Epoch: 6 [20000/60000 (33%)] Loss: 105.759844 Train Epoch: 6 [30000/60000 (50%)] Loss: 106.383887 Train Epoch: 6 [40000/60000 (67%)] Loss: 107.190732 Train Epoch: 6 [50000/60000 (83%)] Loss: 104.868232 ======> Epoch: 6 Average loss: 107.0933 Train Epoch: 7 [0/60000 (0%)] Loss: 105.953066 Train Epoch: 7 [10000/60000 (17%)] Loss: 104.909785 Train Epoch: 7 [20000/60000 (33%)] Loss: 107.827002 Train Epoch: 7 [30000/60000 (50%)] Loss: 101.640234 Train Epoch: 7 [40000/60000 (67%)] Loss: 106.692578 Train Epoch: 7 [50000/60000 (83%)] Loss: 106.376230 ======> Epoch: 7 Average loss: 106.1553 Train Epoch: 8 [0/60000 (0%)] Loss: 105.961562 Train Epoch: 8 [10000/60000 (17%)] Loss: 105.487451 Train Epoch: 8 [20000/60000 (33%)] Loss: 107.798799 Train Epoch: 8 [30000/60000 (50%)] Loss: 108.522139 Train Epoch: 8 [40000/60000 (67%)] Loss: 105.996377 Train Epoch: 8 [50000/60000 (83%)] Loss: 108.597998 ======> Epoch: 8 Average loss: 105.4670 Train Epoch: 9 [0/60000 (0%)] Loss: 103.179580 Train Epoch: 9 [10000/60000 (17%)] Loss: 104.647793 Train Epoch: 9 [20000/60000 (33%)] Loss: 111.026025 Train Epoch: 9 [30000/60000 (50%)] Loss: 102.803320 Train Epoch: 9 [40000/60000 (67%)] Loss: 108.175078 Train Epoch: 9 [50000/60000 (83%)] Loss: 105.696172 ======> Epoch: 9 Average loss: 104.9323 Train Epoch: 10 [0/60000 (0%)] Loss: 112.144561 Train Epoch: 10 [10000/60000 (17%)] Loss: 106.368193 Train Epoch: 10 [20000/60000 (33%)] Loss: 108.646758 Train Epoch: 10 [30000/60000 (50%)] Loss: 103.212568 Train Epoch: 10 [40000/60000 (67%)] Loss: 105.399805 Train Epoch: 10 [50000/60000 (83%)] Loss: 107.668037 ======> Epoch: 10 Average loss: 104.3479 Train Epoch: 11 [0/60000 (0%)] Loss: 105.569150 Train Epoch: 11 [10000/60000 (17%)] Loss: 105.102314 Train Epoch: 11 [20000/60000 (33%)] Loss: 105.984170 Train Epoch: 11 [30000/60000 (50%)] Loss: 103.380215 Train Epoch: 11 [40000/60000 (67%)] Loss: 102.058281 Train Epoch: 11 [50000/60000 (83%)] Loss: 102.898174 ======> Epoch: 11 Average loss: 103.9439 Train Epoch: 12 [0/60000 (0%)] Loss: 101.243496 Train Epoch: 12 [10000/60000 (17%)] Loss: 101.192813 Train Epoch: 12 [20000/60000 (33%)] Loss: 107.487275 Train Epoch: 12 [30000/60000 (50%)] Loss: 104.657148 Train Epoch: 12 [40000/60000 (67%)] Loss: 103.619219 Train Epoch: 12 [50000/60000 (83%)] Loss: 99.455664 ======> Epoch: 12 Average loss: 103.5433 Train Epoch: 13 [0/60000 (0%)] Loss: 99.807988 Train Epoch: 13 [10000/60000 (17%)] Loss: 99.422549 Train Epoch: 13 [20000/60000 (33%)] Loss: 102.127734 Train Epoch: 13 [30000/60000 (50%)] Loss: 101.630654 Train Epoch: 13 [40000/60000 (67%)] Loss: 104.807686 Train Epoch: 13 [50000/60000 (83%)] Loss: 105.987422 ======> Epoch: 13 Average loss: 103.1795 Train Epoch: 14 [0/60000 (0%)] Loss: 104.273926 Train Epoch: 14 [10000/60000 (17%)] Loss: 100.939023 Train Epoch: 14 [20000/60000 (33%)] Loss: 100.226221 Train Epoch: 14 [30000/60000 (50%)] Loss: 101.301211 Train Epoch: 14 [40000/60000 (67%)] Loss: 103.158867 Train Epoch: 14 [50000/60000 (83%)] Loss: 99.778281 ======> Epoch: 14 Average loss: 102.8011 Train Epoch: 15 [0/60000 (0%)] Loss: 99.790820 Train Epoch: 15 [10000/60000 (17%)] Loss: 99.110977 Train Epoch: 15 [20000/60000 (33%)] Loss: 102.017529 Train Epoch: 15 [30000/60000 (50%)] Loss: 103.266738 Train Epoch: 15 [40000/60000 (67%)] Loss: 99.977402 Train Epoch: 15 [50000/60000 (83%)] Loss: 101.743838 ======> Epoch: 15 Average loss: 102.5100 Train Epoch: 16 [0/60000 (0%)] Loss: 104.467207 Train Epoch: 16 [10000/60000 (17%)] Loss: 104.957793 Train Epoch: 16 [20000/60000 (33%)] Loss: 98.702861 Train Epoch: 16 [30000/60000 (50%)] Loss: 100.608086 Train Epoch: 16 [40000/60000 (67%)] Loss: 103.535977 Train Epoch: 16 [50000/60000 (83%)] Loss: 95.841504 ======> Epoch: 16 Average loss: 102.2404 Train Epoch: 17 [0/60000 (0%)] Loss: 98.688867 Train Epoch: 17 [10000/60000 (17%)] Loss: 104.643984 Train Epoch: 17 [20000/60000 (33%)] Loss: 104.386133 Train Epoch: 17 [30000/60000 (50%)] Loss: 102.690625 Train Epoch: 17 [40000/60000 (67%)] Loss: 101.449238 Train Epoch: 17 [50000/60000 (83%)] Loss: 103.108447 ======> Epoch: 17 Average loss: 102.0103 Train Epoch: 18 [0/60000 (0%)] Loss: 102.028936 Train Epoch: 18 [10000/60000 (17%)] Loss: 97.913799 Train Epoch: 18 [20000/60000 (33%)] Loss: 98.429551 Train Epoch: 18 [30000/60000 (50%)] Loss: 101.847578 Train Epoch: 18 [40000/60000 (67%)] Loss: 100.705889 Train Epoch: 18 [50000/60000 (83%)] Loss: 102.582432 ======> Epoch: 18 Average loss: 101.8116 Train Epoch: 19 [0/60000 (0%)] Loss: 100.149072 Train Epoch: 19 [10000/60000 (17%)] Loss: 101.126016 Train Epoch: 19 [20000/60000 (33%)] Loss: 103.698516 Train Epoch: 19 [30000/60000 (50%)] Loss: 107.523057 Train Epoch: 19 [40000/60000 (67%)] Loss: 101.705967 Train Epoch: 19 [50000/60000 (83%)] Loss: 101.478340 ======> Epoch: 19 Average loss: 101.5871 Train Epoch: 20 [0/60000 (0%)] Loss: 106.349521 Train Epoch: 20 [10000/60000 (17%)] Loss: 97.959316 Train Epoch: 20 [20000/60000 (33%)] Loss: 99.977500 Train Epoch: 20 [30000/60000 (50%)] Loss: 106.995879 Train Epoch: 20 [40000/60000 (67%)] Loss: 103.514375 Train Epoch: 20 [50000/60000 (83%)] Loss: 98.176465 ======> Epoch: 20 Average loss: 101.4303 Train Epoch: 21 [0/60000 (0%)] Loss: 97.706143 Train Epoch: 21 [10000/60000 (17%)] Loss: 102.700449 Train Epoch: 21 [20000/60000 (33%)] Loss: 102.006572 Train Epoch: 21 [30000/60000 (50%)] Loss: 98.587891 Train Epoch: 21 [40000/60000 (67%)] Loss: 101.706328 Train Epoch: 21 [50000/60000 (83%)] Loss: 101.301133 ======> Epoch: 21 Average loss: 101.2766 Train Epoch: 22 [0/60000 (0%)] Loss: 101.133516 Train Epoch: 22 [10000/60000 (17%)] Loss: 95.686934 Train Epoch: 22 [20000/60000 (33%)] Loss: 103.842383 Train Epoch: 22 [30000/60000 (50%)] Loss: 99.829551 Train Epoch: 22 [40000/60000 (67%)] Loss: 104.678301 Train Epoch: 22 [50000/60000 (83%)] Loss: 102.039531 ======> Epoch: 22 Average loss: 101.1270 Train Epoch: 23 [0/60000 (0%)] Loss: 99.184053 Train Epoch: 23 [10000/60000 (17%)] Loss: 101.183145 Train Epoch: 23 [20000/60000 (33%)] Loss: 97.917607 Train Epoch: 23 [30000/60000 (50%)] Loss: 100.442383 Train Epoch: 23 [40000/60000 (67%)] Loss: 96.948516 Train Epoch: 23 [50000/60000 (83%)] Loss: 101.452061 ======> Epoch: 23 Average loss: 100.9848 Train Epoch: 24 [0/60000 (0%)] Loss: 100.648438 Train Epoch: 24 [10000/60000 (17%)] Loss: 100.094521 Train Epoch: 24 [20000/60000 (33%)] Loss: 106.357363 Train Epoch: 24 [30000/60000 (50%)] Loss: 99.551328 Train Epoch: 24 [40000/60000 (67%)] Loss: 106.692432 Train Epoch: 24 [50000/60000 (83%)] Loss: 99.728916 ======> Epoch: 24 Average loss: 100.8677 Train Epoch: 25 [0/60000 (0%)] Loss: 103.130508 Train Epoch: 25 [10000/60000 (17%)] Loss: 102.915723 Train Epoch: 25 [20000/60000 (33%)] Loss: 100.347910 Train Epoch: 25 [30000/60000 (50%)] Loss: 104.037715 Train Epoch: 25 [40000/60000 (67%)] Loss: 101.637393 Train Epoch: 25 [50000/60000 (83%)] Loss: 100.649287 ======> Epoch: 25 Average loss: 100.7052 Train Epoch: 26 [0/60000 (0%)] Loss: 100.205098 Train Epoch: 26 [10000/60000 (17%)] Loss: 102.856914 Train Epoch: 26 [20000/60000 (33%)] Loss: 105.518652 Train Epoch: 26 [30000/60000 (50%)] Loss: 102.477754 Train Epoch: 26 [40000/60000 (67%)] Loss: 103.736006 Train Epoch: 26 [50000/60000 (83%)] Loss: 97.502842 ======> Epoch: 26 Average loss: 100.6276 Train Epoch: 27 [0/60000 (0%)] Loss: 101.625039 Train Epoch: 27 [10000/60000 (17%)] Loss: 97.826123 Train Epoch: 27 [20000/60000 (33%)] Loss: 93.148711 Train Epoch: 27 [30000/60000 (50%)] Loss: 99.472930 Train Epoch: 27 [40000/60000 (67%)] Loss: 104.249277 Train Epoch: 27 [50000/60000 (83%)] Loss: 101.920234 ======> Epoch: 27 Average loss: 100.4991 Train Epoch: 28 [0/60000 (0%)] Loss: 104.199424 Train Epoch: 28 [10000/60000 (17%)] Loss: 103.389521 Train Epoch: 28 [20000/60000 (33%)] Loss: 98.610176 Train Epoch: 28 [30000/60000 (50%)] Loss: 99.213203 Train Epoch: 28 [40000/60000 (67%)] Loss: 103.012998 Train Epoch: 28 [50000/60000 (83%)] Loss: 100.017441 ======> Epoch: 28 Average loss: 100.4038 Train Epoch: 29 [0/60000 (0%)] Loss: 98.956094 Train Epoch: 29 [10000/60000 (17%)] Loss: 96.868320 Train Epoch: 29 [20000/60000 (33%)] Loss: 98.289580 Train Epoch: 29 [30000/60000 (50%)] Loss: 103.034043 Train Epoch: 29 [40000/60000 (67%)] Loss: 101.750078 Train Epoch: 29 [50000/60000 (83%)] Loss: 101.579453 ======> Epoch: 29 Average loss: 100.3396
%load_ext tensorboard
# %는 매직 커맨드를 사용할 수 있도록 하는데 이는 터미널 명령어를 jupyter notebook에서 사용할 수 있도록 한다.
%tensorboard --logdir scalar --port=6013
# tensorboard에서 log를 보여준다.
# --logdir: data가 저장된 위치
# --port; 웹 브라우저에서 tensorboard를 확인할 때 사용하는 포트 번호
Output hidden; open in https://colab.research.google.com to view.
13.3 적대적 생성 신경망(GAN)이란¶
- 적대적 생성 신경망(Generative Adversarial Network, GAN)을 제안한 이안 굿펠로우(Ian Goodfellow)는 GAN을 경찰과 위조지폐범 사이의 게임에 비유했다.
- 위조지폐범은 진짜와 같은 위조 화폐를 만들어 경찰을 속이고, 경찰은 진짜 화폐와 위조화폐를 판별하여 위조지폐범을 검거합니다.
- 위조지폐범과 경찰의 경쟁이 지속되면 어느 순간 위조지폐범은 진짜와 같은 위조지폐범을 만들 수 있게 되고, 결국 경찰은 위조지폐와 실제 화폐를 구분할 수 없는 상태에 이르게 된다.
- 생성 모델은 최대한 진짜와 비슷한 데이터를 생성하려는 생성자와 진짜와 가짜를 구별하는 판별자가 각각 존재하여 서로 적대적으로 학습
- 판별자는 실제 이미지를 받아 진짜로 분류하도록 학습을 하고 생성자가 많든 모조 이미지를 입력해 가짜로 분류하도록 학습
- 반복하다보면 생성자는 진짜 이미지에 완벽히 가까울 정도의 유사한 모조 이미지를 만들고, 이에 따라 판별자는 실제 이미지와 모조 이미지를 구분할 수 없게 된다. 즉, 서로 경쟁적으로 발전시키는 구조
13.3.1 GAN의 동작 원리¶
- 생성자 G는 판별자 D를 속이려고 원래 이미지와 최대한 비슷한 이미지를 만들도록 학습
- 판별자 D는 원래 이미지와 생성자 G가 만든 이미지를 잘 구분하도록 학습
- D는 이미지 x가 주어졌을 때 판별자 D의 출력에 해당하는 D(x)가 진짜 이미지일 확률을 반환
- G는 진짜와 같은 모조 이미지를 노이즈 데이터를 사용해 만들어 냄
- GAN의 loss funciton에서 D는 loss를 최대가 되도록 parameter를 update, G는 loss를 최소가 되도록 parameter를 update
- D의 parameter를 update할 때는 G의 parameter는 고정, G의 parameter를 update할 때는 D의 parameter를 고정해 학습을 진행
13.3.2 GAN 구현하기¶
import imageio # image data를 읽고 쓸 수 있는 쉬운 인터페이스를 제공하는 라이브러리
from tqdm import tqdm
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
import matplotlib
import matplotlib.pylab as plt
from torchvision.utils import make_grid, save_image
import torchvision.datasets as datasets
import torchvision.transforms as transforms
matplotlib.style.use('ggplot') # stylesheet를 ggplot으로 설정하면 background가 격자무늬로 설정된다.
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device
device(type='cuda')
batch_size = 512
epochs = 200
sample_size = 64 # 생성자에 제공할 고정 크기의 노이즈 벡터에 대한 크기
nz = 128 # 잠재 벡터의 크기를 의미. 잠재 벡터의 크기는 생성자의 입력 크기와 동일해야 한다.
k = 1 # 판별자에 적용할 스텝 수를 의미. 스텝 수를 1로 지정한 이유는 훈련 비용을 최소화하기 위해
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5,),(0.5,)),
])
train_dataset = datasets.MNIST(
root="/content/drive/MyDrive/deep_learning_pytorch_book/deep learning pytorch book/13장/data", train=True, transform=transform, download=True)
train_loader = DataLoader(
train_dataset, batch_size=batch_size, shuffle=True, num_workers=4)
class Generator(nn.Module):
def __init__(self, nz):
super(Generator, self).__init__()
self.nz = nz
self.main = nn.Sequential(
nn.Linear(self.nz, 256),
nn.LeakyReLU(0.2),
nn.Linear(256, 512),
nn.LeakyReLU(0.2),
nn.Linear(512, 1024),
nn.LeakyReLU(0.2),
nn.Linear(1024, 784),
nn.Tanh(),
)
def forward(self, x):
return self.main(x).view(-1, 1, 28, 28) # 생성자 네트워크의 반환값은 'batch_size, 1, 28, 28'
class Discriminator(nn.Module):
def __init__(self):
super(Discriminator, self).__init__()
self.n_input = 784
self.main = nn.Sequential(
nn.Linear(self.n_input, 1024),
nn.LeakyReLU(0.2),
nn.Dropout(0.3),
nn.Linear(1024, 512),
nn.LeakyReLU(0.2),
nn.Dropout(0.3),
nn.Linear(512, 256),
nn.LeakyReLU(0.2),
nn.Dropout(0.3),
nn.Linear(256, 1),
nn.Sigmoid(),
)
def forward(self, x):
x = x.view(-1, 784)
return self.main(x) # 이미지가 진짜인지 가짜인지를 분류하는 값
generator = Generator(nz).to(device)
discriminator = Discriminator().to(device)
print(generator)
print(discriminator)
Generator( (main): Sequential( (0): Linear(in_features=128, out_features=256, bias=True) (1): LeakyReLU(negative_slope=0.2) (2): Linear(in_features=256, out_features=512, bias=True) (3): LeakyReLU(negative_slope=0.2) (4): Linear(in_features=512, out_features=1024, bias=True) (5): LeakyReLU(negative_slope=0.2) (6): Linear(in_features=1024, out_features=784, bias=True) (7): Tanh() ) ) Discriminator( (main): Sequential( (0): Linear(in_features=784, out_features=1024, bias=True) (1): LeakyReLU(negative_slope=0.2) (2): Dropout(p=0.3, inplace=False) (3): Linear(in_features=1024, out_features=512, bias=True) (4): LeakyReLU(negative_slope=0.2) (5): Dropout(p=0.3, inplace=False) (6): Linear(in_features=512, out_features=256, bias=True) (7): LeakyReLU(negative_slope=0.2) (8): Dropout(p=0.3, inplace=False) (9): Linear(in_features=256, out_features=1, bias=True) (10): Sigmoid() ) )
# generator와 discriminator의 optimizer는 따로 정의해야 한다.
optim_g = optim.Adam(generator.parameters(), lr=0.0002)
optim_d = optim.Adam(discriminator.parameters(), lr=0.0002)
criterion = nn.BCELoss()
losses_g = []
losses_d = []
images = []
def save_generator_image(image, path):
save_image(image, path)
def train_discriminator(optimizer, data_real, data_fake):
b_size = data_real.size(0) # batch 크기 정보 얻기
real_label = torch.ones(b_size, 1).to(device)
fake_label = torch.zeros(b_size, 1).to(device)
optimizer.zero_grad()
output_real = discriminator(data_real) # real data에 대한 discriminator의 판별 결과
loss_real = criterion(output_real, real_label)
output_fake = discriminator(data_fake) # fake data에 대한 discriminator의 판별 결과
loss_fake = criterion(output_fake, fake_label)
loss_real.backward()
loss_fake.backward()
optimizer.step()
return loss_real + loss_fake
def train_generator(optimizer, data_fake):
b_size = data_fake.size(0)
real_label = torch.ones(b_size, 1).to(device)
optimizer.zero_grad()
output = discriminator(data_fake)
loss = criterion(output, real_label)
loss.backward()
optimizer.step()
return loss
generator.train()
discriminator.train()
for epoch in range(epochs):
loss_g = 0.0
loss_d = 0.0
for idx, data in tqdm(enumerate(train_loader), total=int(len(train_dataset)/train_loader.batch_size)):
image, _ = data
image = image.to(device)
b_size = len(image)
for step in range(k): # step 수에 맞춰 학습 진행
data_fake = generator(torch.randn(b_size, nz).to(device)).detach() # generator가 새로운 image를 만들기 위해서는 noise data가 필요하기 때문에 randn을 통해 생성
data_real = image
loss_d += train_discriminator(optim_d, data_real, data_fake)
data_fake = generator(torch.randn(b_size, nz).to(device))
loss_g += train_generator(optim_g, data_fake)
generated_img = generator(torch.randn(b_size, nz).to(device)).cpu().detach()
generated_img = make_grid(generated_img) # 생성된 이미지를 그리드 형태로 표현
save_generator_image(generated_img, f"/content/drive/MyDrive/deep_learning_pytorch_book/deep learning pytorch book/13장/data/gen_img{epoch}.png")
images.append(generated_img)
epoch_loss_g = loss_g / idx # epoch에 대한 총 generator loss
epoch_loss_d = loss_d / idx # epoch에 대한 총 discriminator loss
losses_g.append(epoch_loss_g)
losses_d.append(epoch_loss_d)
print(f"Epoch {epoch} of {epochs}")
print(f"Generator loss: {epoch_loss_g:.8f}, Discriminator loss: {epoch_loss_d:.8f}")
118it [00:10, 11.11it/s]
Epoch 0 of 200 Generator loss: 1.40528142, Discriminator loss: 1.08623302
118it [00:10, 10.87it/s]
Epoch 1 of 200 Generator loss: 3.60054708, Discriminator loss: 0.76324338
118it [00:12, 9.76it/s]
Epoch 2 of 200 Generator loss: 3.13213038, Discriminator loss: 0.99347991
118it [00:10, 11.09it/s]
Epoch 3 of 200 Generator loss: 2.46181798, Discriminator loss: 0.96229964
118it [00:10, 11.07it/s]
Epoch 4 of 200 Generator loss: 1.96802509, Discriminator loss: 1.18371904
118it [00:11, 10.59it/s]
Epoch 5 of 200 Generator loss: 1.41291094, Discriminator loss: 1.10638332
118it [00:12, 9.76it/s]
Epoch 6 of 200 Generator loss: 1.80611491, Discriminator loss: 1.06526840
118it [00:10, 11.27it/s]
Epoch 7 of 200 Generator loss: 2.42672944, Discriminator loss: 1.01680863
118it [00:10, 11.18it/s]
Epoch 8 of 200 Generator loss: 1.60827863, Discriminator loss: 1.09687352
118it [00:10, 11.12it/s]
Epoch 9 of 200 Generator loss: 1.37234855, Discriminator loss: 1.04695129
118it [00:10, 11.26it/s]
Epoch 10 of 200 Generator loss: 1.34442055, Discriminator loss: 1.10864902
118it [00:10, 11.35it/s]
Epoch 11 of 200 Generator loss: 1.40253603, Discriminator loss: 1.30892384
118it [00:10, 10.85it/s]
Epoch 12 of 200 Generator loss: 1.49706459, Discriminator loss: 0.98984951
118it [00:10, 11.38it/s]
Epoch 13 of 200 Generator loss: 1.42974555, Discriminator loss: 1.11239266
118it [00:10, 11.32it/s]
Epoch 14 of 200 Generator loss: 1.50825131, Discriminator loss: 0.88190150
118it [00:10, 11.36it/s]
Epoch 15 of 200 Generator loss: 2.03075051, Discriminator loss: 1.27066386
118it [00:14, 8.38it/s]
Epoch 16 of 200 Generator loss: 1.58900559, Discriminator loss: 0.91025376
118it [00:12, 9.76it/s]
Epoch 17 of 200 Generator loss: 3.84450293, Discriminator loss: 1.25609851
118it [00:12, 9.22it/s]
Epoch 18 of 200 Generator loss: 2.13393450, Discriminator loss: 0.80376202
118it [00:11, 10.01it/s]
Epoch 19 of 200 Generator loss: 2.49538994, Discriminator loss: 0.82441795
118it [00:12, 9.42it/s]
Epoch 20 of 200 Generator loss: 2.30032802, Discriminator loss: 0.79384750
118it [00:10, 11.11it/s]
Epoch 21 of 200 Generator loss: 2.02973723, Discriminator loss: 0.72468203
118it [00:10, 10.86it/s]
Epoch 22 of 200 Generator loss: 2.25538969, Discriminator loss: 0.84459788
118it [00:12, 9.57it/s]
Epoch 23 of 200 Generator loss: 1.95227361, Discriminator loss: 0.81288713
118it [00:12, 9.45it/s]
Epoch 24 of 200 Generator loss: 2.01967144, Discriminator loss: 0.81481498
118it [00:10, 10.98it/s]
Epoch 25 of 200 Generator loss: 2.04493737, Discriminator loss: 0.73089886
118it [00:12, 9.65it/s]
Epoch 26 of 200 Generator loss: 2.33261943, Discriminator loss: 0.52037609
118it [00:10, 11.15it/s]
Epoch 27 of 200 Generator loss: 2.86389446, Discriminator loss: 0.54487431
118it [00:10, 11.17it/s]
Epoch 28 of 200 Generator loss: 2.60056829, Discriminator loss: 0.59966314
118it [00:10, 11.25it/s]
Epoch 29 of 200 Generator loss: 2.57114077, Discriminator loss: 0.77724707
118it [00:10, 11.23it/s]
Epoch 30 of 200 Generator loss: 2.30522704, Discriminator loss: 0.59729707
118it [00:10, 11.17it/s]
Epoch 31 of 200 Generator loss: 3.02717113, Discriminator loss: 0.66856194
118it [00:10, 11.10it/s]
Epoch 32 of 200 Generator loss: 2.48466349, Discriminator loss: 0.55437911
118it [00:10, 11.25it/s]
Epoch 33 of 200 Generator loss: 2.29503965, Discriminator loss: 0.59522289
118it [00:10, 11.21it/s]
Epoch 34 of 200 Generator loss: 2.47692132, Discriminator loss: 0.53213531
118it [00:10, 11.24it/s]
Epoch 35 of 200 Generator loss: 2.42191291, Discriminator loss: 0.59363371
118it [00:10, 11.05it/s]
Epoch 36 of 200 Generator loss: 2.88277793, Discriminator loss: 0.47679979
118it [00:10, 11.08it/s]
Epoch 37 of 200 Generator loss: 2.58440757, Discriminator loss: 0.62076229
118it [00:10, 10.93it/s]
Epoch 38 of 200 Generator loss: 2.57086682, Discriminator loss: 0.55338478
118it [00:10, 10.83it/s]
Epoch 39 of 200 Generator loss: 2.70754766, Discriminator loss: 0.58150166
118it [00:10, 11.13it/s]
Epoch 40 of 200 Generator loss: 2.54097486, Discriminator loss: 0.58736169
118it [00:10, 11.15it/s]
Epoch 41 of 200 Generator loss: 2.46001554, Discriminator loss: 0.65745699
118it [00:10, 11.08it/s]
Epoch 42 of 200 Generator loss: 2.78504658, Discriminator loss: 0.52498609
118it [00:10, 10.96it/s]
Epoch 43 of 200 Generator loss: 3.20861006, Discriminator loss: 0.43251893
118it [00:10, 11.00it/s]
Epoch 44 of 200 Generator loss: 2.88919067, Discriminator loss: 0.58307922
118it [00:10, 11.41it/s]
Epoch 45 of 200 Generator loss: 2.82962251, Discriminator loss: 0.48182660
118it [00:10, 11.28it/s]
Epoch 46 of 200 Generator loss: 2.84572315, Discriminator loss: 0.47346431
118it [00:12, 9.57it/s]
Epoch 47 of 200 Generator loss: 2.79516506, Discriminator loss: 0.51394665
118it [00:10, 11.05it/s]
Epoch 48 of 200 Generator loss: 2.83875489, Discriminator loss: 0.54665279
118it [00:10, 11.19it/s]
Epoch 49 of 200 Generator loss: 3.06894946, Discriminator loss: 0.67160344
118it [00:10, 11.28it/s]
Epoch 50 of 200 Generator loss: 3.00349498, Discriminator loss: 0.51968420
118it [00:10, 11.48it/s]
Epoch 51 of 200 Generator loss: 3.10888863, Discriminator loss: 0.53833401
118it [00:10, 11.26it/s]
Epoch 52 of 200 Generator loss: 2.92989445, Discriminator loss: 0.55603176
118it [00:10, 11.17it/s]
Epoch 53 of 200 Generator loss: 3.17987561, Discriminator loss: 0.43682569
118it [00:12, 9.31it/s]
Epoch 54 of 200 Generator loss: 3.09826684, Discriminator loss: 0.48965669
118it [00:10, 11.17it/s]
Epoch 55 of 200 Generator loss: 2.92726660, Discriminator loss: 0.53815722
118it [00:10, 11.17it/s]
Epoch 56 of 200 Generator loss: 2.84686518, Discriminator loss: 0.52033180
118it [00:10, 11.29it/s]
Epoch 57 of 200 Generator loss: 2.95557117, Discriminator loss: 0.50571185
118it [00:10, 11.30it/s]
Epoch 58 of 200 Generator loss: 3.19326043, Discriminator loss: 0.50151944
118it [00:10, 11.08it/s]
Epoch 59 of 200 Generator loss: 2.82097840, Discriminator loss: 0.54927397
118it [00:10, 10.93it/s]
Epoch 60 of 200 Generator loss: 2.59805512, Discriminator loss: 0.56739861
118it [00:10, 11.15it/s]
Epoch 61 of 200 Generator loss: 2.85696864, Discriminator loss: 0.55226201
118it [00:10, 11.28it/s]
Epoch 62 of 200 Generator loss: 2.68389034, Discriminator loss: 0.61122763
118it [00:10, 11.32it/s]
Epoch 63 of 200 Generator loss: 2.68388319, Discriminator loss: 0.61505461
118it [00:11, 10.65it/s]
Epoch 64 of 200 Generator loss: 2.41056919, Discriminator loss: 0.61390167
118it [00:11, 10.09it/s]
Epoch 65 of 200 Generator loss: 2.61752057, Discriminator loss: 0.57465488
118it [00:10, 11.00it/s]
Epoch 66 of 200 Generator loss: 2.69355130, Discriminator loss: 0.56732911
118it [00:12, 9.75it/s]
Epoch 67 of 200 Generator loss: 2.57339406, Discriminator loss: 0.57771057
118it [00:10, 11.28it/s]
Epoch 68 of 200 Generator loss: 2.56719398, Discriminator loss: 0.59448344
118it [00:10, 11.11it/s]
Epoch 69 of 200 Generator loss: 2.56143093, Discriminator loss: 0.60793769
118it [00:10, 11.17it/s]
Epoch 70 of 200 Generator loss: 2.46422315, Discriminator loss: 0.62857068
118it [00:10, 11.06it/s]
Epoch 71 of 200 Generator loss: 2.65412951, Discriminator loss: 0.60285097
118it [00:10, 11.10it/s]
Epoch 72 of 200 Generator loss: 2.48614955, Discriminator loss: 0.62051612
118it [00:10, 11.37it/s]
Epoch 73 of 200 Generator loss: 2.61903048, Discriminator loss: 0.61521542
118it [00:10, 11.31it/s]
Epoch 74 of 200 Generator loss: 2.48087645, Discriminator loss: 0.64549685
118it [00:10, 11.16it/s]
Epoch 75 of 200 Generator loss: 2.64835620, Discriminator loss: 0.60836732
118it [00:10, 11.10it/s]
Epoch 76 of 200 Generator loss: 2.42855120, Discriminator loss: 0.64909124
118it [00:10, 11.12it/s]
Epoch 77 of 200 Generator loss: 2.44395494, Discriminator loss: 0.63707364
118it [00:10, 10.78it/s]
Epoch 78 of 200 Generator loss: 2.36440611, Discriminator loss: 0.64290339
118it [00:10, 11.25it/s]
Epoch 79 of 200 Generator loss: 2.46714830, Discriminator loss: 0.63622212
118it [00:10, 11.16it/s]
Epoch 80 of 200 Generator loss: 2.26563239, Discriminator loss: 0.67442703
118it [00:13, 8.88it/s]
Epoch 81 of 200 Generator loss: 2.21237016, Discriminator loss: 0.68918383
118it [00:12, 9.41it/s]
Epoch 82 of 200 Generator loss: 2.21210766, Discriminator loss: 0.67186236
118it [00:11, 10.64it/s]
Epoch 83 of 200 Generator loss: 2.25388646, Discriminator loss: 0.65171647
118it [00:10, 10.74it/s]
Epoch 84 of 200 Generator loss: 2.34440446, Discriminator loss: 0.67611921
118it [00:11, 10.58it/s]
Epoch 85 of 200 Generator loss: 2.29790950, Discriminator loss: 0.72201699
118it [00:10, 10.80it/s]
Epoch 86 of 200 Generator loss: 2.18459153, Discriminator loss: 0.69040287
118it [00:12, 9.70it/s]
Epoch 87 of 200 Generator loss: 2.12543154, Discriminator loss: 0.72536641
118it [00:11, 10.54it/s]
Epoch 88 of 200 Generator loss: 2.21223974, Discriminator loss: 0.67614448
118it [00:10, 11.05it/s]
Epoch 89 of 200 Generator loss: 2.29532957, Discriminator loss: 0.67123520
118it [00:10, 11.06it/s]
Epoch 90 of 200 Generator loss: 2.11595821, Discriminator loss: 0.71078843
118it [00:10, 10.91it/s]
Epoch 91 of 200 Generator loss: 2.24437642, Discriminator loss: 0.74584115
118it [00:10, 10.87it/s]
Epoch 92 of 200 Generator loss: 2.09346008, Discriminator loss: 0.74650925
118it [00:10, 10.91it/s]
Epoch 93 of 200 Generator loss: 2.18243694, Discriminator loss: 0.73644489
118it [00:10, 10.86it/s]
Epoch 94 of 200 Generator loss: 2.16841483, Discriminator loss: 0.72604871
118it [00:10, 11.23it/s]
Epoch 95 of 200 Generator loss: 2.15787578, Discriminator loss: 0.70481855
118it [00:10, 10.82it/s]
Epoch 96 of 200 Generator loss: 2.13780284, Discriminator loss: 0.70200396
118it [00:11, 10.71it/s]
Epoch 97 of 200 Generator loss: 2.13361883, Discriminator loss: 0.72981638
118it [00:11, 10.66it/s]
Epoch 98 of 200 Generator loss: 2.03311181, Discriminator loss: 0.78195286
118it [00:10, 10.79it/s]
Epoch 99 of 200 Generator loss: 2.03726220, Discriminator loss: 0.76787233
118it [00:10, 10.76it/s]
Epoch 100 of 200 Generator loss: 2.05792141, Discriminator loss: 0.76215667
118it [00:10, 10.98it/s]
Epoch 101 of 200 Generator loss: 1.97744596, Discriminator loss: 0.76962125
118it [00:10, 10.91it/s]
Epoch 102 of 200 Generator loss: 1.97665727, Discriminator loss: 0.79015470
118it [00:10, 10.80it/s]
Epoch 103 of 200 Generator loss: 1.93963349, Discriminator loss: 0.78371692
118it [00:10, 10.84it/s]
Epoch 104 of 200 Generator loss: 2.11709023, Discriminator loss: 0.75644368
118it [00:10, 11.05it/s]
Epoch 105 of 200 Generator loss: 1.99000013, Discriminator loss: 0.77553058
118it [00:10, 10.92it/s]
Epoch 106 of 200 Generator loss: 1.89500785, Discriminator loss: 0.78546369
118it [00:10, 10.95it/s]
Epoch 107 of 200 Generator loss: 1.88375151, Discriminator loss: 0.80725110
118it [00:12, 9.44it/s]
Epoch 108 of 200 Generator loss: 1.87493539, Discriminator loss: 0.84372514
118it [00:10, 10.79it/s]
Epoch 109 of 200 Generator loss: 1.90984046, Discriminator loss: 0.81079090
118it [00:10, 10.77it/s]
Epoch 110 of 200 Generator loss: 1.78631914, Discriminator loss: 0.85702813
118it [00:10, 10.98it/s]
Epoch 111 of 200 Generator loss: 1.94452953, Discriminator loss: 0.81320095
118it [00:13, 8.79it/s]
Epoch 112 of 200 Generator loss: 1.86767459, Discriminator loss: 0.83617032
118it [00:12, 9.36it/s]
Epoch 113 of 200 Generator loss: 1.92490923, Discriminator loss: 0.82652318
118it [00:13, 8.88it/s]
Epoch 114 of 200 Generator loss: 1.85909140, Discriminator loss: 0.82867348
118it [00:12, 9.16it/s]
Epoch 115 of 200 Generator loss: 1.77876198, Discriminator loss: 0.84978026
118it [00:12, 9.32it/s]
Epoch 116 of 200 Generator loss: 1.83030272, Discriminator loss: 0.85947526
118it [00:11, 10.27it/s]
Epoch 117 of 200 Generator loss: 1.74057448, Discriminator loss: 0.86152577
118it [00:13, 8.63it/s]
Epoch 118 of 200 Generator loss: 1.77872169, Discriminator loss: 0.86541337
118it [00:13, 9.03it/s]
Epoch 119 of 200 Generator loss: 1.73787189, Discriminator loss: 0.86078960
118it [00:13, 8.92it/s]
Epoch 120 of 200 Generator loss: 1.80334973, Discriminator loss: 0.86760443
118it [00:13, 8.54it/s]
Epoch 121 of 200 Generator loss: 1.68630743, Discriminator loss: 0.86530858
118it [00:13, 8.77it/s]
Epoch 122 of 200 Generator loss: 1.75381625, Discriminator loss: 0.86804771
118it [00:12, 9.31it/s]
Epoch 123 of 200 Generator loss: 1.82077634, Discriminator loss: 0.86948806
118it [00:12, 9.59it/s]
Epoch 124 of 200 Generator loss: 1.67493701, Discriminator loss: 0.89091146
118it [00:14, 8.20it/s]
Epoch 125 of 200 Generator loss: 1.78277671, Discriminator loss: 0.85939747
118it [00:12, 9.09it/s]
Epoch 126 of 200 Generator loss: 1.68459487, Discriminator loss: 0.88337535
118it [00:13, 8.86it/s]
Epoch 127 of 200 Generator loss: 1.70636284, Discriminator loss: 0.87627912
118it [00:13, 8.72it/s]
Epoch 128 of 200 Generator loss: 1.72802389, Discriminator loss: 0.90253562
118it [00:13, 8.49it/s]
Epoch 129 of 200 Generator loss: 1.69168293, Discriminator loss: 0.91186154
118it [00:13, 9.03it/s]
Epoch 130 of 200 Generator loss: 1.66582322, Discriminator loss: 0.89121467
118it [00:10, 10.78it/s]
Epoch 131 of 200 Generator loss: 1.69239867, Discriminator loss: 0.90106910
118it [00:12, 9.12it/s]
Epoch 132 of 200 Generator loss: 1.64027774, Discriminator loss: 0.91525382
118it [00:12, 9.18it/s]
Epoch 133 of 200 Generator loss: 1.64780080, Discriminator loss: 0.92815250
118it [00:12, 9.29it/s]
Epoch 134 of 200 Generator loss: 1.67628348, Discriminator loss: 0.93094921
118it [00:12, 9.62it/s]
Epoch 135 of 200 Generator loss: 1.61148822, Discriminator loss: 0.92955494
118it [00:12, 9.23it/s]
Epoch 136 of 200 Generator loss: 1.64984453, Discriminator loss: 0.91248882
118it [00:11, 10.04it/s]
Epoch 137 of 200 Generator loss: 1.71475101, Discriminator loss: 0.90585041
118it [00:13, 8.66it/s]
Epoch 138 of 200 Generator loss: 1.65905321, Discriminator loss: 0.89858145
118it [00:13, 8.64it/s]
Epoch 139 of 200 Generator loss: 1.65053988, Discriminator loss: 0.91362870
118it [00:13, 8.85it/s]
Epoch 140 of 200 Generator loss: 1.55437195, Discriminator loss: 0.94750881
118it [00:13, 8.76it/s]
Epoch 141 of 200 Generator loss: 1.60374773, Discriminator loss: 0.94733793
118it [00:12, 9.10it/s]
Epoch 142 of 200 Generator loss: 1.60323453, Discriminator loss: 0.93621135
118it [00:10, 11.12it/s]
Epoch 143 of 200 Generator loss: 1.50805700, Discriminator loss: 0.97121149
118it [00:11, 10.26it/s]
Epoch 144 of 200 Generator loss: 1.55218875, Discriminator loss: 0.96685529
118it [00:12, 9.68it/s]
Epoch 145 of 200 Generator loss: 1.52295554, Discriminator loss: 0.96003973
118it [00:13, 8.55it/s]
Epoch 146 of 200 Generator loss: 1.53509307, Discriminator loss: 0.97016114
118it [00:13, 8.87it/s]
Epoch 147 of 200 Generator loss: 1.51788068, Discriminator loss: 0.96941870
118it [00:12, 9.22it/s]
Epoch 148 of 200 Generator loss: 1.56098616, Discriminator loss: 0.95218074
118it [00:12, 9.14it/s]
Epoch 149 of 200 Generator loss: 1.56184959, Discriminator loss: 0.94258600
118it [00:13, 8.72it/s]
Epoch 150 of 200 Generator loss: 1.53858066, Discriminator loss: 0.94596398
118it [00:12, 9.42it/s]
Epoch 151 of 200 Generator loss: 1.51764572, Discriminator loss: 0.95867562
118it [00:10, 10.75it/s]
Epoch 152 of 200 Generator loss: 1.52186143, Discriminator loss: 0.97056013
118it [00:11, 9.97it/s]
Epoch 153 of 200 Generator loss: 1.54301751, Discriminator loss: 0.94576049
118it [00:12, 9.30it/s]
Epoch 154 of 200 Generator loss: 1.51500368, Discriminator loss: 0.96162009
118it [00:13, 9.05it/s]
Epoch 155 of 200 Generator loss: 1.52951419, Discriminator loss: 0.97485179
118it [00:13, 8.87it/s]
Epoch 156 of 200 Generator loss: 1.53670430, Discriminator loss: 0.95879108
118it [00:13, 8.51it/s]
Epoch 157 of 200 Generator loss: 1.53067458, Discriminator loss: 0.97059417
118it [00:13, 8.91it/s]
Epoch 158 of 200 Generator loss: 1.53972423, Discriminator loss: 0.97287750
118it [00:13, 9.02it/s]
Epoch 159 of 200 Generator loss: 1.50103784, Discriminator loss: 0.97492433
118it [00:14, 7.99it/s]
Epoch 160 of 200 Generator loss: 1.50457025, Discriminator loss: 0.98323220
118it [00:11, 10.11it/s]
Epoch 161 of 200 Generator loss: 1.50600111, Discriminator loss: 0.98644567
118it [00:13, 8.91it/s]
Epoch 162 of 200 Generator loss: 1.44643056, Discriminator loss: 0.99109596
118it [00:11, 10.29it/s]
Epoch 163 of 200 Generator loss: 1.48837006, Discriminator loss: 0.96992552
118it [00:12, 9.37it/s]
Epoch 164 of 200 Generator loss: 1.46793628, Discriminator loss: 0.99709153
118it [00:13, 9.07it/s]
Epoch 165 of 200 Generator loss: 1.39611030, Discriminator loss: 1.01801097
118it [00:13, 8.66it/s]
Epoch 166 of 200 Generator loss: 1.47840226, Discriminator loss: 0.99023587
118it [00:13, 9.04it/s]
Epoch 167 of 200 Generator loss: 1.45977855, Discriminator loss: 0.99352127
118it [00:13, 8.78it/s]
Epoch 168 of 200 Generator loss: 1.45984066, Discriminator loss: 1.01650643
118it [00:13, 8.91it/s]
Epoch 169 of 200 Generator loss: 1.37448096, Discriminator loss: 1.02929127
118it [00:13, 8.70it/s]
Epoch 170 of 200 Generator loss: 1.44157362, Discriminator loss: 1.00335169
118it [00:13, 8.97it/s]
Epoch 171 of 200 Generator loss: 1.41645741, Discriminator loss: 1.00347543
118it [00:10, 10.92it/s]
Epoch 172 of 200 Generator loss: 1.45591068, Discriminator loss: 1.00626850
118it [00:12, 9.15it/s]
Epoch 173 of 200 Generator loss: 1.44757259, Discriminator loss: 1.01161194
118it [00:12, 9.31it/s]
Epoch 174 of 200 Generator loss: 1.40042913, Discriminator loss: 1.01839304
118it [00:10, 10.97it/s]
Epoch 175 of 200 Generator loss: 1.39941704, Discriminator loss: 1.02620947
118it [00:10, 10.89it/s]
Epoch 176 of 200 Generator loss: 1.42153192, Discriminator loss: 1.01607561
118it [00:10, 10.77it/s]
Epoch 177 of 200 Generator loss: 1.40737641, Discriminator loss: 1.02566302
118it [00:12, 9.18it/s]
Epoch 178 of 200 Generator loss: 1.31939471, Discriminator loss: 1.05257809
118it [00:10, 10.75it/s]
Epoch 179 of 200 Generator loss: 1.37698376, Discriminator loss: 1.04337299
118it [00:11, 10.61it/s]
Epoch 180 of 200 Generator loss: 1.35302973, Discriminator loss: 1.05144620
118it [00:10, 11.21it/s]
Epoch 181 of 200 Generator loss: 1.32598770, Discriminator loss: 1.03711867
118it [00:10, 11.37it/s]
Epoch 182 of 200 Generator loss: 1.35947001, Discriminator loss: 1.04796863
118it [00:10, 11.29it/s]
Epoch 183 of 200 Generator loss: 1.37044895, Discriminator loss: 1.05451810
118it [00:10, 11.23it/s]
Epoch 184 of 200 Generator loss: 1.38544965, Discriminator loss: 1.03614426
118it [00:10, 11.28it/s]
Epoch 185 of 200 Generator loss: 1.34136951, Discriminator loss: 1.06269443
118it [00:10, 11.37it/s]
Epoch 186 of 200 Generator loss: 1.30051553, Discriminator loss: 1.06527996
118it [00:10, 11.26it/s]
Epoch 187 of 200 Generator loss: 1.37843776, Discriminator loss: 1.04664910
118it [00:10, 11.15it/s]
Epoch 188 of 200 Generator loss: 1.28786850, Discriminator loss: 1.07686460
118it [00:10, 10.86it/s]
Epoch 189 of 200 Generator loss: 1.35450065, Discriminator loss: 1.04691613
118it [00:10, 11.49it/s]
Epoch 190 of 200 Generator loss: 1.33774006, Discriminator loss: 1.04698277
118it [00:10, 11.40it/s]
Epoch 191 of 200 Generator loss: 1.33903599, Discriminator loss: 1.05998266
118it [00:10, 11.32it/s]
Epoch 192 of 200 Generator loss: 1.30355370, Discriminator loss: 1.07268226
118it [00:10, 11.26it/s]
Epoch 193 of 200 Generator loss: 1.27843606, Discriminator loss: 1.08297980
118it [00:10, 11.27it/s]
Epoch 194 of 200 Generator loss: 1.31746149, Discriminator loss: 1.06844008
118it [00:10, 11.08it/s]
Epoch 195 of 200 Generator loss: 1.28788543, Discriminator loss: 1.07884276
118it [00:10, 11.27it/s]
Epoch 196 of 200 Generator loss: 1.33817387, Discriminator loss: 1.06054509
118it [00:10, 11.26it/s]
Epoch 197 of 200 Generator loss: 1.28181005, Discriminator loss: 1.07411826
118it [00:11, 10.71it/s]
Epoch 198 of 200 Generator loss: 1.32240629, Discriminator loss: 1.06699717
118it [00:11, 10.43it/s]
Epoch 199 of 200 Generator loss: 1.29611182, Discriminator loss: 1.07842553
plt.figure()
losses_g = [fl.item() for fl in losses_g ]
plt.plot(losses_g, label='Generator loss')
losses_d = [f2.item() for f2 in losses_d ]
plt.plot(losses_d, label='Discriminator Loss')
plt.legend()
<matplotlib.legend.Legend at 0x7f5319c91670>
import numpy as np
fake_images = generator(torch.randn(b_size, nz).to(device))
for i in range(10):
fake_images_img = np.reshape(fake_images.data.cpu().numpy()[i],(28, 28))
plt.imshow(fake_images_img, cmap = 'gray')
plt.show()
13.4 GAN 파생기술¶
GAN은 생성자와 판별자가 서로 대결하면서 학습하는 구조이기 때문에 학습이 매우 불안정하다. 생성자와 판별자 중 한 쪽으로 치우친 훈련이 발생하면 성능에 문제가 생겨 정상적인 분류가 불가능하다. 이러한 제약을 해결한 모델이 DCGAN(Deep Convolution GAN)
DCGAN은 말 그대로 GAN 학습에 CNN을 사용한다. GAN과 DCGAN은 가짜 이미지를 생성하기 위해 임의의 노이즈 값을 사용했다면 cGAN(convolution GAN)은 출력에 어떤 조건을 주어 변형하는 모델이다. 즉, GAN이 임의의 노이즈로 무작위 이미지를 출력한다면, cGAN은 시드 역할을 하는 임의의 노이즈와 함께 어떤 조건이 추가된다. 조건이 추가되고 데이터 훈련 과정에서 인간이 통제할 수 있게 되면서 실제 이미지와 가깝거나 원래 이미지에 없던 문자열 태그 등도 넣는 것이 가능해짐
또한, CycleGAN이라는 것도 있다. CycleGAN은 사진이 주어졌을 때 다른 사진으로 변형시키는 모델이다. CycleGAN은 Pix2Pix 원리를 사용한다.
13.4.1 DCGAN¶
DCGAN은 GAN과 동일하게 입력된 이미지를 바탕으로 그것과 매우 유사한 가짜 이미지를 만들고, 이를 평가하는 과정을 반복해 실제와 매우 유사한 이미지를 생산하는 학습법
- 생성자 네트워크
generator는 임의의 입력으로 주어지는 노이즈 데이터는 '가로 x 세로' 형태가 아니기 때문에 입력 형태를 '가로 x 세로' 형태로 reshape해야 한다. 형태가 변경된 input은 합성곱층으로 넘겨진 후 이미지 형태의 출력을 위해 분수-스트라이드 합성곱(fractional-strided convolution)을 사용해 출력 값을 키운다.
생성자 네트워크의 특징으로
- pooling층을 모두 없애고, 분수-스트라이드 합성곱을 사용한다.
- Batch Normalization을 이용해 네트워크의 층이 많아도 안정적으로 기울기를 계산할 수 있도록 한다. 단 Batch Normalization을 모든 계층마다 추가할 경우 안정성이 떨어지는 문제가 있으므로 최종 출력층에서는 사용하지 않는다.
- activation function은 ReLU를 사용하며, 최종 출력층에서는 tanh를 사용
- 판별자 네트워크
discriminator는 64 x 64 크기의 이미지를 입력받아 진짜 혹은 가짜의 1차원 결과를 출력한다. activation function으로 LeakyReLU를 사용하며, 최종 출력층에서는 sigmoid를 사용해 0 ~ 1 사이의 값을 출력
판별자 네트워크의 특징으로
- 풀링층을 모두 없애고, 스트라이드 합성곱을 사용
- Batch Normalization을 이용해 네트워크 층이 많아도 안정적으로 기울기를 계산할 수 있도록 한다. 단 생성자 네트워크와 마찬가지로 Batch Normalization을 모든 계층에 추가하면 안정성이 떨어지는 문제가 있으므로 최초 입력층에서는 사용하지 않는다.
- activation function으로 LeakyReLU를 사용하고, 최종 출력층에서는 sigmoid를 사용
13.4.2 cGAN¶
cGAN은 GAN의 출력에 조건을 주어 통제하려는 시도에서 만들어짐
GAN을 이용하면 input image와 유사한 output image가 생성되었다. 그런데 input image에 새로운 객체를 추가하거나 image에 자동으로 문자열 태그를 붙이고 싶은 경우 기존 GAN으로는 불가능했다. cGAN을 이용해 조건을 변경한다면 가능해진다.
생성자에 noise vector 뿐만 아니라 조건을 넣어주고 판별자에도 조건을 넣어준다면 조건이 추가되면서 이미지에 대한 변형이 가능해짐.
13.4.3 CycleGAN¶
- Pix2Pix
Pix2Pix는 임의의 노이즈 벡터가 아닌 image를 input으로 받아 다른 스타일의 이미지를 출력하는 지도 학습 알고리즘이며 따라서 입력을 위한 dataset과 나올 정답 image도 필요로 한다.
- 생성자 네트워크
Pix2Pix의 생성자 네트워크는 input과 output이 모두 image이기 때문에 전체적으로 크기가 줄었다가 늘어나는 인코더-디코더 구조다. 크기가 줄어드는 인코더에서는 input data의 특징을 찾아내고, 크기가 다시 커지는 decoder에서는 image를 생성하는 역할을 한다. 출력층의 activation function은 tanh로 -1 ~ 1 사이의 값을 갖는다. 그렇기 때문에 input image도 -1 ~ 1 사이의 값으로 변경해서 사용해야 한다.
- 판별자 네트워크
판별자 네트워크는 DCGAN과 마찬가지로 스트라이드가 2인 합성곱층으로 구성되어 있다. 하지만 뒤의 두 계층은 스트라이드가 1인 합성곱을 이용해 최종적으로 30 x 30 형태의 데이터를 출력한다. 일반적인 GAN 모델의 출력이 0 ~ 1 사이의 스칼라인 것과는 차이가 있는데, 출력에서 차이가 있는 이유는 판별자를 image의 각 부분별로 진행하기 위해서다. 판별자는 image를 통째로 진짜인지 아닌지 판별하는 것이 아니라 이미지의 각 부분이 진짜인지 아닌지를 판별한다.
손실함수는 생성자가 판별자를 속이는 것 말고도 생성한 이미지가 정답과 같아야 하기 때문에 L1 loss를 추가적으로 사용한다.
- CycleGAN Pix2Pix는 데이터 쌍이 필요하다는 단점이 존재한다. 데이터 쌍을 구하는 것은 쉽지 않다. 따라서 쌍을 이루지 않는 이미지(unpaired image)로 학습할 수 있는 방법이 필요한데, 이때 사용하는 것이 CycleGAN이다.
CycleGAN은 하나가 아닌 두개의 생성자(G, F)를 갖는다. G는 이미지 X를 Y로 변환하며, 생성자 F는 Y를 다시 X로 변환한다. 이때 D_X, D_Y는 각각 이미지 X와 Y를 위한 판별자다. 따라서 생성자 G는 D_Y에 대한 적대적 학습을 진행하고 생성자 F는 D_X에 대한 적대적 학습을 진행한다.
G가 input image X를 만나 생성한 이미지를 Y'라고 하자. Y'를 input image로 F가 만든 이미지를 X'이라고 할 때 X와 X'가 얼마나 가까운지는 L1 loss를 사용해 계산한다.
즉, CycleGAN에서는 G(X) = Y'에 대한 생성자, Y'값을 다시 X'로 복원하는 F(Y') = X'에 대한 생성자와 이 값을 판별하는 판별자(D_Y, D_X)가 추가되어 총 네 개의 네트워크를 사용한다.
X -> Y', Y' -> X'으로 연결되는 것을 순환 일관성이라고 한다. X -> Y'을 정방향 일관성(forward consistency), Y' -> X'을 역방향 일관성(backward consistency)라 한다.
'Deep Learning(강의 및 책) > Pytorch' 카테고리의 다른 글
[Pytorch] Deep Learning Pytorch 12. 강화 학습(Reinforcement learning) (0) | 2023.01.24 |
---|---|
[Pytorch] Deep Learning Pytorch 11. 클러스터링(Clustering) (0) | 2023.01.16 |
[Pytorch] Deep Learning Pytorch 8. 성능 최적화 (0) | 2023.01.15 |
[Pytorch] Deep Learning Pytorch 6. 합성곱신경망 2 (0) | 2023.01.12 |
[Pytorch] Deep Learning Pytorch 5. 합성곱 신경망Ⅰ (0) | 2022.09.25 |