👽 졸업 논문 ( 17 ) - Zoobot 분석
2025. 5. 13. 12:19ㆍ개발/👽 졸업 논문
Zoobot 개요
📌 목적
Zoobot은 Galaxy Zoo 프로젝트에서 구축한 은하 이미지 분류 모델
- 은하의 모양 분류 (나선 vs 타원, 바의 유무, 회전 방향 등)
- 구조적 특징 분석
- Galaxy Zoo 설문 결과 예측 : 사용자 투표 기반
1. 은하의 전반적인 형태는 무엇인가요?
Smooth / Features or Disk / Star or Artifact
2. 은하에 중심 막대 구조가 있나요?
Yes / No
3. 은하에 나선 구조가 있나요?
Yes / No
4. 나선팔이 몇 개 있나요?
1개 / 2개 / 3개 / 4개 / 5개 이상 / 확실하지 않음
5. 은하의 나선팔이 시계 방향으로 감기나요, 반시계 방향으로 감기나요?
시계 방향 / 반시계 방향 / 확실하지 않음
6. 은하에 중심 팽대부가 있나요?
Yes / No
7. 은하가 다른 은하와 상호작용하거나 병합 중인가요?
Yes / No / 확실하지 않음
8. 은하에 링 구조가 있나요?
Yes / No / 확실하지 않음
9. 은하에 불규칙한 구조나 이상한 특징이 있나요?
Yes / No / 확실하지 않음
📌 구조
Encoder + Classification Head
Encoder : 이미지 임베딩( ex - 모양, 색, 모서리 등 이미지에서 추출한 특징 ) 추출기
Classification Head : Galaxy Zoo의 설문 항목들에 대한 분류 결과를 뱉어냄
📍 우리 모델 구조
Zoobot에서 Classification Head 떼어내고 Encoder만 가져올 예정
Encoder(이미지 임베딩) + 수치 데이터 벡터 -> Custom Classification Head
이미지 인코더: zoobot의 pretrained encoder
(ex - ConvNeXt, EfficientNet 등 => timm 라이브러리로 여러 encoder test 가능)
수치 데이터: 시뮬레이션에서 얻은 물리량 (ex. 질량, 속도분산 등)
라벨: 병합 여부
학습 방식: 이미지 인코더 출력 + 수치 데이터 → 융합 → fully-connected head → 지도 학습
코드 구조
import torch
import torch.nn as nn
import timm
# 1. Zoobot 이미지 인코더 불러오기 (ConvNeXt Nano 기반)
# - Hugging Face Hub에서 pretrained 모델을 로드
# - num_classes=0 → classification head 제거하고 feature extractor로만 사용
encoder = timm.create_model(
'hf_hub:mwalmsley/zoobot-encoder-convnext_nano',
pretrained=True,
num_classes=0
)
# 2. 이미지 + 수치 데이터를 입력받아 병합 여부를 예측하는 멀티모달 분류 모델 정의
class MergerClassifier(nn.Module):
def __init__(self, encoder, num_numerical_features):
"""
Args:
encoder (nn.Module): pretrained image encoder (Zoobot에서 가져온 ConvNeXt 등)
num_numerical_features (int): 수치 데이터의 feature 수 (예: 질량, 속도, 금속도 등)
"""
super().__init__()
# 이미지 인코더 (Zoobot에서 가져온 pretrained 모델)
self.encoder = encoder
# 이미지 인코더의 출력 차원 수 (예: EfficientNet-B0은 1280, ConvNeXt Nano는 768)
self.encoder_out_dim = encoder.num_features
# 이미지 임베딩 + 수치 feature → MLP로 이진 분류
self.mlp = nn.Sequential(
nn.Linear(self.encoder_out_dim + num_numerical_features, 128), # feature 합쳐서 128차원으로 축소
nn.ReLU(), # 비선형 활성화 함수
nn.Linear(128, 1) # 출력층: 1개의 값 (시그모이드를 통과해 확률로 해석)
)
def forward(self, image, numerical):
"""
Forward pass (순전파)
Args:
image (Tensor): 이미지 배치 (예: [B, 3, 224, 224])
numerical (Tensor): 수치 데이터 배치 (예: [B, N])
Returns:
Tensor: 병합 확률 (예: [B, 1])
"""
# 1. 이미지 → 인코더 → 임베딩 벡터 (예: [B, 768])
img_features = self.encoder(image)
# 2. 이미지 임베딩 + 수치 feature를 채널 차원(axis=1)으로 concat
# → [B, encoder_out_dim + num_numerical_features]
combined = torch.cat([img_features, numerical], dim=1)
# 3. 결합된 feature를 MLP에 통과시켜 병합 확률 예측
return self.mlp(combined)