Transformers 대형 모델 로딩, device_map·dtype·offload를 함께 고르는 법

대형 AI 모델 로딩을 상징하는 일반 GPU 보드와 메모리 모듈, 빈 저장장치가 놓인 현실적인 작업대 1

AI를 활용하여 생성한 이미지입니다.

대형 모델을 Transformers로 불러올 때 “GPU 메모리가 부족하다”는 오류만 보고 양을 줄이거나 장비를 바꾸기 쉽죠. 하지만 실제로는 가중치를 어떤 dtype으로 읽는지, 레이어를 어느 장치에 배치하는지, CPU나 디스크로 넘길지에 따라 결과가 달라져요. device_map="auto"는 부족한 모델을 마법처럼 빠르게 만드는 옵션이 아니라, 가용 장치에 가중치를 배치하는 기능이에요.[1][2]

중급 단계에서는 로딩 성공보다 로딩 뒤의 경로를 확인해야 해요. 어떤 레이어가 GPU에 있고, 어떤 레이어가 CPU나 디스크에 있는지 확인하지 않으면 첫 응답이 지나치게 느린 이유를 찾기 어렵거든요. Hugging Face 문서가 안내하는 Big Model Inference의 장점과 비용을 기준으로 순서를 잡아 볼게요.

먼저 계산할 것은 모델 파일 크기예요

모델의 파라미터 수만으로 필요한 메모리를 정확히 정할 수는 없어요. 저장 dtype, 임시 버퍼, KV 캐시, 입력 길이, 런타임 구현이 함께 메모리를 사용하기 때문이에요. 모델을 로드하는 순간에는 초기화된 가중치와 체크포인트를 동시에 다루는 과정도 생길 수 있어요. Transformers는 큰 모델을 위해 메타 장치에 빈 뼈대를 만들고 가중치를 순서대로 배치하는 경로를 제공해요.[2]

선택 메모리 효과 성능 비용 먼저 쓸 상황
GPU에 모두 배치 GPU 여유가 충분해야 해요. 장치 이동이 적어요. 반복 추론과 낮은 지연이 중요할 때
device_map="auto" GPU 다음 CPU로 나눠요. CPU와 GPU 사이 이동이 생겨요. 모델이 GPU에 완전히 들어가지 않을 때
디스크 offload 더 큰 모델을 올릴 수 있어요. 저장장치 접근이 병목이 될 수 있어요. 실행 가능성 확인이 우선인 일회성 작업
낮은 dtype 가중치 메모리를 줄일 수 있어요. 모델별 지원과 품질을 확인해야 해요. 지원되는 dtype이 명확할 때

device_map=auto가 하는 일

Transformers의 device_map="auto"는 기본적으로 빠른 장치부터 공간을 채우고 남은 가중치를 CPU, 필요하면 디스크로 보내요.[1][3] 모델 전체를 한 장치에 억지로 넣는 대신 레이어 단위로 분산할 수 있다는 뜻이에요. 로딩이 끝난 뒤에는 model.hf_device_map을 출력해 실제 배치를 확인할 수 있어요.[1]

from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained(
    "your-org/your-model",
    device_map="auto",
    dtype="auto",
)
print(model.hf_device_map)

문서 버전에 따라 인자 이름과 예제가 달라질 수 있으므로, 설치한 Transformers 버전의 from_pretrained 도움말과 모델 카드를 같이 확인하세요. 특정 모델이 torch_dtype 예제를 제공한다면 그 모델의 안내를 우선 따르는 편이 안전해요. 지원되지 않는 dtype을 억지로 지정하면 로딩 오류나 연산 호환성 문제가 생길 수 있어요.

dtype은 로딩 전부터 정해요

가중치를 기본 float32로 먼저 만든 뒤 float16으로 바꾸면 로딩 중에 메모리를 더 사용할 수 있어요. Hugging Face 문서는 원하는 dtype을 직접 지정하거나, 저장된 가중치 dtype을 따라가도록 dtype="auto"를 사용할 수 있다고 설명해요.[1][2] 다만 dtype을 낮추면 메모리만 줄어드는 것이 아니라 연산 지원과 출력 품질 조건도 함께 바뀔 수 있어요.

