TRENDSHIFT 딥다이브 · 일간 #17 · 2026-06-05

AirLLM 딥다이브
— 4GB 그래픽카드로 70B 거대 모델을 돌리는 '레이어 한 겹씩 흘려보내기' 마술

AirLLM(에어LLM)은 700억(70B) 파라미터짜리 거대 언어 모델을, 양자화·증류·가지치기 없이도 단 한 장의 4GB GPU에서 추론(inference)하게 해 주는 파이썬 라이브러리다. 비결은 모델 전체를 한꺼번에 VRAM에 올리지 않고, 신경망을 레이어(층) 단위로 잘게 쪼개 디스크에 저장해 두었다가, 계산할 때 한 겹씩만 GPU에 올렸다 내리며 흘려보내는 레이어드 추론(layered inference) 기법. 덕분에 "VRAM이 모델 전체를 담을 수 있어야 한다"는 상식을 깨고, 4GB로 70B를, 8GB로 405B(Llama 3.1)를 돌린다. (저장소: lyogavin/airllm · Python/Jupyter · Apache-2.0 · ⭐ 약 18.1k · 제작자 Gavin Li)
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 하드웨어 / 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

한 문장으로 이 프로젝트가 뭘 하는지부터.

AirLLM = "VRAM이 모델 전체를 담지 못해도, 모델을 한 겹씩 디스크에서 꺼내 계산하며 추론을 끝까지 마치게 해 주는 메모리 절약 추론 엔진". 보통 70B 모델을 16비트로 돌리려면 약 140GB의 VRAM이 필요하다 — A100(80GB) 두 장이 있어야 한다는 뜻이다. AirLLM은 발상을 뒤집는다: "어차피 한 순간에 계산되는 건 신경망의 '한 층'뿐인데, 왜 모든 층을 동시에 VRAM에 올려둬야 하지?" 그래서 모델을 층별로 쪼개 디스크에 저장해 두고, 추론할 때 ① 1번 층을 GPU에 올려 계산 → ② 결과만 남기고 1번 층을 VRAM에서 비움 → ③ 2번 층을 올려 계산 …을 마지막 층까지 반복한다.

✈️ 한 줄 비유

"좁은 책상 위에서 1,000쪽짜리 백과사전을 한 쪽씩 꺼내 읽기"

책상(=GPU의 VRAM)이 너무 작아 백과사전(=70B 모델) 전체를 펼칠 수 없다고 해서 책을 못 읽는 건 아니다. 책장(=디스크·SSD)에서 지금 읽을 한 쪽만 꺼내 책상에 올려 읽고, 다 읽으면 덮어서 책장에 돌려보낸 뒤 다음 쪽을 꺼내면 된다. 책상은 항상 '한 쪽'만 감당하면 되니까 작아도 괜찮다.

대가는 분명하다 — 매번 책장을 오가야 하니 읽는 속도는 느리다. AirLLM의 본질은 "빠르게"가 아니라 "애초에 불가능했던 걸 가능하게"다. 가진 GPU가 작아 70B를 아예 못 올리던 사람이, 느리더라도 일단 돌려볼 수 있게 만든다.

용어
추론 (Inference)
이미 다 학습된 모델에게 입력을 주고 답(다음 토큰)을 뽑아내는 과정. 모델을 '훈련(training)'시키는 것과 구분된다. AirLLM은 훈련이 아니라 추론의 메모리 문제를 푸는 도구다 — 즉 "내 손에 있는 가중치 파일로 답변을 생성"하는 단계를 작은 GPU에서 가능케 한다.
용어
VRAM (그래픽카드 메모리)
GPU에 달린 전용 메모리. 모델의 가중치와 계산 중간값이 여기 올라가야 GPU가 빠르게 연산한다. "70B 모델을 돌리려면 VRAM이 얼마나 필요한가"가 곧 "얼마나 비싼 GPU가 필요한가"를 결정한다. AirLLM은 이 VRAM 요구량을 '모델 전체'에서 '가장 큰 한 층'으로 끌어내린다.

핵심을 한 번 더 못 박자면, AirLLM이 줄이는 것은 "한 순간에 GPU가 들고 있어야 하는 가중치의 양(peak VRAM)"이다. 70B 모델 전체는 여전히 디스크에 140GB가량 그대로 있고, 계산 총량도 줄지 않는다. 다만 '동시에 올라가는' 양만 한 층치(70B 기준 약 1.6GB 안팎)로 압축해, 4GB짜리 소비자용 GPU의 좁은 문을 통과시키는 것이다.

한눈에 그림

일반 추론 = 뷔페 음식을 전부 한 접시에 담으려다 접시가 작아 포기 — VRAM이 모델 전체를 못 담으면 "메모리 부족(OOM)" 에러로 시작조차 못 한다.

