Encoding: Data를 저차원 latent space의 특정 point에 mapping시키는 것. Decoding: 이 point의 위치를 받아 해당 Data를 다시 생성하려 시도하는 것. encoder는 decoder가 정확하게 재구성하도록 가능한 많은 정보를 내포시키려 하는데, 이 벡터를 embedding이라 한다.
Auto Encoder: encoding과 decoding작업을 수행하도록 훈련된 신경망. → 원본에 가까워지도록 train시킨다. 보통 Loss function으론 원본과 재구성 img의 pixel간의 RMSE나 BCE를 사용한다. input은 latent embedding vector z로 encoding, 원본픽셀공간으로 decoding
🤔 이미 갖고 있는 img를 왜 재구성?
이미 갖고있는 img를 왜 재구성해야할까? "Auto Encoder 사용이유": Embedding공간(latent space) 때문! latent space에서 sampling하여 새로운 img를 생성할 수 있기 때문.
cf) test_set을 encoder에 통과시켜 만들어진 embedding을 그래프(scatter 등)로 나타내면, img가 latent space에 어떻게 embedding되는지 시각화가능하다.
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
# 예시: Autoencoder 모델 정의
class Autoencoder(nn.Module):
def __init__(self, input_size, hidden_size):
super(Autoencoder, self).__init__()
self.encoder = nn.Linear(input_size, hidden_size)
self.decoder = nn.Linear(hidden_size, input_size)
def forward(self, x):
encoded = self.encoder(x)
decoded = self.decoder(encoded)
return encoded, decoded
# 예시: 잠재 공간 시각화 함수
def visualize_latent_space(data_loader, model, device):
model.eval()
latent_space, labels = [], []
with torch.no_grad():
for images, labels_batch in data_loader:
images = images.view(images.size(0), -1).to(device)
encoded, _ = model(images)
latent_space.append(encoded.cpu().numpy())
labels.append(labels_batch.numpy())
latent_space = torch.cat(latent_space, dim=0)
labels = torch.cat(labels, dim=0)
plt.figure(figsize=(10, 8))
plt.scatter(latent_space[:, 0], latent_space[:, 1], c=labels, cmap='viridis')
plt.colorbar()
plt.title('Latent Space Visualization')
plt.show()
# 예시: 데이터 로딩
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])
mnist_data = datasets.MNIST(root='./data', train=True, transform=transform, download=True)
data_loader = DataLoader(mnist_data, batch_size=64, shuffle=True)
# 예시: 모델 및 학습 설정
input_size = 28 * 28 # MNIST 이미지 크기
hidden_size = 2 # 잠재 공간 차원
autoencoder_model = Autoencoder(input_size, hidden_size)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
autoencoder_model.to(device)
# 예시: 학습된 모델의 가중치 로드
autoencoder_model.load_state_dict(torch.load('autoencoder_model.pth'))
autoencoder_model.eval()
# 예시: 잠재 공간 시각화
visualize_latent_space(data_loader, autoencoder_model, device)
이에대해, Decoder를 사용해 다시 pixel공간으로 변환하면 새로운 img를 생성할 수 있다.
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
# 예시: Autoencoder 모델 정의
class Autoencoder(nn.Module):
def __init__(self, input_size, hidden_size):
super(Autoencoder, self).__init__()
self.encoder = nn.Linear(input_size, hidden_size)
self.decoder = nn.Linear(hidden_size, input_size)
def forward(self, x):
encoded = self.encoder(x)
decoded = self.decoder(encoded)
return encoded, decoded
# 예시: 이미지 생성 함수
def generate_image_from_latent_space(latent_vector, model, device):
model.eval()
with torch.no_grad():
latent_vector = torch.tensor(latent_vector).float().to(device)
reconstructed_image = model.decoder(latent_vector)
reconstructed_image = reconstructed_image.view(1, 1, 28, 28) # MNIST 이미지 크기
return reconstructed_image
# 예시: 이미지 시각화 함수
def visualize_image(image):
plt.imshow(image.squeeze().cpu().numpy(), cmap='gray')
plt.axis('off')
plt.show()
# 예시: 데이터 로딩
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])
mnist_data = datasets.MNIST(root='./data', train=True, transform=transform, download=True)
data_loader = DataLoader(mnist_data, batch_size=64, shuffle=True)
# 예시: 모델 및 학습 설정
input_size = 28 * 28 # MNIST 이미지 크기
hidden_size = 2 # 잠재 공간 차원
autoencoder_model = Autoencoder(input_size, hidden_size)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
autoencoder_model.to(device)
# 예시: 학습된 모델의 가중치 로드
autoencoder_model.load_state_dict(torch.load('autoencoder_model.pth'))
autoencoder_model.eval()
# 예시: 잠재 공간에서 샘플링하여 이미지 생성 및 시각화
latent_vector_sample = [0.5, 0.5] # 잠재 공간에서 샘플링한 값
generated_image = generate_image_from_latent_space(latent_vector_sample, autoencoder_model, device)
visualize_image(generated_image)
2. Variational Auto Encoder
Auto Encoder의 문제점.
Auto Encoder는 latent space가 연속적인지 강제하지 않기에, 다룰 수 있는 차원 수가 적다. 그렇기에, 더 복잡한 img생성 시, latent space에 더 많은 차원 사용 시, 이 문제는 뚜렷해진다. 즉, encoding 시, latent space를 자유롭게 사용하면 비슷한 point가 모인 그룹간의 큰 간격이 발생한다. 이런 간격이 발생한 공간에서는 잘 형성된 img를 생성할 가능성이 낮다.
이를 위해 Auto Encoder 대신, Variational Auto Encoder로 바꿔야한다.
VAE
AE: 각 img가 latent space의 한 point에 직접 mapping됨. VAE: 각 img가 latent space point주변의 다변량정규분포에 mapping됨. 다변량 정규분포 N(0,I)는 평균벡터가 0, 공분산행렬이 단위벡터이다. 즉, 요약해보면 Encoder는 input을 받아 latent space의 다변량정규분포를 정의하는 2개의 벡터로 encoding한다. ∙ z_mean: 이 분포의 평균벡터 ∙ z_log_var: 차원별 분산의 로그값
이런 작은 변화로 어떻게 Encoder를 향상시킬 수 있었을까? 이전 AE: latent space를 연속적으로 만들필요❌ VAE: z_mean주변영역에서 random point를 sampling하기에 재구성손실이 작게 유지되도록 동일영역의 Point의 img와 매우 비슷하게 decoding.
cf) reparameterization trick이란?
mean과 log_var로 정의된 정규분포에서 직접 sampling하는 대신, 표준정규분포에서 epsilon을 sampling → 올바른 평균과 분산을 갖도록 sample수동조정.
이 방법은 epsilon을 포함함으로써 출력의 편도함수를 결정론적(= random epsilon과 무관함)으로 표시할 수 있어 역전파를 위해 필수적이다.
🧐 Loss Function
AE의 손실함수: Src_img와 AE통과한 출력간의 Reconstruction Loss VAE: Reconstruction Loss + KL-Divergence (Latent Loss)
KL Divergence는 z_mean과 z_log_var가 표준정규분포와 얼마나 다른지를 측정한다.