로컬에서 언어 모델을 실행하는 llama.cpp의 새 버전은 Gemma 모델의 토큰 임베딩 가중치, 토큰을 수치 벡터로 바꾸는 학습값이 CPU 메모리에 두 벌 잡히던 문제를 고쳤다. 모델 파일을 메모리에 연결하는 메모리 매핑, 파일을 메모리에 직접 연결하는 기능을 끈 이용자라면, 해당 조건에서 같은 모델을 더 적은 메모리로 불러올 수 있다.
1. 입력·출력 가중치를 공유하도록 수정
수정 대상은 Gemma 3n과 Gemma 4다. 두 모델은 입력을 처리할 때 쓰는 토큰 임베딩 가중치, 토큰을 수치 벡터로 바꾸는 학습값을 마지막 출력층, 모델 답을 내는 마지막 계산 단계에서도 함께 쓴다. 입력과 출력이 같은 표를 펼쳐 보는 셈이어서, 같은 메모리 공간을 쓸 수 있다면 표를 두 벌 보관할 필요가 없다.
기존에는 출력층부터 만들어 공유할 임베딩을 찾지 못했지만, 이번에는 임베딩을 먼저 만들고 출력층이 이를 참조하도록 순서를 바꿨다. 모델의 가중치 내용을 바꾸는 대신, 공유할 대상을 먼저 준비해 불필요한 사본이 생기는 원인을 없앤 수정이다.
변경 작성자는 입력과 출력이 가중치를 공유하는 다른 94개 모델 구조가 이미 이 순서를 사용하며, 두 모델만 예외였다고 설명했다. 이번 수정으로 두 모델도 기존 구조들과 같은 순서로 가중치를 준비하게 됐다.
2. 중복은 메모리 매핑을 끈 CPU 실행에서 발생
문제가 생기는 조건은 파일을 불러오는 방식과 장치 배치가 겹치는 지점에 있다. 메모리 매핑을 사용하지 않으면서 입력과 출력이 같은 종류의 메모리 버퍼를 쓰면 중복이 발생했다. CPU만 쓰는 실행과, 일부 층을 다른 장치로 보내더라도 출력층은 CPU에 남기는 실행이 여기에 해당한다.
기본 메모리 매핑에서는 입력과 출력의 가중치가 같은 매핑 영역을 가리키므로 원래부터 별도 사본을 잡지 않는다. 따라서 업데이트 효과를 확인하려는 이용자는 CPU 사용 여부와 함께 모델을 어떤 방식으로 불러오는지도 살펴볼 필요가 있다.
3. 시험 모델에서 버퍼 216 MiB 감소
변경 작성자가 gemma-4-E2B-it Q4_K_M을 CPU 전용, 메모리 매핑 없이 불러와 측정한 결과, CPU 모델 버퍼, 모델 가중치를 담는 메모리 영역이 3163.73 MiB에서 2947.73 MiB로 줄었다. 작성자는 변경 제안문에서 차이 216 MiB가 토큰 임베딩 한 벌의 크기와 정확히 같다고 설명했다.
표: Gemma 4 CPU 모델 버퍼 측정
조건: gemma-4-E2B-it Q4_K_M, CPU 전용, 메모리 매핑 없음, 가중치 재포장 비활성화
단위: MiB
| 항목 | 값 |
|---|---|
| 변경 전 | 3163.73 |
| 변경 후 | 2947.73 |
| 감소량 | 216 |
비교 기준은 수정 전 개발 버전인 cf24317be다. 표의 감소량은 작성자가 제시한 차이로, 중복으로 잡히던 임베딩 사본 하나가 빠지며 줄어든 메모리다.
작성자는 같은 모델을 CPU 전용으로 실행해, 매번 가장 가능성이 높은 토큰을 고르는 방식의 출력도 확인했다. 메모리 매핑을 켰을 때와 껐을 때 모두 수정 전과 출력이 같았다고 밝혔다.
4. 재현 명령과 메모리 절감의 범위
아래는 변경 제안문에 실린 시험 명령 그대로다. CPU 전용 실행과 메모리 매핑 비활성화에 더해 가중치 재포장, 가중치 배열을 실행용으로 재구성하는 작업을 끈 설정이 들어 있으며, 모델 로딩 중 보고되는 버퍼 크기를 확인하는 데 쓴다.
llama-server -m gemma-4-E2B-it-Q4_K_M.gguf -dev none -ngl 0 -lm none --no-repack -lv 4실질적인 이익은 CPU 메모리가 빠듯한 환경에서 모델을 담을 여유가 생긴다는 점이다. 반면 출력층을 GPU에 올리는 구성에서는 그 장치에 임베딩 사본을 별도로 두는 메모리 비용이 그대로 남는다.
공개된 절감 수치는 위 모델과 설정의 결과이며, 별도의 실행 속도 측정은 제시되지 않았다.
b12008은 Gemma의 공유 가중치를 올바른 순서로 연결해, 메모리 매핑 없는 CPU 실행에서 중복 메모리를 덜 쓰게 한다.
