
가짜연구소 9기 "AI를 잘 활용하는 개발자로 성장하기" 프로젝트에 참여하여 Datacamp의 "Machine Learning Engineer" 강의를 수강하고 해당 내용을 정리한 게시글입니다.
Datacamp Machine Learning 코스 페이지
MLFlow는 모델 생명주기의 전 과정에 걸쳐 다양한 자동화 기능을 제공하여 MLOps를 지원한다.
MLflow는 크게 네 가지의 컴포넌트를 지원한다.
client와 mlflow 두가지 모듈을 지원한다.client : 저수준 API로 관리할 데이터들을 자유롭게 커스텀 가능mlflow : 고수준 API로 set_experiment 메서드 하나로 모듈내의 데이터 추적을 자동화하여 제공ML 실험에 대한 추적 플랫폼이 필요한 이유는, 목표 달성을 위해 학습해야 할 모델이 많아질수록 알고리즘, metrics, 사용 데이터 등이 서로 달라 이들을 전부 관리하는 것이 어려워지기 떄문이다.
MLflow Tracking은 metrics, 파라미터 등을 등록하여 쉽게 관리할 수 있게한다.
mlflow.start_run() : 실험 시작을 선언하는 API. 프로그램이 종료되거나 end_run()을 실행할 때까지 로깅된 모든 데이터와 아티팩트들을 지정된 uri에 저장한다.log_metric, log_metrics : metric 로깅log_param, log_params : 파라미터 로깅log_artifact, lof_artifacts : 아티팩트 로깅mlflow ui를 명령어로 실행하면 로컬호스트에서 로깅된 결과를 UI로 확인가능mlflow는 한 run에 대한 시각화 뿐만 아니라, 여러 run을 조회하고, 서로 비교할 수 있는 쿼리 기능을 제공한다.
mlflow.search_runs() : 현재 mlflow에 저장된 runs 정보를 반환max_results : 반환할 run의 최대 개수 지정order_by : 수치값 기준 정렬filter_string : 조건을 문자열 형태로 지정하여 query string 기반 검색experiment_names : 실험 이름으로 특정 실험 검색f1_score_filter = "metrics.f1_score > 0.60"
# experiment1 실험에서 f1 score가 0.6보다 큰 runs를 recall 기준으로 내림차순으로 정렬하여 반환
mlflow.search_runs(experiment_names=["experiment1"],
filter_string=f1_score_filter,
order_by=["metrics.recall DESC"])
여러 라이브러리에서 개발된 ML 모델에 대한 표준화된 패키징을 지원하는 컴포넌트
기본값으로 Flavors라는 포맷으로 패키지가 저장된다.
표준화된 패키지는 MLflow가 지원하는 다양한 유명 ML 플랫폼에서 배포를 지원한다.
mlflow에서는 autolog() 함수를 통해 명시적인 로깅 정의 없이 metric, parameter, model 등을 자동으로 저장할 수 있다.
model.get_param()으로 얻을 수 있는 파라미터들을 저장import mlflow
from sklearn.linear_model import LinearRegression
mlflow.sklearn.autolog()
lr = LinearRegression()
lr.fit(X, y) # Auto logging
autolog를 통해 모델의 정보를 저장할 경우 다음과 같은 형식으로 저장된다.
model
-- MLmodel # 저장 위치, 사용 라이브러리, 버전 등 중요 정보에 대해 yaml 형식으로 저장, 이후 모델을 import할 때 라이브러리가 정보를 참조하기 위해 사용
-- model.pkl
-- python_env.yaml
-- requirements.txt
MLflow의 Model 모듈은 모델을 저장, 로드, 로깅하기 위한 다양한 API 함수를 지원한다.
예를들어 MLflow는 sklearn을 내장하고 있어 다음과 같이 사용할 수 있다.
mlflow.sklearn.save_model(model, path) # 앞서 배운 표준 형식으로 저장
mlflow.sklearn.load_model(model_uri)
MLflow에서는 모델 로드를 위해 절대경로, 상대경로 외에 다양한 방법을 제공한다.
runs:/<run_id>/relative-path-to-models3://my_bucket/path-to-modelrun을 불러왔다면 last_active_run() 함수를 통해 마지막 run을 재현성 있게 실행할 수 있다.
last_active_run()이 반환하는 객체는 마지막 run의 정보를 갖고 있어, 해당 run의 정보를 조회 가능하다.
MLflow는 강력한 API를 지원해주기는 하지만, 모든 상황에 대응할 수는 없다. 때문에 사용자가 커스텀 해야하는 경우 Model Customization 기능을 지원한다.
mlflow.pyfunc 모듈은 파이썬 함수를 FLAVOR 형식으로 사용 가능하도록 지원한다.
mlflow.pyfunc.PythonModel을 상속하는 클래스를 만들어서 FLAVOR 형식으로 저장하기 위한 코드와 함수를 정의load_context : load_model()이 호출되었을 때 실행되는 메서드predict : 로드된 모델에 대해 예측을 했을 때 실행되는 메서드경로와 함께 커스텀 파이프라인 클래스를 호출하여 저장하면 된다.
mlflow.pyfunc.save_model(path="custom_model", python_model=CustomPredict())mlflow.pyfunc.log_model(artifact_path="custom_model", python_model=CustomPredict())mlflow.evaluate() 함수를 통해 데이터셋을 기반으로 모델의 예측 결과를 평가할 수 있다. (predict 함수가 정의되어있기 때문에가능)
# 사용 예시
mlflow.evaluate("runs:/run_id/model",
eval_data,
targets="test_label",
model_type="regressor") # [regressor, classifier]
evaluate를 진행하면, 자동으로 shap 시각화 라이브러리로 시각화된 plot file이 생성된다.
모델을 표준화된 형식으로 패키징했기 때문에 쉽게 배포할 수 있다.
mlflow models serve [OPTIONS]mlflow models serve --help를 통해 확인할 수 있다.모델을 mlflow로 배포할 경우 모델에 접근 가능한 REST API를 제공한다.
/ping, /health : mlflow 서버의 health check를 위한 API/version : MLflow의 버전/invocations : 배포된 모델의 스코어링pandas_df.dataframe_split() 함수를 통해 json 형식으로 변환이 가능하다.모델의 생명주기 동안 모델은 개발 환경, 스테이징 환경, 배포 환경 등 서로 다른 환경에서 관리되어야 한다.
MLflow의 Model Registry는 다양한 환경들에 대해 하나로 통합된 MLflow 중앙 저장소에서 관리할 수 있는 컴포넌트이다.
Model Registry는 크게 모델의 상태를 크게 4개로 구분하여, 모델이 생명주기에서 어떤 상태인지를 나타낸다.
1. None : MLflow에 의해 추적되고 있는 상태 (logging)
2. Staging : MLflow에 등록된 상태
3. Production
4. Archived
MLflow의 client 모듈을 통해 MLflow에 모델을 등록하고, 등록된 모델(Registered Model)을 관리할 수 있다.
client 모듈은 MlflowClient 클래스의 인스턴스를 기반으로 동작한다.
from mlflow import MlflowClient
client = MlflowClient()
create_registered_model() 메서드를 통해 모델을 MLflow에 등록search_registered_models 메서드로 필터 스트링에 기반하여 검색"name LIKE 'Unicorn%'" : Unircorn을 모델 이름으로 포함한 모든 Registered model 검색mlflow.register_model(model_uri, name)model_uri는 로컬 디렉토리나 load_model과 동일한 문법을 이용할 수 있음log_model을 호출할 때 registered_model_name 인자를 지정하여 해당 이름으로 모델의 아티팩트를 저장하며 함께 등록할 수 있음client 인스턴스의 transition_model_version_stage(name, verstion, stage) 메서드에서 모델의 이름과 버전을 지정하여 특정 stage로 변경할 수 있다.[정보]
https://mlflow.org/docs/latest/model-registry.html#migrating-from-stages
MLflow 2.9.0 버전 부터는 보다 유연한 관리를 위해 Model stages가 deprecate된다고 한다.
이후로는 model version tags와 model verion aliases를 제공하여 모델의 환경을 관리할 수 있도록 한다고 한다.
model version tags는 docker의 tag와 유사하게 <모델이름>@<태그이름>으로 구성되어, 태그별로 모델을 구분할 수 있다.
MLflow는 Model registry에 등록된 모델을 배포하기 위해 두 가지 옵션을 제공한다.
1. load_model() 함수
2. mlflow models serve 명령어 (CLI)
특정 모델을 지정해서 배포하기 위해 model uri가 필요하다
버전이나 stage 상태를 이용해서 특정 버전 또는 특정 스테이지의 모델을 지정할 수 있다.
models:/model_name/version or stageimport mlflow.sklearn
model = mlflow.sklearn.load_model("models:/Unicorn/Production")
mlflow models serve -m "models:/Unicorn/Production"
모델은 기본적으로 5000번 포트에 서빙되며, API를 통해 데이터를 보낼 수 있다.
데이터는 csv 또는 json 형태여야 한다.
MLflow Projects 컴포넌트는 ML code를 재실행하고, 모델을 재생산 할 수 있는 방법을 제공
코드를 MLflow가 실행 가능한 단위로 패키징하여 재현성을 보장한다.
project/
-- MLproject
-- train_model.py
-- python_env.yaml
-- requirements.txt
MLproject 파일은 프로젝트에 대한 프로퍼티들을 저장한 yaml 파일로, 프로젝트를 불러올 때 참조된다.
name, entry_points, python_env 등을 저장name: insurance_model
python_env: python_env.yaml
entry_points:
main:
command: 'python3.9 train_model.py'
MLflow Projects는 API 또는 CLI 명령어를 통해 실행할 수 있다.
mlflow는 projects라는 모듈을 제공하여 MLflow Project 관련 함수를 지원한다.
mlflow.projects.run() 으로 로컬 저장소 또는 git 저장소에 있는 프로젝트 실행 가능uri, entry_point, experiment_name, env_manager 등을 설정 가능mlflow.projects.run(
uri="./", # 실행할 프로젝트의 경로
entry_pont="main",
experiment_name="Salary Model"
)
mlflow run --entry-point main --experiment-name "Salary Model" ./
MLflow Projects 이전 코드를 그대로 재사용 할 수도 있고, 파라미터를 사용하여 유연하게 커스텀 할수도 있다.
이러한 기능은 하이퍼파라미터 튜닝과 같이 동일한 환경에서 일부 설정을 변경하면서 ML 모델을 탐색하는 활동에 유리하다.
파라미터 정의는 MLproject 파일의 entry_points 내에서 할 수 있다.
entry_points:
main:
parameters:
parameter_1_name:
type: data_type # float, string 등 파이썬이 지원하는 데이터 타입
default: default_value
parameter_2_name:
type: ... # default: string
전달된 파라미터는 다음과 같이 가져올 수 있다.
import sys
parameter_1_name = int(sys.argv[1])
parameter_2_name = bool(sys.argv[2])
이는 CLI 명령어로 전달된 파라미터와 동일하게 취급되므로, argparse와 같은 다른 파라미터 파싱 도구와 함께 사용할 수도 있다.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--parameter_1_name", type=int, default=1)
parser.add_argument("--parameter_2_name", type=bool, default=False)
...
args = parser.parse_args()
print(args.parameter_1_name, args.parameter_2_name)
또한 run 인스턴스의 params 딕셔너리를 통해서도 접근할 수 있다.
import mlflow
parameter_1_name = mlflow.active_run().data.params["parameter_1_name"]
mlflow.projects 모듈을 사용한다면, run 함수 실행 시 딕셔너리 형태로 파라미터를 지정할 수 있다.
import mlflow
mlflow.projects.run(
...,
parameters = {
'parameter_1_name': value1,
'parameter_2_name': value2
}
)
CLI를 사용한다면 -P 옵션과 함께 파라미터를 전달할 수 있다.
mlflow run ... -P parameter_1_name=value1 -P parameter_2_name=value2 ...
MLflow Projects는 여러 단계의 워크플로우를 순차적으로 수행하도록 만들수도 있다.
MLproject 파일은 여러개의 entry_points를 만들 수 있다.
entry_points:
step_1:
...
step_2:
...
이제 run 함수를 실행할 때 어떤 entry_points를 실행해야 하는지 순차적으로 정의할 수 있다.
step_1 = mlflow.projects.run(uri="./", entry_point="step_1")
step_2 = mlflow.projects.run(uri="./", entry_point="step_2")
run 함수는 mlflow.projects.SubmittedRun 객체를 반환하므로, 후속 작업에서 필요시 사용할 수 있다. (공식문서 참조)
run.cancel() : 현재 run 취소run.get_status() : 현재 run의 정보 획득run.run_id() : 현재 run의 run_id 획득run.wait() : run이 종료될 때까지 대기예전에 국비학원에서 mlflow를 잠깐 다루었을 때 실험 저장 및 모델 배포용으로 잠깐 배운 적이 있는데, 이렇게 전체 생명주기에 걸쳐 다양한 기능을 지원한다는 것을 배울 수 있었습니다.
또 강의 내용을 정리하고, 궁금한 점을 검색하면서 stages가 deprecate된다는 사실을 알게 되었는데, 역시 이런 라이브러리, 프레임워크를 사용할 때는 버전에 맞는 공식문서를 참조하는 것이 중요하다는 것을 느꼈습니다.
mlflow가 다양한 모델을 지원한다는 것은 처음 알았는데, 실무에서도 mlflow.sklearn과 같이 mlflow가 지원하는 모듈을 많이 사용하는지가 궁금합니다.