MLOps

[MLOps] 10. MLflow + Optuna 실습

mlslly 2024. 4. 22. 17:10

MLflow와 Optuna를 함께 사용 해보도록 하겠다. 

시작하기 전, MLflow만 실습한 내용과 Optuna만 실습한 내용 각각은 아래 링크를 참고.

https://ysryuu.tistory.com/14

https://ysryuu.tistory.com/16

 

[MLOps] 7. MLflow 로깅 실습

모델 파일 실행시 mlflow로 로깅해보기 모델이 있는 py파일에 로깅 코드를 함께 추가해서 실행해보자. 원래 train.py에 있는 내용은 아래 링크 참고하면 된다. 아래 파일 내용에서 mlflow관련 부분 제

ysryuu.tistory.com

 

[MLOps] 9. Optuna 실습

Optuna란? 하이퍼파라미터를 최적화 할 수 있는 대표적인 프레임워크 중 하나에 대해 모른다면 아래 포스팅 참고. https://ysryuu.tistory.com/15 [MLOps] 8. 하이퍼파라미터 최적화 Hyperparameter Optmization이란?

ysryuu.tistory.com

 


1. MLflow + Optuna 파일 작성 

주의 해야 할 부분 

  • def objective(trial) : objective 함수 작성하고 가장 먼저 탐색할 파라미터 및 범위를 지정함 
  • mlflow.log_params(trial.params) : 파라미터 로깅시에 params를 따로 변수 지정하지 않고 옵튜나의 'trial.params'로 지정
  • Classifier(n_estimators=trial.params['n_estimators'] : params를 classifier에 지정할 때  'trial.params[~]'
  • if __name__ == '__main__' : 스크립트 실행 코드. set mlflow, optuna study, optuna optimize 파트를 실행부에 적어줌
  • 'hpo-tutorial' : mlflow (set_experiment) 와 optuna (study_name) 의 실행 이름 맞춰주기

<optuna_train.py 파일 내용>

import mlflow
import optuna 
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

def objective(trial) :
    # suggest new parameter
    trial.suggest_int('n_estimators',100,1000, step=100)
    trial.suggest_int('max_depth', 3,10)

    with mlflow.start_run():

        # log parameter
        mlflow.log_params(trial.params)

        # load data
        iris = load_iris(as_frame=True)
        X, y = iris['data'], iris['target']

        X_train, X_valid, y_train, y_valid = train_test_split(X,y,test_size=0.3, random_state=2024)

        # train data

        clf = RandomForestClassifier(n_estimators=trial.params['n_estimators'], max_depth=trial.params['max_depth'], random_state=2024)
        clf.fit(X_train, y_train)

        # evaluate data

        y_pred = clf.predict(X_valid)
        acc_score = accuracy_score(y_valid, y_pred)
        
        # log metrics
        mlflow.log_metrics({'accuracy': acc_score})
    
    return acc_score


if __name__ == '__main__' : 

    # set mlflow
    mlflow.set_tracking_uri('http://0.0.0.0:5001')
    mlflow.set_experiment('hpo-tutorial')

    # study
    sampler = optuna.samplers.RandomSampler(seed=2024)
    study = optuna.create_study(sampler=sampler, study_name = 'hpo-tutorial', direction='maximize')

    # optimize
    study.optimize(objective, n_trials=5)

 


2. optuna_train.py 파일 실행하기 

2-1) Docker Compose 실행하기 

 

mlflow 실행을 설정했던 도커 compose 파일의 폴더 경로로 가서, compose 파일 다시 실행

아래 코드는 Docker compose 파일에 정의된 Docker 컨테이너를 백그라운드 모드로 실행하는 명령어임. 

Docker compose가 구성 파일을 읽고 해당 파일에 지정된 컨테이너를 시작함. 

$ docker compose up -d

https://ysryuu.tistory.com/8

 

[MLOps] 5. 도커 Compose로 MLflow 시작하기

