본문 바로가기
AI/딥러닝

[AI 부트캠프] DAY 91 - 트랙학습 CV 5

by HOHHOH 2023. 11. 29.

[오늘의 일지]

트랙학습 실시간 강의 - Transfer learning 실습

[상세 내용]

Transfer learning 실습

- 이번 실시간 수업에서는 어제 녹화강의에서 배웠던 transfer learning을 적용시켜 보는 내용을 배웠습니다. 녹화강의보다 수월했던 점은 기존 데이터에 단계별로 기본 CNN으로 시작해서 이미 만들어져 있는 ResNet을 가져와서 성능을 비교해 보고 마지막으로 pre-trained 되어있는 transfer learning을 적용시키는 것까지 이어졌다는 것입니다. 

 

ResNet

- ResNet은 매우 깊은 신경망을 훈련하고 최적화하는 데 어려움을 겪는 기존의 문제를 해결하기 위해 제안되었습니다. 이 아키텍처는 이미지 인식 및 다양한 컴퓨터 비전 작업에 사용되며, 특히 매우 깊은 네트워크를 구축할 때 그 성능이 두드러지게 나타납니다.

- ResNet의 핵심 아이디어는 잔여 학습(residual learning)입니다. 일반적인 딥 뉴럴 네트워크에서는 입력이 네트워크를 통과하면서 차원을 변경하거나 변형시키는 여러 층(레이어)으로 구성됩니다. 이러한 변형은 학습 가능한 가중치를 사용하여 수행됩니다. 그러나 이러한 변형이 너무 깊은 네트워크에서는 학습하기 어렵고, 성능이 향상되지 않는 문제가 발생할 수 있습니다.

- ResNet은 이 문제를 해결하기 위해 레지듀얼 블록(Residual Block)을 도입했습니다. 이 블록은 입력 데이터를 변형하는 대신, 입력 데이터를 그대로 전달하면서 변형된 부분만을 학습하는 아이디어를 기반으로 합니다.

- Output=Input+F(Input)

- 여기서 은 입력 데이터를 변형하는 함수를 나타냅니다. 이러한 구조는 입력과 출력 간의 잔여(residual)를 학습하는 것이기 때문에 "잔여 네트워크"라는 이름이 붙여졌습니다.

- ResNet은 이러한 레지듀얼 블록을 여러 층에 걸쳐 쌓아 올린 것으로, 이를 통해 매우 깊은 네트워크를 구성할 수 있게 되었습니다. 덕분에 훈련이 쉽고 높은 정확도를 얻을 수 있게 되었으며, 다양한 비전 태스크에서 우수한 성능을 보여주고 있습니다.

 

출처:https://medium.com/@siddheshb008/resnet-architecture-explained-47309ea9283d

 

- ResNet 예시 코드

import torch
import torch.nn as nn
import torch.nn.functional as F

# Residual Block 정의
class ResidualBlock(nn.Module):
    def __init__(self, in_channels, out_channels, stride=1, downsample=None):
        super(ResidualBlock, self).__init__()
        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(out_channels)
        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(out_channels)
        self.downsample = downsample

    def forward(self, x):
        residual = x
        out = self.conv1(x)
        out = self.bn1(out)
        out = F.relu(out)
        out = self.conv2(out)
        out = self.bn2(out)

        if self.downsample:
            residual = self.downsample(x)

        out += residual
        out = F.relu(out)
        return out

# 간단한 ResNet 네트워크 정의
class ResNet(nn.Module):
    def __init__(self, block, layers, num_classes=10):
        super(ResNet, self).__init__()
        self.in_channels = 64
        self.conv = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False)
        self.bn = nn.BatchNorm2d(64)
        self.layer1 = self.make_layer(block, 64, layers[0])
        self.layer2 = self.make_layer(block, 128, layers[1], 2)
        self.layer3 = self.make_layer(block, 256, layers[2], 1)
        self.avg_pool = nn.AdaptiveAvgPool2d((1, 1))
        self.fc = nn.Linear(256, num_classes)

    def make_layer(self, block, out_channels, blocks, stride=1):
        downsample = None
        if (stride != 1) or (self.in_channels != out_channels):
            downsample = nn.Sequential(
                nn.Conv2d(self.in_channels, out_channels, kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(out_channels))
        layers = []
        layers.append(block(self.in_channels, out_channels, stride, downsample))
        self.in_channels = out_channels
        for _ in range(1, blocks):
            layers.append(block(out_channels, out_channels))
        return nn.Sequential(*layers)

    def forward(self, x):
        out = self.conv(x)
        out = self.bn(out)
        out = F.relu(out)
        out = self.layer1(out)
        out = self.layer2(out)
        out = self.layer3(out)
        out = self.avg_pool(out)
        out = out.view(out.size(0), -1)
        out = self.fc(out)
        return out

# 예시로 ResNet-18 생성
def resnet18():
    return ResNet(ResidualBlock, [2, 2, 2])

# 네트워크 인스턴스화
net = resnet18()
print(net)

 

Transfer learning 적용

- 벌 이미지를 구별하는 데이터를 학습했던 설정을 불러와서 개와 고양이를 구별하는 데이터에 적용시켰을 때 처음 이미지 크기만 잘 맞추고 적용시키면 정확도가 매우 많이 올라가는 것을 확인했습니다.

model_ft = models.resnet18(weights='IMAGENET1K_V1')
num_ftrs = model_ft.fc.in_features
# 여기서 각 출력 샘플의 크기는 출력 크기로 설정합니다.
model_ft.fc = nn.Linear(num_ftrs, 2)

model_ft = model_ft.to(device)

criterion = nn.CrossEntropyLoss()

# 모든 매개변수들이 최적화되었는지 관찰
optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.0001, momentum=0.9)

# 7 에폭마다 0.1씩 학습률 감소
exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)

 

[마무리]

 오늘은 어제 이론적으로만 이해했었던 transfer learning에 대해서 실습 코드를 이용해서 더 간단하게 이해하는 과정을 가졌습니다. 아직까지 이미지의 크기를 맞추고 차원을 구별하는 부분에서 미숙함이 있는데 시간을 더 내서 자세하게 공부해 봐야 될 거 같습니다.

반응형

댓글