본문 바로가기
데이터 사이언스

생성형AI 로 hyperparameter optimization code 만들어 공부하기

by 빛나는존재 2024. 10. 13.

생성형AI로 hyperparameter optimization code 를 만들게 된 배경

오픈소스에서 신약개발 관련된 데이터로 pIC50 을 예측하는 딥러닝 모델을 만들어보려고 하고 있었다. 나에게는 이미 기존에 신약개발 부트캠프 강의에서 배웠던 코드를 보며 참고삼아 도전해볼 수 있었지만 기존 코드에는 뛰어넘을 수 없는 단점이 있었다. hyperparameter tuning 이 자동으로 안돼서 사람이 일일이 model architecture 를 손으로 manual 하게 바꿔야 한다는거였다. 그래서 기존에 내가 머신러닝에는 적용했던 optuna 를 pytorch 딥러닝 코드에도 적용해보려 했으나 class 구조가 등장하다보니 쉽지 않아 생성형AI 에 다음과 같은 작업을 했다.

  • baseline code 를 첨부
  • 첨부된 파일을 바탕으로 optuna 를 적용시키는 code를 만들어 줘.

그리고 무언가의 코드가 나왔지만, 내가 봐도 잘 모르는 코드가 나와서 사용할 수가 없었다. 일단 나는 deep learning 이전에 pytorch 에서 사용되는 class 인 dataset, dataloader 에 대한 이해도 부족했고 모든게 class, def 으로 깔끔하게 구성된 코드는 내가 알아볼 수가 없었다. 그리고 생성형AI가 만든 code 가 정말로 제대로 된 code 인지 조차 믿을 수가 없었다. 결국 내가 code 를 line-by-line 으로 이해하고, 내가 이를 바탕으로 쓸 줄 알아야 하는 것이다.

검증된 예제 code 를 생성형 AI 에게 설명해달라고 하자

그래서 그 다음으로 생각해 낸 것이 Google 에서 pytorch 에 optuna 로 hypermarameter tuning 이 자동으로 optimization 되는 제대로 검증 된 예제 code를 찾고, 이를 첨부하여 이에 대해 하나하나 설명해달라는 프롬프트를 만들었다. 물론 프롬프트는 한 번 생성하고 그에 대한 답을 본다 그래서 이해할 수 있는 것이 아니라, 수십개의 꼬리질문을 하며 아래와 같이 해석하는 일을 했으며 어디에 정리할까 하다가 최종적으로는 스크롤을 무제한으로 할 수 있는 figma에 하기로 했다. 아래가 바로 그 figma 화면의 스크린샷 이미지이다.

참고로 아래 예제 코드의 출처는 https://github.com/optuna/optuna-examples/blob/main/pytorch/pytorch_simple.py 이다.


아래와 같이 code 의 구조와 기능을 정리하며 어떤 흐름으로 구성되어있고 어떤 작업이 수행 되는지 알아보았다.


Class 및 def 정의하는 part

Class 및 def 정의하는 part

  1. class Net
  2. class LightningNet
  3. class FashionMINISTDataModule
  4. def objective

1. class Net

기능 요약

  • model layer architecture 를 생성하고 그 model 에 data 를 입력하여 결과물로 category 값 분류할 수 있는 blueprint 제공. 여기서는 실제 계산이 일어나지 않고 training 에서 이 파트가 불러와졌을때 사용됨

구조

  • nn.Module 을 상속받아 생성되었으며 def __init__, def forward 로 구성
    • input: dropout, output_dims
    • output: F.log_softmax(logits, dim=1)

