| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
Tags
- python 기초
- 랭그래프
- RDBMS
- Transformer
- 딥러닝
- TTS
- 힙정렬
- LangGraph
- 정보처리기사
- 캐글
- UMAP
- SQL
- Python
- 객체지향
- 자연어처리
- RNN
- 데이터 시각화
- 알고리즘
- CNN
- dementional reduction
- 기초
- 에이전트
- 생성형 인공지능
- python기초
- ASR
- 소프트웨어 개발
- 데이터엔지니어
- CLIP
- 트랜스포머
- 머신러닝
Archives
- Today
- Total
수달이네 기술 블로그
3. AutoEncoder2(Sparse AE, Denoising AE, AutoEncoder + CIFAR10) 본문
AI공부/Vision
3. AutoEncoder2(Sparse AE, Denoising AE, AutoEncoder + CIFAR10)
슬픈 수달이 2026. 3. 11. 12:05Sparse Autoencoder

입력 데이터를 압축된 형태로 표현하는 오토인코더의 한 종류.
- 잠재 공간에서 대부분의 뉴런이 0에 가깝고, 일부만 활성화하도록 강제.
- 평균 활성도가 특정 목표값보다 낮도록 함.
- 활성된 뉴런 = 특정 결과에만 반응하는 뉴런(역할을 부여)
- 비활성된 뉴런 = 결과에 연관이 거의 없는 뉴런
- 희소성을 주기 위해 L1정규화, KL Divergence 기반의 제약을 추가
- L1 정규화: 가중치를 0에 가깝게 만들어 모델을 희소하도록 만듦.
- KLD: 뉴런의 평균 활성도가 목표와 얼마나 다른지를 파악(Loss function)
- 결과적으로 데이터의 핵심적인 특징을 더 해석하고, 압축된 방식으로 표현한다.
- 차원축소, 특징추출, 이상 탐지등의 분야에서 사용.
KL Divergence: VAE같은 곳에서의 KLD는 분포간의 차이의 유사도를 측정
Denoising Autoencoder

입력 데이터에 일부러 노이즈를 추가한 후, 손상된 데이터를 원래의 클린 데이터로 복원하도록 학습하는 오토인코더의 종류
- 입력을 복사하는 것이 아니므로 데이터의 본질적 패턴, 구조등을 더 잘 학습할 수 있다.
- 테스트 데이터에 노이즈가 끼어있어도 기존 오토인코더보다 더 잘 표현할 수 있다.
- 따라서, 특징 추출, 데이터 전처리, 이상 탐지 등에 활용
더 성능좋은 AutoEncoder구현
인코더
import torch.nn as nn
class Encoder(nn.Module):
def __init__(self, num_input_channels, base_channel_size, latent_dim):
super().__init__()
self.net = nn.Sequential(
nn.Conv2d(num_input_channels, base_channel_size, kernel_size=3, padding=1, stride=2), # 32x32 => 16x16
nn.GELU(),
nn.Conv2d(base_channel_size, base_channel_size, kernel_size=3, padding=1),
nn.GELU(),
nn.Conv2d(base_channel_size, 2 * base_channel_size, kernel_size=3, padding=1, stride=2), # 16x16 => 8x8
nn.GELU(),
nn.Conv2d(2 * base_channel_size, 2 * base_channel_size, kernel_size=3, padding=1),
nn.GELU(),
nn.Conv2d(2 * base_channel_size, 2 * base_channel_size, kernel_size=3, padding=1, stride=2), # 8x8 => 4x4
nn.GELU(),
nn.Flatten(),
nn.Linear(2 * 16 * base_channel_size, latent_dim),
)
def forward(self, x):
return self.neㅇ
- 이전 AE와는 다르게 MaxPooling을 사용하지 않고, Conv2d(stride=2)를 이용해 데이터를 압축했다.
- MaxPooling연산은 복원하기 어려운 정보손실을 만든다. (영역 내의 최대값만 남기고 버리기 때문 = 영구손상)
- 그러나 Conv연산은 영역내 모든 값을 사용함. = 복구가능
- 이전 AE에서는 ReLU연산을 사용했지만 여기선 GELU연산을 사용했다.

