본문으로 건너뛰기

CacheVerifier 파인튜닝 장애와 임계값 착시

RQ timeout의 선점 한계와 self-attention 메모리 폭증, threshold calibration 착시가 한 장애에서 겹쳤습니다.

이 요약은 AI가 원문을 분석해 생성했습니다. 정확한 내용은 원문 기준으로 확인하세요.

TL;DR

CacheVerifier의 tenant별 fine-tuning 작업이 1시간 timeout을 무시하고 9시간 40분 동안 멈춘 원인은 RQ SimpleWorker의 SIGALRM 방식이 PyTorch의 단일 C-level self-attention 연산을 선점하지 못했기 때문입니다. 명시적인 max_length 제한이 없어 실제 데이터에서 peak memory가 약 5.6 GB까지 치솟았고, max_length를 128 tokens로 제한하고 batch size를 낮추자 메모리는 약 1.27 GB, 처리 시간은 905초에서 224초로 줄었습니다. 이후 새 모델의 precision이 약 10 percentage points 낮아 보였지만 AUC는 0.890에서 0.8905로 거의 같았고, 전체 threshold sweep에서 두 모델의 곡선도 겹쳐 threshold calibration 차이로 판명됐습니다. 작성자는 live threshold와 hit rate 또는 error rate가 10 percentage points 넘게 달라지는 자동 전환을 막고 명시적 확인을 요구하도록 바꿨으며, 첫 fine-tune에는 이 검사를 제외했습니다.

실용적 조언

  • RQ의 timeout을 실제 hard timeout으로 사용해야 한다면 작업을 종료할 수 있는 별도 프로세스 경계를 두는 방안을 우선 검토해야 합니다. 글에서는 SimpleWorker 대신 외부에서 자식 프로세스를 종료할 수 있는 RQ의 regular Worker 전환을 다음 후보로 두고 있습니다. 다만 process fork에 따른 job overhead 때문에 더 가벼운 대안을 찾는 상태이며, 이 부분은 아직 확정되지 않았습니다.
  • Transformer 기반 fine-tuning 입력에는 base model의 기본값을 그대로 두지 말고 tenant 데이터에 맞는 max_length 상한을 명시해야 합니다. 긴 입력 하나가 batch 전체의 self-attention 메모리 비용을 키우므로 training batch size도 함께 낮추고 실제 데이터에서 peak memory와 처리 시간을 재측정해야 합니다. 이 사례에서는 max_length 128 tokens와 batch size 조정으로 peak memory가 약 5.6 GB에서 약 1.27 GB로 내려갔습니다.
  • Fine-tuned verifier의 모델 품질은 각 모델이 자동으로 선택한 threshold 한 점만 비교하지 말고 전체 cutoff의 operating curve로 평가해야 합니다. AUC가 거의 같은데 production precision이나 hit rate가 크게 달라지면 모델의 구분 능력보다 threshold calibration 차이를 먼저 확인해야 합니다. 새 threshold가 live 운영 지표를 10 percentage points 넘게 바꾸는 경우에는 자동 전환을 막고 사유 기록과 명시적 확인을 거치게 하는 방식이 제안됐습니다.

섹션별 상세

01
CacheVerifier의 tenant별 cross-encoder fine-tuning 작업이 1시간 job_timeout을 넘겨 9시간 40분 동안 종료되지 않았고, worker container 메모리는 limit의 99.8 percent에 고정됐습니다. 원인은 RQ의 SimpleWorker가 작업을 같은 프로세스에서 실행하며, 타임아웃을 SIGALRM 이후 Python 예외로 처리하기 때문입니다. PyTorch가 큰 batch의 self-attention forward pass를 하나의 C-level tensor 연산으로 수행하는 동안 Python 인터프리터로 제어가 돌아오지 않아, 시그널은 전달돼도 작업을 선점하지 못했습니다.
02
self-attention의 메모리 비용이 sequence length에 따라 대략 제곱으로 늘어나는데도 모델에 명시적인 max_length 상한이 없었습니다. 실제 tenant 데이터로 재현한 결과 peak training memory는 약 5.6 GB까지 올랐고, max_length를 128 tokens로 제한하면서 training batch size를 낮추자 약 1.27 GB로 감소했습니다. 같은 수정으로 training 시간도 905초에서 224초로 줄었고 quality metrics는 거의 변하지 않아, 단순한 container 증설보다 입력 길이와 배치의 상한 설정이 핵심 해결책으로 확인됐습니다.
03
수정 후 첫 fine-tune은 3분 이내에 정상 종료됐지만, 이전 모델과 production threshold에서 비교하자 approval rate는 약 10 percentage points 오르고 precision은 약 10 percentage points 낮아졌습니다. 그러나 AUC는 0.890에서 0.8905로 거의 그대로였고, 모든 cutoff를 훑은 전체 operating curve도 두 모델이 거의 겹쳤습니다. 이전 모델은 tenant 데이터와 무관한 고정 default를 사용했고 새 모델은 작은 held-out slice에서 Youden's-J calibration으로 더 공격적인 threshold를 골랐기 때문에, 실제 품질 저하가 아니라 같은 곡선 위 operating point의 차이가 regression처럼 보였습니다.
04
작성자는 새 calibration threshold가 현재 live threshold와 비교해 hit rate 또는 error rate를 10 percentage points 넘게 움직이면 새 모델을 자동 활성화하지 않고 보류하도록 바꿨습니다. 시스템은 보류 사유를 기록하고 명시적인 확인이 있을 때만 전환하며, 이전 threshold가 없는 첫 fine-tune에는 이 검사를 적용하지 않습니다. fresh tenant로 별도 테스트한 결과 첫 사용자에게 임의의 default와의 차이를 적용하면 거의 모든 첫 fine-tune이 차단될 수 있다는 edge case도 확인됐습니다.

