์ด ๊ธ์์ ๋ค๋ฃจ๋ ๊ฒ
PythonOperator๋ก MLflow ์คํ์ ์๋ํํ์ฌ, ํ์ดํผํ๋ผ๋ฏธํฐยท๋ฉํธ๋ฆญยท๋ชจ๋ธ์ ์๋ ๊ธฐ๋กํ๋ Airflow + MLflow ์ฐ๋ ํจํด์ ๋ค๋ฃน๋๋ค.
์ ์์ง์
- Airflow 4๋จ๊ณ: BashOperator๋ก ์ธ๋ถ ํ์ต ์คํฌ๋ฆฝํธ ์คํ โ ์ธ๋ถ ์คํฌ๋ฆฝํธ ๋ถ๋ฆฌ ํจํด
์ด ๋จ๊ณ์์ ํด๊ฒฐํ๋ ค๋ ๋ฌธ์
๋ชจ๋ธ์ ํ์ตํ ๋๋ง๋ค ํ์ดํผํ๋ผ๋ฏธํฐ, ์ ํ๋, ๋ชจ๋ธ ์ํฐํฉํธ๋ฅผ ์๋์ผ๋ก ๊ธฐ๋กํ๋ฉด ์คํ ์ฌํ์ด ๋ถ๊ฐ๋ฅํฉ๋๋ค. MLflow Tracking์ ์ด ๋ชจ๋ ์ ๋ณด๋ฅผ ์๋ ๊ธฐ๋กํ๊ณ , Airflow DAG์์ ํธ์ถํ๋ฉด ํ์ต ํ์ดํ๋ผ์ธ ์์ฒด๋ฅผ ์๋ํํ ์ ์์ต๋๋ค.
์ค์ต ์ฝ๋: GitHub (Airflow_and_MLflow)
๐งญ ์ค์ต ์ ์ฒด ํ๋ฆ ์์ฝ
[1๋จ๊ณ] MLflow ์คํ ์คํฌ๋ฆฝํธ ์์ฑ
[2๋จ๊ณ] Airflow DAG ๊ตฌ์ฑ
[3๋จ๊ณ] DAG ์คํ ๋ฐ ํ๋ผ๋ฏธํฐ/๋ฉํธ๋ฆญ ํ์ธ
[4๋จ๊ณ] ๋ชจ๋ธ ์ ์ฅ ๋ฐ ๋ก๊น
์ํ ์ ๊ฒ
๐ ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ
airflow/
โโโ dags/
โ โโโ train_with_mlflow.py โ DAG ํ์ผ
โโโ ml_code/
โ โโโ train_mlflow.py โ MLflow ์ฐ๋ ํ์ต ์คํฌ๋ฆฝํธ
โโโ mlruns/ โ MLflow ๋ก๊น
๊ฒฐ๊ณผ ์ ์ฅ ํด๋ (์๋ ์์ฑ)
๐งช 1๋จ๊ณ: MLflow ํ์ต ์คํฌ๋ฆฝํธ (ํต์ฌ ๋ถ๋ถ)
# airflow/ml_code/train_mlflow.py
def run_experiment():
mlflow.set_tracking_uri("file:/opt/airflow/mlruns")
mlflow.set_experiment("airflow_mlflow_example")
with mlflow.start_run():
data = load_iris()
X, y = data.data, data.target
model = RandomForestClassifier(n_estimators=50, max_depth=3)
model.fit(X, y)
preds = model.predict(X)
# ํ์ต ๋ฐ์ดํฐ๋ก ํ๊ฐ โ ์ค์ ์ด์์์๋ train_test_split ํ์
acc = accuracy_score(y, preds)
mlflow.log_param("n_estimators", 50)
mlflow.log_param("max_depth", 3)
mlflow.log_metric("accuracy", acc)
mlflow.sklearn.log_model(model, "model")
์ ์ฒด ์ฝ๋: GitHub (train_mlflow.py)
๐งช 2๋จ๊ณ: Airflow DAG ์์ฑ
# airflow/dags/train_with_mlflow.py
from airflow import DAG
from airflow.operators.python import PythonOperator
from datetime import datetime
import sys
sys.path.append("/opt/airflow/ml_code")
from train_mlflow import run_experiment
with DAG(
dag_id='mlflow_tracking_dag',
start_date=datetime(2023, 1, 1),
schedule_interval=None,
catchup=False,
) as dag:
run_mlflow = PythonOperator(
task_id='run_mlflow_training',
python_callable=run_experiment,
)
โ ์คํ ์ ์ฐจ
train_mlflow.py์์ฑtrain_with_mlflow.pyDAG ๋ฑ๋ก- Airflow UI์์ DAG ์คํ
- Task ๋ก๊ทธ์์ ํ๋ผ๋ฏธํฐ/๋ฉํธ๋ฆญ/๋ชจ๋ธ ๊ธฐ๋ก ํ์ธ
โ ๋ชจ๋ ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด?
docker-compose.yaml์์ ๋ณผ๋ฅจ ํ์ธ:volumes: - ./ml_code:/opt/airflow/ml_coderequirements.txt์ MLflow ์ถ๊ฐ:mlflowDockerfile ์์ฑ ํ ์ฌ๋น๋:
docker-compose down docker-compose build docker-compose up -d
๐ ํ์ธ ํฌ์ธํธ
| ํญ๋ชฉ | ํ์ธ ๋ฐฉ๋ฒ |
|---|---|
| MLflow ๋ก๊ทธ | /opt/airflow/mlruns/ ๊ฒฝ๋ก์์ ํ์ธ |
| ์ ํ๋ ๋ก๊ทธ | DAG ๋ก๊ทธ์์ acc = ... ํ์ธ |
| DAG ์ด๋ฆ | mlflow_tracking_dag |
| Experiment ์ด๋ฆ | airflow_mlflow_example |
์ค๊ณ ํ๋จ (Why This Way?)
MLflow ํจ์๋ฅผ ์ง์ ํธ์ถํด์ผ ํ๋ฏ๋ก PythonOperator๊ฐ ์ ํฉํ๋ฉฐ, ๋ก์ปฌ file URI ๋์ ํ๋ก๋์ ์์๋ PostgreSQL+S3 ๋ฐฑ์๋์ MLflow ์๋ฒ๋ฅผ ์ฌ์ฉํด ํ ๋จ์ ์คํ ์ถ์ ๊ณผ ์ํฐํฉํธ ๊ด๋ฆฌ๋ฅผ ์ํํฉ๋๋ค.
๋ค์์ ์ฝ์ ๊ธ
โ MLOps ํ๋ซํผ ๊ตฌ์ถ 1๋จ๊ณ: ์ธํ๋ผ ์ค๊ณ ๋ฐ ํ๊ฒฝ ์ค๋น โ Level 2: Helm ๊ธฐ๋ฐ MLOps ํ๋ซํผ ๊ตฌ์ถ ์์