AirLLM = 한 코너씩 돌며 그 자리에서 먹고 비우기 — 접시(VRAM)는 항상 한 코너 분량만 담으면 되니, 작은 접시로도 뷔페 전체를 결국 다 맛본다. 느릴 뿐, 못 먹는 음식은 없다.

2왜 주목받는가

TrendShift 일간 17위까지 다시 올라온 이유 — 트렌딩의 배경.

2023년에 처음 나와 ⭐ 1.8만을 모은 '고전'이지만, 오픈웨이트 거대 모델(Llama 3.1 405B, Qwen2.5 등)이 쏟아지면서 "이 큰 걸 내 RTX 한 장으로 만져나 볼 수 없을까"라는 갈증이 다시 커졌고, 그때마다 AirLLM이 소환된다. 인기의 핵심을 다섯 가지로 정리한다.

① "불가능 → 가능"이라는 강렬한 한 줄

"4GB GPU로 70B", "8GB로 405B"는 한 번 들으면 안 잊히는 카피다. 보통은 모델 크기를 줄여(양자화·증류) 작은 GPU에 맞추는데, AirLLM은 모델을 줄이지 않고도(기본값) 돌린다는 점에서 접근이 신선하다. "내 게임용 그래픽카드로 최첨단 모델을?"이라는 호기심이 별점으로 직결된다.

② 설치·사용이 거의 transformers 그대로

거창한 분산 추론 프레임워크가 아니라 pip install airllm 한 줄로 끝나고, 사용법도 HuggingFace transformers와 판박이다. AutoModel.from_pretrained("...")model.generate(...)를 호출하면 된다. 기존 코드 습관을 거의 안 바꾸고 거대 모델을 만질 수 있다는 점이 진입장벽을 크게 낮췄다.

③ '양자화 없이'가 기본 — 정확도 손실 회피

4비트 양자화는 메모리를 줄이지만 미세한 정확도 손실과 출력 변형을 부른다. AirLLM의 기본 경로는 원본 16비트 가중치를 그대로 한 층씩 흘려보내므로, 모델의 답 품질이 원본과 동일하다. "메모리는 부족하지만 품질은 타협하기 싫다"는 연구·평가 용도와 궁합이 맞는다.

④ 폭넓은 모델·플랫폼 지원

Llama 2/3/3.1, Mistral, Mixtral, Qwen·Qwen2.5, Baichuan, ChatGLM, InternLM 등 오픈 LLM 리더보드 상위 모델 대부분AutoModel이 자동 감지해 처리한다. 게다가 맥(Apple Silicon)에서는 MLX 백엔드로, CPU 단독 추론까지 지원한다. "내가 가진 하드웨어가 뭐든 일단 시도는 된다"가 강점.

⑤ 디스크 병목을 정조준한 '모델 압축' 옵션

느린 게 약점인 걸 알기에, 블록 단위 양자화(block-wise quantization)로 가중치만 압축해 디스크 로딩량을 줄이는 옵션(compression='4bit'/'8bit')을 더했다. 로딩이 병목이므로 로딩량을 줄이면 추론이 최대 3배 빨라지는데 정확도 손실은 거의 무시할 수준이라는 게 저자의 주장. "느리다"는 약점을 정면으로 보완한 영리한 추가다.

구분양자화/증류로 모델 줄이기AirLLM(레이어 스트리밍)
접근모델 자체를 작게 만들어 VRAM에 맞춤모델은 그대로, 한 층씩만 VRAM에 올림
정확도다소 손실(양자화 오차)기본은 무손실(원본 16비트)
속도빠름(상주 모델)느림(매 토큰마다 디스크 왕복)
필요 VRAM줄지만 여전히 모델 크기 비례가장 큰 한 층 + 활성값만큼
제일 잘 맞는 곳실시간 서빙·챗봇작은 GPU에서 거대 모델 실험·오프라인 생성
냉정하게 보기
"4GB로 70B"는 사실이지만, '느림'이라는 큰 글씨가 빠져 있다

AirLLM은 매 토큰을 생성할 때마다 모델 전체를 디스크에서 한 번씩 다시 읽는다. 70B 모델이면 토큰 하나에 140GB를 디스크→VRAM으로 흘려보내야 한다는 뜻이라, 속도는 실시간 채팅에 쓸 수준이 못 된다(문장 몇 개에 수 분~수십 분도 가능). 즉 챗봇·서비스 배포용이 아니라, "작은 GPU밖에 없는데 거대 모델의 출력을 한번 봐야 한다", "오프라인으로 천천히 일괄 생성한다", "구조를 공부한다" 같은 용도다. 또 디스크 공간이 많이 필요하고(원본+층별 분할본), 최신 transformers에서는 KV 캐시가 비활성화된다. 이 레포의 진짜 가치는 "빠른 서빙 도구"가 아니라, 트랜스포머의 레이어 구조·메모리 관리·accelerate의 빈 모델(meta device) 트릭·블록 양자화를 한꺼번에 뜯어볼 수 있는 살아있는 교재라는 데 있다.

