no image
[Pytorch Lightning] 튜토리얼 3 - GPU를 사용해서 훈련해보자
오늘은 GPU를 이용해서 모델을 훈려시키는 방법에 대해 소개해보려고 한다. 본론으로 들어가서 GPU를 사용한 것과 사용하지 않았을 때 시간이 차이나는 것을 확인해보자 GPU를 사용했을 때 대략적으로 2배 정도 빠른 것을 볼 수 있다. 그래서 인공지능을 위해서는 GPU가 필수적이면, 시간을 아껴준다. 그렇다면 gpu는 어떻게 사용하는 것일까? 그에 대해 알아보자 GPU 사용해보기GPU를 사용하는 방법은 크게 2가지로 나뉜다. 자동으로 할당하게 하는 경우와 우리가 직접 할당하도록 하는 방법이 있다. 일단 자동으로 할당하기trainer = pl.Trainer(accelerator="gpu", devices="auto")accelerator  : 가속기를 의미하며 , gpu, tqu, hpu가 있는데 일반적으로..
2024.07.23
no image
[Pytorch Lightning] 튜토리얼 2 - 모델을 저장하고 불러오자
이번에는 훈련한 모델을 저장하는 방법과 불러오는 방법에 대해 알아보려고 한다. 1편에서 사용한 코드를 거의 그대로 사용하며, Trainer선언 부분만 바뀌는 정도이며, 전체 코드는 깃허브에 있으니 참고하기 바란다.요약모델을 특정경로에 체크포인트 저장하기모델의 하이퍼파라미터 저장하기체크포인트로 모델을 불러오기 모델을 특정경로에 체크포인트 저장하기모델을 저장하는 것은 각 epoch마다 자동으로 저장된다. Jupyter 기준으로 설명하면, Jupyter 파일의 같은 디렉터리 내에 lightning_logs폴더에 각 validation_step마다 저장되는 것을 알 수 있다. 하지만, 나는 여기서 특정 경로에 저장하는 방법에 대해 소개하려고 한다.# 이전 코드trainer = pl.Trainer(max_epoc..
2024.07.21
no image
[Pytorch Lightning] 튜토리얼 1 - 모델을 만들고 훈련시키기
오늘은 파이토치 라이트닝과 관련해 기본적인 자료가 부족해서 직접 작성해보기로 했다. 공식 홈페이지를 기반으로 했으니, 많이 도움이 될 것이라고 생각한다. 코드는 여기를 참고하면 된다.대략적인 구조는 다음과 같다. 데이터를 모아서 DataLoader를 이용해 train, valid, test로 분할한다.Model을 선언한다.훈련때마다 사용하는 방법을 선언한다. (e.g., train_step에서는 어떻게 진행하고 ...)Model과 훈련 방법을 Pytorch Lightning Module에 선언한다.Hyper Parameter + Lighitning Module을 Trainer에 추가한다.Trainer를 통해 훈련된 모델(Trained Model)을 사용한다. 요약라이브러리 설치데이터셋 선언모델 구조 만들..
2024.07.19
no image
[Pytorch Lightning] BART를 이용해 Text를 요약해보자 - 4 (완)
1편 : 프로젝트 요약 및 LightningModule 설계2편 : Dataset 구축 및 DataLoader 구축3편 : logger 작성, wandb 연동 및 확인4편 : 모델 로딩 및 실행결과(wandb) 확인이번에는 작성한 코드를 이용해서 모델 로딩 및 실행결과(wandb) 확인을 해보겠습니다.환경설정 및 초기화사용할 모델 및 토크나이저 선택1편을 보시면 알겠지만, 저는 한국어로 입력했을 때, 영어로 출력하도록 Task를 만들었습니다. 그래서 저는 한국어-영어 쌍으로 훈련된 모델을 허깅페이스에서 가져와서 사용했습니다. 궁금하신분은 링크를 클릭해보시면 됩니다. 간단히 말하면 한국어를 입력했을 때, 영어로 출력하는 KoBART 모델입니다.model_id = 'chunwoolee0/circulus-ko..
2024.07.16
no image
[Pytorch Lightning] BART를 훈련해 Text를 요약해보자 - 3
1편 : 프로젝트 요약 및 LightningModule 설계2편 : Dataset 구축 및 DataLoader 구축3편 : logger 작성, wandb 연동 및 확인4편 : 모델 로딩 및 실행결과(wandb) 확인이번에는 훈련이 잘되고 있는지 확인하기 위해 필요한 것들에 대해 알아보려고 합니다. 모델 인수들이 잘 입력되었는지 log에 확인하기 위한 logger 작성과 훈련 loss들이 잘 훈련되고 있는지에 대해 알려주는 wandb, tensorboard에 대해 알아보려고합니다.(tensorboard는 추후에 작성하도록 하겠습니다.) logger 작성import loggingimport sysdef get_logger(name: str) -> logging.Logger: """Return logge..
2024.07.15
no image
[wandb] wandb에 대해 알아보고 사용해보자
머신러닝 및 딥러닝 프로젝트에서 모델의 추적을 위해 강력한 도구인 wandb(Weights and Biases)를 사용하여 모델의 성능을 극대화하는 방법을 소개하려 한다. wandb는 무엇이고 왜 사용하는가wandb(Weights and Biases)는 머신러닝 및 딥러닝 프로젝트에서 모델의 파라미터에 대한 도구로, 실험 결과를 시각화하고, 하이퍼파라미터를 조정하며, 모델의 성능을 모니터링하는 도구이다.   특히, 하이퍼파라미터 최적화를 통해 최적의 모델 설정을 찾는 데 큰 도움이 된다. wandb 가입 및 로그인wandb를 사용하기 위해서는 wandb 공식 웹사이트에서 회원가입과 로그인을 해야 합니다. 이메일 주소와 비밀번호를 입력하거나, 구글 계정이나 GitHub 계정으로 손쉽게 가입하고 로그인할 수..
2024.07.14
no image
[Pytorch Lightning] BART를 훈련해 Text를 요약해보자 - 2
1편 : 프로젝트 요약 및 LightningModule 설계2편 : Dataset 구축 및 DataLoader 구축3편 : logger 작성, wandb 연동 및 확인4편 : 모델 로딩 및 실행결과(wandb) 확인 이번에는 Dataset 구축 및 DataLoader 구축에 대해 설명하려고 한다. 근데 생각을 해보았을 땐, 이 글을 보는 사람들은 데이터셋 구축은 관심이 없을 것이고 아무래도 어떻게 코드를 짜는지 궁금할 것이라 생각하기 때문에 데이터셋 구축에 대해서는 설명하지 않고 데이터셋이 어떻게 구성되어 있는지만 말하려고 한다.   Dataset 구축# Text : Encoder # function : Decoder# 예시# 음료 개수, 메뉴 개수, 메뉴 개수 -> drink(quantity=1); m..
2024.07.13
no image
[Pytorch Lightning] BART를 훈련해 Text를 요약해보자 - 1
1편 : 프로젝트 요약 및 LightningModule 설계2편 : Dataset 구축 및 DataLoader 구축3편 : logger 작성, wandb 연동 및 확인4편 : 모델 로딩 및 실행결과(wandb) 확인  오늘은 이전에 캡스톤디자인에서 BART를 이용해서 Text를 요약하는 Task를 진행했었는데, 이것에 대해 설명하면서 코드를 어떻게 작성했는지 설명하려고 한다. 간단하게 요약하면 다음과 같다. 카페 메뉴에 대한 Text가 입력이 되면, BART를 이용해서 영어로 번역한 뒤 필요한 내용만 출력하는 것이다. 아이스 아메리카노 하나, 카페라떼 하나를 영어로 요약하는 것이다. 다음과 같은 Task를 위해 BART를 훈련시키는 코드에 대해 설명하겠다. 필요한 라이브러리 설치pip install da..
2024.07.11
no image
[Hugging Face] 내가 만든 Dataset을 Hugging Face에 올려보기
오늘은 허깅페이스에 내가 만든 Dataset을 올리는 방법에 대해 소개해드리려고 합니다. 이를 통해 다른 사람들이 업로드한 데이터셋을 사용할 수 있습니다. Dataset을 업로드하려면 허깅페이스 토큰이 필요합니다. 토큰을 발급받지 않은 분들은 여기를 클릭해서 토큰을 발급해주세요데이터셋 저장할 Repo 만들기데이터 만들기데이터 허깅페이스에 업로드하기 코드는 여기에 있습니다. 데이터셋 저장할 Repo 만들기 허깅페이스 홈페이지에 들어갑니다.위의 이미지와 같이 프로필을 누르고 New Dataset 버튼을 누릅니다. 다음과 같이 저장할 Repo 이름을 작성합니다.작성을 하고 Create dataset 버튼을 누릅니다.그러면 다음과 같이 giliit/upload_dataset 이라는 Repo가 생성됩니다. 데이터..
2024.04.30
no image
[Hugging Face] 모델 가져오기(Read), 모델 및 데이터 업로드(Write)를 위한 Token 발급 받는 방법
안녕하세요, 오늘은 허깅페이스에서 특정 모델을 읽거나, 데이터나 모델을 업로드하기 위해 필요한 Token을 발급받는 방법에 대해 알려드리려고 합니다. 글의 목차는 다음과 같습니다.허깅페이스 가입하기토큰 발급받기토큰 삭제하기 허깅페이스 가입하기일단 허깅페이스에 가입하기 위해 허깅페이스 홈페이지를 들어갑니다.https://huggingface.co/ Hugging Face – The AI community building the future.The Home of Machine Learning Create, discover and collaborate on ML better. We provide paid Compute and Enterprise solutions. We are building the found..
2024.04.28
728x90

오늘은 GPU를 이용해서 모델을 훈려시키는 방법에 대해 소개해보려고 한다. 본론으로 들어가서 GPU를 사용한 것과 사용하지 않았을 때 시간이 차이나는 것을 확인해보자 

GPU 사용 X
GPU 사용 O

GPU를 사용했을 때 대략적으로 2배 정도 빠른 것을 볼 수 있다. 그래서 인공지능을 위해서는 GPU가 필수적이면, 시간을 아껴준다. 그렇다면 gpu는 어떻게 사용하는 것일까? 그에 대해 알아보자

 

GPU 사용해보기

GPU를 사용하는 방법은 크게 2가지로 나뉜다. 자동으로 할당하게 하는 경우와 우리가 직접 할당하도록 하는 방법이 있다. 일단 

자동으로 할당하기

trainer = pl.Trainer(accelerator="gpu", devices="auto")
  • accelerator  : 가속기를 의미하며 , gpu, tqu, hpu가 있는데 일반적으로 gpu를 사용하므로 gpu로 설정
  • devices : 몇개를 쓸 것인지 정하는 매개변수이다. 잘 모르겠다면, auto를 쓰면 된다.

 

직접 할당하기

# 0번째, 1번째 gpu에 할당하기
Trainer(accelerator="gpu", devices=[0, 1])

# 0번째, 1번째 gpu에 할당하기
Trainer(accelerator="gpu", devices="0, 1")

# 모든 gpu를 사용하기
Trainer(accelerator="gpu", devices=-1)

 

devices Types Parsed Meaning
3  int [0, 1, 2] 0, 1, 2번째 GPU 사용
-1 int [0, 1, 2, ...] 모든 GPU 사용
[0] list [0] 0번째 GPU 사용
[1,3] list [1, 3] index가 1과 3인 GPU 사용
"3" str [0, 1, 2] 0, 1, 2번째 GPU 사용
"1, 3" str [1, 3] 1번째, 3번째 GPU 사용
"-1" str [0, 1, 2, ...] 모든 GPU 사용

다음과 같이 이용하며, int, list, str 모두 입력할 수 있다. 

728x90

이번에는 훈련한 모델을 저장하는 방법과 불러오는 방법에 대해 알아보려고 한다. 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 파일을 읽어와서 실험을 진행할 수 있다. (그래서 사용한다.)

version_1에서의 저장되어있는 하이퍼파라미터 없음

우리는 모델의 파라미터만 저장하고 하이퍼 파라미터는 저장하지 않았다. 그래서 하이퍼 파라미터를 저장하는 방법에 대해 다루려고 한다. 

 

모델의 하이퍼파라미터 저장하기

하이퍼 파라미터를 저장하는 방법은 간단하다. 코드 한줄을 추가하면 된다.

class LitAutoEncoder(pl.LightningModule):
    def __init__(self, encoder, decoder):
        super().__init__()
        # 코드 추가
        self.save_hyperparameters()
        
        
        self.encoder = encoder
        self.decoder = decoder

# 코드 중략

self.save_hyperparameters() 이 함수를 하나 추가하면 된다.  그리고 코드를 돌리면(훈련하면) 다음과 같이 나온다.

version_2에서 하이퍼파라미터가 저장됨

 

체크포인트로 모델을 불러오기

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 방법에 대해 소개하려고 한다. 

728x90

오늘은 파이토치 라이트닝과 관련해 기본적인 자료가 부족해서 직접 작성해보기로 했다. 공식 홈페이지를 기반으로 했으니, 많이 도움이 될 것이라고 생각한다. 코드는 여기를 참고하면 된다.

Module, Trainer는 Pytorch Lightning이 보라색이라서 그렇게 색깔을 정했다

대략적인 구조는 다음과 같다. 

  1. 데이터를 모아서 DataLoader를 이용해 train, valid, test로 분할한다.
  2. Model을 선언한다.
  3. 훈련때마다 사용하는 방법을 선언한다. (e.g., train_step에서는 어떻게 진행하고 ...)
  4. Model과 훈련 방법을 Pytorch Lightning Module에 선언한다.
  5. Hyper Parameter + Lighitning Module을 Trainer에 추가한다.
  6. Trainer를 통해 훈련된 모델(Trained Model)을 사용한다.

 

요약

  • 라이브러리 설치
  • 데이터셋 선언
  • 모델 구조 만들기
  • Lighitning Module 만들기
  • Trainer를 이용해 훈련 및 테스트하기

5가지 단계로 구성되어 있다.

 

라이브러리 설치 및 선언

pip install torch==2.3.1
pip install torchvision==0.18.1
pip install pytorch_lightning==2.3.3

 

# 필요한 라이브러리 선언

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 데이터셋을 사용한다. 자세한 정보는 여기를 확인하면 된다.

데이터셋 선언 및 분할

# 데이터 셋 불러오기
train_set = MNIST(os.getcwd(), download=True, train=True, transform=transforms.ToTensor())
test_set = MNIST(os.getcwd(), download=True, train=False, transform=transforms.ToTensor())

# 데이터셋 분할
train_set_size = int(len(train_set) * 0.8)
valid_set_size = len(train_set) - train_set_size

# 8 : 2 비율로 train_set과 valid_set 분할
train_set, valid_set = data.random_split(train_set, [train_set_size, valid_set_size])

데이터 확인

image, label = train_set[0]
image = image.numpy()
image = image.squeeze()  # 차원 축소

# 이미지 시각화
plt.imshow(image, cmap='gray')
plt.title(f"answer = {label}")
plt.show()

데이터로더 변환

# DataLoader 변환
train_loader = data.DataLoader(train_set)
valid_loader = data.DataLoader(valid_set)
test_loader = data.DataLoader(test_set)

 

모델 만들기(Encoder, Decoder)

class Encoder(nn.Module):
    def __init__(self):
        super().__init__()
        self.l1 = nn.Sequential(nn.Linear(28 * 28, 64), nn.ReLU(), nn.Linear(64, 3))

    def forward(self, x):
        return self.l1(x)


class Decoder(nn.Module):
    def __init__(self):
        super().__init__()
        self.l1 = nn.Sequential(nn.Linear(3, 64), nn.ReLU(), nn.Linear(64, 28 * 28))

    def forward(self, x):
        return self.l1(x)

Encoder 

  • 목적: 입력 데이터를 저차원의 표현으로 변환(인코딩).
  • 구조:
    • nn.Linear(28 * 28, 64): 입력 데이터의 차원을 784(28x28)에서 64로 줄이는 선형 변환을 수행한다.
    • nn.ReLU(): 비선형 활성화 함수로, 선형 변환 후 적용되어 모델의 표현력을 증가시킨다.
    • nn.Linear(64, 3): 중간 표현의 차원을 64에서 3으로 더 줄여 저차원 특징을 추출한다.

Decoder 클래스

  • 목적: 저차원 표현을 다시 원래의 차원으로 확장하여 데이터를 복원(디코딩).
  • 구조:
    • nn.Linear(3, 64): 저차원 표현(3차원)을 중간 차원(64차원)으로 확장하는 선형 변환을 수행한다.
    • nn.ReLU(): 비선형 활성화 함수를 적용하여 데이터의 비선형적 특징을 유지 및 강화한다.
    • nn.Linear(64, 28 * 28): 최종적으로 중간 차원을 원래의 입력 데이터 차원(784차원)으로 확장하여 재구성한다.

 

Lighitning Module 만들기

class LitAutoEncoder(pl.LightningModule):
    def __init__(self, encoder, decoder):
        super().__init__()
        self.encoder = encoder
        self.decoder = decoder

    def training_step(self, batch, batch_idx):
        # training_step defines the train loop.
        x, _ = batch
        x = x.view(x.size(0), -1)
        z = self.encoder(x)
        x_hat = self.decoder(z)
        loss = F.mse_loss(x_hat, x)
        return loss

    def validation_step(self, batch, batch_idx):
        # this is the validation loop
        x, _ = batch
        x = x.view(x.size(0), -1)
        z = self.encoder(x)
        x_hat = self.decoder(z)
        val_loss = F.mse_loss(x_hat, x)
        self.log("val_loss", val_loss)
    
    def test_step(self, batch, batch_idx):
        # this is the test loop
        x, _ = batch
        x = x.view(x.size(0), -1)
        z = self.encoder(x)
        x_hat = self.decoder(z)
        test_loss = F.mse_loss(x_hat, x)
        self.log("test_loss", test_loss)

    def configure_optimizers(self):
        optimizer = torch.optim.Adam(self.parameters(), lr=1e-3)
        return optimizer

각각 함수에 대한 설명과 코드 해석을 하면 다음과 같다.

  • __init__(self, encoder, decoder): 생성자에서는 인코더와 디코더 객체를 모듈의 속성으로 저장한다.
  • training_step : 훈련 step마다 실행되며, x 입력에 대해 인코딩, 디코딩과정을 통해 정답과 예측에 대해 loss 계산한다.
  • validation_step : 검증 step마다 실행되며, training_step과 동일하다.
  • test_step : 테스트 step에서 실행되며, training_step과 동일하다.
  • configure_optimizers : 학습 과정에서 사용할 옵티마이저를 설정한다. 필요하다면 학습률 스케줄러도 설정할 수 있지만, 여기서는 0.001로 설정한다.

 

모듈을 이용한 모델 선언

# model
model = LitAutoEncoder(Encoder(), Decoder())

 

Trainer로 훈련 및 테스트 하기

 

Trainer 선언

trainer = pl.Trainer(max_epochs=5)

Trainer 내부에 Hyper Parameters 선언하지만, 지금은 간단하게 epoch만 설정했다.

Trainer로  모델 훈련하기

trainer.fit(model, train_loader, valid_loader)

trainer의 fit 함수를 이용하여 train_loader와 valid_loader를 이용해 model 훈련한다.

  • train_loader : training_step에서 사용된다.
  • valid_loader : validation_step에서 사용된다.

실행하면 다음과 같이 모델 정보(파라미터 수, GPU 정보) 와 함께 실험 예상시간이 출력된다.

 

Trainer로 모델 테스트하기

trainer.test(model, dataloaders=test_loader)

실행하면 실행에 대한 결과가 출력된다. 여기서 코드 작성을 통해 원하는 metric을 추가할 수 있다.

 

다음은 훈련된 모델을 불러오고 사용하는 방법에 대해 알아보려고 한다.

728x90
  • 1편 : 프로젝트 요약 및 LightningModule 설계
  • 2편 : Dataset 구축 및 DataLoader 구축
  • 3편 : logger 작성, wandb 연동 및 확인
  • 4편 : 모델 로딩 및 실행결과(wandb) 확인

이번에는 작성한 코드를 이용해서 모델 로딩 및 실행결과(wandb) 확인을 해보겠습니다.

환경설정 및 초기화

사용할 모델 및 토크나이저 선택

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'])

 

하이퍼 파라미터 설정

args = dict()
args['output_dir'] ='20240512'
args['model_path'] = 'chunwoolee0/circulus-kobart-en-to-ko'
args['tokenizer'] = 'chunwoolee0/circulus-kobart-en-to-ko'

args['gpus'] = '1'
args['epochs'] = 100
args['max_learning_rate'] = 2e-5
args['min_learning_rate'] = 1e-6
args['warmup_rate'] = 0.1
args['max_seq_len'] = 128
args['batch_size_train'] =64
args['batch_size_valid'] =8
args['logging_interval'] =100
args['evaluate_interval'] =1.0
args['seed'] =93
args['wandb_project'] ='blog'
args['accumulate_grad_batches'] = 1
  • output_dir: 모델과 출력 파일들을 저장할 디렉토리 경로 ('20240512')
  • model_path: 사용할 모델의 경로
  • tokenizer: 사용할 토크나이저의 경로
  • gpus: 훈련에 사용할 GPU 수
  • epochs: 훈련할 총 에폭 수 (100)
  • max_learning_rate: 최대 학습률 (2e-5)
  • min_learning_rate: 최소 학습률 (1e-6)
  • warmup_rate: 학습률 웜업 비율 (0.1), 학습 초기에 학습률을 점진적으로 증가시키는 비율
  • max_seq_len: 입력 시퀀스의 최대 길이 (128), 너무 긴 입력은 잘라내기 처리
  • batch_size_train: 훈련 데이터의 배치 크기 (64)
  • batch_size_valid: 검증 데이터의 배치 크기 (8)
  • logging_interval: 로깅 간격 (100), 이 간격으로 훈련 로그를 기록
  • evaluate_interval: 평가 간격 (1.0), 각 에폭마다 모델 성능을 평가
  • seed: 랜덤 시드 (93)
  • wandb_project: Weights & Biases에서 사용할 프로젝트 이름 ('blog'), 실험 관리 및 모니터링을 위해 설정
  • accumulate_grad_batches: 그래디언트 누적 배치 수

 

데이터 로딩

train_dataloader, valid_dataloader = OrderDataLoader("../test.jsonl", tokenizer, args['batch_size_train'], args['batch_size_valid'], args['max_seq_len'])

 

훈련 준비(pl.LightningModule 및 pl.Trainer 초기화)

model = AutoModelForSeq2SeqLM.from_pretrained(args['model_path'])

lightning_module = StoryModule(
    model,
    args['output_dir'],
    total_steps,
    args['max_learning_rate'],
    args['min_learning_rate'],
    args['warmup_rate'],
)

하이퍼 파라미터를 Module에 입력한다.

trainer = pl.Trainer(
    strategy="auto",
    accelerator="gpu",
    logger=train_loggers,
    max_epochs=args['epochs'],
    log_every_n_steps=args['logging_interval'],
    val_check_interval=args['evaluate_interval'],
    accumulate_grad_batches=args['accumulate_grad_batches'],
    callbacks=[LearningRateMonitor(logging_interval="step")],
    devices=args['gpus'],
)

하이퍼 파라미터를 Trainer에 입력한다.

 

훈련 시작

trainer.fit(lightning_module, train_dataloader, valid_dataloader)

train_dataloader와 valid_dataloader를 통해 훈련하고 검증을 진행한다.

 

실행 및 결과확인(wandb)

wandb를 통해 loss(train)와 loss(valid)가 둘 다 epoch가 늘어나면서 줄어드는 것을 확인할 수 있다.

전체 코드

https://github.com/Capstone-Amigo/OrderIt-AI/tree/main/ai

이곳에서 확인할 수 있다. BART 훈련에 도움이 되었으면 하는 마음에 다음과 같이 블로그 글을 적어보았다. 다들 이 글을 통해 시간을 아꼈으면 좋겠다. 감사합니다!

 

728x90
  • 1편 : 프로젝트 요약 및 LightningModule 설계
  • 2편 : Dataset 구축 및 DataLoader 구축
  • 3편 : logger 작성, wandb 연동 및 확인
  • 4편 : 모델 로딩 및 실행결과(wandb) 확인

이번에는 훈련이 잘되고 있는지 확인하기 위해 필요한 것들에 대해 알아보려고 합니다. 모델 인수들이 잘 입력되었는지 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는 로그 메시지를 나타낸다.
      • logger.addHandler(handler)는 생성된 핸들러를 로거에 추가

 

wandb 사용

wandb 로그인 방법은 여기를 클릭하세요.

import wandb
from pytorch_lightning.loggers import WandbLogger

wandb.login()

wandb.login()을 이용해 API KEY를 입력하면 wandb 연동 성공입니다.

 

이제 마지막으로 모델로딩, 훈련 및 실행결과를 확인해보도록 하겠습니다.

728x90

 

머신러닝 및 딥러닝 프로젝트에서 모델의 추적을 위해 강력한 도구인 wandb(Weights and Biases)를 사용하여 모델의 성능을 극대화하는 방법을 소개하려 한다.

 

wandb는 무엇이고 왜 사용하는가

wandb(Weights and Biases)는 머신러닝 및 딥러닝 프로젝트에서 모델의 파라미터에 대한 도구로, 실험 결과를 시각화하고, 하이퍼파라미터를 조정하며, 모델의 성능을 모니터링하는 도구이다.   특히, 하이퍼파라미터 최적화를 통해 최적의 모델 설정을 찾는 데 큰 도움이 된다.

 

wandb 가입 및 로그인

wandb를 사용하기 위해서는 wandb 공식 웹사이트에서 회원가입과 로그인을 해야 합니다. 이메일 주소와 비밀번호를 입력하거나, 구글 계정이나 GitHub 계정으로 손쉽게 가입하고 로그인할 수 있다.

가입버튼 클릭

공식사이트에 들어가서 가입버튼을 클릭한다.

나의 경우는 Github로 가입하고 개인정보를 입력한다.

다음과 같은 창이 나오게 되는데 여기서 API KEY를 복사해 두고 저장해 둔다.

 

wandb 로그인

pip install wandb

wandb 설치

import wandb
wandb.login()

다음과 같이 셀을 실행하면 밑에와 같은 창이 생긴다. 이때, 여기에 복사한 API KEY를 입력한다.

 

API KEY를 입력하면 다음과 같이 True가 출력된다.

혹시 키를 까먹었다면 여기를 클릭하면 된다.

 

wandb를 사용하는 방법

훈련코드

import pytorch_lightning as pl
import wandb
from pytorch_lightning.loggers import WandbLogger
import torch
from torch.nn import functional as F
from torch.utils.data import DataLoader, random_split
from torchvision import transforms
from torchvision.datasets import MNIST

# 1. wandb Logger 설정
wandb_logger = WandbLogger(project="pytorch-lightning-demo")

# 2. 데이터 준비
class MNISTDataModule(pl.LightningDataModule):
    def __init__(self, data_dir='./', batch_size=32):
        super().__init__()
        self.data_dir = data_dir
        self.batch_size = batch_size

    def prepare_data(self):
        MNIST(self.data_dir, train=True, download=True)
        MNIST(self.data_dir, train=False, download=True)

    def setup(self, stage=None):
        transform = transforms.Compose([transforms.ToTensor()])
        self.mnist_train = MNIST(self.data_dir, train=True, transform=transform)
        self.mnist_val = MNIST(self.data_dir, train=False, transform=transform)

    def train_dataloader(self):
        return DataLoader(self.mnist_train, batch_size=self.batch_size)

    def val_dataloader(self):
        return DataLoader(self.mnist_val, batch_size=self.batch_size)

# 3. 모델 정의
class LitMNIST(pl.LightningModule):
    def __init__(self):
        super().__init__()
        self.layer_1 = torch.nn.Linear(28 * 28, 128)
        self.layer_2 = torch.nn.Linear(128, 256)
        self.layer_3 = torch.nn.Linear(256, 10)

    def forward(self, x):
        x = x.view(x.size(0), -1)
        x = F.relu(self.layer_1(x))
        x = F.relu(self.layer_2(x))
        x = self.layer_3(x)
        return x

    def training_step(self, batch, batch_idx):
        x, y = batch
        y_hat = self.forward(x)
        loss = F.cross_entropy(y_hat, y)
        self.log('train_loss', loss)
        return loss

    def validation_step(self, batch, batch_idx):
        x, y = batch
        y_hat = self.forward(x)
        loss = F.cross_entropy(y_hat, y)
        self.log('val_loss', loss)
        return loss

    def configure_optimizers(self):
        return torch.optim.Adam(self.parameters(), lr=1e-3)

# 4. 학습
if __name__ == '__main__':
    dm = MNISTDataModule()
    model = LitMNIST()
    trainer = pl.Trainer(logger=wandb_logger, max_epochs=5)
    trainer.fit(model, dm)

위의 코드를 요약하면 다음과 같습니다. 

import wandb
from pytorch_lightning.loggers import WandbLogger

wandb_logger = WandbLogger(project="pytorch-lightning-demo")

trainer = pl.Trainer(logger=wandb_logger, max_epochs=5)

WandbLogger를 선언한 뒤, project 이름을 작성해 준 뒤 trainer 인수로 넣어주고 trinaing을 진행하면 wandb 사이트에 훈련하면서 loss값이 변하는 것을 확인할 수 있다. 

 

wandb를 통해 빠르게 모델 최적화를 하시기를 바랍니다!

728x90
  • 1편 : 프로젝트 요약 및 LightningModule 설계
  • 2편 : Dataset 구축 및 DataLoader 구축
  • 3편 : logger 작성, wandb 연동 및 확인
  • 4편 : 모델 로딩 및 실행결과(wandb) 확인

이번에는 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) 토큰으로 설정

 

템플릿 프로세싱(포스트 프로세서 설정)

# TemplateProcessing
tokenizer._tokenizer.post_processor = TemplateProcessing(
    single=f"{tokenizer.cls_token} $0 {tokenizer.sep_token}",
    pair=f"{tokenizer.cls_token} $A {tokenizer.sep_token} $B:1 {tokenizer.sep_token}:1",
    special_tokens=[(tokenizer.cls_token, tokenizer.cls_token_id), (tokenizer.sep_token, tokenizer.sep_token_id)],
)

다음을 하는 이유는 다음과 같다. BART와 같이 모델이 요구하는 입력 형식에 맞추기 위함이다.

예를 들면 다음과 같다.

  • 입력 : 아이스 카페 라테 4잔 주세요
  • 출력 : [CLS] 아이스 카페 라뗴 4잔 주세요 [SEP]
  • 입력 : 아이스 카페 라떼라테 4잔 주세요 그 외에 따듯한 그린티 라테 줘
  • 출력 : [CLS] 아이스 카페 라뗴 4잔 주세요 [SEP] 그 외에 따듯한 그린티 라테 줘 [SEP]

다음과 같은 형식으로 처리한다.

 

전처리 함수

# 전처리 함수
def preprocess_function(examples):
    processed = {}
    inp = f'{examples["Text"]}'

    # 입력에 대한 토큰화
    tokenizer_input = tokenizer(
        inp,
        padding="max_length",
        max_length=max_length,
        truncation=True
    )
    processed["input_ids"] = tokenizer_input["input_ids"]
    processed["attention_mask"] = tokenizer_input["attention_mask"]

    # 훈련모드인 경우
    if mode == "train":
        #print(examples["code"])

        # 출력에 대한 토큰화
        tokenizer_output = tokenizer(
            examples["function"], 
            padding="max_length", 
            max_length=max_length, 
            truncation=True
        )
        processed["decoder_input_ids"] = tokenizer_output["input_ids"]
        processed["decoder_attention_mask"] = tokenizer_output["attention_mask"]

    # 토큰화된 배열 반환
    return processed

요약을 하면, 입력데이터를 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 형태로 변환한다.

 

데이터셋 분할

dataset = dataset.train_test_split(0.2)

train_dataloader = DataLoader(dataset['train'], shuffle=True, batch_size=train_batch_size, num_workers=8, pin_memory=True)
valid_dataloader = DataLoader(dataset['test'], shuffle=True, batch_size=valid_batch_size, num_workers=8, pin_memory=True)

return train_dataloader, valid_dataloader

train과 valid를 8 : 2로 분할하는 코드이다. 이렇게 되면 dataset은 'train'과 'test'로 데이터를 8 : 2로 나눈다. 

  • shuffle : data를 무작위로 섞는다.
  • batch_size : batch_size를 조절한다. ram이 적다면, 낮게설정하고 ram이 많다면 높게 설정하는 것이 좋다.
  • num_workers : 데이터 로딩을 위해 사용할 별도의 작업 프로세스 수를 지정, 8이면, 8개의 프로세스가 병렬로 데이터를 로딩한다.
  • pin_memory : 데이터를 더 빠르게 GPU로 전송할 수 있게 하여, 특히 GPU를 사용할 때 데이터 전송 병목을 줄여준다.

다음과 같이 분할하여 train_dataloader과 valid_dataloader 형식으로 반환한다.

 

전체 코드

import json
import pandas as pd

from datasets import Dataset
from torch.utils.data import DataLoader
from tokenizers.processors import TemplateProcessing

def OrderDataLoader(fname, tokenizer, train_batch_size,valid_batch_size, max_length,split=False, mode="train"):
    """
    Build Data Loader

    """

    # 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

    # TemplateProcessing
    tokenizer._tokenizer.post_processor = TemplateProcessing(
        single=f"{tokenizer.cls_token} $0 {tokenizer.sep_token}",
        pair=f"{tokenizer.cls_token} $A {tokenizer.sep_token} $B:1 {tokenizer.sep_token}:1",
        special_tokens=[(tokenizer.cls_token, tokenizer.cls_token_id), (tokenizer.sep_token, tokenizer.sep_token_id)],
    )

    # 전처리 함수
    def preprocess_function(examples):
        processed = {}
        inp = f'{examples["Text"]}'
       
        # 입력에 대한 토큰화
        tokenizer_input = tokenizer(
            inp,
            padding="max_length",
            max_length=max_length,
            truncation=True
        )
        processed["input_ids"] = tokenizer_input["input_ids"]
        processed["attention_mask"] = tokenizer_input["attention_mask"]
        
        # 훈련모드인 경우
        if mode == "train":
            #print(examples["code"])
             
            # 출력에 대한 토큰화
            tokenizer_output = tokenizer(
                examples["function"], 
                padding="max_length", 
                max_length=max_length, 
                truncation=True
            )
            processed["decoder_input_ids"] = tokenizer_output["input_ids"]
            processed["decoder_attention_mask"] = tokenizer_output["attention_mask"]
        
        # 토큰화된 배열 반환
        return processed
    

    # dataset에 대해 전처리 함수로 매핑, columns제거 및 torch tensor로 변환
    dataset = dataset.map(preprocess_function,remove_columns=dataset.column_names).with_format("torch")

    # dataset을 dataloader로 변환

    dataset = dataset.train_test_split(0.2)

    train_dataloader = DataLoader(dataset['train'], shuffle=True, batch_size=train_batch_size, num_workers=8, pin_memory=True)
    valid_dataloader = DataLoader(dataset['test'], shuffle=True, batch_size=valid_batch_size, num_workers=8, pin_memory=True)

    return train_dataloader, valid_dataloader
728x90
  • 1편 : 프로젝트 요약 및 LightningModule 설계
  • 2편 : Dataset 구축 및 DataLoader 구축
  • 3편 : logger 작성, wandb 연동 및 확인
  • 4편 : 모델 로딩 및 실행결과(wandb) 확인

 

오늘은 이전에 캡스톤디자인에서 BART를 이용해서 Text를 요약하는 Task를 진행했었는데, 이것에 대해 설명하면서 코드를 어떻게 작성했는지 설명하려고 한다. 

간단하게 요약하면 다음과 같다. 카페 메뉴에 대한 Text가 입력이 되면, BART를 이용해서 영어로 번역한 뒤 필요한 내용만 출력하는 것이다. 아이스 아메리카노 하나, 카페라떼 하나를 영어로 요약하는 것이다. 다음과 같은 Task를 위해 BART를 훈련시키는 코드에 대해 설명하겠다.

 

필요한 라이브러리 설치

pip install datasets==2.17.0
pip install pytorch_lightning==2.2.4
pip install torkenizers==0.15.2
pip install transformers==4.38.1
pip install pandas==2.0.3

위의 라이브러리는 제가 사용한 라이브러리들의 버전이다. 혹시 버전오류가 발생한다면 다음과 같이 라이브러리를 재설치하면 된다.

 

훈련 모듈 설계

요약

training_step 훈련 데이터의 각 배치에 대해 실행  →  Train_dataloader에 대해 실행 

e.g., trainer.fit(module, train_dataloader, valid_dataloader)
validation_step 검증 데이터의 각 배치에 대해 실행 → Valid_dataloader에 대해 실행

e.g., trainer.fit(module, train_dataloader, valid_dataloader)
test_step 시험 데이터의 각 배치에 대해 실행 → Test_dataloader에 대해 실행

e.g., trainer.test(module, test_dataloader)
configure_optimizers 모델의 optimizer를 구성
on_validation_epoch_end 각 validation_epoch가 종료될때마다 실행

 

모델 초기화

def __init__(
        self,
        model,
        model_save_dir,
        total_steps,
        max_learning_rate: float = 2e-4,
        min_learning_rate: float = 2e-5,
        warmup_rate: float = 0.1,
    ):
    super().__init__()

    self.model = model
    self.total_steps = total_steps
    self.max_learning_rate = max_learning_rate
    self.min_learning_rate = min_learning_rate
    self.warmup_rate = warmup_rate
    self.model_save_dir = model_save_dir
    self.validation_step_loss = []

모델 설계에 필요한 인수들을 입력받습니다.

  • model : BART 모델 인스턴스
  • model_save_dir : 모델을 저장할 경로
  • total_steps, max_learning_step, min_learning_rate, warmup_rate : 학습에 사용될 hyper parameter
  • validation_step_loss : validation_epoch가 끝난 후 손실을 저장하기 위한 리스트

 

훈련 단계( training_step)

def training_step(self, batch, batch_idx):
    output = self.model(
        input_ids=batch["input_ids"],
        attention_mask=batch["attention_mask"],
        decoder_input_ids=batch["decoder_input_ids"],
        decoder_attention_mask=batch["decoder_attention_mask"],
        return_dict=True,
    )

    labels = batch["decoder_input_ids"][:, 1:].reshape(-1)
    logits = output["logits"][:, :-1].reshape([labels.shape[0], -1])

    loss = F.cross_entropy(logits, labels, ignore_index=self.model.config.pad_token_id)
    metrics = {"loss": loss}
    self.log_dict(metrics, prog_bar=True, logger=True, on_step=True)

    return metrics

모델에 특정 배치가 들어갔을 때 훈련을 하게 된다. 

  • input_ids: 입력 시퀀스의 토큰 ID 배열.
  • attention_mask: 입력 시퀀스의 어텐션 마스크 배열, 패딩 된 부분을 0으로, 유효한 토큰을 1로 표시.
  • decoder_input_ids: 디코더에 입력되는 시퀀스의 토큰 ID 배열.
  • decoder_attention_mask: 디코더 시퀀스의 어텐션 마스크 배열.
  • labels : 맨 앞 토큰([BOS])을 제외하고 나머지 토큰을 사용
  • logits : 모델 출력에서 마지막 토큰을 제외한 나머지
  • cross_entropy : label과 logits의 손실을 계산하며 ignore_index를 통해 [PAD] 토큰 무시
  • log_dict : 여러 메트릭을 로깅하는데 사용
    • metrics: 로깅하고자 하는 메트릭을 담고 있는 딕셔너리. 키는 메트릭의 이름, 값은 로깅하려는 수치.
    • prog_bar: 메트릭이 훈련 프로그레스 바에 표시. 
    • logger: 로깅하는 메트릭이 백엔드 로거(예: TensorBoard, CSVLogger 등)에 전송.
    • on_epoch: 로깅되는 메트릭이 에폭 단위로 기록. 각 에폭에서 메트릭의 평균값을 계산하여 로깅

cross_entropy함수를 이용해서 정답과 예측값의 손실을 계산한다. 또한 ignore_index인수를 통해 [PAD] 토큰들을 무시하도록 합니다. 마지막

 

검증 단계, 테스트 단계( validation_step, test_step)

def validation_step(self, batch, batch_idx):
    output = self.model(
        input_ids=batch["input_ids"],
        attention_mask=batch["attention_mask"],
        decoder_input_ids=batch["decoder_input_ids"],
        decoder_attention_mask=batch["decoder_attention_mask"],
        return_dict=True,
    )

    labels = batch["decoder_input_ids"][:, 1:].reshape(-1)
    logits = output["logits"][:, :-1].reshape([labels.shape[0], -1])

    loss = F.cross_entropy(logits, labels, ignore_index=self.model.config.pad_token_id)
    metrics = {"loss(v)": loss}
    self.validation_step_loss.append(loss)

    self.log_dict(metrics, prog_bar=True, logger=True, on_epoch=True)

    return metrics
    

def test_step(self, *args, **kwargs):
    return self.validation_step(*args, **kwargs)

train_step과 거의 동일하지만, 다른점은 validation_step_loss를 저장하며 test_step은 validation_step과 동일하다.

 

옵티마이저 설정( configure_optimizers)

def configure_optimizers(self):
    optimizer = torch.optim.AdamW(params=self.model.parameters(), lr=self.max_learning_rate)

    return {
        "optimizer": optimizer
    }

optimizer를 adamW로 설정하고 학습률에 따라서 model의 파라미터를 업데이트한 것을 optimizer를 반환하여 가중치를 업데이트한다.

 

검증 에폭 종료 시 ( on_validation_epoch_end)

def on_validation_epoch_end(self):
    if self.trainer.is_global_zero:
        losses = [output.mean() for output in self.validation_step_loss]
        loss_mean = sum(losses) / len(losses)

        self.model.save_pretrained(
            os.path.join(
                self.model_save_dir,
                f"model-{self.current_epoch:02d}epoch-{self.global_step}steps-{loss_mean:.4f}loss",
            ),
        )

    self.validation_step_loss.clear()  # free memory
  • self.trainer.is_global_zero : 멀티 GPU 또는 분산 설정에서의 주 노드에서 실행되고 있는지를 검사
  • self.model.save_pretrained : 모델의 파라미터를 저장하며, 제목은 다음과 같이 한다.
  • self.validation_step_loss.clear : 리스트를 비우고 다음 에폭에서 새로운 손실 데이터를 깨끗하게 수집

 

전체코드

import os

import torch
import pytorch_lightning as pl
import torch.nn.functional as F


class StoryModule(pl.LightningModule):
    """
    Attributes:
        model: BART model
        total_steps: total training steps for lr scheduling
        max_learning_rate: Max LR
        min_learning_rate: Min LR
        warmup_rate: warmup step rate
        model_save_dir: path to save model
    """

    def __init__(
        self,
        model,
        model_save_dir,
        total_steps,
        max_learning_rate: float = 2e-4,
        min_learning_rate: float = 2e-5,
        warmup_rate: float = 0.1,
    ):
        super().__init__()

        self.model = model
        self.total_steps = total_steps
        self.max_learning_rate = max_learning_rate
        self.min_learning_rate = min_learning_rate
        self.warmup_rate = warmup_rate
        self.model_save_dir = model_save_dir
        self.validation_step_loss = []

        self.save_hyperparameters(
            {
                **model.config.to_dict(),
                "total_steps": total_steps,
                "max_learning_rate": self.max_learning_rate,
                "min_learning_rate": self.min_learning_rate,
                "warmup_rate": self.warmup_rate,
            }
        )

    def training_step(self, batch, batch_idx):
        output = self.model(
            input_ids=batch["input_ids"],
            attention_mask=batch["attention_mask"],
            decoder_input_ids=batch["decoder_input_ids"],
            decoder_attention_mask=batch["decoder_attention_mask"],
            return_dict=True,
        )

        labels = batch["decoder_input_ids"][:, 1:].reshape(-1)
        logits = output["logits"][:, :-1].reshape([labels.shape[0], -1])

        loss = F.cross_entropy(logits, labels, ignore_index=self.model.config.pad_token_id)
        metrics = {"loss": loss}
        self.log_dict(metrics, prog_bar=True, logger=True, on_step=True)

        return metrics
    
    def validation_step(self, batch, batch_idx):
        output = self.model(
            input_ids=batch["input_ids"],
            attention_mask=batch["attention_mask"],
            decoder_input_ids=batch["decoder_input_ids"],
            decoder_attention_mask=batch["decoder_attention_mask"],
            return_dict=True,
        )

        labels = batch["decoder_input_ids"][:, 1:].reshape(-1)
        logits = output["logits"][:, :-1].reshape([labels.shape[0], -1])

        loss = F.cross_entropy(logits, labels, ignore_index=self.model.config.pad_token_id)
        metrics = {"loss(v)": loss}
        self.validation_step_loss.append(loss)
        
        self.log_dict(metrics, prog_bar=True, logger=True, on_epoch=True)

        return metrics

    def test_step(self, *args, **kwargs):
        return self.validation_step(*args, **kwargs)

    def configure_optimizers(self):
        optimizer = torch.optim.AdamW(params=self.model.parameters(), lr=self.max_learning_rate)

        return {
            "optimizer": optimizer
        }

    def on_validation_epoch_end(self):
        if self.trainer.is_global_zero:
            losses = [output.mean() for output in self.validation_step_loss]
            loss_mean = sum(losses) / len(losses)

            self.model.save_pretrained(
                os.path.join(
                    self.model_save_dir,
                    f"model-{self.current_epoch:02d}epoch-{self.global_step}steps-{loss_mean:.4f}loss",
                ),
            )

        self.validation_step_loss.clear()  # free memory

 

다음은 dataset 및 DataLoader 구축에 대해 설명하겠습니다!

728x90

오늘은 허깅페이스에 내가 만든 Dataset을 올리는 방법에 대해 소개해드리려고 합니다. 이를 통해 다른 사람들이 업로드한 데이터셋을 사용할 수 있습니다. Dataset을 업로드하려면 허깅페이스 토큰이 필요합니다. 토큰을 발급받지 않은 분들은 여기를 클릭해서 토큰을 발급해주세요

  1. 데이터셋 저장할 Repo 만들기
  2. 데이터 만들기
  3. 데이터 허깅페이스에 업로드하기

 

코드는 여기에 있습니다.

 

데이터셋 저장할 Repo 만들기


 

허깅페이스 홈페이지에 들어갑니다.

위의 이미지와 같이 프로필을 누르고 New Dataset 버튼을 누릅니다.

 

다음과 같이 저장할 Repo 이름을 작성합니다.

작성을 하고 Create dataset 버튼을 누릅니다.

그러면 다음과 같이 giliit/upload_dataset 이라는 Repo가 생성됩니다.

 

데이터 만들기


데이터셋을 생성

from datasets import Dataset

# Dataset 객체 생성(train)
sample_train = {'first' : '1', 'second' : '2', 'third' : '3'}
sample_train_dataset = Dataset.from_dict(sample_train)

# type과 dataset 내용 확인
print(type(sample_train_dataset))
print(sample_train_dataset)

# Dataset 객체 생성(test)
sample_test = {'first' : '11', 'second' : '22', 'third' : '33'}
sample_test_dataset = Dataset.from_dict(sample_test)

데이터셋을 Dictionary형태로 생성하고 Dataset에서 from_dict 함수를 통해 데이터셋 객체로 변환을 합니다.

데이터셋 train, test 두 개를 생성했습니다. 

 

데이터셋을 담는 데이터셋딕셔너리 생성

from datasets import DatasetDict

# datasetDcit 객체 생성
sample_datasetDict = DatasetDict({"train": sample_train_dataset, "test" : sample_test_dataset})

print(type(sample_datasetDict))
print(sample_datasetDict)

 

데이터셋 허깅페이스에 업로드하기


!huggingface-cli login --token hf_

hf_로 시작하는 토큰을 입력(Write로 써져 있는 Token 발급)

 

sample_datasetDict.push_to_hub('giliit/upload_dataset', token="hf_")

push_to_hub 함수, Repo와 토큰을 입력하고 함수를 실행합니다.

 

from datasets import load_dataset

dataset = load_dataset('giliit/upload_dataset')

print(dataset)

load_dataset 함수를 이용해서 데이터셋을 로드해서 확인합니다.

728x90

안녕하세요, 오늘은 허깅페이스에서 특정 모델을 읽거나, 데이터나 모델을 업로드하기 위해 필요한 Token을 발급받는 방법에 대해 알려드리려고 합니다. 글의 목차는 다음과 같습니다.

  1. 허깅페이스 가입하기
  2. 토큰 발급받기
  3. 토큰 삭제하기

 

허깅페이스 가입하기


일단 허깅페이스에 가입하기 위해 허깅페이스 홈페이지를 들어갑니다.

https://huggingface.co/

 

Hugging Face – The AI community building the future.

The Home of Machine Learning Create, discover and collaborate on ML better. We provide paid Compute and Enterprise solutions. We are building the foundation of ML tooling with the community.

huggingface.co

 

허깅페이스 홈페이지

사진을 보게 되면 우상단에 Sign Up 버튼을 눌러주세요

가입할 이메일과 비밀번호를 입력해주시고 Next 버튼을 눌러주세요

여기서 필요한 정보들을 입력해주세요.  UsernameFull name만 입력하셔도 됩니다. 그리고 Create Account 버튼을 눌러주세요. 그러면 가입이 됩니다.

가입이 끝이 아니라 확인 인증 이메일을 받아서 링크를 클릭해야 합니다. 위에 Resend confirmation email 버튼을 누르면 인증 메일이 갑니다.

다음과 같이 이메일 인증이 오는데 링크를 클릭하시면 됩니다!

 

토큰 발급하기


가입하고 홈페이지를 들어가면 다음과 같은 화면이 나오는데 여기서 Setting 버튼을 누릅니다.

 

그리고 오른쪽에 Access Tokens를 누르고, New token을 누릅니다.

Name은 Token 키를 기억하기 위해 작성하는 것이고, Type은 어떤 종류로 사용할 건지 정하는 것입니다.

  • Read : 특정 모델을 불러올 때 사용
  • Write : 내가 만든 모델 또는 데이터셋을 업로드 할 때 사용

생성하면, 다음과 같이 나옵니다. 이때 오른쪽에 Show 버튼을 누르면 Token을 확인할 수 있습니다. 그리고 Hide를 누르면 안보이게 숨길 수 있습니다.

 

토큰 삭제하기


Manage 버튼을 누릅니다. Token을 재생성하려면 위의 키를 누르면 되고, Delete 키를 누르면 키를 삭제합니다.