- 부드러움(Smoothness): 0 부근에서 미분이 연속이라 기울기 소실/폭주 완화에 유리. 학습이 안정적(ReLU는 0에서 끊김)
- 0에서 안 끊기므로 음수영역 뉴런이 죽지 않음.
- NLP의 Transformer나, 비전의 최신 아키텍쳐가 GELU가 성능이 더 좋은 경우가 보고됨.
class Decoder(nn.Module):
def __init__(self, num_input_channels, base_channel_size, latent_dim):
super().__init__()
self.linear = nn.Sequential(nn.Linear(latent_dim, 2 * 16 * base_channel_size), nn.GELU())
self.net = nn.Sequential(
nn.ConvTranspose2d(
2 * base_channel_size, 2 * base_channel_size, kernel_size=3, output_padding=1, padding=1, stride=2
), # 4x4 => 8x8
nn.GELU(),
nn.Conv2d(2 * base_channel_size, 2 * base_channel_size, kernel_size=3, padding=1),
nn.GELU(),
nn.ConvTranspose2d(2 * base_channel_size, base_channel_size, kernel_size=3, output_padding=1, padding=1, stride=2), # 8x8 => 16x16
nn.GELU(),
nn.Conv2d(base_channel_size, base_channel_size, kernel_size=3, padding=1),
nn.GELU(),
nn.ConvTranspose2d(
base_channel_size, num_input_channels, kernel_size=3, output_padding=1, padding=1, stride=2
), # 16x16 => 32x32
nn.Tanh(),
)
def forward(self, x):
x = self.linear(x)
x = x.reshape(x.shape[0], -1, 4, 4)
x = self.net(x)
return x
- Upsampling연산 대신 ConvTranspose2d연산을 사용함
- UpSample: 학습이 되지 않고, 단순이 이미지만 키움
[1 2] [1 1 2 2]
[3 4] -> [1 1 2 2]
[3 3 4 4]
[3 3 4 4]
- x --Upsample--> 크기 증가 ------> Conv --> 특징 생성
- ConvTranspose2d: 엄샘플 과정에서 학습되며, 필터링, 패턴을 생성한다.
- 즉, 일단 입력값 사이에 0을 채우고 conv수행해 패턴 생성
- x --ConvTranspose--> 크기 증가 + 특징 생성 동시에
AutoEncoder
class Autoencoder(nn.Module):
def __init__(self, num_input_channels, base_channel_size, latent_dim):
super().__init__()
self.encoder = Encoder(num_input_channels, base_channel_size, latent_dim)
self.decoder = Decoder(num_input_channels, base_channel_size, latent_dim)
def forward(self, x):
latent = self.encoder(x)
output = self.decoder(latent)
return latent, output
model = Autoencoder(num_input_channels=3, base_channel_size=64, latent_dim=256)
데이터 변형, 정규화
import torch
from torchvision.transforms import v2
trn_transforms = v2.Compose([
v2.ToImage(),
v2.RandomResizedCrop(size=(32, 32), antialias=True),
v2.RandomHorizontalFlip(p=0.5),
v2.RandomVerticalFlip(p=0.5),
v2.ToDtype(torch.float32, scale=True),
v2.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]),
])
test_transforms = v2.Compose([
v2.ToImage(),
v2.Resize(size=(32, 32), antialias=True),
v2.ToDtype(torch.float32, scale=True),
v2.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]),
])
CIFAR10데이터 로드
from torchvision.datasets import CIFAR10
trn_dataset = CIFAR10(".", train=True, download=True, transform=trn_transforms)
test_dataset = CIFAR10(".", train=False, download=True, transform=test_transforms)
- 이번엔 MNIST가 아닌 CIFAR10을 불러왔다.
데이터로더 정의
import torch
trn_loader = torch.utils.data.DataLoader(trn_dataset, batch_size=64, shuffle=True, num_workers=2)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=64, shuffle=False, num_workers=2)
학습
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
from tqdm import tqdm
def train(model, criterion, optimizer, trn_loader, test_loader, device, num_epochs):
for epoch in range(num_epochs):
model.train()
trn_loss = 0.0
for inputs, _ in tqdm(trn_loader):
inputs = inputs.to(device)
_, outputs = model(inputs)
loss = criterion(outputs, inputs)
optimizer.zero_grad()
loss.backward()
optimizer.step()
trn_loss += loss.item() * inputs.size(0)
trn_epoch_loss = trn_loss / len(trn_loader.dataset)
print(f"[Train] Loss: {trn_epoch_loss:.4f}")
with torch.no_grad():
model.eval()
test_loss = 0.0
for inputs, _ in tqdm(test_loader):
inputs = inputs.to(device)
_, outputs = model(inputs)
loss = criterion(outputs, inputs)
test_loss += loss.item() * inputs.size(0)
test_epoch_loss = test_loss / len(test_loader.dataset)
print(f"[Test] Loss: {test_epoch_loss:.4f}")
imshow(inputs.cpu(), "Inputs")
imshow(outputs.cpu(), "outputs")
- 데이터에 따라 모델을 학습시켜준다.
import torch.optim as optim
model = model.to(device)
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
train(model, criterion, optimizer, trn_loader, test_loader, device, num_epochs=10)
# epoch 1
# 100%|██████████| 782/782 [02:31<00:00, 5.15it/s]
# [Train] Loss: 0.0419
# 100%|██████████| 157/157 [00:33<00:00, 4.76it/s]
# [Test] Loss: 0.0374
#epoch 6
# 100%|██████████| 782/782 [03:08<00:00, 4.14it/s]
# [Train] Loss: 0.0051
# 100%|██████████| 157/157 [00:28<00:00, 5.54it/s]
# [Test] Loss: 0.0147