3기술 스택 전체 지도

requirements.txt · 소스 트리(air_llm/airllm)에서 뽑아낸 실제 구성.

AirLLM은 화려한 풀스택 앱이 아니라 "transformers·accelerate 위에 올라탄 한 장의 추론 레이어"다. 그래서 의존성도 단출하다. 핵심은 ⓐ 모델 로딩/실행을 빌려 오는 HuggingFace 생태계 ⓑ 빈 모델 골격을 만드는 accelerate ⓒ 디스크 저장 포맷 safetensors ⓓ 압축용 bitsandbytes ⓔ 맥 전용 MLX 백엔드, 이렇게 다섯 축으로 읽으면 된다.

ⓐ 모델·토크나이저 두뇌 — HuggingFace transformers

구성요소무엇역할
transformers모델/토크나이저 허브AutoConfig로 아키텍처를 감지하고, AutoModelForCausalLM·AutoTokenizer로 모델 정의와 토크나이저를 가져온다. AirLLM은 이 모델 '정의'만 빌리고, 가중치는 자기 방식으로 층별 로딩한다.
GenerationMixin생성 루프AirLLMBaseModel이 이 믹스인을 상속해, .generate()·빔서치·샘플링 같은 표준 생성 기능을 그대로 물려받는다.
huggingface_hub모델 다운로더repo id("garage-bAInd/Platypus2-70B-instruct")를 주면 가중치를 캐시에 받아온다. gated 모델은 hf_token으로 인증.

ⓑ 빈 골격 만들기 — accelerate (핵심 트릭)

구성요소무엇역할
init_empty_weights'메타 디바이스' 골격실제 메모리를 0바이트도 안 쓰고 모델의 '형태'만 만든다. 70B 골격을 RAM/VRAM 거의 없이 세워 두고, 나중에 층마다 가중치를 채워 넣는다.
set_module_tensor_to_device한 텐서를 장치에 꽂기"이 층의 이 가중치를 GPU에 올려라"를 한 텐서 단위로 수행. AirLLM이 한 층씩 채우고 비우는 동작의 실제 손발.

ⓒ 디스크 포맷 · 압축 · 가속

구성요소무엇역할
safetensors안전·고속 텐서 포맷층별로 쪼갠 가중치를 .safetensors로 저장/로딩. load_file로 필요한 층만 빠르게 읽는다(메모리 매핑).
bitsandbytes블록 양자화 라이브러리compression='4bit'/'8bit'일 때 가중치만 블록 단위로 양자화해 디스크 로딩량을 줄인다. dequantize_nf4·dequantize_blockwise로 GPU에서 되돌려 계산.
optimum / BetterTransformer어텐션 가속가능한 경우 더 빠른 어텐션 커널로 변환해 레이어 계산을 가속.
ThreadPoolExecutor프리페치 병렬표준 라이브러리. 지금 층을 계산하는 동안 다음 층을 디스크에서 미리 읽어 두는 프리페칭에 쓰인다.

ⓓ 맥 전용 백엔드 — MLX

구성요소무엇역할
mlx (mlx.core/mlx.nn)Apple 실리콘 ML 프레임워크맥에서는 AirLLMLlamaMlx가 PyTorch 대신 MLX로 같은 레이어 스트리밍을 구현. RMSNorm·Attention·RoPE를 MLX로 직접 정의한다.
sentencepiece토크나이저MLX 경로에서 텍스트를 토큰으로 쪼개는 데 사용.
용어
safetensors
모델 가중치를 저장하는 파일 포맷. 기존 PyTorch .bin(pickle)과 달리 코드 실행 위험이 없고(안전), 메모리 매핑으로 필요한 부분만 빠르게 읽을 수 있다. AirLLM은 모델을 층별 .safetensors로 잘라 저장해 두고, 추론 때 그 층 파일만 콕 집어 로딩한다.
용어
메타 디바이스 / 빈 가중치(init_empty_weights)
accelerate가 제공하는 트릭. 텐서를 실제로 만들지 않고 '모양과 이름표'만 가진 가짜 텐서('meta' 장치)로 모델을 세운다. 메모리를 거의 안 쓰므로 70B 같은 거대 모델의 '골격'을 순식간에 만들 수 있고, 그 뒤 진짜 가중치를 층 단위로 끼워 넣는다. AirLLM의 '한 층씩 로딩'이 가능한 출발점이다.

