네이버 부스트캠프 🔗/⭐주간 학습 정리

[네이버 부스트 캠프 AI Tech] Pretrained Model & Training Monitoring

Dobby98 2023. 3. 15. 16:00

본 글은 네이버 부스트 캠프 AI Tech 기간동안

개인적으로 배운 내용들을 주단위로 정리한 글입니다

 

본 글의 내용은 새롭게 알게 된 내용을 중심으로 정리하였고

복습 중요도를 선정해서 정리하였습니다

 

+ ✅일주일 동안 글쓰는 내용이 많아져서 딱딱한 말투와 재미없는 글로 변화하고 있다고 생각했습니다

그래서 학습의 효율성을 올리고 누구나 봐도 이해하기 쉽운 글로 변화를 주고 싶어서 

우리의 친구 집요정 도비 를 이번 글 부터 출연시키게 되었습니다

앞으로 함께할 도비와 그의 AI 학습 여정에 기대를 해주세요 :)

 

🎈도비의 프로필

 - 출생 : ?년 6월 28일

 - 종 : 집요정

 - 키 : 약 91cm

 - 좋아하는 것 : 양말

 - 경력 :

    - 말포이 가문 집요정  (? - 1993)

    - 호그와트 집요정 (1994 - 1998)

 - 딥러닝을 시작하게 된 계기 : 

    - 더이상 마법을 쓰지않기 위해서

 

 

 

 

 Week 2

목차

  1. Using Model
    1. model.save() & model.load()
    2. pretrained model ?
  2. Monitoring tools for Pytorch
    1. Tensorboard
    2. Weights & biases

✅ Intro -

도비는 어제까지의 공부내용을 금지된 마법을 사용해서 한번에 학습했다

 

"어제까는 모델을 어떻게 만들고

이렇게 작성한 모델을 어떻게 학습하는지에 대한 과정을 학습했군..."

 

도비는 이제 딥러닝을 실행할 수 있게 되었다 😢 - 딥러닝 보다 빠른 학습능력...

도비는 지금까지 배운 내용을 기반으로 밤새 모델을 작성하였다

import torch
import torch.nn as nn

class Dobby(nn.Module):
    def __init__(self):
        super(Dobby, self).__init__()
        self.layer1 = nn.Sequential(
            nn.Conv2d(3, 16, kernel_size=3, stride=2, padding=0),
            nn.BatchNorm2d(16),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2))

        self.layer2 = nn.Sequential(
            nn.Conv2d(16, 32, kernel_size=3, stride=2, padding=0),
            nn.BatchNorm2d(32),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2))
        
        self.layer3 = nn.Sequential(
            nn.Conv2d(32, 64, kernel_size=3, stride=2, padding=0),
            nn.BatchNorm2d(64),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2))

        self.drop_out = nn.Dropout()
        self.fc1 = nn.Linear(3 * 3 * 64, 1000)
        self.fc2 = nn.Linear(1000, 1)

    def forward(self, x):
        out = self.layer1(x)
        out = self.layer2(out)
        out = self.layer3(out)

        out = out.view(out.size(0), -1)
        out = self.drop_out(out)
        out = self.fc1(out)
        out = self.fc2(out)
        return out

이렇게 어렵게 만든 모델을 활용해 도비는 밤새 학습을 진행했다

모든 과정이 끝난 후 모델을 완성하고 도비는 다른 집요정 친구들에게 도비는 자랑하고 싶어졌다

하지만 아직 어렵게 만든 모델을 어떻게 자랑할지는 배우지 않았다 😢😢

 

흠... 그럼 무엇부터 해야할까?

도비는 혼란스럽다...

 

도비는 먼저 모델을 저장하고 활용하는 다양한 방법에 대해서 알아보기로 했다

 

1. Using Model  in pytorch 

1.1 Model.save() & Model.load()

✅Model.save()

"흠.. pytorch에는 model.save()라는 함수가 있군!!"

 

도비는 공식 문서를 통해서 model.save()라는 함수를 알아냈다

이 함수는 

 

- 모델의 학습 결과를 저장하기 위한 함수로