기능

  • layer 를 생성
    • Linear, activation function, dropout 을 하는 layer 를 쌓음
    • 다음 layer 의 차원을 맞추기 위해 output_dim 을 input_dim 으로 맞춤
    • 마지막으로 class가 10개이니 이에 맞춰서 append 함
    • nn.Sequential(*layers) 를 통해 모델 구축함
  • forward 를 통해 data 를 layer 에 통과시켜 계산한 결과를 마지막에 log_softmax로 받아와서 class가 뭐로 떨어지는지 반환함.
  • def __init__()

    • layer 를 쌓는 부분

    def __forward()

  • data를 입력하여 결과값 계산 (Q)self.layers 는 사실상 model 인건가?)
    • 사실상 모델 예측을 하는 것 처럼 data 를 forward 에서 self.layer 에 넣으면 분류를 위한 수치로 된 output 값이 반환된다. sequential 하게 쌓아뒀던 layer 들을 통과하면서.
    • 그리고 이 수치로 된 output 은 나중에 log.softmax 를 거치면서 분류를 위한 카테고리 값으로 반환됨
  • 2. class LightningNet

    구조

    • def __init__, def forward, def training_step, validation_step, configure_optimizers 로 구성
      • input: dropout, outout_dims
      • output: self.model(), F.nll_loss, optim.Adam()

    기능

    • mini batch 를 받아서 training 시켜서 loss 계산, validation 도 진행
    • (Q: 각각 def 안에서 무슨 일이 세부적으로 일어나는지는 모르겠다)

    def 별 기능

    def __init__()

  • class Net() 과 같이 dropout, output_dim 을 input parameter 로 받아 class Net() 의 instance 생성, self.model() 에 저장
  • 이 과정에서 class LightningNet 이 class Net 을 wrap 함. 즉, class Net() 에서 작성된 class 의 instance 를 class LightningNet 에서 생성
  • LightningNet 의 constructor 에서 Net 의 instance 가 만들어짐
  • 만약 LightningNet class 에 __init__ 이 없다? 그럼
    • Net instance 생성 못함 dropout, output_dims 인자를 pass못함
    • self.model 생성안됨
  • 기억할것

    • class Net, class LightningNet 은 서로 분리된 독자적인 class 들임.
    • Net 에서 parameter 가 define 됐다고 해서 이를 바로 자동으로 LightningNet 에서 당연하게 사용할 수 있는게 아님
    • LightningNet object 를 생성할 때 이 안에 Net object 도 들어가게 만들어야 함. 그걸 해주는게 LightningNet 안의 __init__임.
    • 입력 parameter 인 dropout, output_dims 는 LightningNet.init() -> Net.init() 으로 흐름

    def forward()

    • input: image data 의 mini batch
    • output: log_softmax 를 거친 결과
    • data 를 torch.tensor 형태로 입력받아 dimension 을 바꾼 후 model 에 넣음.
    • model 의 architecture 만을 생성하는것. 실제로 data가 model 로 계산까지 되는건 training 에서 이다.

    def training_step

    • input: batch: List[torch.Tensor] 는 뭐고 batch_idx: int 는 뭐냐
      • batch: List[torch.Tensor] 는 data loader 로 부터 나온 mini batch data 자체이며 여기에는 feature 에 해당하는 데이터, target 에 해당하는 데이터 각각이 list 형태로 들어있다.
      • batch_idx: int 는 mini batch 를 핸들링 하기 위한 index 번호인데 이의 type 을 int 로 해라 라는 뜻
      • : colon 의 뜻: python 에서 힌트를 주기 위해 사용됨. batch 에 대한 자료형이 무엇이다 라는걸 지정해줌.
      • 콜론 왼쪽에 나온 것: 변수, 콜론 오른쪽: 변수의 자료형. 가독성을 좋게 만들기 위해 : 이 python3.5 부터 사용됨. 자료형 관련한 error 를 쉽게 초기에 잡을 수 있게 해줌.
    • output=self(data) 여기서 실제 prediction 연산이 일어남.
    • 왜 self(data) 냐? 이게 LightningNet instance 의 __call__ 을 호출 (무슨뜻인지는 모르겠다만..) 하고 그게 또 차례로 forward 를 호출함
    • training_step method 에서 self(data) 라고 하면 LightningNet instance 인 self 를 함수처럼 사용하겠다는 뜻. (이건 아직 이해 못함)
    • F.nll_loss 는 negative log likelihood 계산. cross entropy 계산하는 것과 상응. 보통 분류문제에서 log_softmax 한 다음 이걸 사용해준다고 함

    def validation_step

    • input: same as def training_step
    • 요약: validation data loader 로부터 validation dataset 을 mini batch 로 받아서 정답과 prediction 을 비교하여 classification accuracy 계

    def configure_optimizers(self)

    • input:
    • output:
    • 요약: 모든 model 의 parameter 가 adam 이라는 optimizer 로 최적화 되게 하라는 기능.
      • 어느 parameter 를 어느 optimzer로 최적화 할 지 정함.
      • 이 코드에선 안나왔지만, learning rate, scheduler 에 대한 setting 도 가능

    3. class FashionMNISTDataModule(pl.LightningDataModule)

    구조

    • def __init__, def setup, def train_dataloader, val_dataloader, test_dataloader
    • Q) __init__. setup 에서는 무슨일이 일어나는지 모르겠다

    기능

    • train, validation, test dataset 을 batch 마다 loading
    • Q) 언제 shuffle 을 하고 안하고 를 모르겠다
    • pl.LightningDataModule 의 기능: data download, preprocess, split data

    def __init__

    • data directory, batch size 로 초기화

    def setup

    • dataset download, train 과 validation split

    def train_dataloader, val_dataloader, test_dataloader

    • train, validation, test dataset 의 dataloader 를 return

    4. def objective

    구조

  • 최적화 대상 hyperparameter 정의
  • model 정의
  • datamodule 정의
  • trainer 정의
  • trainer 로 model fitting
  • 기능

  • 최적화 할 hyperparameter 정의(n_layer, dropout rate, output_dims 등)
  • Model = lightningNet() 은 model architecture 를 생성하는 부분으로, 실제 prediction 은 일어나지 않고 이 모델은 어떻게 생겼냐를 정의하는 부분
  • Trainer 역할:
    • training process 의 low-level 단에서 일어나는 일들을 abstraction 함
    • epoch, batch, optimization step handling
    • validation
    • logging
    • model save/load
    • early stop 기능
  • 실제 training 은 trainer.fit 에서 일어남
  • batch 마다 datamodule 로 받아서 모델 학습시킴
  • optimization process 의 각 trial 마다 이 함수가 호출
  • 마지막에 return 되는 것이 그 다음 trial 에서 더 최적화된 hyperparamter 적용하게 함.
  • 5. main

    구조

  • argument parsing (Q. 이부분은 뭔지 잘 모르겠지만 필수는 아닌것 같아 넘어감)
  • pruner 정의
  • study 생성하여 optimize
  • best_trial 저장
  • 반응형