4아키텍처 심화 분석

가중치 파일 하나가 '추론 결과'가 되기까지 — 레이어 스트리밍의 한살이.

AirLLM의 동작은 크게 두 단계다. ① 최초 1회: 받아온 모델을 층별 safetensors로 쪼개 디스크에 저장(splitting). ② 매 추론: 빈 모델 골격을 세우고, 층 목록을 순서대로 돌며 "디스크→CPU(고정 메모리)→GPU→계산→비움"을 반복. 아래 그림이 핵심 흐름이다.

━━ 단계 ① 최초 1회: 모델을 '층별 파일'로 분해 ━━ ┌──────────────────────────────────────────────────────────────────┐ │ HF 모델 (예: 70B, 80개 레이어, 통짜 가중치 ~140GB) │ │ find_or_create_local_splitted_path() │ │ embed / layer.0 / layer.1 / ... / layer.79 / norm / lm_head │ │ └─ 각각 별도 .safetensors 로 저장 (splitted_model/) │ └──────────────────────────────────────────────────────────────────┘ ━━ 단계 ② 매 추론(forward) : 한 겹씩 흘려보내기 ━━ 입력 토큰 ──▶ init_empty_weights() 로 '빈 70B 골격' 생성 (VRAM 거의 0) │ ┌──────────────┼─────────── 레이어 루프 (i = 0 … N) ───────────┐ ▼ ▼ │ [프리페치 스레드] [메인: 계산] │ 다음 층(i+1)을 ──▶ ① load_layer(i): 디스크 → CPU(pin_memory) │ 디스크에서 미리 ② move_layer_to_device: CPU → GPU 에 가중치 채움 │ 읽어 둠(겹치기) ③ layer(seq): 그 층 계산 (어텐션/FFN) │ ④ 결과(hidden state)만 남기고 층 가중치 VRAM 비움 │ └───────────────────────────────────────────────────────────┘ │ (마지막 층까지 반복) ▼ norm → lm_head ──▶ 다음 토큰 1개 예측 ──▶ (생성 끝? 아니면 처음부터 다시) ▲ │ └──────────────────────────────────┘ ※ 토큰 하나 만들 때마다 위 레이어 루프 전체가 다시 돈다 = 매 토큰마다 모델 전체를 디스크에서 한 번씩 다시 읽음(병목!)

핵심 설계 패턴 ① — 레이어 스트리밍 (한 층씩 로드·계산·해제)

트랜스포머는 층(layer)을 차례로 통과시키는 구조다. 입력이 1번 층을 지나 나온 결과가 2번 층의 입력이 되고… 이렇게 마지막까지 간다. 그러니 한 순간에 실제로 필요한 가중치는 '지금 통과 중인 한 층'뿐이다. AirLLM은 이 사실을 그대로 이용해, forward() 안에서 층 목록(embed → layers[0..N] → norm → lm_head)을 돌며 ① 그 층을 디스크에서 로드 → ② GPU에 올림 → ③ 계산 → ④ 비움을 반복한다. 그래서 peak VRAM이 '모델 전체'가 아니라 '가장 큰 한 층 + 활성값'으로 떨어진다.

핵심 설계 패턴 ② — 빈 골격 + 채우고 비우기 (accelerate)

모델을 통째로 메모리에 만들면 그 순간 OOM이다. 그래서 init_empty_weights()가중치가 비어 있는 70B '골격'을 먼저 세운다(메모리 거의 0). 그다음 매 층에서 set_module_tensor_to_device(model, 층이름, 'cuda', value=가중치)로 그 층의 자리에만 진짜 텐서를 꽂아 넣고, 계산이 끝나면 다시 비운다. "형태는 미리, 내용은 그때그때"라는 분리가 이 모든 마술의 토대다.

핵심 설계 패턴 ③ — 프리페칭으로 디스크 I/O와 계산 겹치기

디스크에서 층을 읽는 시간이 병목이라면, 읽는 동안 GPU를 놀리지 않으면 된다. AirLLM은 ThreadPoolExecutor지금 층(i)을 계산하는 사이에 다음 층(i+1)을 백그라운드 스레드가 미리 디스크→CPU로 읽어 둔다(future = executor.submit(load_layer_to_cpu, ...)). CPU의 pin_memory()로 고정해 두면 CPU→GPU 전송도 더 빠르다. 이 겹치기(overlap)로 약 10% 속도 향상을 얻는다.