- 모델의 형태와 파라미터를 저장할 수 있다

- 또한 이렇게 저장된 모델은 mode.state_dict()를 활용해서 파라미터만를 저장할 수 있고

- 또는 model을  save해서 구조와 파라미터를 모두 저장할 수 있다

 

용량면에서는 model 전체를 저장하는 것이 파라미터를 저장하는 것 보다 많이 소모된다

 

도비는 예시로 코드를 작성해 보았다 - model은 앞에서 도비가 밤색 작성한 "Dobby"를 활용하였다

import os
import torch

#저장경로 지정
PATH = "./Dobby/"

#저장경로가 없다면 저장경로 생성
if not os.path.exists(PATH):
	os.makedirs(PATH)

#모델 생성
model = Dobby() #(가정)학습되었다고 가정

#방법 1. 생성한 모델 파라미터만 저장
torch.save(model.state_dict(), os.path.join(PATH, "model_parameter.pt"))  #os.path.join은 입력된 두개를 합쳐서 하나의 경로로 만들어준다
#대부분 모델은 pt or pth의 확장자로 저장된다.

#방법 2. 모델 전체 저장
torch.save(model, os.path.join(PATH, "model_all.pt"))

이제 도비는 모델을 저장하는 방법을 배웠다

이렇게 배운 방법을 활용하면 

 

- 모델 학습과정에서 결과 좋은 모델을 뽑아서 저장할 수도 있고 

- 학습한 모델의 결과를 다른 사람과 공유할 수도 있다

 


✅Model.load()

이제 도비는 저장한 모델을 갖고 친구 집요정인 도미의 집을 찾아갔다

도미

그리고 자신이 작성한 딥러닝 모델이라며 자랑을 하려고 했다

 

그러나... 도비가 한가지 잊은게 있었다

저장한 모델을 불러오는 방법을 배우지 않았던 것이다

도비는 모니터 앞에서 혼란스러워졌다

도비는 혼란스럽다...

가엾은 도비를 도와주자...

 

모델을 불러오는 방법은 생각보다 쉽다

바로 model.load()를 활용하면된다

 

여기서 주의할 점이 모델을 저장한 방식에 따라서 불러오는 방법이 다르다는 것이다

앞에서 우리가 모델을 저장할때 

 

1. 파라미터만 저장

2. 모델 전체를 저장

 

두 가지 방법을 활용하였다

따라서 이를 적용해서 도비에게 예시 코드를 작성해 주자

import torch

#모델이 저장되어있는 위치
PATH = "./Dobby/"

#방법1. 파라미터만 저장된 모델 불러오기
## 이경우 모델의 구조가 선언되어 있어야한다
### (가정) 모델 class가 해당 코드내에 있다고 가정하자
new_model = Dobby()
### 파라미터 불러와서 new_model에 넣어주기
new_model.load_state_dict(torch.load(os.path.join(PATH, "model_parameter.pt")))

#방법2. 모델 전체가 저장된 모델 불러오기
new_model2 = torch.load(os.path.join(PATH, "model_all.pt"))

도비는 예시 코드를 보고 

코드를 작성해서 친구에게 모델을 사랑하였다 - 흐뭇☺️

 

마침내 도비는 친구에게 모델을 자랑 할 수 있게 되었다

+)

도비의 추가학습

위에서 배운 model.save()와 model.load()를 활용하면 추후에 배울  earlystop이나 checkpoint를 활용할 수 있다

도비 같이 돈없는 집요정은 좋은 컴퓨팅 자원을 얻기가 쉽지않은데... 😢

 

때문에 코랩과 같은 환경에서 학습을 진행하여야한다

이런과정에서 특히, 코랩 무료는 8시간이 지나면 연결이 종료되기 때문에

학습중간에 저장하지 않으면 모델이 날아가 버린다 🛫

따라서 학습 과정에서 model을 save해서 기록해 둔다면 어느 정도 방지할 수 있다

torch.save({
        'epoch' : e,
        'model_state_dict' : model.state_dict(),
        'optimizer_state_dict' : optimizer.state_dict(),
        'loss' : epoch_loss,
        }
	f."save/checkpoint_model_{e}_{epoch_loss/len(dataloader)}_{epoch_acc/len(dataloader)}.pt")