이미지 분석

SemCacheLMArena에서 Error rate와 Hit rate의 관계를 다섯 방식으로 비교한 산점도입니다.
Chart

그래프는 A Static Threshold (GPTCache-style), B Adaptive Threshold (vCache-style), C Synchronous Krites, D This proposal, E Fine-tuned verifier의 hit rate를 error rate에 따라 표시합니다. E Fine-tuned verifier와 D This proposal의 점들은 대체로 error rate 약 0.05~0.07 구간에서 hit rate 약 0.72~0.92로 상승한 뒤 0.94 안팎에 모이며, A 방식은 error rate가 약 0.026에서 0.114까지 커지는 동안 hit rate가 약 0.36에서 0.996까지 증가합니다. 이 시각화는 단일 threshold가 아니라 error rate와 hit rate의 전체 operating curve를 비교해야 한다는 글의 calibration 논점과 연결됩니다.

SemCacheLMArena에서 Error rate와 Hit rate의 관계를 다섯 방식으로 비교한 산점도입니다.

용어 해설

RQ의 동일 프로세스 작업 실행기(SimpleWorker)
SimpleWorker는 작업마다 종료 가능한 자식 프로세스를 따로 만들지 않고 worker 프로세스 안에서 작업을 실행하는 RQ 실행기입니다. 이 구조에서는 타임아웃이 SIGALRM과 Python 예외에 의존하므로, PyTorch처럼 긴 C-level 연산이 진행되는 동안 Python 인터프리터가 제어권을 되찾지 못하면 작업을 즉시 중단하기 어렵습니다.
Unix 알람 시그널(SIGALRM)
SIGALRM은 지정된 시간이 지나면 프로세스에 전달되는 Unix 시그널입니다. RQ의 SimpleWorker는 이 시그널을 받은 뒤 Python 핸들러가 예외를 발생시키는 방식으로 타임아웃을 처리하지만, 프로세스가 하나의 차단된 C-level tensor 연산 안에 머물면 핸들러 실행이 지연될 수 있습니다.
셀프 어텐션(self-attention)
self-attention은 입력 토큰 사이의 관계를 계산해 각 토큰의 표현을 갱신하는 Transformer 연산입니다. cross-encoder 학습에서는 sequence length가 길어질수록 attention 메모리 사용량이 대략 제곱으로 증가하므로, max_length 제한이 없으면 긴 배치 하나가 메모리 부족과 극심한 thrashing을 일으킬 수 있습니다.
최대 시퀀스 길이(max_length)
max_length는 모델이 한 입력에서 처리하도록 허용하는 최대 토큰 수입니다. 이 글에서는 값을 128 tokens로 제한하고 training batch size를 낮춰 동일한 tenant 데이터의 peak memory를 약 5.6 GB에서 약 1.27 GB로 줄였으며, 처리 시간도 905초에서 224초로 단축했습니다.
분류 성능 곡선 아래 면적(AUC)
AUC는 분류기가 가능한 threshold 전 범위에서 양성과 음성을 얼마나 일관되게 구분하는지 나타내는 지표입니다. 새 모델과 이전 모델의 AUC가 0.890에서 0.8905로 거의 변하지 않았는데도 특정 production threshold에서 precision이 10 percentage points 낮아져, 단일 threshold 비교만으로는 실제 품질 변화를 판단하기 어려웠습니다.
Youden's-J 임계값 보정(Youden's-J)
Youden's-J는 held-out 데이터에서 sensitivity와 specificity의 균형을 기준으로 분류 threshold를 고르는 calibration 방식입니다. 이 사례에서는 작은 held-out slice에 적용한 결과가 기존 threshold보다 더 공격적인 operating point를 선택했고, 모델의 discriminative power가 아니라 threshold 위치 차이가 precision 하락처럼 보이는 현상을 만들었습니다.

언급된 도구

RQ중립

Redis Queue 기반 worker에서 fine-tuning job을 실행하고 job_timeout을 처리합니다.

SimpleWorker비추천

작업을 별도 자식 프로세스가 아니라 같은 프로세스에서 실행해 SIGALRM 기반 timeout의 선점 한계를 만들었습니다.

PyTorch중립

큰 batch의 self-attention forward pass와 tensor 연산을 수행하며 C-level 연산 중 Python timeout 처리가 지연되는 상황을 만들었습니다.

언급된 리소스

AI 분석 전체 내용 보기

AI 요약 · 북마크 · 개인 피드 설정 — 무료

출처 · 인용 안내

원문 발행 2026. 08. 25.수집 2026. 08. 25.출처 타입 REDDIT

인용 시 "요약 출처: AI Trends (aitrends.kr)"를 표기하고, 사실 확인은 원문 보기 기준으로 진행해 주세요. 자세한 기준은 운영 정책을 참고해 주세요.