용어
프리페칭 (Prefetching) · pin_memory
프리페칭은 "곧 쓸 데이터를 미리 가져다 두기". 다음 층을 미리 읽어 두면 계산이 끝나자마자 바로 GPU에 올릴 수 있어 기다림이 준다. pin_memory(고정 메모리)는 CPU 메모리의 특정 영역을 '페이지 잠금' 해 둬서, CPU→GPU 복사가 더 빠르고 비동기로 가능하게 만드는 PyTorch 기법이다.

핵심 설계 패턴 ④ — 블록 양자화로 '로딩량' 줄이기 (≠ 일반 양자화)

저자의 통찰: 병목은 '계산'이 아니라 '디스크 로딩'이다. 그러니 가중치만 압축해 파일을 작게 만들면 로딩이 빨라져 추론 전체가 빨라진다. 일반 양자화가 가중치와 활성값을 모두 양자화해 정확도를 해치는 것과 달리, AirLLM은 가중치만 블록 단위로 양자화(4bit/8bit)하고 GPU에서 다시 복원(dequantize)해 계산한다. 그래서 정확도 손실이 거의 없으면서 로딩량이 1/4~1/2로 줄어 최대 3배 빨라진다.

왜 '가중치만' 양자화하면 정확도가 덜 깨질까

일반 양자화는 모델의 모든 입출력 숫자(활성값)까지 거칠게 반올림한다. 입력은 천차만별이라 이상치(outlier) 하나가 결과를 크게 흔들 수 있어 정확도 관리가 어렵다. AirLLM은 목적이 다르다 — '계산 가속'이 아니라 '파일 축소'가 목표다. 그래서 디스크에 있는 가중치만 압축해 두었다가, GPU에 올릴 때 원래 정밀도로 풀어서(dequantize) 계산한다. 계산 자체는 원본과 거의 같은 정밀도로 하니, 압축은 '디스크에서 GPU로 옮기는 길'만 좁히고 품질은 거의 안 건드린다.

핵심 설계 패턴 ⑤ — AutoModel 아키텍처 자동 디스패치

모델마다 층 이름 구조가 조금씩 다르다(Llama·Qwen·ChatGLM…). auto_model.pyAutoModel.from_pretrainedconfig.architectures[0]를 보고 Qwen2→AirLLMQWen2, Mistral→AirLLMMistral, Llama→AirLLMLlama2 …처럼 알맞은 서브클래스로 분기한다. 각 서브클래스는 set_layer_names_dict()에서 그 모델의 embed/layer_prefix/norm/lm_head 이름만 바꿔 끼우면 되는, 깔끔한 전략 패턴이다. 맥이면 분기 이전에 통째로 MLX 경로로 보낸다.

5디렉토리 구조 해부

저장소를 열면 보이는 폴더·파일이 각각 무슨 일을 하는가.

저장소는 ① 실제 라이브러리 코드(air_llm/)와 ② 같은 저자가 만든 다른 프로젝트(anima_100k/, training/, rlhf/ 등)가 한곳에 섞여 있다. 우리가 공부할 핵심은 air_llm/airllm/ 한 폴더에 거의 다 들어 있다.

airllm/ ├── air_llm/ ◀── pip 패키지 'airllm' 의 본체 │ ├── airllm/ │ │ ├── airllm_base.py ★ 심장. AirLLMBaseModel │ │ │ - init_model(빈 골격) / forward(레이어 루프) │ │ │ - load_layer_to_cpu / move_layer_to_device │ │ ├── auto_model.py ★ AutoModel: 아키텍처 감지 → 서브클래스 분기 │ │ ├── airllm.py Llama 2/3/3.1 전용 (AirLLMLlama2 클래스 포함, 층 이름 매핑) │ │ ├── airllm_qwen.py QWen 전용 │ │ ├── airllm_qwen2.py Qwen2 / Qwen2.5 전용 │ │ ├── airllm_mistral.py Mistral 전용 │ │ ├── airllm_mixtral.py Mixtral(MoE) 전용 │ │ ├── airllm_chatglm.py ChatGLM 전용(rotary_pos_emb 특수처리) │ │ ├── airllm_baichuan.py Baichuan 전용 │ │ ├── airllm_internlm.py InternLM 전용 │ │ ├── airllm_llama_mlx.py ★ 맥(Apple Silicon) MLX 백엔드 │ │ ├── utils.py ★ clean_memory / load_layer / 분할경로 생성 │ │ │ / 4bit·8bit 역양자화(dequantize) │ │ ├── profiler.py LayeredProfiler(로딩/계산 시간 측정) │ │ └── persist/ ★ 저장·로딩 추상화 │ │ ├── model_persister.py 인터페이스 + OS별 자동 선택 │ │ ├── safetensor_model_persister.py 리눅스/윈도(safetensors) │ │ └── mlx_model_persister.py 맥(MLX) │ ├── examples/ Colab 노트북(70B·405B·맥 실행 예제) │ └── setup.py 패키지 메타데이터 ├── anima_100k/ 같은 저자의 '100k 컨텍스트' Llama 프로젝트(별개) ├── training/ · rlhf/ · eval/ Anima 모델 학습·RLHF·평가 코드(별개) ├── requirements.txt 의존성(transformers/accelerate/bitsandbytes…) └── README.md / README_ja.md 문서(영어/일본어)