이런식으로 체크 포인트를 저장해 두면 나중에 저장된 체크포인트를 불러와서  지정하면 해당 체크포인트의 모델을 불러올 수 있다

checkpoint = torch.load(PATH)
model.load_state_dict(checkpoint['model_state_dict'])
optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
epoch = checkpoint['epoch']
loss = checkpoint['loss']

 

 

PyTorch에서 일반적인 체크포인트(checkpoint) 저장하기 & 불러오기

추론(inference) 또는 학습(training)의 재개를 위해 체크포인트(checkpoint) 모델을 저장하고 불러오는 것은 마지막으로 중단했던 부분을 선택하는데 도움을 줄 수 있습니다. 체크포인트를 저장할 때는

tutorials.pytorch.kr

 


 

1.2 Pretrained Model

그러던 중 도미가 도비에게 대회를 나가보자고 제안했다

도비는 당당하게 자신이 만든 모델로 대회 데이터를 학습하고 제출했다

당당한 도비

그러나

.

.

.

결과는 처참했다...

도비는 혼란스럽다...

리더보드 순서를 보았을 때 

도비가 만든 모델은 뒤에서 1등이었다...

 

도비는 자신의 순위를 높이기 위해서 다른사람들이 공유한 코드를 보던 중 'backborn'이라는 단어와 'pretrained model'

이라는 단어가 눈에 들어왔다

 

도비는 검색을 하고 난 이후 이들이 활용한 모델이 다른 사람이 만들 모델을 활용해 학습한 모델이라는 것을 알게되었다

 

Cifar, ImageNet과 같은 대용량 데이터셋을 활용해서 튜닝되어 있는 모델을 다시 활용해서 학습을 진행한 것이다

 

도비는 자신도 pretrained모델을 활용해보기로 했다

 

우리가 불쌍한 도비를 도와주자✅

 

✅Pretrained Model load

기본적으로 TorchVision에서는 다양한 CNN 모델들을 제공해준다

NLP의 경우 HuggingFace에서 많은 pretrained 자연어 처리모델을 제공해준다 - Bert같은 

Timm도 있다

 

따라서 우리는 이러한 잘 만들어지 또는 잘 학습된 모델을 가져와서 사용하면 된다

#CNN 모델을 가져오는 예시
import torch
from torchvision import models

device =  torch.device('cuda' if torch.cuda.is_available() else 'cpu') #GPU 사용여부

#pretrained된 VGG16 가져오기
Vgg16 = model.vgg16(pretrained=True).to(device) #pretrained : 사용여부, 이를 GPU or CPU에 맞게 변환

너무 간단하다

 

그럼 이렇게 가져온 모델의 구조를 한번 살펴보자

from torchsummary import summary
summary(vgg, (3, 224, 224)) #input : (model, input_data_size)

torchsummary 라이브러리에 summary를 활용하면 

keras구조의 형태로 모델 구조가 나타난다

물론 논문에 위의 구조가 아주아주 자세히 나타나있지만

컴퓨터 상에서 확인할 때 이것만큼 간편한게 없다

 

✅Transfer learning - Freezing, Plus Classifier

도비는 이렇게 불러온 모델을 조금 다른 방식으로 학습하고 싶어졌다

그러던 중 새로운 방법을 알게 되었는데 바로 Freezing이다

 

불러온 학습된 모델에서 모델의 일부분을 Frozen 말 그대로 '얼음 마법'을 활용하는 것인데

쉽게 말해서 역전파 가정에서 지정한 레이어에서는 가중치 업데이트가 일어나지 않게 설정해 주는것이다

 

이를 조금더 다양하게 활용하여 

Batch마다 frozen을 다르게 설정해 줄 수 있고 과적합을 피할 수도 있다

 

그러나 최대 단점 : 귀찮다

 

🎈우리가 귀찮은 도비를 위해서 한번 예시 코드를 작성해주자!!

#앞에서 불러온 vgg 활용


