데이터 로드 및 전처리
이미지 데이터는 지정된 폴더 구조에 따라 구성되어야 하며, 각 클래스별로 폴더를 분리하여 저장합니다.
data_dir = "./data"
transform = {
'train': transforms.Compose([
transforms.Resize((64, 64)),
transforms.ToTensor()
]),
'valid': transforms.Compose([
transforms.Resize((64, 64)),
transforms.ToTensor()
])
}
dataset = {
phase: datasets.ImageFolder(root=os.path.join(data_dir, phase), transform=transform[phase])
for phase in ['train', 'valid']
}
dataloader = {
phase: torch.utils.data.DataLoader(
dataset=dataset[phase],
batch_size=16,
shuffle=True
)
for phase in ['train', 'valid']
}
모델 설계
기본적인 순환 신경망 아키텍처를 사용하여 이미지 분류 모델을 정의합니다. 컨볼루션 블록과 이후의 풀링, 선형 계층으로 구성됩니다.
class ImageClassifier(torch.nn.Module):
def __init__(self):
super(ImageClassifier, self).__init__()
self.features = torch.nn.Sequential(
torch.nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1),
torch.nn.ReLU(),
torch.nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2, stride=2),
torch.nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1),
torch.nn.ReLU(),
torch.nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2, stride=2)
)
self.classifier = torch.nn.Sequential(
torch.nn.Linear(16 * 16 * 256, 512),
torch.nn.ReLU(),
torch.nn.Dropout(p=0.5),
torch.nn.Linear(512, 7)
)
def forward(self, x):
x = self.features(x)
x = x.view(-1, 16 * 16 * 256)
x = self.classifier(x)
return x
model = ImageClassifier()
학습 설정
손실 함수와 최적화 알고리즘을 설정하고, 장치(가능한 경우 GPU)를 지정합니다.
loss_fn = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.0005)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)
num_epochs = 10
모델 학습
각 에포크마다 훈련 및 검증 단계를 반복하며 손실과 정확도를 기록합니다.
for epoch in range(num_epochs):
print(f"Epoch {epoch+1}/{num_epochs}")
print("-" * 10)
for phase in ['train', 'valid']:
model.train(phase == 'train')
running_loss = 0.0
running_corrects = 0
for batch_idx, (inputs, labels) in enumerate(dataloader[phase], 1):
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(inputs)
_, preds = torch.max(outputs, 1)
loss = loss_fn(outputs, labels)
if phase == 'train':
loss.backward()
optimizer.step()
running_loss += loss.item()
running_corrects += torch.sum(preds == labels.data)
if batch_idx % 500 == 0 and phase == 'train':
print(f"Batch {batch_idx}, Train Loss: {running_loss / batch_idx:.4f}, "
f"Train Acc: {100 * running_corrects / (4 * batch_idx):.4f}%")
epoch_loss = running_loss * 4 / len(dataset[phase])
epoch_acc = 100 * running_corrects / len(dataset[phase])
print(f"{phase.capitalize()} Loss: {epoch_loss:.4f}, Accuracy: {epoch_acc:.4f}%")
모델 저장 및 불러오기
학습 완료 후 모델 상태를 파일로 저장하고, 필요 시 다시 불러옵니다.
torch.save(model, 'trained_model.pth')
# 불러오기
loaded_model = torch.load('trained_model.pth')
정규화 기법 및 트릭
- Dropout: 훈련 중 무작위로 일부 노드를 비활성화하여 과적합 방지.
- model.train(): 배치 정규화 및 드롭아웃 활성화.
- model.eval(): 평가 모드에서 동작, 모든 드롭아웃/배치 정규화는 고정됨.
- with torch.no_grad(): 그래디언트 계산을 일시적으로 비활성화하여 메모리 절약 및 성능 향상.
데이터 증강
훈련 데이터의 다양성을 높이기 위해 다양한 변환을 적용합니다.
augmentation = transforms.Compose([
transforms.Resize((80, 80)),
transforms.RandomHorizontalFlip(),
transforms.RandomCrop(64),
transforms.ColorJitter(brightness=0.5, contrast=0.5, hue=0.5),
transforms.ToTensor(),
transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
])
파일 및 경로 처리
파일 읽기, 경로 조합, 디렉터리 목록 추출 등의 기초 작업 예시입니다.
with open('data.txt', 'r') as f:
content = f.read()
print(f"File content: {content}")
file_list = os.listdir('./data/train')
path = os.path.join('./data', 'train')
네트워크 구성 요소 이해
- Backbone: 특징 추출을 담당하는 주요 네트워크 (예: ResNet).
- Head: 최종 출력을 생성하는 분류기 부분.
- Neck: 특징 맵을 보다 효과적으로 조합하는 중간 구조.
- Bottleneck: 차원 축소를 통해 정보를 압축하는 구조.
- GAP (Global Average Pooling): 채널별 평균값을 취해 입력 크기를 줄이는 방법.
- Embedding: 입력 데이터를 벡터 공간으로 매핑하는 과정.
- Pretext Task vs Downstream Task: 사전 훈련과 미세 조정의 역할 구분.
- Warm-up: 초기 학습률을 낮게 시작하여 수렴 안정성 향상.