도커 Compose란? : 복잡한 명령 arguments, 다수 컨테이너를 처리해야 할때 활용 - 도커 명령어들을 코드로 관리할 수 있다. - 여러 컨테이너들의 실행 순서를 지정할 수 있다. - 여러 컨테이너 간의 볼

ysryuu.tistory.com

 

2-2) MLflow 실행 확인

 

http://0.0.0.0:5001/ 를 주소창에 입력해 MLflow를 실행한다

 

2-3) optuna_train.py 파일을 실행한다 

 

터미널에서 optuna_train.py를 실행 

$ python3 optuna_train.py


3. 실행 결과 확인

다시 MLflow로 가보면, 'hpo-tutorial'이라는 이름으로 5개의 실험이 추가된 것을 확인 가능, 

각각의 경우의 max_depth 와 n_estimator에 따른 accuracy 값을 확인 가능함

기본 View 

 

compare 기능

 


4. Run name을 추가하기 

 

중복된 파일 실행시, MLflow에서는 5개씩 실험이 쌓일뿐 서로 다른 실험인지 구분되지 않음.

(위의 경우 1개의 실험에 peaceful-lamb ~ grandiose ~ 까지 5개 실험이 쌓였는데, 또 다른 5개가 쌓여도 이름상 구분은 어려움)

5개씩 하나의 실험에서 나왔다는 것, 서로 다른 실험 여부를 표시하기 위한 run name, prefix를 지정해줄 필요가 있음.

  

uuid를 활용하여 run name에 UNIQUE_PREFIX라는 고유한 8자리의 숫자를 붙여줌으로써 실험 단위로 구분할 수 있도록 처리 

import uuid
'''
'''

UNIQUE_PREFIX = str(uuid.uuid4())[:8]


def objective(trial) : 

    # suggest new parameter
    trial.suggest_int('n_estimators', 100, 1000, step=100)
    trial.suggest_int('max_depth', 3, 10)
    
    prefix = str(uuid.uuid4())[:8]
    run_name = f'{UNIQUE_PREFIX}-{trial.number}'
    with mlflow.start_run(run_name=run_name) : 
    
    	# log parameter
    	mlflow.log_params(trial.params)
        
        '''
        '''

 

최종 실행 코드 

 

<optuna_train.py의 내용>

import uuid
import mlflow
import optuna 
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

UNIQUE_PREFIX = str(uuid.uuid4())[:8]

def objective(trial) :
    # suggest new parameter
    trial.suggest_int('n_estimators',100,1000, step=100)
    trial.suggest_int('max_depth', 3,10)

    run_name = f'{UNIQUE_PREFIX}-{trial.number}'
    with mlflow.start_run(run_name=run_name):

        # log parameter
        mlflow.log_params(trial.params)

        # load data
        iris = load_iris(as_frame=True)
        X, y = iris['data'], iris['target']

        X_train, X_valid, y_train, y_valid = train_test_split(X,y,test_size=0.3, random_state=2024)

        # train data

        clf = RandomForestClassifier(n_estimators=trial.params['n_estimators'], max_depth=trial.params['max_depth'], random_state=2024)
        clf.fit(X_train, y_train)

        # evaluate data

        y_pred = clf.predict(X_valid)
        acc_score = accuracy_score(y_valid, y_pred)
        
        # log metrics
        mlflow.log_metrics({'accuracy': acc_score})
    
    return acc_score


if __name__ == '__main__' : 

    # set mlflow
    mlflow.set_tracking_uri('http://0.0.0.0:5001')
    mlflow.set_experiment('hpo-tutorial')

    # study
    sampler = optuna.samplers.RandomSampler(seed=2024)
    study = optuna.create_study(sampler=sampler, study_name = 'hpo-tutorial', direction='maximize')

    # optimize
    study.optimize(objective, n_trials=5)

 

실행 결과 다시 확인 

$ python3 optuna_train.py

 

연속으로 여러번 py파일을 실행해도, 이제 동일한 실험은 고유 id로 묶여있기 때문에, 서로 구분이 쉬워짐. (22695a51, 549a803c)

 

 

 

 

* 프로그래머스의 마키나락스 MLOPS 강의를 참고하여 작성함