Skip to content

Latest commit

 

History

History
253 lines (186 loc) · 7.44 KB

10-4-2. ImageFolder2.md

File metadata and controls

253 lines (186 loc) · 7.44 KB

0. 들어가기 전에

  • 이번 시간에는 지난시간 강의에 이어, 내 사진들을 분류하는 CNN 모델을 만들 것이다!
  • 모델을 저장하고 다시 불러오는 법을 배울 것이다.



1. Pretrained model이란?

  • Pretrained model이란, 이미 학습을 진행한 모델을 불러와서 이용하는 것이다.
  • 모델을 이용할 때마다 학습시키는 것 보다, 학습 된 모델을 불러와서 이용하는게 더 시간적으로 좋기 때문!



2. Pretrained model 이용 방법

<기존 방법>

(1) CNN 모델의 구조를 미리 만들어 둔다.

(2) 그 구조를 변수에 담는다.

(3) 변수(모델)에 Train 데이터를 통해 학습시킨다.


<Pretrained 된 모델 불러와서 이용하기>

(1) (이용할 Pretrained 모델과 동일한) CNN 모델의 구조를 미리 만들어 둔다.

(2) 그 구조를 변수에 담는다.

(3) 변수(모델)에 Pretrained 모델을 불러온다.

  • Pretrained 모델을 이용하는 것은 미리 학습 된 모델을 이용하는 것이다. 즉, '모델에 Train 데이터로 학습 시키는 과정을 생략하는 것'이다.



3. CNN 모델 구성하기

(1) Input

  • 나의 이미지

(2) CNN 레이어

1) Layer 1

  • Convolution
  • ReLU
  • MaxPool

2) Layer 2

  • Convolution
  • ReLU
  • MaxPool

3) FC Layer (Fully-Connected Layer)

  • view (FC를 위한 작업)
  • FC1
  • ReLU
  • FC2

(3) Cross Entropy Loss

  • SoftMax
  • NLL loss



4. 구성한 CNN 모델 코드로 작성해 보기

# 1. Input Image : 3 * 64 * 128 (RGB 3채널 * Height * Width)

# 2. Layer 1
Convolution layer = (in_c=3, out_c=6, kernel_size = 5, stride=1) # RGB의 3 채널을 받아서, output은 6채널로!
MaxPool layer = (kernel_size=2, stride=2)

# 3. Layer 2
Convolution layer = (in_c=6, out_c=16, kernel_size=5, stride=1) # 6 채널을 받아서, output은 16채널로!
MaxPool layer = (kernel_size=2, stride=2)

# 4. FC Layer
view # Layer 2 까지 거친 output은 [16, 13, 29] 이다. FC를 이용하기 전에 직선으로 펼치기 위해 batch_size * [16, 13, 29]를 한다. => batch_size * [6032]
Fully_Connect layer # input으로 6032를 받아서, output은 120으로!
Fully_Connect layer # input으로 120을 받아서, output은 2로! Grey인지 Red인지 구분하는 Binary classification이기 때문이다.



5. 전체 코드 작성해보기

# 1. 라이브러리 로드
import torch
import torch.nn as nn
import torch.nn.functional as F
import torcdh.optim as optim
from torch.utils.data import DataLoader
import torchvision
import torchvision.transform as transforms

# 2. GPU 사용 설정
device = 'cuda' if torch.cuda.is_available() els 'cpu'

torch.manual_seed(777) # 랜덤 값 Seed 고정
if device == 'cuda':
  torch.cuda.manual_seed_all(777)

# 3. 데이터 로드
trans = transforms.Compose([
  transforms.ToTensor() # 불러올 때 Tensor로 바꿔서 불러옴
])

train_data = torch.vision.datasets.ImageFolder(root='./custom_data/train_data', transform = trans) # 지난 시간에 만들어 둔 train_data!

data_loader = DataLoader(dataset = train_data, batch_size = 8, shuffle = True, num_workers=2) # Data Loader 설정

