컨텍스트가 채워짐에 따라 로컬 LLM의 속도를 몰래 갉아먹는 것은 무엇인가 - 파트 2
요약
로컬 LLM 사용 시 컨텍스트 크기가 증가함에 따라 생성 속도가 저하되는 원인을 분석합니다. 테스트 결과, 컨텍스트 확장에 따른 공유 메모리(shared memory) 증가가 KV 캐시를 RAM으로 넘기게 만들어 성능 병목을 유발함을 확인했습니다.
핵심 포인트
- 컨텍스트 크기 증가 시 공유 메모리 사용량도 함께 증가함
- 공유 메모리 증가로 인해 토큰 데이터가 RAM으로 이동하며 속도 저하 발생
- 공유 메모리가 500MB 이상 증가할 경우 설정이 불안정할 수 있음
- PowerShell과 nvidia-smi를 활용한 모델 성능 테스트 방법 제시
자, 이전 장에서는 몇 가지 데이터와 통찰을 남겨두었습니다.
이번에는 그 이면에 숨겨진 이야기에 대해 이야기해 보겠습니다.
저는 로컬에서 llama-server.exe를 통해 모델을 서빙하고 있었습니다. 채팅을 하던 중, 성능이 갑자기 떨어지는 것을 발견했습니다.
처음에는 열려 있는 다른 애플리케이션들이 문제를 일으키는 것이라고 생각했습니다.
모든 것을 종료하고, 작업 관리자를 실행하여 브라우저 페이지와 나란히 띄워 놓았습니다.
확인해 보니 제 VRAM은 안정적이었고... RAM도 마찬가지였습니다.
이 시점에서 Google과 Reddit을 검색해 보니, 사용자들은 컨텍스트가 채워짐에 따라 생성 속도가 떨어지는 것이 꽤 흔한 일이라고 말하고 있었습니다. 이 첫 번째 답변이 _합리적(reasonable)_으로 보였음에도 불구하고, 이에 만족하지 못해 더 깊이 파고들기로 했습니다.
제 첫 인상은 모델 자체의 아키텍처와 높은 컨텍스트로 인해 모델이 병목 현상(bottleneck)의 원인이라는 것이었습니다. 하지만 여전히 추측에 불과하다고 느껴졌기에, 다른 모델들과 비교하여 답을 찾아보기로 했습니다.
제 하드 드라이브에는 그냥 놓여 있는 모델이 30 GB나 있었기에 — 누구나 다 그렇지 않나요, 제 말이 맞죠? ㅎㅎ — 제가 가진 모든 모델을 가져와 다양한 설정(configuration)으로 실행할 수 있는 _PowerShell 스크립트_를 만들기로 했습니다.
왜냐고요?
단순합니다. 두 가지 질문에 답하기 위해서였습니다:
- 내 기기에서 실행하기에 가장 좋은 모델은 무엇인가?
- 각 모델에 대한 최적의 설정은 무엇인가?
정말 순진했습니다. 상황이 얼마나 복잡해질지 상상조차 하지 못했습니다.
저는 실제로 간단한 PowerShell 스크립트로 시작했습니다. 4단계로 구성되었습니다: 폴더 내 모델(.gguf 파일) 스캔, 다양한 설정으로 테스트하기 위한 계획 수립, 특정 설정으로 llama-server.exe 실행, 그리고 로그(log) 생성입니다. 거기에는 nvidia-smi로부터 수집된 모든 통계가 포함된 로그가 있었습니다. nvidia-smi는 프롬프트 내에서 GPU의 상태와 프로세스의 작업 부하를 추적하는 데 사용할 수 있는 매우 유용한 명령어입니다. 불행히도 Windows에서는 각 프로세스를 볼 수 없는데, 이에 대한 자세한 내용은 다음에 다루도록 하겠습니다. ㅎㅎ
이 PowerShell 스크립트가 저에게 통찰을 주었습니다!
작은 모델들은 높은 컨텍스트 (context) 상황에서도 성능이 급격하게 떨어지지 않았습니다.
수상하군요.
곧 저는 작업 관리자 (task manager) 자체에서 처음에 알아차리지 못했던 것 중 하나가 바로 **공유 메모리 (shared memory)**라는 사실을 깨달았습니다.
**컨텍스트 크기 (context size)**가 증가함에 따라 (16k에서 32k로), **공유 메모리 (shared memory)**도 함께 증가했습니다.
첫 번째 파트에서 언급했듯이, 이 사실은 결국 LLM 토큰의 일부를 RAM에 저장하게 된다는 것을 의미하며, 이는 속도를 저하시키게 됩니다.
이 경험적 사례 (empirical use-case)에 대한 테스트를 통해 저는 제 PowerShell 스크립트에 하나의 규칙을 설정하기로 했습니다. 공유 메모리 (shared_memory)가 500MB 이상 증가한다는 것은 제 설정에서 KV 캐시 (cache)가 넘쳐흐르게 되어 모델을 실행하기에 안전하지 않다는 것을 의미했습니다.
만약 모델의 **공유 메모리 (shared_memory)**가 500MB를 초과하면, 해당 설정을 _안전하지 않음 (not safe)_으로 표시합니다. 저는 수많은 다양한 모델들을 다운로드했습니다.
더 많은 샘플 모델들을 대상으로 스크립트를 실행해 본 결과, 또 다른 패턴을 발견했습니다. 너무나 많은 모델이 _안전하지 않음 (not safe)_으로 분류되었습니다. 너무 많았습니다.
규칙은 작동하고 있었지만, 잘못된 사례들도 표시하고 있었는데, 이는 하나의 문제였습니다. 하지만... 보통 GPU와 RAM 사이에 분산되어 있는 MoE와 같은 종류의 모델들이 있습니다.
이 경우, 저는 **공유 메모리 (shared_memory)**를 제 문제에 대한 낙관적인 해결책으로 오해하고 있었습니다. 로그는 제 PC의 처리량 (throughput) 관점에서는 잘 작동하고 있음에도 _안전하지 않음 (not safe)_으로 표시된 모델들로 가득 찼습니다.
MoE는 때때로 8-10GB의 RAM을 사용하며, 결과적으로 **공유 메모리 (shared_memory)**가 증가하게 됩니다. 제가 놓친 것은 그것뿐만 아니라, llama-server.exe 프로세스 또한 **공유 메모리 (shared_memory)**의 일부를 할당하고 있었다는 점이었습니다.
또 순진하게 생각했네요, ㅎㅎ.
llama-server.exe에서 할당된 조각들이 CPU에 있어야 함에도 불구하고 결과에 영향을 미치고 있었습니다. 이 조각들은 모델이 사용됨에 따라 늘어나지 않았으며, 이는 단순히 고정된 양의 메모리가 할당되어 잘못된 양성 (false-positive) 결과를 주고 있었음을 의미합니다.
메모리 증가를 막기 위해 단일 게이트 규칙에 의존하는 것은 실무적인 접근 방식에서 비롯되었습니다. 이는 데이터에 기반(data-driven)하기는 했지만, 충분히 정밀하지는 않았습니다. 모델이 70k에 도달하면 RAM으로 넘어가서 이런 거대한 문제가 발생한다는 식의 명확한 설명이라기보다는,
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기