19장. MLOps 와 LLMOps, 워크플로 자동화
자동 배포의 관문
새 메뉴는 주방에서 맛있어도 시식회를 통과해야 메뉴판에 오릅니다. 시식회의 기준은 미리 정해 둡니다. "지금 메뉴보다 맛 점수가 낮지 않을 것, 짠맛 불만이 없을 것"처럼요. 품질 게이트가 이 시식회입니다.
1번에서 새 후보를 정해 둔 시험 묶음으로 잽니다. 2번에서 지금 쓰는 챔피언도 같은 묶음으로 재어 견줍니다. 3번 기준을 넘으면 별칭을 옮기고, 4번 넘지 못하면 챔피언을 그대로 두고 사람에게 알립니다. 시식회가 게이트, 지금 메뉴가 챔피언, 새 메뉴가 도전자입니다.
게이트 규칙의 예
| 규칙 | 막는 것 |
|---|---|
| 정확도가 챔피언보다 낮지 않다 | 나빠진 모델 |
| 분류마다 재현율이 정한 값 이상이다 | 평균은 같아도 한 분류만 무너진 모델 |
| 검색 적중률이 정한 값 이상이다 | 문서가 빠지거나 옛 판으로 덮인 색인 |
| 지금 판보다 정한 폭 넘게 떨어지지 않는다 | 조금씩 나빠지는 일이 쌓이는 것 |
| 응답 시간, 크기가 한도 안이다 | 정확해도 너무 느리거나 큰 모델 |
게이트 함수
def gate(candidate, champion, floor=0.9, max_drop=0.05):
"""(통과 여부, 까닭). 후보와 챔피언은 같은 시험 묶음으로 잰 점수다"""
if candidate < floor:
return False, f"{candidate:.3f} 은 바닥 {floor} 보다 낮다"
if champion is not None and candidate < champion - max_drop:
return False, f"챔피언 {champion:.3f} 보다 {champion - candidate:.3f} 떨어졌다"
return True, "통과"
# 결과: 첫 판, 같은 점수, 많이 떨어진 후보, 바닥보다 낮은 후보
for cand, champ in [(1.0, None), (0.95, 0.95), (0.81, 1.0), (0.85, 0.86)]:
print(cand, champ, gate(cand, champ))코드에 나오는 함수
| 코드 | 쉬운 뜻 |
|---|---|
gate(candidate, champion, floor=0.9, max_drop=0.05) | candidate(후보)와 champion(지금 쓰는 모델)의 점수를 받는다. floor(바닥)는 넘어야 할 최저 점수, max_drop 은 챔피언보다 떨어져도 되는 가장 큰 폭이다 |
champion is not None | 챔피언이 있을 때만 견준다. 첫 판은 챔피언이 없어 None 을 넘긴다 |
f"{candidate:.3f}" | 소수 셋째 자리까지 적는다. f 는 fixed point(고정 소수점)다 |
return False, f"…" | 통과 여부와 까닭을 함께 돌려준다 |
이 코드가 뜻하는 것
반 대표 계주 선수를 바꾸는 일을 떠올려 봅니다. 새 선수는 먼저 정해 둔 최소 기록을 넘어야 하고, 지금 선수보다 너무 뒤지지도 않아야 합니다. 두 관문을 차례로 봅니다. 여기서 새 선수가 후보, 지금 선수가 챔피언, 최소 기록이 floor, 뒤져도 되는 폭이 max_drop 입니다.
| 줄 | 하는 일 | 쉽게 말하면 |
|---|---|---|
if candidate < floor | 바닥 0.9 보다 낮으면 바로 탈락이다 | 최소 기록을 못 넘으면 탈락 |
if champion is not None and candidate < champion - max_drop | 챔피언보다 0.05 넘게 낮으면 탈락이다 | 지금 선수보다 너무 뒤지면 탈락 |
(1.0, None) | 챔피언이 없고 바닥을 넘어 통과한다 | 첫 대표 선수 |
(0.95, 0.95) | 바닥을 넘고 챔피언과 같아 통과한다 | 지금 선수와 비슷하다 |
(0.81, 1.0), (0.85, 0.86) | 둘 다 바닥 0.9 에 걸려 탈락한다 | 최소 기록부터 못 넘었다 |
예시의 주석은 셋째를 "많이 떨어진 후보"라고 불렀지만, 코드가 바닥부터 검사하므로 까닭에는 바닥 이야기가 나옵니다. 챔피언과의 차이로 막히는 경우는 아래 작은 예에서 봅니다. 비유와 다른 점은, 계주 선수는 대개 더 빨라야 바꾸지만 이 게이트는 0.05 안에서 조금 낮아도 통과시킨다는 것입니다.
작게 줄여서 눈으로 보기
바닥은 넘지만 챔피언보다 낮은 후보 둘을 넣어 봅니다. 점수는 설명을 위해 지어낸 것입니다.
def gate(candidate, champion, floor=0.9, max_drop=0.05):
if candidate < floor:
return False, f"{candidate:.3f} 은 바닥 {floor} 보다 낮다"
if champion is not None and candidate < champion - max_drop:
return False, f"챔피언 {champion:.3f} 보다 {champion - candidate:.3f} 떨어졌다"
return True, "통과"
# 바닥 0.9 는 넘지만 챔피언보다 많이 떨어진 후보, 조금만 떨어진 후보(예시 점수)
for cand, champ in [(0.92, 0.99), (0.96, 0.99)]:
print(cand, champ, gate(cand, champ))0.92 0.99 (False, '챔피언 0.990 보다 0.070 떨어졌다')
0.96 0.99 (True, '통과')| 결과 | 읽는 법 |
|---|---|
0.92 0.99 (False, …0.070 떨어졌다) | 바닥은 넘었지만 챔피언보다 0.07 낮아 허용 폭 0.05 를 넘었다. 둘째 관문에서 막혔다 |
0.96 0.99 (True, '통과') | 0.03 낮지만 허용 폭 안이라 통과한다 |
주의할 점
- 게이트의 시험 묶음은 학습과 고르기에 쓰지 않은 것이 좋습니다. 이 장의 실습은 데이터가 작아 실습 4의 고르기와 게이트에 같은 시험 문의 40개를 씁니다. 그만큼 점수가 후하게 나올 수 있습니다.
- 게이트를 통과해도 운영에서 문제가 날 수 있습니다. 일부 요청에만 먼저 내보내 보는 카나리 배포와 되돌리기를 함께 준비합니다.