LabHub
学习 学习路径 课程

上周那个模型更好,可没人找得到

更差的模型上了生产

在 LabHub 中继续学习

한국어 원문으로 표시합니다.

목표

모델 버전과 별칭(champion·challenger)을 갖춘 작은 레지스트리를 세우고, 지표가 떨어지면 승격을 막는 관문을 만들고, 관문을 무시한 승격을 되돌리고, 마지막으로 입력 분포가 움직였는지를 숫자로 만듭니다.

왜 중요한가

모델을 배포한다는 것은 파일을 복사하는 일이 아니라 어느 버전을 가리킬지 정하는 일 입니다. 운영이 버전 번호를 직접 들고 있으면 되돌리기가 배포 설정 변경이 되지만, 별칭을 한 겹 두면 되돌리기는 이름이 가리키는 곳을 바꾸는 일이 됩니다. 그래서 레지스트리는 버전·별칭·이력 셋을 함께 둡니다. 승격 관문은 여기에 '자동으로 가되 아무 때나 가지는 않는다' 를 더하는 장치입니다 — 재학습이 끝났다고 바로 운영으로 가면, 어느 주에는 더 나쁜 모델이 조용히 올라갑니다. 관문이 막았는데도 사람이 밀어붙이는 일은 실제로 일어나므로, 막는 것만큼이나 막았다는 사실과 밀어붙였다는 사실을 함께 남기는 것이 중요합니다.

단계

  1. 지금 운영에 나가 있는 모델을 버전 1로 등록합니다.
  2. champion 별칭이 버전 1을 가리키게 합니다.
  3. 재학습 결과를 버전 2로 등록하고 challenger 로 세웁니다.
  4. 승격 관문을 코드로 만들어 판정을 남깁니다.
  5. 별칭이 움직인 이력을 감사 기록으로 남깁니다.
  6. 관문을 무시한 승격을 재현하고 그 사실을 기록에 남깁니다.
  7. 되돌리고 얼마나 잃었는지 적습니다.
  8. 입력 분포가 얼마나 이동했는지를 재서 재학습 판단에 붙입니다.

참고

지금 나가 있는 모델을 버전 1로 등록한다

lr 0.1, epochs 40, seed 7 로 학습기를 돌려 모델 파일을 만들고 /root/registry/registry.json 에 model 을 "churn-classifier" 로, versions 의 첫 항목으로 version 1 을 등록하세요. 각 버전은 version·run_id·params·metrics·model_path·model_sha256·data_sha256·created_at 를 담습니다. model_sha256 은 model_path 가 가리키는 파일의 해시이고, data_sha256 은 /opt/fixtures/mlops/train.csv 의 해시입니다.

학습기의 --out 옵션이 모델 파일을 써 줍니다. 버전마다 파일을 따로 두세요 — 덮어쓰면 되돌릴 것이 남지 않습니다.

배포 대상을 번호가 아니라 이름으로 가리킨다

/root/registry/aliases.json 에 {"champion": 1} 을 저장하세요. 이 실습에서 쓰는 별칭은 champion 과 challenger 둘뿐입니다.

운영이 버전 번호를 직접 보게 두면 되돌릴 때 배포 설정을 고쳐야 합니다. 별칭을 한 겹 두면 되돌리기가 이 파일 한 줄이 됩니다.

재학습 결과를 도전자로 등록한다

lr 0.3, epochs 30, seed 3 으로 다시 학습시켜 버전 2를 /root/registry/registry.json 에 등록하고 /root/registry/aliases.json 의 challenger 가 2를 가리키게 하세요. 버전 번호는 1부터 1씩 올라가야 하고, champion 은 아직 1이어야 합니다.

재학습이 곧 배포는 아닙니다. 새 버전은 일단 도전자로 세워 두고, 승격은 다음 단계의 관문이 판단합니다.

승격을 사람이 아니라 규칙이 판단하게 한다

/root/registry/gate.py 를 작성해 /root/registry/registry.json 과 /root/registry/aliases.json 을 읽고 /root/registry/gate.json 에 champion_version·challenger_version·champion_metric·challenger_metric·margin·decision·reasons 를 저장하세요. margin 은 0.005 이고, 도전자의 valid_accuracy 가 챔피언 + margin 이상일 때만 decision 이 promote, 아니면 block 입니다. reasons 는 10자 이상인 문장들의 목록입니다.

여유폭을 두는 이유는 측정 잡음 때문입니다. 0.001 차이로 챔피언을 바꾸면 다음 주에 다시 바꾸게 됩니다.

별칭이 움직인 이력을 남긴다

/root/registry/audit.jsonl 에 지금까지 별칭을 세운 일을 한 줄씩 남기세요. 각 줄은 ts·alias·from(처음이면 null)·to·actor·reason(10자 이상)을 담습니다. 기록을 처음부터 재생하면 /root/registry/aliases.json 과 정확히 같은 상태가 나와야 합니다.

감사 기록은 '지금 무엇인가' 가 아니라 '어떻게 여기까지 왔는가' 를 담습니다. from 을 적어 두면 재생했을 때 어긋난 곳이 바로 드러납니다.

관문을 무시한 승격이 무엇을 남기는지 본다

관문이 막았는데도 사람이 champion 을 버전 2로 올린 상황을 재현하세요. /root/registry/aliases.json 의 champion 을 2로 바꾸고, /root/registry/audit.jsonl 에 alias champion, from 1, to 2 인 줄을 추가하되 그 줄에 gate_decision 키로 gate.json 의 판정을 그대로 적으세요.

막는 것만으로는 모자랍니다. 밀어붙인 사람이 무엇을 알고 있었는지가 남아야 다음에 같은 일을 두고 이야기할 수 있습니다.

되돌리고 얼마나 잃었는지 적는다

champion 을 다시 버전 1로 되돌리고 그 변경도 /root/registry/audit.jsonl 에 남기세요(기록은 모두 4줄 이상이 되고 마지막 줄이 champion 2→1 이어야 합니다). 그다음 /root/registry/rollback.json 에 restored_version·bad_version·detected_by(10자 이상)·metric_delta(버전 1의 valid_accuracy − 버전 2의 값, 소수점 넷째 자리 반올림)를 저장하세요.

되돌리기는 별칭을 옮기는 일입니다. 모델 파일을 지우거나 버전을 삭제하면 무슨 일이 있었는지가 함께 사라집니다.

입력 분포가 움직였는지를 숫자로 만든다

/opt/fixtures/mlops/train.csv 를 기준으로 /opt/fixtures/mlops/week2.csv 의 다섯 특징(tenure_months·monthly_fee·support_tickets·late_payments·usage_hours)이 얼마나 이동했는지 재서 /root/registry/drift.json 에 baseline·current·features·max_abs_shift_sigma·alert·retrain_required 를 저장하세요. features 의 각 항목은 train_mean·new_mean·pstdev(기준 데이터의 모집단 표준편차)·shift_sigma((new_mean − train_mean) ÷ pstdev)를 담고, 빈 값이나 숫자가 아닌 값은 세지 않습니다. alert 와 retrain_required 는 max_abs_shift_sigma 가 1.0 을 넘는가입니다.

분포 이동은 계약 위반이 아닙니다 — 값이 전부 허용 범위 안에 있어도 평균이 옮겨 갈 수 있습니다. 그래서 따로 재야 합니다.