이번에는 훈련한 모델을 저장하는 방법과 불러오는 방법에 대해 알아보려고 한다. 1편에서 사용한 코드를 거의 그대로 사용하며, Trainer선언 부분만 바뀌는 정도이며, 전체 코드는 깃허브에 있으니 참고하기 바란다.
요약
모델을 특정경로에 체크포인트 저장하기
모델의 하이퍼파라미터 저장하기
체크포인트로 모델을 불러오기
모델을 특정경로에 체크포인트 저장하기
모델을 저장하는 것은 각 epoch마다 자동으로 저장된다. Jupyter 기준으로 설명하면, Jupyter 파일의 같은 디렉터리 내에 lightning_logs폴더에 각 validation_step마다 저장되는 것을 알 수 있다. 하지만, 나는 여기서 특정 경로에 저장하는 방법에 대해 소개하려고 한다.
# 이전 코드
trainer = pl.Trainer(max_epochs=2)
위의 코드는 1편에서 사용된 코드이다. 여기서 저장할 특정경로를 지정하지 않았기 때문에 실행파일과 동일한 디렉토리에 모델이 저장된다.
trainer = pl.Trainer(
max_epochs=2,
# 저장 경로 지정
default_root_dir='ckpt/'
)
위의 코드는 수정된 코드이며, 'ckpt/' 경로에 모델이 저장되는 것이다. 그림으로 살펴보자.
ckpt 폴더 내에 무언가 저장된 것을 볼 수 있는데 각각 요소에 대해 설명하겠다.
version_숫자 : n번째에 실행했을때 저장되는 것들이다.
hparams.yaml : hyperparameter들이 저장되어 있는 yaml 파일이다. 이에 대해서는 밑에서 다루도록 하겠다.
metrics.csv : 우리가 측정하려는 metric들이 각 epoch마다 csv 형태로 저장되는 파일이다.
checkpoints : 모델이 훈련하고 각 epoch가 끝날 때마다 얼마나 훈련되어 있는지 저장되어 있는 파일이다. 이 파일을 통해 어떠한 오류로 실험이 중단되면 저 ~~~.ckpt 파일을 읽어와서 실험을 진행할 수 있다. (그래서 사용한다.)
우리는 모델의 파라미터만 저장하고 하이퍼 파라미터는 저장하지 않았다. 그래서 하이퍼 파라미터를 저장하는 방법에 대해 다루려고 한다.
모델의 하이퍼파라미터 저장하기
하이퍼 파라미터를 저장하는 방법은 간단하다. 코드 한줄을 추가하면 된다.
class LitAutoEncoder(pl.LightningModule):
def __init__(self, encoder, decoder):
super().__init__()
# 코드 추가
self.save_hyperparameters()
self.encoder = encoder
self.decoder = decoder
# 코드 중략
self.save_hyperparameters() 이 함수를 하나 추가하면 된다. 그리고 코드를 돌리면(훈련하면) 다음과 같이 나온다.
체크포인트로 모델을 불러오기
model = LitAutoEncoder(Encoder(), Decoder())
trainer = pl.Trainer()
# 수정 코드
trainer.fit(model,
train_dataloaders=train_loader,
val_dataloaders=valid_loader,
# 체크포인트 저장한 경로
ckpt_path='ckpt/lightning_logs/version_0/checkpoints/epoch=1-step=96000.ckpt')
여기서 Trainer에서는 건드릴 것이 없다. 그 이유는 ckpt파일에 정보가 저장되어 있다. 그래서 필요한 것은 다음과 같다.
model : 훈련시킬 모델의 틀
dataloader: 훈련시킬 데이터를 다시 가져와야 함
ckpt_path = 훈련되어있는 parameter를 불러올 경로
다음 것들을 알면, 이제부터 훈련이 날아가서 처음부터 다시 돌리는 경우가 안 생긴다. 파이토치 라이트닝을 사용한다면, 꼭 이것을 알아주었으면 한다. 다음은 OverFitting을 방지하는 Early stopping 방법에 대해 소개하려고 한다.
# 필요한 라이브러리 선언
import os
import torch
import numpy as np
import matplotlib.pyplot as plt
from torch import nn
import torch.nn.functional as F
from torchvision import transforms
from torchvision.datasets import MNIST
from torch.utils import data
import pytorch_lightning as pl
데이터셋 선언(분할) 및 확인
dataset은 손글씨로 유명헌 MNIST 데이터셋을 사용한다. 자세한 정보는 여기를 확인하면 된다.
1편을 보시면 알겠지만, 저는 한국어로 입력했을 때, 영어로 출력하도록 Task를 만들었습니다. 그래서 저는 한국어-영어 쌍으로 훈련된 모델을 허깅페이스에서 가져와서 사용했습니다. 궁금하신분은 링크를 클릭해보시면 됩니다. 간단히 말하면 한국어를 입력했을 때, 영어로 출력하는 KoBART 모델입니다.
model_id = 'chunwoolee0/circulus-kobart-en-to-ko'
model = AutoModelForSeq2SeqLM.from_pretrained(args['model_path'], cache_dir='/home/hgjeong/hdd1/hub')
tokenizer = AutoTokenizer.from_pretrained(args['tokenizer'])
이번에는 훈련이 잘되고 있는지 확인하기 위해 필요한 것들에 대해 알아보려고 합니다. 모델 인수들이 잘 입력되었는지 log에 확인하기 위한 logger 작성과 훈련 loss들이 잘 훈련되고 있는지에 대해 알려주는 wandb, tensorboard에 대해 알아보려고합니다.(tensorboard는 추후에 작성하도록 하겠습니다.)
logger 작성
import logging
import sys
def get_logger(name: str) -> logging.Logger:
"""Return logger for logging
Args:
name: logger name
"""
logger = logging.getLogger(name)
logger.propagate = False
logger.setLevel(logging.DEBUG)
if not logger.handlers:
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(logging.Formatter("[%(asctime)s] %(message)s"))
logger.addHandler(handler)
return logger
logging.getLogger(name) : 이름이 'name'인 로거 객체를 생성하거나, 존재하는 경우 해당 로거를 반환한다.
logger.setLevel(logging.DEBUG) : 로거의 로그 레벨을 'DEBUG'로 설정
logger.handler : 로거에 핸들러(콘솔, 파일)가 없는 경우 설정
handler.setFormatter(logging.Formatter("[%(asctime)s] %(message)s"))는 로그 메시지의 형식을 설정
%(asctime)s는 로그가 기록된 시간, %(message)s는 로그 메시지를 나타낸다.
이번에는 Dataset 구축 및 DataLoader 구축에 대해 설명하려고 한다. 근데 생각을 해보았을 땐, 이 글을 보는 사람들은 데이터셋 구축은 관심이 없을 것이고 아무래도 어떻게 코드를 짜는지 궁금할 것이라 생각하기 때문에 데이터셋 구축에 대해서는 설명하지 않고 데이터셋이 어떻게 구성되어 있는지만 말하려고 한다.
Dataset 구축
# Text : Encoder
# function : Decoder
# 예시
# 음료 개수, 메뉴 개수, 메뉴 개수 -> drink(quantity=1); menu(quantity=3); menu(quantity=2);
{"Text": "아이스 카페 라떼 4잔 주세요 그 외에 따듯한 그린티 라떼 줄래?", "function": "ICE_cafe_latte(quantity=4); HOT_greentea_latte(quantity=1); "}
데이터셋의 구성은 다음과 같다.
Encoder에는 한국어로 되어있는 Text
Decoder는 메뉴에 대해 요약된 Text
결론은 카페 메뉴에 대한 text가 들어갔을 때, 영어로 요약된 text가 출력되도록 하는 것이다.
DataLoader 구축
라이브러리
from datasets import Dataset
from torch.utils.data import DataLoader
from tokenizers.processors import TemplateProcessing
라이브러리는 다음과 같이 사용합니다.
데이터셋 로딩
# json을 dataset으로 변환
dataset = Dataset.from_json(fname)
토크나이저 설정
# cls token과 sep token이 설정되어있지 않으면 설정
if not tokenizer.cls_token:
tokenizer.cls_token = tokenizer.eos_token
if not tokenizer.sep_token:
tokenizer.sep_token = tokenizer.eos_token
토크나이저에 클래스 시작(cls_token)과 분리(sep_token) 토큰이 설정되어 있지 않다면, 각각을 문장 종료(eos_token) 토큰으로 설정
요약을 하면, 입력데이터를 BART의 출력에 맞도록 tokenizing 하는 것이라고 생각하면 된다.
train mode : encoder, decoder 모두 tokenizing
not train mode : encoder만 tokenizing
그 이유는 테스트 모드의 경우에는 decoder는 예측을 하는 것이기 때문에 정답이 없다.
데이터셋 전처리 적용
# dataset에 대해 전처리 함수로 매핑, columns제거 및 torch tensor로 변환
dataset = dataset.map(preprocess_function,remove_columns=dataset.column_names).with_format("torch")
dataset에 대해 전처리를 적용한 뒤, 이전에 필요 없는 column을 삭제한 뒤, pytorch 형태로 변환한다.
오늘은 이전에 캡스톤디자인에서 BART를 이용해서 Text를 요약하는 Task를 진행했었는데, 이것에 대해 설명하면서 코드를 어떻게 작성했는지 설명하려고 한다.
간단하게 요약하면 다음과 같다. 카페 메뉴에 대한 Text가 입력이 되면, BART를 이용해서 영어로 번역한 뒤 필요한 내용만 출력하는 것이다. 아이스 아메리카노 하나, 카페라떼 하나를 영어로 요약하는 것이다. 다음과 같은 Task를 위해 BART를 훈련시키는 코드에 대해 설명하겠다.
요즘 딥러닝과 관련해서 파이토치 라이트닝을 다룰일이 많은데 생각보다 한국어로 되어있는 Document, Blog가 너무 적어서 직접 적어보려고 한다. 생각보다 글솜씨가 좋지 않더라도 많은 도움이 되었으면 한다.
파이토치를 사용하는 이유는?
다음과 같은 딥러닝 파이프라인에서 파이토치 라이트닝은 다음과 같은 추상화 계층을 이용해 딥러닝 파이프라인 설계를 매우 간단하게 만들어주기 때문에 사용한다.
LightningModule은 모델 구조, 훈련 방법, 평가 방법, 테스트 방법, 추론 방법, 옵티마이저 등을 정의하는 클래스이다.
Trainer은 LightningModule에서 정의한 모델을 훈련 및 평가하는 방법을 추상화한 클래스이다.
간단하게 LightningModule에는 무엇이 있으며 Trainer에는 무엇이 있는지 간단하게 살펴보고 포스팅을 마치려고 합니다.
LightningModule
필수적으로 사용하는 코드 위주로 적었습니다.
__init__
초기화를 정의
forward( )
데이터를 모델에 넣어서 실행
training_step( )
모델 훈련시 사용하는 코드
validation_step( )
모델 평가시 사용하는 코드
test_step( )
모델 테스트시 사용하는 코드
predict_step( )
모델 예측시 사용하는 코드
configure_optimizers( )
optimizer, learning rate 스케줄러를 선택합니다. GAN의 경우 여러가지 optimizer를 가질 수 있습니다.
Trainer
Trainer에 대해 선언하는 방법과 GPU를 사용하는 방법에 대해서 설명해드리겠습니다.
모델 훈련
model = MyLightningModule()
trainer = Trainer()
# 훈련만 하는 경우
trainer.fit(model, train_dataloader)
# 훈련과 평가를 하는 경우
trainer.fit(model, train_dataloader, val_dataloader)
모델 평가
model = MyLightningModule()
trainer = Trainer()
trainer.validate(model=model, dataloaders=val_dataloaders)
모델 GPU 사용
# CPU 사용
trainer = Trainer(accelerator="cpu")
# Training with GPU Accelerator using 2 GPUs
# 훈련시 GPU 2개를 사용
trainer = Trainer(devices=2, accelerator="gpu")
# Training with TPU Accelerator using 8 tpu cores
# 훈련시 8개의 TPU 사용
trainer = Trainer(devices=8, accelerator="tpu")
# Training with GPU Accelerator using the DistributedDataParallel strategy
# 4개의 GPU를 사용하며, DDP 방식 사용
trainer = Trainer(devices=4, accelerator="gpu", strategy="ddp")