본문으로 건너뛰기

[sglang] 성능 최적화의 함정: DeepSeek-V3.2 정확도 붕괴를 막기 위한 SGLang의 긴급 롤백 분석

PR 링크: sgl-project/sglang#26358 상태: Merged | 변경: +6 / -26

들어가며: 성능과 정확도 사이의 아슬아슬한 줄타기

LLM 추론 엔진의 세계에서 성능 최적화는 끝없는 숙제입니다. 특히 Speculative Decoding(추측 디코딩) 기술 중 하나인 EAGLE은 드래프트 모델을 통해 미래 토큰을 미리 예측함으로써 추론 속도를 획기적으로 높입니다. 최근 SGLang 프로젝트에서는 EAGLE 드래프트 모델의 topk가 1일 때, 굳이 비싼 softmax 연산을 수행할 필요가 없다는 아이디어에서 출발한 최적화(#26235)가 제안되었습니다.

하지만 이 "합리적인" 최적화는 예상치 못한 결과를 초래했습니다. 최신 모델인 DeepSeek-V3.2MTP(Multi-Token Prediction) 아키처 조합에서 모델의 정확도가 0.975에서 0.035로 급락하는 참사가 발생한 것입니다. 사실상 모델이 정상적인 답변을 내놓지 못하는 수준(Invalid output 96%)이었습니다. 이번 글에서는 왜 이 최적화가 문제가 되었는지, 그리고 왜 다시 코드를 되돌려야 했는지 기술적으로 분석해 보겠습니다.

코드 분석: 무엇이 문제였나?

문제가 된 변경사항은 EAGLE 드래프트 모델의 실행 로직에서 topk=1인 경우(즉, 가장 확률이 높은 토큰 하나만 선택하는 경우) softmax 과정을 건너뛰고 바로 argmax를 사용하도록 한 것이었습니다. 이번 PR은 이를 다시 안전한 기존 방식으로 되돌리는 작업을 수행합니다.

1. eagle_draft_extend_cuda_graph_runner.py의 변경

이 파일은 CUDA Graph를 사용하여 드래프트 모델의 실행을 가속화하는 역할을 합니다.

[Before] 최적화가 적용된 (문제가 발생한) 코드:

if self.topk == 1:
    # Softmax를 생략하고 바로 argmax를 수행
    ret.topk_index = torch.argmax(
        ret.next_token_logits, dim=-1, keepdim=True
    )
    # 확률값은 단순히 1.0으로 채움
    ret.topk_p = torch.ones_like(ret.topk_index, dtype=torch.float32)
else:
    probs = torch.softmax(ret.next_token_logits, dim=-1)
    ret.topk_p, ret.topk_index = fast_topk(probs, self.topk, dim=-1)

[After] 롤백 후 (정상 작동하는) 코드:

# topk 값에 상관없이 항상 softmax와 fast_topk를 수행
probs = torch.softmax(ret.next_token_logits, dim=-1)
ret.topk_p, ret.topk_index = fast_topk(probs, self.topk, dim=-1)

2. eagle_worker_v2.py의 변경

드래프트 모델의 워커 로직에서도 동일한 "최적화"가 적용되어 있었습니다.

[Before] 최적화가 적용된 (문제가 발생한) 코드:

if self.topk == 1:
    # topk=1 -> degenerate single-path tree; `topk_p`는 사용되지 않는다고 가정
    topk_index = torch.argmax(
        logits_output.next_token_logits, dim=-1, keepdim=True
    )
    topk_p = torch.ones_like(topk_index, dtype=torch.float32)
else:
    probs = torch.softmax(logits_output.next_token_logits, dim=-1)
    topk_p, topk_index = fast_topk(probs, self.topk, dim=-1)

[After] 롤백 후 (정상 작동하는) 코드:

probs = torch.softmax(logits_output.next_token_logits, dim=-1)
topk_p, topk_index = fast_topk(probs, self.topk, dim=-1)

왜 이게 좋은 롤백인가? (정확도 붕괴의 원인 분석)

1. MTP(Multi-Token Prediction)와의 충돌

이번 장애의 핵심은 DeepSeek-V3.2에서 사용하는 MTP 구조에 있습니다. 일반적인 EAGLE은 topk=1일 때 단일 경로 트리(degenerate single-path tree)로 작동하므로 확률값(topk_p)이 중요하지 않을 수 있습니다. 하지만 MTP 경로에서는 드래프트 토큰 선택 과정이 단순한 탐욕적 선택(Greedy search) 이상의 로직을 포함할 수 있습니다.

PR 설명에 따르면, MTP 경로는 하위 드래프트 선택(downstream draft selection)을 위해 전체 어휘(full-vocab)에 대한 Softmax 결과에 의존하는 것으로 보입니다. 단순히 argmax로 인덱스만 뽑고 확률을 1.0으로 고정하는 방식은 MTP 모델이 기대하는 확률 분포 정보를 완전히 파괴해 버린 것입니다.

2. 성능 수치로 증명된 심각성

ROCm 7.2 환경에서 수행된 테스트 결과는 충격적이었습니다.

  • 최적화 적용 시: Accuracy 0.035 (Invalid output 96%)
  • 롤백 후: Accuracy 0.975 (정상 회복)

아무리 연산 속도가 빨라져도 결과값이 틀리다면 그 최적화는 가치가 없습니다. 특히 94% 이상의 정확도를 기대하는 벤치마크에서 3.5%가 나왔다는 것은 모델이 완전히 망가졌음을 의미합니다.

교훈: 일반화된 최적화의 위험성

이 사례는 시니어 엔지니어들에게 중요한 교훈을 줍니다.

  1. 가정의 위험성: "topk=1이면 확률값은 필요 없다"는 가정은 일반적인 모델에서는 맞을 수 있지만, MTP와 같은 특수한 아키텍처에서는 치명적인 오류가 될 수 있습니다.
  2. 가드레일의 필요성: 최적화를 적용할 때는 해당 최적화가 유효한 범위를 명확히 정의해야 합니다. 이번 PR의 논의에서도 향후 topk == 1 AND not is_mtp_path와 같은 조건부 가드(Guard)를 추가하여 최적화를 재적용하자는 제안이 나왔습니다.
  3. 회귀 테스트의 중요성: Nightly 빌드와 정확도 체크가 없었다면, 이 치명적인 버그는 사용자들에게 그대로 노출되었을 것입니다.

결론

이번 리버트(Revert) PR은 단순히 코드를 이전으로 돌리는 것이 아니라, 시스템의 신뢰성을 복구하는 과정이었습니다. 성능 최적화는 항상 매력적이지만, 모델의 수학적 무결성을 해치지 않는 범위 내에서 이루어져야 함을 다시 한번 일깨워줍니다. SGLang 팀은 이번 롤백을 통해 정확도를 완벽히 회복했으며, 향후 MTP 경로를 고려한 더 정교한 최적화를 기약하게 되었습니다.

참고 자료

⚠️ 알림: 이 분석은 AI가 실제 코드 diff를 기반으로 작성했습니다.

댓글

관련 포스트

PR Analysis 의 다른글