가장 먼저 열어볼 3개 파일

파일왜 중요한가
airllm_base.py모든 마술이 여기 있다. forward()의 레이어 루프(로드→GPU→계산→해제)와 프리페칭, init_model()의 빈 골격 생성을 직접 읽으면 AirLLM의 90%를 이해한 것.
utils.pyload_layer()(층 파일 읽기), find_or_create_local_splitted_path()(최초 분할), clean_memory()(RAM/VRAM 청소), 4bit/8bit uncompress_layer_state_dict()(역양자화)가 모여 있다.
auto_model.py짧지만 핵심. "어떻게 모델 종류를 알아내고 알맞은 클래스로 보내는가"라는 디스패치 로직의 교과서적 예시.
헷갈리기 쉬움
'airllm'(추론 라이브러리)과 'Anima'(모델 학습)는 다른 프로젝트다

같은 저장소 안에 있지만 anima_100k/·training/·rlhf/는 저자가 만든 중국어 33B/100k 컨텍스트 모델 'Anima'의 학습 코드다. AirLLM 추론을 공부하려면 air_llm/airllm/ 폴더만 보면 된다. 나머지는 "이 저자가 모델도 직접 만든다"는 맥락 정도로만 알아 두자.

6학습 포인트 (기술별)

이 레포에서 '진짜로' 배울 수 있는 것 — 기술별 정리 + 실습 아이디어.

① 트랜스포머의 '레이어 순차 통과' 구조

AirLLM이 성립하는 이유 자체가 "트랜스포머는 층을 차례로 통과한다"는 사실이다. forward()를 읽으면 embed → layers[0..N] → norm → lm_head가 어떤 순서로, 어떤 중간값(hidden state)을 주고받으며 흘러가는지가 손에 잡힌다.

실습 아이디어

profiling_mode=True로 작은 7B 모델을 돌려, 각 층의 '디스크 로딩 시간 vs 계산 시간'을 출력해 보라. 어디가 병목인지(거의 항상 로딩) 숫자로 확인된다.

② accelerate의 빈 모델(meta device) 트릭

"메모리를 안 쓰고 거대 모델의 골격만 만든다"는 발상은 분산 로딩·체크포인트 샤딩 등 현대 LLM 인프라 전반에서 쓰인다. init_empty_weights() + set_module_tensor_to_device() 한 쌍을 여기서 제대로 익혀 두면 다른 프레임워크 코드도 읽힌다.

실습 아이디어

10줄짜리 미니 스크립트로 작은 모델을 init_empty_weights()로 세운 뒤, 층 하나만 GPU에 올려 nvidia-smi로 VRAM 변화를 관찰해 보라. "골격은 0, 한 층 올리니 쑥" 하는 그림이 보인다.

③ I/O와 계산을 겹치는 동시성(프리페칭)

ThreadPoolExecutor + future.result()다음 데이터를 미리 읽으며 현재 계산을 진행하는 패턴은 데이터 로더·스트리밍 처리의 보편 기법이다. GIL이 있는 파이썬에서도 I/O 대기는 스레드로 겹칠 수 있다는 실전 예시이기도 하다.

실습 아이디어

같은 모델을 prefetching=TrueFalse로 각각 돌려 총 시간을 비교해 보라. 겹치기가 만드는 차이를 체감할 수 있다.

④ 양자화 두 갈래: '계산용'과 '저장용'의 차이

일반 양자화(활성값까지)와 AirLLM의 '가중치만, 로딩 축소용' 블록 양자화가 왜 목적과 정확도 영향이 다른지를 코드로 비교할 수 있다. utils.pydequantize_nf4/dequantize_blockwise가 압축을 어떻게 되돌리는지 보라.

실습 아이디어

같은 프롬프트를 compression=None vs '4bit'로 생성해, 출력 텍스트가 얼마나 같은지 + 속도가 얼마나 빨라지는지를 직접 표로 만들어 보라.

⑤ 전략 패턴: 모델별 서브클래스 분기

AirLLMBaseModel(공통) + 모델별 서브클래스(set_layer_names_dict()만 다름)는 "공통 알고리즘 + 부분만 교체"라는 객체지향 설계의 모범 사례다. 새 아키텍처를 추가할 때 무엇만 바꾸면 되는지가 명확히 보인다.