#모든 레이어 가중치 업데이트 끄기 (반대로 모두 켜고, 끄는 방식도 가능)
for params in Vgg16.parameters():
	params.requires_grad = False
    
#1 이중 fc1  업데이트 켜기
Vgg16.fc1.weights.requires_grad = True
Vgg16.fc1.bias.requires_grad = True



#2. 조건문 활용해서 원하는 레이어만 켜기
for name, params in model.named_parameters():
	if name in ['linear.0.weight', 'linear.2.weight']:
    		params.requires_grad = True

 

 

이제 차별성을 준 방법을 적용한 도비는 모델을 학습시키려 했다

 

그러나 모델의 학습 output의 형태가 조금 달랐다 

도비는 혼란스럽다...

바로 모델에서 분류하는 클래스가 다르기 때문이다 

쉽게 말해 ImageNet으로 학습된 모델의 경우 1000개의 클래스가 있지만

이번 도비가 참여한 대회에는 10개의 클래스 밖에 존재하지 않는다....  

 

혼란스러운 😢 도비에게 한 줄기 빛을 내려주자⭐

 

vgg16 = models.vgg16(pretrained=True).to(device) #모델을 불러오기

#나만의 VGG모델 선언하기
class MyVgg(nn.Module):
	def init (self):
            super(MyVgg, self).__init__()
            self.vgg16 = models.vgg16(pretrained = True) 
            self.linear_layer = nn.Linear(1000, 10) #pretrained 모델을 지나서 나오는 아웃풋을 다시 Linear를 지나서 우리의 데이터셋 클래스에 맞추기
        
   	def forward(self, x):
            x = self.vgg16(x)
            return self.linear_layer(x)

간단하게  마지막에 linear를 추가해주어서 아웃풋의 크기를 맞춰주었다

우리의 데이터로 추가학습하기 때문에 마지막 Linear도 학습이 진행될 것이다

 

물론 앞에서 적용한 frozen을 활용해서 복합적으로 활용할 수도 있다!!


2. Monitoring tools for Pytorch

우리가 작성해준 코드를 활용해서 도비는 대회에서 좋은 성적을 거두었다

이후 도비는 자신이 활용한 모델의 학습 과정을 되돌아 보았다

 

대회에 참여했을 때 모델의 학습이 중간에 멈추었지만

도비는 이걸 모르고 하루 동안 방치했던 적이 있었다

 

대회와 같이 기간이 정해져있는 경우 생각만해도 끔찍하다...

 

도비는 자신의 모델 학습이 잘 되고 있는 감시할 방법이 궁금해졌다

그러던 중 도비는 Monitoring tools이 존재한다는 것을 알게 되었다

 

 

✅이번에 우리가 도비에게 Monitoring tool에 대해서 알려줄 차례이다

2.1 Tensorboard

tensorboard는 tensorflow의 프로젝트로 제작된 시각화 도구이다

모델의 학습 그래프와 같이 모델의 학습 과정을 시각적으로 나타낸다

 

물론 tensorflow의 프로젝트로 시작되었지만 

다.행.스.럽.게도 pytorch에서도 사용이 가능하다 

도비의 마법과 비슷하다

 

PyTorch로 TensorBoard 사용하기

TensorBoard는 머신러닝 실험을 위한 시각화 툴킷(toolkit)입니다. TensorBoard를 사용하면 손실 및 정확도와 같은 측정 항목을 추적 및 시각화하는 것, 모델 그래프를 시각화하는 것, 히스토그램을 보는

tutorials.pytorch.kr

 

도비에게 보여줄 예시 코드는 다음과 같다

import torch
from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter() #tensorboard를 위해서 writer 선언

#모델에 사용할 데이터 정의
x = torch.arange(-5, 5, 0.1).view(-1, 1)
y = -5 * x + 0.1 * torch.randn(x.size())

#모델, 손실함수, 옵티마이저 지정
model = torch.nn.Linear(1, 1)
criterion = torch.nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr = 0.1)

def train_model(iter):
    for epoch in range(iter):
        y1 = model(x)
        loss = criterion(y1, y)
        writer.add_scalar("Loss/train", loss, epoch) ## 각 에폭, loss를 scalar에 저장 (저장위치, 저장할 것들)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

