19장. MLOps 와 LLMOps, 워크플로 자동화
실험 기록
요리사가 노트에 "설탕 2큰술, 중불 5분, 맛 점수 4점"을 적어 두면, 가장 맛있던 날의 레시피를 다시 찾을 수 있습니다. 적지 않으면 "지난주 그게 뭐였더라"가 됩니다. 실험 기록은 학습 한 번마다 이런 노트를 남기는 일입니다.
그림의 네 칸이 실행 하나에 남기는 것입니다. 설정값(파라미터)은 재료 양, 점수(지표)는 맛 점수, 파일(산출물)은 완성된 요리 사진, 꼬리표(태그)는 "추석 메뉴" 같은 메모입니다. 노트 한 쪽이 MLflow 의 실행(run) 하나이고, 노트 한 권이 실험(experiment) 하나입니다.
MLflow 의 낱말
| 낱말 | 뜻 | 이 장의 예 |
|---|---|---|
| 실험(experiment) | 같은 목표의 실행을 모은 묶음 | 문의분류 |
| 실행(run) | 학습 한 번 | e5-C0.3 |
| 파라미터(param) | 실행에 쓴 설정값 | C=0.3, features=e5 |
| 지표(metric) | 실행이 낸 점수 | accuracy, macro_f1 |
| 산출물(artifact) | 실행이 만든 파일 | 학습한 모델 |
| 태그(tag) | 찾기 쉽게 붙인 메모 | 데이터의 지문 |
MLflow 는 기록을 파일이나 데이터베이스에 둡니다. 이 장의 실습은 sqlite:///out_mlflow.db 로 SQLite 파일 하나에 둡니다. mlflow ui 명령으로 기록을 웹 화면으로 볼 수도 있지만, 이 장에서는 코드로 표를 뽑아 봅니다.
기록의 생김새
MLflow 없이도 생각은 같습니다. 실행마다 설정과 점수를 사전으로 쌓고, 점수로 줄 세웁니다.
runs = []
def log_run(name, params, metrics):
"""실행 하나를 기록한다(MLflow 의 start_run, log_params, log_metrics 가 하는 일)"""
runs.append({"실행": name, **params, **metrics})
# 설정을 바꿔 가며 세 번 학습했다고 하자(점수는 예시 숫자)
log_run("C0.3", {"C": 0.3}, {"accuracy": 0.70})
log_run("C1", {"C": 1}, {"accuracy": 0.68})
log_run("C10", {"C": 10}, {"accuracy": 0.70})
# 결과: 정확도가 높은 차례. 같은 점수면 먼저 한 실행이 앞에 온다
for r in sorted(runs, key=lambda r: -r["accuracy"]):
print(r)코드에 나오는 함수
| 코드 | 쉬운 뜻 |
|---|---|
runs = [] | 실행 기록을 쌓을 빈 목록이다. MLflow 에서는 데이터베이스가 이 일을 한다 |
{"실행": name, **params, **metrics} | ** 로 두 사전을 펼쳐 한 사전으로 합친다. 실행 이름, 설정, 점수가 한 줄에 모인다 |
sorted(runs, key=lambda r: -r["accuracy"]) | 정확도에 빼기를 붙인 값으로 줄 세운다. 작은 값이 앞이므로 정확도가 큰 실행이 앞에 온다 |
start_run, log_params, log_metrics | 이 예시가 흉내 내는 MLflow 함수 이름이다. 실행 시작, 설정 기록, 점수 기록을 뜻한다. 이 절의 코드는 MLflow 를 부르지 않는다 |
이 코드가 뜻하는 것
달리기 기록 앱을 떠올려 봅니다. 달릴 때마다 신은 신발과 기록이 한 줄씩 쌓이고, 기록 순으로 줄 세워 가장 좋았던 날을 찾습니다. 여기서 달리기 한 번이 실행(run), 신발이 파라미터, 기록이 지표입니다.
| 줄 | 하는 일 | 쉽게 말하면 |
|---|---|---|
log_run("C0.3", {"C": 0.3}, {"accuracy": 0.70}) | 실행 하나를 이름, 설정, 점수와 함께 쌓는다 | 오늘 달린 기록을 저장한다 |
log_run 세 번 | C 를 0.3, 1, 10 으로 바꾼 세 실행을 쌓는다. 점수는 예시 숫자다 | 신발을 바꿔 세 번 달린다 |
sorted(…) | 정확도가 높은 차례로 줄 세운다 | 좋은 기록 순으로 본다 |
for r in …: print(r) | 한 줄에 실행 하나씩 보여 준다 | 기록표를 위에서부터 읽는다 |
결과에서 C0.3 과 C10 은 둘 다 0.7 입니다. 파이썬의 sorted 는 값이 같으면 원래 차례를 지키므로 먼저 기록한 C0.3 이 앞에 옵니다. 출력에 0.70 이 아니라 0.7 로 나오는 것은 파이썬이 끝의 0 을 적지 않기 때문입니다. 비유와 다른 점은, 달리기는 숫자가 작을수록 좋은 기록이지만 여기서는 정확도가 클수록 앞에 온다는 것입니다.
주의할 점
- 점수만 적으면 나중에 같은 모델을 다시 만들 수 없습니다. 데이터의 지문, 씨앗, 패키지 버전도 함께 남깁니다.
- 여러 설정을 견줄 때 고르는 데 쓴 시험 묶음으로 마지막 성적까지 내면 점수가 부풀려집니다. 데이터가 넉넉하면 고르는 묶음과 마지막 시험 묶음을 나눕니다.