실습 아이디어

airllm_llama2.pyairllm_chatglm.pyset_layer_names_dict()를 나란히 펼쳐, 두 모델의 층 이름이 어디서 갈라지는지 찾아보라(ChatGLM은 rotary_pos_emb를 따로 둔다).

7하드웨어 / 시스템 요구사항

"진짜로 돌리려면" 무엇이 필요한가 — VRAM만 보면 함정에 빠진다.

AirLLM의 광고 문구는 VRAM만 말하지만, 실제로 발목을 잡는 건 디스크 용량과 디스크 속도다. 매 토큰마다 모델 전체를 디스크에서 읽기 때문이다. 아래 표로 현실적인 요건을 정리한다.

자원요건 / 현실
GPU(VRAM)70B는 4GB 이상, 405B(Llama 3.1)는 8GB 이상. CUDA GPU 권장. 맥은 Apple Silicon(MLX)로, CPU 단독 추론도 지원(더 느림).
디스크 공간가장 자주 터지는 병목. 70B 16비트면 원본 ~140GB + 층별 분할본까지 합쳐 수백 GB가 필요할 수 있다. 부족하면 MetadataIncompleteBuffer 에러. delete_original=True로 원본을 지워 절반 절약 가능.
디스크 속도NVMe SSD 강력 권장. HDD면 토큰당 수십~수백 초로 체감이 무너진다. 추론 속도 ≈ 디스크 읽기 속도다.
RAM층을 CPU에 거쳐(pin_memory) GPU로 보내므로, 가장 큰 층 + 프리페치 1개를 담을 여유가 필요. 16~32GB면 대체로 무난.
소프트웨어Python 3.10 권장, PyTorch + CUDA, transformers·accelerate·safetensors. 압축 쓰려면 bitsandbytes. 맥은 mlx + torch.
현실 가이드
"되네!"와 "쓸 만하네!"는 다르다 — 기대치를 맞춰라

AirLLM으로 70B를 4GB GPU에 올리는 것은 "동작 확인·소량 생성·구조 학습"까지가 적정 기대치다. 실시간 챗봇이 필요하면 양자화 모델(GGUF/llama.cpp)이나 더 큰 GPU/클라우드가 맞다. "가진 카드로 일단 거대 모델을 만져보고 싶다"가 AirLLM의 자리다.

8직접 해볼 수 있는 실습 과제

난이도별 5개 — 직접 손으로 돌려야 진짜 이해된다.

🟢 Lv.1 — 7B 모델로 첫 추론 성공시키기 입문

거대 모델로 바로 가지 말고 작은 7B(예: Mistral-7B)로 파이프라인을 익힌다. 최초 실행 때 모델이 층별로 쪼개져 저장되는 로그를 눈으로 확인하는 게 목표.

pip install airllm
python -c "
from airllm import AutoModel
m = AutoModel.from_pretrained('mistralai/Mistral-7B-Instruct-v0.1')
t = m.tokenizer(['What is the capital of Korea?'],
                return_tensors='pt', return_attention_mask=False)
out = m.generate(t['input_ids'].cuda(), max_new_tokens=10,
                 use_cache=True, return_dict_in_generate=True)
print(m.tokenizer.decode(out.sequences[0]))
"
체크포인트: 첫 실행은 분할 때문에 오래 걸린다. 두 번째 실행이 더 빠른지(캐시 재사용) 확인하라.

🟢 Lv.2 — 프로파일링으로 '병목' 눈으로 보기 입문+

profiling_mode=True로 초기화해, 층마다 디스크 로딩 시간과 계산 시간이 따로 찍히게 한다. "거의 다 로딩이고 계산은 짧다"는 AirLLM의 본질을 데이터로 확인한다.

from airllm import AutoModel
m = AutoModel.from_pretrained('mistralai/Mistral-7B-Instruct-v0.1',
                              profiling_mode=True)
# 생성 후 출력되는 load_safe_tensor vs create_layer 시간을 비교

🟡 Lv.3 — 압축 ON/OFF 비교 실험 중급

compression=None vs '4bit'로 같은 프롬프트를 생성해, ① 출력 텍스트 일치도 ② 총 생성 시간 ③ 디스크 사용량을 표로 만든다. "정확도 거의 그대로, 속도는 빨라짐"이라는 주장을 직접 검증한다. (pip install -U bitsandbytes 선행)

확장: delete_original=True를 켜고 디스크 절약량도 같이 기록해 보라.

🟡 Lv.4 — '레이어 루프'를 손으로 재현하기 중급+

