로컬에서 먼저 검증하기
플랫폼 업로드 전 docker run 과 mlflow models serve 로 계약 준수를 확인하는 절차
플랫폼 업로드 전에 로컬 PC 에서 계약 준수 확인. Docker 와 로컬 MLflow 서버 필요. 아래 명령은 MNIST 예제 디렉터리에서 실행. 로컬 MLflow 도 예제 이미지 내부의 mlflow 로 실행하므로 호스트에 파이썬 패키지 설치 불필요.
1. 이미지 빌드
docker build -t example/mnist-trainer:v1 .
2. 검증용 데이터 만들기
플랫폼이 /geo/dataset 에 수행하는 작업을 재현. --synthetic 은 네트워크 없이 숫자를 그려 넣은 합성 이미지 생성.
docker run --rm -u "$(id -u):$(id -g)" -v "$PWD:/w" -w /w \
--entrypoint python example/mnist-trainer:v1 \
make_sample_data.py ./sample-data --synthetic --count 400
# -> sample-data/manifest.json (400 files)
3. 로컬 MLflow 실행
docker run -d --name mlflow-local --network host -u "$(id -u):$(id -g)" -e HOME=/tmp \
-v "$PWD:/w" -w /w --entrypoint mlflow example/mnist-trainer:v1 \
server --host 127.0.0.1 --port 5500 \
--backend-store-uri sqlite:////w/store.db --artifacts-destination /w/mlartifacts
4. 플랫폼처럼 run 을 먼저 만들고 학습 실행
플랫폼은 run 을 미리 만들어 MLFLOW_RUN_ID 로 전달. 같은 방식으로 실행해야 검증 조건이 실제 환경과 동일.
export MLFLOW_TRACKING_URI=http://127.0.0.1:5500
RUN_ID=$(docker run --rm --network host -e MLFLOW_TRACKING_URI \
--entrypoint python example/mnist-trainer:v1 -c "
from mlflow.tracking import MlflowClient
c = MlflowClient()
exp = c.get_experiment_by_name('local-verify')
exp_id = exp.experiment_id if exp else c.create_experiment('local-verify')
print(c.create_run(exp_id).info.run_id)" | tail -1)
docker run --rm --network host \
-v "$PWD/sample-data:/geo/dataset:ro" \
-e GEO_DATA_DIR=/geo/dataset \
-e GEO_WORK_DIR=/geo/work \
-e GEO_HP_EPOCHS=2 \
-e GEO_PARAM_DEVICE=cpu \
-e MLFLOW_TRACKING_URI \
-e MLFLOW_EXPERIMENT_NAME=local-verify \
-e MLFLOW_RUN_ID=$RUN_ID \
example/mnist-trainer:v1
echo "exit=$?"
-> train 320 / val 80 @ cpu
-> epoch 1/2 loss=2.2821 val_acc=0.1000
-> epoch 2/2 loss=2.1825 val_acc=0.3500
-> done. best val accuracy = 0.3500
🏃 View run intrigued-hen-480 at: http://127.0.0.1:5500/#/experiments/1/runs/79676e08…
exit=0
--network host 는 MLflow 가 같은 PC 의 localhost 에 있어서 지정. 원격 MLflow 주소를 사용하면 생략 가능.
5. 확인할 것
| # | 확인 | 통과하지 못하면 |
|---|---|---|
| 1 | 종료 코드가 0 인가 | 지표가 모두 남아 있어도 실패로 기록 |
| 2 | MLflow 의 그 run($RUN_ID)에 지표 곡선이 그려지는가 | 학습은 진행되지만 학습 화면이 비어 있음. MLFLOW_RUN_ID 를 덮어쓰거나 set_experiment() 를 호출하지 않았는지 확인. |
| 3 | param epochs 와 지표의 step 이 있는가 | epochs 가 없으면 진행률 막대 없이 "학습 중" 으로만 표시. step 이 없으면 진행률과 곡선이 첫 점에서 멈춤. |
| 4 | run 에 model 이 로깅되고 MLmodel · signature 가 표시되는가 | 플랫폼이 등록한 버전에 MLmodel 이 없어 서빙 이미지 생성 불가 |
| 5 | 필요한 산출물이 MLflow 에 기록되었는가 | /geo/work 는 회수하지 않음 |
| 6 | 아래 serve 검증이 통과하는가 | 학습은 성공하지만 배포 불가. 가장 중요한 항목. |
1~5 는 MLflow 화면(http://127.0.0.1:5500)에서 직접 확인.
6. serve 검증: 배포의 전제 조건
플랫폼의 추론 서빙은 등록된 모델 버전을 MLflow scoring server 로 그대로 실행하는 방식. 로컬에서 기동되면 플랫폼에서도 기동.
# 1) 학습이 로깅한 모델을 로컬 레지스트리에 등록 (플랫폼에서는 자동)
docker run --rm --network host -e MLFLOW_TRACKING_URI --entrypoint python \
example/mnist-trainer:v1 -c "
import mlflow
from mlflow.tracking import MlflowClient
c = MlflowClient()
run = c.get_run('$RUN_ID')
m = c.search_logged_models(experiment_ids=[run.info.experiment_id],
filter_string=\"source_run_id = '$RUN_ID'\")[0]
mv = mlflow.register_model(f'models:/{m.model_id}', 'mnist')
print('registered', mv.name, mv.version)"
# 2) 등록된 버전을 그대로 띄운다
docker run -d --name mnist-serve --network host -e MLFLOW_TRACKING_URI \
--entrypoint mlflow example/mnist-trainer:v1 \
models serve -m models:/mnist/1 -h 127.0.0.1 -p 5501 --env-manager local
# 3) 요청 한 건. 200 과 JSON 예측이 오는가
python3 -c "
import base64, json
b = base64.b64encode(open('sample-data/images/00001.png','rb').read()).decode()
json.dump({'dataframe_split': {'columns': ['image_b64'], 'data': [[b]]}}, open('input.json','w'))"
curl -X POST 127.0.0.1:5501/invocations -H 'Content-Type: application/json' -d @input.json
{"predictions": [{"label": "1", "confidence": 0.11639321595430374}]}
여기서 확인할 것은 응답이 반환되는가(모델이 로드되고 signature 대로 요청을 처리하는가). 합성 데이터는 학습 신호가 약하므로 예측이 틀려도 문제없음.
가장 흔한 실패는 signature 누락, predictor.py 의 학습 코드 import, 학습 환경과 다른 pip_requirements 세 가지. 셋 모두 학습 단계에서는 증상이 없고 서빙에서만 나타나므로 이 단계에서 발견 필요.
정리
docker rm -f mlflow-local mnist-serve
다음: 플랫폼에 이미지 업로드하기