- 위 결과처럼 점차 선명해지는것을 알 수 있다.
잠재 벡터 추출
def get_embed(model, data_loader):
image_list, embed_list = [], []
model.eval() # 1) 모델을 평가 모드로 전환 (Dropout/BatchNorm 고정)
with torch.no_grad(): # 2) 추론 모드 (그래디언트 계산/메모리 사용 줄임)
for inputs, _ in tqdm(data_loader): # 3) 데이터로더에서 배치 반복 (라벨은 사용 안 함)
inputs = inputs.to(device) # 4) 배치를 장치(GPU/CPU)로 이동
latents = model.encoder(inputs) # 5) 인코더 통과 → 잠재표현(latent/embedding) 추출
image_list.append(inputs.cpu()) # 6) 입력 배치를 CPU로 옮겨 누적
embed_list.append(latents) # 7) 임베딩 배치를 누적 (GPU에 둔 상태)
image_list = torch.cat(image_list, dim=0) # 8) 배치들을 샘플 차원으로 이어붙임
embed_list = torch.cat(embed_list, dim=0)
return image_list, embed_list # 9) (이미지_전체, 임베딩_전체) 반환
이미지 출력(유사 이미지)
def find_similar_images(query_image, query_embed, key_images, key_embeds, k=7):
dist = torch.cdist(query_embed[None, :], key_embeds, p=2)
dist = dist.squeeze(dim=0)
_, topk_indices = torch.topk(dist, k, largest=False)
topk_images = torch.cat([query_image[None], key_images[topk_indices.cpu()]], dim=0)
imshow(topk_images, f"Top-{k} images")
_, bottomk_indices = torch.topk(dist, k, largest=True)
bomttomk_images = torch.cat([query_image[None], key_images[bottomk_indices.cpu()]], dim=0)
imshow(bomttomk_images, f"Bottom-{k} images")
test_images, test_embeds = get_embed(model, test_loader)
for i in range(8):
find_similar_images(test_images[i], test_embeds[i], test_images[i+1:], test_embeds[i+1:])
'AI공부 > Vision' 카테고리의 다른 글
| 2. AutoEncoder(오토인코더) (0) | 2026.03.10 |
|---|---|
| 1. ViT(Vision Transformer (0) | 2026.03.09 |