[250416수428H] 딥러닝 이론 (8) 모델 관련 팁

윤승호·2025년 4월 16일

같은 기능을 하는 함수가 생각보다 많은 것 같다. 헷갈리지 않도록 조심해야지!

학습시간 09:00~02:00(당일17H/누적428H)

◆ 학습내용

1. CNN 모델에 관하여

  • MLP = CNN의 Fully Connected(FC) 부분
  • LeNet = CNN의 구모델 (Conv + Pool + Sigmoid + FC)
  • CNN = LeNet + ReLU + BatchNorm + Dropout + 깊이
항목MLPLeNetCNN
기본 아이디어모든 입력을 일렬로 펼쳐서 처리 (Flatten + Linear)이미지의 공간 정보를 살리기 위해 Convolution 사용깊고 복잡한 convolution 블록으로 특징 추출
입력 형태(B, D) / (B, C×H×W)(B, 1, 28, 28)(B, 1~3, H, W)
주요 레이어Linear, ReLU, DropoutConv2d, AvgPool, Sigmoid, FCConv2d, MaxPool, BatchNorm, ReLU, FC, Dropout
반복 구조없음 (Dense만 연속)Conv → Pool 블록 2번Conv → BN → ReLU → Pool 블록 수십 번까지 가능
공간 구조 인식없음 (Flatten해서 공간감 사라짐)약함 (Conv 있음)매우 강함 (멀티스케일 특징 인식)
비선형성 처리ReLU (or LeakyReLU)SigmoidReLU, LeakyReLU, GELU 등 다양
정규화없음없음BatchNorm, LayerNorm 등 사용
출력 구조Linear → SoftmaxFC 3단 구성FC or Global AvgPool + Linear
주요 용도수치형, 표형 데이터 (CSV)숫자 이미지 (MNIST 등)이미지 전반 (사진, 영상 등)
모델 깊이얕음 (3~4층)얕음 (5~6층)깊음 (수십~수백층)
파라미터 수많음 (입력 차원에 따라 폭발)적음 (conv로 파라미터 감소)상황에 따라 다양 (최적화 가능)
현대성고전적CNN 시초실전 표준 모델

2. ToTensor()에 관하여

아래 3개 코드는 정확히 동일한 기능을 한다.
ToTensor() 함수는 다음 릴리즈에 삭제 예정이라고 함.
transforms 보다 v2가 짧으니 애용해야겠다.

# 1.
transforms = v2.Compose([
    v2.ToTensor()
])

# 2.
transforms = v2.Compose([
    v2.ToImage(),
    v2.ToDtype(torch.float32, scale=True)
])

# 3.
transforms = transforms.Compose([
    transforms.ToImage(),
    transforms.ToDtype(torch.float32, scale=True)
])

3. 데이터 로드에 관하여

아래 두 코드는 정확히 같은 기능을 한다.
1번은 라이브러리 데이터 불러오기, 2번은 로컬 데이터 불러오기.

# 1.
transforms = v2.Compose([
    v2.Resize((224, 224)),
    v2.ToImage(),
    v2.ToDtype(torch.float32, scale=True), 
    v2.Normalize(mean=[0.4914, 0.4822, 0.4465], std=[0.2470, 0.2435, 0.2616]),
])
train_dataset = datasets.CIFAR10(
    root='./images',
    train=True,
    download=True,
    transform=transforms
)
test_dataset = datasets.CIFAR10(
    root='./images',
    train=False,
    download=True,
    transform=transforms
)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)

print(f'▶ Train set: {len(train_dataset)} | Test set: {len(test_dataset)}')
print(next(iter(train_loader))[0].shape)



# 2.
transforms = v2.Compose([
    v2.Resize((224, 224)),
    v2.ToImage(),
    v2.ToDtype(torch.float32, scale=True),
    v2.Normalize(mean=[0.4914, 0.4822, 0.4465], std=[0.2470, 0.2435, 0.2616]),
])
dataset = datasets.ImageFolder(root='./images', transform=transforms)

train_size = int(len(dataset) * 0.8)
test_size = len(dataset)-train_size
train_dataset, test_dataset = random_split(dataset, [train_size, test_size])
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)

print(f'▶ Train set: {len(train_dataset)} | Test set: {len(test_dataset)}')
print(next(iter(train_loader))[0].shape)

4. 이미지 전처리에 관하여

아래 mean & std는 0.5로 넣어도 문제는 없지만, 좋은 성능을 위해선 직접 구해줄 필요가 있다.

torch.stack([train_dataset[i][0] for i in range(len(train_dataset))]) 이걸로 한 줄이면 끝!

transforms = v2.Compose([
    v2.ToImage(),
    v2.ToDtype(torch.float32, scale=True),
    v2.Normalize(mean=[0.4860, 0.4661, 0.4140], std=[0.2569, 0.2502, 0.2622]),
])

5. nn.Sequential() 에 관하여

지금은 시퀀셜 써도 무방할 것 같은데 제어문이 안 먹힌다고 한다. 결국 수동에 익숙해지는 수밖에 없는 것 같다.

항목SequentialManual
선언 방식레이어들을 한 줄로 묶음개별적으로 선언
커스터마이징제한적자유롭게 조건문, skip 연결 가능
추천 상황구조 단순할 때복잡한 흐름, 다양한 분기 처리할 때

아래 두 코드는 정확히 같은 기능을 한다.

# 1. 시퀀셜 O
class CNN_Sequential(nn.Module):
    def __init__(self):
        super().__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 16, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2),

            nn.Conv2d(16, 32, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.classifier = nn.Sequential(
            nn.Flatten(),
            nn.Linear(32 * 56 * 56, 10)
        )

    def forward(self, x):
        x = self.features(x)
        x = self.classifier(x)
        return x




# 2. 시퀀셜 X
class CNN_Manual(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1)
        self.conv2 = nn.Conv2d(16, 32, kernel_size=3, padding=1)
        self.fc = nn.Linear(32 * 56 * 56, 10)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        x = F.max_pool2d(x, 2)
        x = F.relu(self.conv2(x))
        x = F.max_pool2d(x, 2)
        x = x.view(x.size(0), -1)
        x = self.fc(x)
        return x

이제 시작이구나 무서운 미션...

profile
나는 AI 엔지니어가 된다.

0개의 댓글