모델 카드에 권장 dtype과 GPU 지원 범위가 적혀 있다면 그 정보를 먼저 확인하세요. “반으로 줄어든다”처럼 단순 계산하지 말고, 로딩 후 실제 GPU·CPU 사용량과 한 토큰 생성 시간을 기록해야 해요. 공식 문서에 특정 모델의 처리량이 없으면 그 수치를 만들어 내지 않는 게 맞아요.

CPU offload와 디스크 offload를 구분해요

CPU offload는 GPU에 들어가지 않는 가중치를 시스템 메모리에 두고 필요할 때 이동시키는 방식이에요. 디스크 offload는 그보다 더 큰 모델을 실행할 수 있게 하지만, 레이어를 읽어 오는 시간이 추가돼요. Accelerate 문서는 장치별로 레이어를 보내고, 디스크는 가장 느린 경로라고 설명해요.[3] 그래서 디스크 offload는 “실행이 되는가”를 확인하는 데는 도움이 되지만, 사용자에게 빠른 서비스로 제공할 기본값으로 보기는 어려워요.

특히 큰 레이어 하나가 GPU에 들어갈 공간도 없으면 자동 배치가 성공하지 않을 수 있어요. Accelerate 문서도 가장 큰 레이어가 들어갈 장치 공간이 필요하다고 설명해요.[3] GPU를 조금 비우고, 모델의 일부를 CPU로 보내는 것만으로 해결되지 않는 경우에는 더 작은 checkpoint나 양자화된 배포본을 검토해야 해요.

실패 원인을 좁히는 순서

  1. 모델 카드에서 지원 아키텍처와 권장 dtype을 확인해요.
  2. 가중치와 tokenizer를 로컬 디스크에 받을 공간을 확보해요.
  3. 가장 작은 입력으로 dtype="auto"와 device_map="auto"를 시험해요.
  4. 로딩 뒤 hf_device_map을 출력해 GPU·CPU·disk 배치를 기록해요.
  5. 첫 토큰 시간과 생성 속도를 따로 기록해 offload 비용을 확인해요.
  6. 실행이 느리면 디스크 offload를 먼저 제거하고, 모델 크기와 dtype을 다시 조정해요.

로딩 중 프로세스가 죽는다면 코드 한 줄만 바꾸기보다 피크 메모리를 확인하세요. 체크포인트가 shard로 나뉘어 있으면 한 번에 모든 파일을 메모리에 올리는 부담을 줄일 수 있지만, shard 크기와 모델 전체 크기가 사라지는 것은 아니에요.[2] 디스크 용량 부족과 RAM 부족은 다른 오류로 분리해 봐야 해요.

서비스로 올릴 때는 자동 배치를 그대로 쓰지 않아요

대화형 서비스에서는 응답 시간과 동시 요청 수가 중요하므로, 자동 배치가 로딩을 통과했다는 사실만으로 운영에 적합하다고 판단하면 안 돼요. CPU나 디스크로 자주 이동하는 구조라면 짧은 테스트에서는 괜찮아 보여도 여러 요청에서 지연이 크게 늘 수 있어요. 서버용 엔진과 모델별 지원 방식이 따로 있다면 그 문서를 비교해야 해요.

로컬 실험이나 일회성 변환처럼 처리량보다 실행 가능성이 중요한 작업은 CPU·디스크 offload가 유효할 수 있어요. 반대로 API 서버라면 GPU에 자주 쓰는 레이어가 안정적으로 남는지, 요청 길이와 KV 캐시가 추가로 얼마나 필요한지까지 측정한 뒤 구성을 고르는 편이 낫습니다.

메모리 압박을 더 깊게 보고 싶다면 Ollama의 컨텍스트와 KV 캐시 점검을 함께 참고해 보세요. 서버 지연을 실제 요청 단위로 나누고 싶을 때는 TTFT·TPOT·KV 캐시 지표 글이 이어지는 주제예요.

출처

  1. Loading models | Hugging Face Transformers documentation [1]
  2. Instantiate a big model | Hugging Face Transformers documentation [2]
  3. Big Model Inference | Hugging Face Accelerate documentation [3]

함께 읽을 글