# 4. CNN 모델 만들어 놓기
class CNN(nn.Module):
  def __init_(self):
    super(CNN, self).__init()
    
    # Layer 1
    self.layer1 = nn.Sequential(
      nn.Conv2d(3, 6, 5), # RGB 3채널 입력, 6채널 출력, 필터 5
      nn.ReLU(),
      nn.MaxPool2d(2),
    )
    
    # Layer 2
    self.layer2 = nn.Sequential(
      nn.Conv2d(6, 16, 5), # 6채널 입력, 16채널 출력, 필터 5
      nn.ReLU(),
      nn.MaxPool2d(2),
    )
    
    # FC Layer
    self.layer3 = nn.Sequential(
      nn.Linear(16 * 13 * 29, 120), # FC1
      nn.ReLU(),
      nn.Linear(120, 2) # FC2
    )
  
  # 모델의 forward 정의
  def forward(self, x):
    out = self.layer1(x) # Layer 1 통과
    # print(out.shape) # 꿀팁! 이런 방식으로 모델이 forward할 때 점차 바뀌는 output의 shape을 체크할 수 있다. 나중에 추가적으로 모델의 레이어 구조 등을 변형하고 싶을 때 이 방법이 유용하다. 이 코드로 shape만 확인하고 바로 꼭 지워주는 센스! 
    out = self.layer2(out) # Layer 2 통과
    # print(out.shape)
    out = out.view(out.shape[0], -1) # Flatten으로 펼치기
    # print(out.shape)
    out = self.layer3(out) # FC1 & FC 2 통과
    return out

# (생략 가능) 5. CNN 모델을 오류 없이 만들었는지 테스트 해보기
net = CNN().to(device)
test_input = (torch.Tensor(3, 3, 64, 128)).to(device)
test_out = net(test_input)

# 6. Optimizer와 Loss 설정
optimizer = optim.Adam(net.parameters(), lr = 0.00005)
loss_func = nn.CrossEntropyLoss().to(device)

total_batch = len(data_loader)
epochs = 7

# 7. 모델 학습 시작!
for epoch in range(epochs):
  avg_cost = 0.0
  for num, data in enumerate(data_loader):
    imgs, labels = data
    
    imgs = imgs.to(device) # 독립 변수
    labels = labels.to(device) # 종속 변수
    
    out = net(imgs) # 모델에 독립 변수를 넣어 Prediction 얻기
    loss = loss_func(out, labels)
    
    # BP
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    
    avg_cost += loss / total_batch
    
  print('[Epoch:{}] cost = {}'.format(epoch+1, avg_cost))
print('Learning Finished!')
    
# 8. 학습된 CNN 모델 저장하기
torch.save(net.state_dict(), "./model/model.pth") # 경로를 지정해서 학습된 모델 저장

# 9. Pretrained 된 CNN 모델 : 불러와서 이용하기

'''
<기존 방법>
 (1) CNN 모델의 구조를 미리 만들어 둔다.
 (2) 그 구조를 변수에 담는다.
 (3) 변수(모델)에 Train 데이터를 통해 학습시킨다.
 
<Pretrained 된 모델 불러와서 이용하기>
 (1) (이용할 Pretrained 모델과 동일한) CNN 모델의 구조를 미리 만들어 둔다.
 (2) 그 구조를 변수에 담는다.
 (3) 변수(모델)에 Pretrained 모델을 불러온다.
  - Pretrained 모델을 이용하는 것은 미리 학습 된 모델을 이용하는 것이다. 즉, '모델에 Train 데이터로 학습 시키는 과정을 생략하는 것'이다.
'''

new_net = CNN().to(device) # 이용할 Pretrained 모델과 동일한 구조를 가진 모델!
new_net.load_state_dict(torch.load('./model/model.pth')) # 거기에 Pretrained 모델을 담는다.

# (생략 가능) 10. Pretrainted 된 CNN 모델 : 구조 확인
print(net.layer1[0])
print(new_net.layer1[0])

print(net.layer1[0].weight[0][0][0])
print(new_net.layer1[0].weight[0][0][0])

net.layer1[0].weight[0] == new_net.layer1[0].weight[0]

# 11. Pretrained 된 CNN 모델 : 테스트 데이터 로드 (기존과 동일)
trans = torchvision.transforms.Compose([
  transforms.Resize((64, 128))
  transforms.ToTensor()
])

test_data = torchvision.datasets.ImageFolder(root='./custom_data/test_data', transform = trans) # test data 로드

test_set = DataLoader(dataset = test_data, batch_size = len(test_data)) # DataLoader 이용!

# 12. Pretrainted 된 CNN 모델 : 모델 평가 (기존과 동일)
with torch.no_grad(): # 모델 평가시에는 Gradient Descent 안함!
  for num, data in enumerate(test_set):
    imgs, label = data
    imgs = imgs.to(device)
    label = label.to(device)
    
    prediction = net(imgs)
    
    correct_prediction = torch.argmax(prediction, 1) == label
    
    accuracy = correct_prediction.float().mean()
    print('Accuracy:', accuracy.item())