AirLLM 없이, 작은 모델로 직접 미니 레이어 스트리밍을 구현해 본다: ① init_empty_weights()로 골격 → ② 층 하나를 set_module_tensor_to_device로 GPU에 올림 → ③ 그 층만 통과 → ④ 비움. airllm_base.pyforward()를 교과서 삼아 핵심 30줄만 베껴 보면 구조가 완전히 내 것이 된다.

🔴 Lv.5 — 70B를 작은 GPU에서 끝까지 돌려 리포트 쓰기 고급

충분한 디스크(NVMe 권장)를 확보하고, 70B(예: Llama 3 70B)를 4~8GB GPU에서 실제로 추론해 토큰당 평균 시간·총 VRAM·디스크 사용량을 측정한다. 같은 모델을 클라우드 양자화 추론과 비교해 "AirLLM은 언제 합리적인 선택인가"에 대한 자기만의 판단 기준을 글로 정리하면, 이 레포 학습의 완성이다.

9관련 기술 심화 학습 로드맵

AirLLM을 출발점으로 'LLM 추론 최적화' 전반을 익히는 4주 코스.

주차주제구체적으로 할 것
1주차트랜스포머 추론 기초어텐션·FFN·레이어 구조, KV 캐시가 무엇이고 왜 추론을 빠르게 하는지 이해. AirLLM에서 KV 캐시가 왜 비활성인지 연결지어 본다.
2주차메모리 관리 & accelerateinit_empty_weights, device_map, 오프로딩(offload)을 학습. AirLLM의 '한 층씩'을 accelerate의 CPU/디스크 오프로딩과 비교.
3주차양자화 생태계GPTQ·AWQ·NF4(bitsandbytes)·GGUF의 차이. '계산 가속용'과 AirLLM의 '로딩 축소용' 양자화가 어떻게 다른지 정리.
4주차실전 추론 엔진 비교llama.cpp(GGUF)·vLLM·ExLlama·Ollama를 같은 모델로 돌려 보고, "메모리 vs 속도 vs 정확도" 삼각형에서 AirLLM의 위치를 자기 말로 설명.
큰 그림

AirLLM은 LLM 추론 최적화라는 큰 산의 "메모리 극단(최소 VRAM)" 봉우리다. 반대편엔 "속도 극단"의 vLLM(상주·배칭), 그 사이에 "균형"의 llama.cpp(양자화+상주)가 있다. 한 도구만 외우지 말고, '내 제약(가진 하드웨어·필요 속도·허용 정확도)에 따라 무엇을 고를까'라는 판단력을 기르는 게 진짜 목표다.

10핵심 키워드 사전

이 문서·이 레포에 등장한 주요 용어 한 줄 정리.

용어한 줄 뜻
레이어드 추론모델을 층별로 쪼개 한 겹씩만 GPU에 올렸다 내리며 추론하는 AirLLM의 핵심 기법.
Peak VRAM추론 중 한 순간에 GPU가 동시에 들고 있어야 하는 최대 메모리. AirLLM이 낮추는 바로 그 값.
OOM (Out Of Memory)메모리 부족 에러. VRAM이 모델을 못 담으면 일반 추론은 여기서 멈춘다.
safetensors안전하고 빠른(메모리 매핑) 텐서 저장 포맷. 층별 분할 저장에 사용.
init_empty_weights실제 메모리 없이 모델 '골격'만 만드는 accelerate 기능(메타 디바이스).
set_module_tensor_to_device특정 가중치 텐서 하나를 지정 장치(GPU)에 꽂는 함수. 층 채우기의 손발.
프리페칭(Prefetching)다음 층을 미리 디스크에서 읽어 두어 계산과 로딩을 겹치는 최적화.
pin_memoryCPU 메모리를 잠가 CPU→GPU 전송을 빠르고 비동기로 만드는 기법.
블록 양자화가중치를 작은 블록 단위로 4/8비트 압축. AirLLM은 '로딩량 축소'가 목적이라 정확도 손실이 작다.
dequantize압축한 가중치를 GPU에서 원래 정밀도로 되돌려 계산하는 과정(dequantize_nf4 등).
KV 캐시이미 계산한 토큰의 키/값을 재사용해 생성을 빠르게 하는 기법. 최신 transformers 경로에서 AirLLM은 미지원.
AutoModel 디스패치config의 architectures를 보고 Llama/Qwen/Mistral 등 알맞은 AirLLM 서브클래스로 분기하는 로직.
MLXApple Silicon용 머신러닝 프레임워크. 맥에서 AirLLM의 레이어 스트리밍을 담당.
Anima같은 저자가 만든 중국어 33B/100k 컨텍스트 모델. 저장소에 학습 코드가 함께 있을 뿐 AirLLM 추론과는 별개.

11참고 링크

원문과 더 깊이 파고들 자료.