train_model(10)
writer.flush() #값 기록, disk에 쓰기

writer.close()#기록이 더이상 필요없으면

간단히 말하자면 위 코드는 scalar : epoch이나 loss같은 것들을 기록하는 방법이다

SummaryWriter()의 .add를 활용해 값을 넣어지고 .flush()로 기록하는 것이다

그리고 더 이상 기록이 필요없으면 .close()로 닫아주면 된다

 

$ pip install tensorboard
$ tensorboard --logdir=runs

http://localhost:6006/

그리고 난이후 tensorboard를 설치해주고 위에서 저장한 위치를 --logdir와 바꾸어 입력해주어 실행하게 되면  localhost:6006에 페이지가 열리는데

이곳에 들어가면 다음과 같이 우리가 넣은 Scalars의 값이 그래프로 그려져서 나타난다

 

tensorboard에는 다양한 기능이 존재하고 있지만 

이를 모두 다루기에는 시간이 부족하기 때문에 도비에게 직접해보라고 명령😢 했다

 

그래도 도비가 실습하기 편하게 대표적으로 많이 쓰이는 것을 정리 하면 아래와 같다

 

스칼라(scalar) :  epoch과 loss와 같이 상수 값의 연속을 표시

그래프(graph) : computational graph를 표시

히스토그램(historgram) : 가중치등 값의 분포를 표시

이미지(Image) : 예측 값과 실제 값을 비교 표시

메쉬(mesh) : 3D 형태로 데이터를 표시 - 조금 신기

mesh 예시

 

 

 

2.2 Weights & biases

Tensorboard 말고도 다른 툴이 존재한다 

 

PyTorch | Weights & Biases Documentation

Open In Colab

docs.wandb.ai

많이 알면 알 수록 좋은 거니까 이것도 도비에게 알려주자 ⭐

먼저 코드에서 실행하기 전에

사이트에서 가입을 하고 API키를 받아야한다

그리고 사이트에서 새로운 프로젝트를 생성하고 이름을 지정해주어야 한

 

 wandb 라는 라이브러리를 활용하면 Weights & biases을 실행할 수 있다


import wandb
wandb.init(config=args) #confing = 학습에 활용된 하이퍼 파라미터 : dic type

model = ... # set up your model 사용할 모델 지정

# Magic
wandb.watch(model, log_freq=100)

#학습과정
model.train()
for batch_idx, (data, target) in enumerate(train_loader):
    output = model(data)
    loss = F.nll_loss(output, target)
    loss.backward()
    optimizer.step()
    if batch_idx % args.log_interval == 0:
        wandb.log({"loss": loss}) #기록 앞에서 본 add와 같은기능

 

이런식의 과정을 통해서 학습에서 로그가 기록되고 이를 사이트에서 시각화해서 볼 수 있다

역시 백문이불여일라고 직접해보면 금방 알게 될 것이다 

이것도 도비에게 해보라고 명령했다 😢

 

다행스럽게도 위대한 머글 중 한 분께서 깔끔하게 정리해놓으신 글이 있길래 도비에게 주었다

 

3-1. Training 과정 Visualization (Feat. WandB)

안녕하세요. 이번 글에서는 training 과정을 visualization 해주는 패키지를 소개하려고 합니다. 기본적으로 pytorch에서는 tensorboard를 사용하여 loss, accuracy 등 다양한 metrics와 weight, gradient 값들을 histogra

89douner.tistory.com

관심이 있다면 블로그 글을 읽어보면서 실습하면 도움이 많이 될 것이다

 


오늘은 도비는 딥러닝 과정에서

1. 모델을 저장하고 저장한 모델을 불러오는 방법

2. Pretrained된 모델을 활용하는 방법 

3. 전이학습의 다양한 방법

4. 딥러닝 모델의 학습과정 및 결과 시각화 툴에 대해서 알아 보았다

 

이정도 학습 속도이면 조만간 도비는 집요정이 아니라 딥러닝 요정이 될것 같다 :)