# microgpt - 200줄 순수 파이썬으로 구현한 GPT 학습 및 추론

> Clean Markdown view of GeekNews topic #26746. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=26746](https://news.hada.io/topic?id=26746)
- GeekNews Markdown: [https://news.hada.io/topic/26746.md](https://news.hada.io/topic/26746.md)
- Type: GN+
- Author: [xguru](https://news.hada.io/@xguru)
- Published: 2026-02-17T07:25:47+09:00
- Updated: 2026-02-17T07:25:47+09:00
- Original source: [karpathy.github.io](https://karpathy.github.io/2026/02/12/microgpt/)
- Points: 69
- Comments: 1

## Summary

**microgpt**는 200줄짜리 순수 Python 코드로 GPT의 학습과 추론 전 과정을 구현한 karpathy의 실험적 프로젝트입니다. 외부 라이브러리 없이 **autograd 엔진부터 Transformer 아키텍처, Adam 옵티마이저**까지 직접 구성해, 대규모 LLM이 수행하는 알고리듬의 본질을 최소 단위로 드러냅니다. 프로덕션 모델과의 차이는 규모와 효율성뿐이며, 이 코드를 이해하면 GPT가 어떻게 “다음 토큰을 예측하는 기계”로 작동하는지 구조적으로 파악할 수 있습니다.

## Topic Body

- karpathy가 공개한 아트 프로젝트. 200줄 단일 파일로 외부 의존성없이 **GPT 전체 알고리듬을 구현**  
- 프로덕션 LLM과의 차이는 **규모와 효율성**일 뿐 핵심은 동일, 이 코드를 이해하면 **GPT의 알고리듬적 본질을 이해한 것**임  
- 데이터셋, 토크나이저, **autograd 엔진**, GPT-2 유사 **Transformer 아키텍처**, **Adam 옵티마이저**, 학습·추론 루프까지 포함  
- micrograd, makemore, nanogpt 등 기존 프로젝트들과 10년간의 **LLM 단순화 작업의 결정체**로, 더 이상 단순화할 수 없는 최소 형태로 GPT의 본질을 담음  
- 32,000개의 이름 데이터를 학습해 **그럴듯한 새로운 이름을 생성**하며, 모든 계산을 **스칼라 단위 autograd**로 직접 수행  
- 학습 과정은 **손실 계산 → 역전파 → Adam 업데이트**로 구성되며, 약 1분 내 실행 가능  
  
---  
  
### microgpt 개요  
- microgpt는 **200줄짜리 Python 스크립트**로, GPT 모델의 학습과 추론 과정을 완전하게 구현  
  - 외부 라이브러리 없이 **데이터셋, 토크나이저, autograd, 모델, 옵티마이저, 학습 루프**를 모두 포함  
- 기존의 micrograd, makemore, nanogpt 등의 프로젝트를 통합해 단일 파일로 정리  
- “더 이상 단순화할 수 없음” 수준으로 알고리듬적 핵심만 남긴 구현  
- 전체 코드는 [GitHub Gist](https://gist.github.com/karpathy/8627fe009c40f57531cb18360106ce95), [웹페이지](https://karpathy.ai/microgpt.html), [Google Colab](https://colab.research.google.com/drive/1vyN5zo6rqUp_dYNbT4Yrco66zuWCZKoN?usp=sharing)에서 제공  
  
### 데이터셋 구성  
- 대규모 언어 모델의 연료는 **텍스트 데이터 스트림**이며, 프로덕션에서는 인터넷 웹페이지를 사용하지만 microgpt에서는 **32,000개의 이름**을 한 줄씩 담은 단순한 예제 사용  
- 각 이름이 하나의 "문서"로 취급되며, 모델은 데이터 내의 **통계적 패턴을 학습**해 유사한 새 문서를 생성하는 것이 목표  
- 학습 완료 후 모델은 "kamon", "karai", "vialan" 같은 **그럴듯한 새 이름을 "환각(hallucinate)"**  
- ChatGPT 관점에서 사용자와의 대화도 "특이하게 생긴 문서"일 뿐이며, 프롬프트로 문서를 초기화하면 모델의 응답은 **통계적 문서 완성**에 해당  
  
### 토크나이저  
- 신경망은 문자가 아닌 숫자로 작동하므로 텍스트를 **정수 토큰 ID 시퀀스**로 변환하고 다시 복원하는 방법 필요  
- tiktoken(GPT-4 사용) 같은 프로덕션 토크나이저는 효율을 위해 문자 청크 단위로 작동하지만, 가장 단순한 토크나이저는 **데이터셋의 각 고유 문자에 하나의 정수를 할당**  
- 소문자 a-z를 정렬해 각 문자에 인덱스로 ID 부여하며, 정수 값 자체는 의미가 없고 각 토큰은 **별개의 이산 심볼**  
- **BOS(Beginning of Sequence)** 특수 토큰을 추가해 "새 문서가 시작/종료됨"을 알리며, "emma"는 `[BOS, e, m, m, a, BOS]`로 래핑  
- 최종 어휘 크기는 27개(소문자 26개 + BOS 1개)  
  
### 자동 미분(Autograd)  
- 신경망 학습에는 **그래디언트**가 필요: 각 파라미터에 대해 "이 값을 살짝 올리면 손실이 올라가는가, 내려가는가, 얼마나?"를 알아야 함  
- 연산 그래프는 많은 입력(모델 파라미터와 입력 토큰)을 가지지만 **단일 스칼라 출력인 손실(loss)** 로 수렴  
- **역전파(Backpropagation)** 는 출력에서 시작해 그래프를 역방향으로 따라가며 미적분의 **체인 룰**에 의존해 모든 입력에 대한 손실의 그래디언트 계산  
- **Value 클래스**로 구현: 각 Value는 단일 스칼라(.data)를 감싸고 어떻게 계산되었는지 추적  
  - 덧셈, 곱셈 등의 연산 시 새 Value가 입력(`_children`)과 해당 연산의 **국소 도함수(`_local_grads`)** 를 기억  
  - 예: `__mul__`은 ∂(a·b)/∂a=b, ∂(a·b)/∂b=a를 기록  
- 지원되는 연산 블록: 덧셈, 곱셈, 거듭제곱, log, exp, ReLU  
- `backward()` 메서드가 **역위상 순서**로 그래프를 순회하며 각 단계에서 체인 룰 적용  
  - 손실 노드에서 `self.grad = 1`로 시작(∂L/∂L=1)  
  - 국소 그래디언트를 경로 따라 곱해가며 파라미터까지 전파  
- **+=로 누적(할당이 아님)**: 그래프가 분기될 때 각 분기에서 독립적으로 그래디언트가 흘러와 **합산**되어야 함(다변수 체인 룰의 결과)  
- PyTorch의 `.backward()`와 **알고리듬적으로 동일**하나, 텐서 대신 스칼라 단위로 작동해 훨씬 단순하지만 효율성은 낮음  
  
### 파라미터 초기화  
- 파라미터는 모델의 **지식**으로, 무작위로 시작해 학습 중 반복적으로 최적화되는 부동소수점 숫자의 대규모 집합  
- **가우시안 분포**에서 작은 무작위 값으로 초기화  
- `state_dict`로 명명된 행렬들로 구성: **임베딩 테이블**, **어텐션 가중치**, **MLP 가중치**, **최종 출력 프로젝션**  
- 하이퍼파라미터 설정:  
  - `n_embd = 16`: 임베딩 차원  
  - `n_head = 4`: 어텐션 헤드 수  
  - `n_layer = 1`: 레이어 수  
  - `block_size = 16`: 최대 시퀀스 길이  
- 소형 모델 기준 **4,192개 파라미터**(GPT-2는 16억 개, 현대 LLM은 수천억 개)  
  
### 아키텍처  
- 모델 아키텍처는 **무상태 함수**: 토큰, 위치, 파라미터, 이전 위치의 캐시된 키/값을 받아 다음 토큰에 대한 **로짓(점수)** 반환  
- GPT-2를 따르되 약간 단순화: **RMSNorm**(LayerNorm 대신), 바이어스 없음, **ReLU**(GeLU 대신)  
- ## 헬퍼 함수  
  - **linear**: 행렬-벡터 곱셈으로 가중치 행렬의 각 행에 대해 하나의 **내적** 계산, 신경망의 기본 구성 요소인 학습된 선형 변환  
  - **softmax**: 원시 점수(로짓)를 **확률 분포**로 변환, 모든 값이 [0,1] 범위에 들어가고 합이 1이 됨, 수치적 안정성을 위해 최대값 먼저 빼기  
  - **rmsnorm**: 벡터를 **단위 제곱평균제곱근**을 갖도록 재조정해 활성화가 네트워크를 통과하며 커지거나 줄어드는 것 방지, 학습 안정화  
- ## 모델 구조  
  - **임베딩**: 토큰 ID와 위치 ID가 각각의 임베딩 테이블(`wte`, `wpe`)에서 행을 참조, 두 벡터를 더해 토큰이 **무엇**인지와 시퀀스에서 **어디**에 있는지 동시 인코딩  
    - 현대 LLM은 위치 임베딩을 건너뛰고 RoPE 같은 **상대 기반 위치 지정 기법** 사용  
  - **어텐션 블록**: 현재 토큰을 Q(쿼리), K(키), V(값) 세 벡터로 프로젝션  
    - 쿼리: "내가 찾는 것은?", 키: "내가 담고 있는 것은?", 값: "선택되면 제공하는 것은?"  
    - 예: "emma"에서 두 번째 "m"이 다음을 예측할 때 "최근 어떤 모음이 있었나?" 같은 쿼리 학습 가능, 앞의 "e"가 이 쿼리와 잘 맞아 높은 어텐션 가중치 획득  
    - 키와 값은 **KV 캐시**에 추가되어 이전 위치 참조 가능  
    - 각 어텐션 헤드가 쿼리와 모든 캐시된 키 사이의 **내적**(√d_head로 스케일)을 계산, softmax로 어텐션 가중치 얻고 캐시된 값의 가중 합 계산  
    - 모든 헤드 출력을 연결해 `attn_wo`로 프로젝션  
    - 어텐션 블록은 **위치 t의 토큰이 과거 0..t-1의 토큰을 "볼" 수 있는 유일한 곳**, 어텐션은 **토큰 통신 메커니즘**  
  - **MLP 블록**: 2층 **피드포워드 네트워크**: 임베딩 차원의 4배로 확장 → ReLU 적용 → 다시 축소  
    - 위치별 "사고"의 대부분이 이루어지는 곳  
    - 어텐션과 달리 시간 t에 완전히 **로컬한 계산**  
    - Transformer는 통신(어텐션)과 계산(MLP)을 **교차 배치**  
  - **잔차 연결**: 어텐션과 MLP 블록 모두 출력을 입력에 다시 더함  
    - 그래디언트가 네트워크를 직접 통과하게 해 **깊은 모델의 학습 가능**하게 함  
  - **출력**: 최종 은닉 상태를 `lm_head`로 어휘 크기에 프로젝션해 토큰당 하나의 로짓 생성(여기서는 27개 숫자), 높은 로짓 = 해당 토큰이 다음에 올 가능성 높음  
  - **KV 캐시 특이점**: 학습 중에도 KV 캐시 사용은 드문 경우이나, microgpt가 한 번에 하나의 토큰만 처리하므로 명시적으로 구축, 캐시된 키와 값이 연산 그래프의 **라이브 Value 노드**로 역전파 대상  
  
### 학습 루프  
- 학습 루프는 반복적으로: (1) 문서 선택 → (2) 토큰에 대해 모델 순방향 실행 → (3) 손실 계산 → (4) 역전파로 그래디언트 획득 → (5) 파라미터 업데이트  
- ## 토큰화  
  - 각 학습 스텝에서 하나의 문서를 선택해 양쪽에 BOS 래핑: "emma" → `[BOS, e, m, m, a, BOS]`  
  - 모델의 목표는 이전 토큰들이 주어졌을 때 **각 다음 토큰을 예측**  
- ## 순방향 패스와 손실  
  - 토큰을 한 번에 하나씩 모델에 공급하며 KV 캐시 구축  
  - 각 위치에서 모델이 27개 로짓 출력, softmax로 확률 변환  
  - 각 위치의 손실은 올바른 다음 토큰의 **음의 로그 확률**: −log p(target), 이를 **교차 엔트로피 손실**이라 함  
  - 손실은 모델이 실제로 오는 것에 **얼마나 놀랐는지** 측정: 확률 1.0 할당 시 손실 0, 확률 0 근처 시 손실 +∞  
  - 문서 전체의 위치별 손실을 평균해 **단일 스칼라 손실** 획득  
- ## 역방향 패스  
  - `loss.backward()` 한 번 호출로 전체 연산 그래프에 대해 역전파 실행  
  - 이후 각 파라미터의 `.grad`가 손실을 줄이기 위해 **어떻게 변경해야 하는지** 알려줌  
- ## Adam 옵티마이저  
  - 단순 경사 하강(`p.data -= lr * p.grad`) 대신 **Adam** 사용  
  - 파라미터당 두 개의 이동 평균 유지:  
    - `m`: 최근 그래디언트의 평균(모멘텀)  
    - `v`: 최근 그래디언트 제곱의 평균(파라미터별 학습률 적응)  
  - `m_hat`, `v_hat`은 0으로 초기화된 m, v의 **바이어스 보정**  
  - 학습률은 학습 중 **선형 감소**  
  - 업데이트 후 `.grad = 0`으로 초기화  
- ## 학습 결과  
  - 1,000 스텝 동안 손실이 약 3.3(27개 토큰 중 무작위 추측: −log(1/27)≈3.3)에서 약 **2.37로 감소**  
  - 낮을수록 좋고 최저는 0(완벽한 예측)이므로 개선 여지 있으나 모델이 **이름의 통계적 패턴을 학습** 중임이 명확  
  
### 추론  
- 학습 완료 후 모델에서 **새 이름 샘플링** 가능, 파라미터 고정 후 순방향 패스를 루프로 실행, 각 생성 토큰을 다음 입력으로 피드백  
- ## 샘플링 과정  
  - 각 샘플을 BOS 토큰으로 시작("새 이름 시작")  
  - 모델이 27개 로짓 생성 → 확률로 변환 → 해당 확률에 따라 **무작위로 하나의 토큰 샘플링**  
  - 해당 토큰을 다음 입력으로 피드백, 모델이 다시 BOS 생성("완료") 또는 최대 시퀀스 길이 도달까지 반복  
- ## 온도(Temperature)  
  - softmax 전에 로짓을 온도로 나눔  
  - **온도 1.0**: 모델이 학습한 분포에서 직접 샘플링  
  - **낮은 온도(예: 0.5)**: 분포를 날카롭게 해 모델이 더 **보수적**으로 상위 선택을 할 가능성 높임  
  - **온도 0 근처**: 항상 가장 확률 높은 단일 토큰 선택(**탐욕적 디코딩**)  
  - **높은 온도**: 분포를 평평하게 해 더 **다양하지만 덜 일관된** 출력  
  
### 실행 방법  
- **Python만 필요**(pip install 없음, 의존성 없음): `python train.py`  
- MacBook에서 약 **1분** 소요  
- 각 스텝에서 손실 출력: ~3.3(무작위)에서 ~2.37로 감소  
- 학습 완료 후 **환각된 새 이름** 생성: "kamon", "ann", "karai" 등  
- **Google Colab 노트북**에서도 실행 가능, Gemini에게 질문 가능  
- 다른 데이터셋 시도, `num_steps` 증가로 더 오래 학습, 모델 크기 증가로 더 나은 결과 가능  
  
### 코드 진행 단계  
| 파일 | 추가 내용 |  
|------|----------|  
| `train0.py` | 바이그램 카운트 테이블 — 신경망 없음, 그래디언트 없음 |  
| `train1.py` | MLP + 수동 그래디언트(수치적 & 해석적) + SGD |  
| `train2.py` | Autograd(Value 클래스) — 수동 그래디언트 대체 |  
| `train3.py` | 위치 임베딩 + 단일 헤드 어텐션 + rmsnorm + 잔차 |  
| `train4.py` | 멀티헤드 어텐션 + 레이어 루프 — 전체 GPT 아키텍처 |  
| `train5.py` | Adam 옵티마이저 — 이것이 `train.py` |  
  
- **build_microgpt.py** Gist의 Revisions에서 모든 버전과 각 스텝 간 diff 확인 가능  
  
### 프로덕션 LLM과의 차이  
- microgpt는 GPT 학습 및 실행의 **완전한 알고리듬적 본질** 포함, ChatGPT 같은 프로덕션 LLM과의 차이는 핵심 알고리듬을 바꾸지 않으며 **규모에서 작동하게 하는 요소**들  
- ## 데이터  
  - 32K 짧은 이름 대신 **수조 개의 인터넷 텍스트 토큰**(웹페이지, 책, 코드 등)으로 학습  
  - 데이터 중복 제거, 품질 필터링, 도메인 간 신중한 혼합  
- ## 토크나이저  
  - 단일 문자 대신 **BPE(Byte Pair Encoding)** 같은 서브워드 토크나이저 사용  
  - 자주 함께 나타나는 문자 시퀀스를 단일 토큰으로 병합, "the" 같은 일반 단어는 단일 토큰, 희귀 단어는 조각으로 분리  
  - ~100K 토큰 어휘, 위치당 더 많은 콘텐츠를 보므로 **훨씬 효율적**  
- ## Autograd  
  - 순수 Python의 스칼라 Value 객체 대신 **텐서**(대규모 다차원 숫자 배열) 사용, 초당 수십억 부동소수점 연산 수행하는 **GPU/TPU**에서 실행  
  - PyTorch가 텐서에 대한 autograd 처리, FlashAttention 같은 **CUDA 커널**이 여러 연산 융합  
  - 수학은 동일, 많은 스칼라가 **병렬 처리**  
- ## 아키텍처  
  - microgpt: 4,192개 파라미터, GPT-4급 모델: **수천억 개**  
  - 전반적으로 매우 유사한 Transformer 신경망이나 훨씬 넓고(임베딩 차원 10,000+) 훨씬 깊음(100+ 레이어)  
  - 추가 레고 블록 유형과 순서 변경:  
    - **RoPE**(회전 위치 임베딩) — 학습된 위치 임베딩 대신  
    - **GQA**(그룹화된 쿼리 어텐션) — KV 캐시 크기 감소  
    - **게이트 선형 활성화** — ReLU 대신  
    - **MoE**(전문가 혼합) 레이어  
  - 잔차 스트림 위에 어텐션(통신)과 MLP(계산)가 교차하는 **핵심 구조는 잘 보존**  
- ## 학습  
  - 스텝당 하나의 문서 대신 **대규모 배치**(스텝당 수백만 토큰), 그래디언트 누적, 혼합 정밀도(float16/bfloat16), 신중한 하이퍼파라미터 튜닝  
  - 프론티어 모델 학습에 **수천 개의 GPU가 수개월간** 실행  
- ## 최적화  
  - microgpt: Adam + 단순 선형 학습률 감소  
  - 대규모에서 최적화는 **독자적 분야**: 감소된 정밀도(bfloat16, fp8), 대규모 GPU 클러스터에서 학습  
  - 옵티마이저 설정(학습률, 가중치 감쇠, 베타 파라미터, 워밍업/감쇠 스케줄)을 정밀하게 튜닝 필요, 올바른 값은 모델 크기, 배치 크기, 데이터셋 구성에 따라 다름  
  - **스케일링 법칙**(예: Chinchilla)이 고정 컴퓨팅 예산을 모델 크기와 학습 토큰 수 사이에 어떻게 할당할지 안내  
  - 대규모에서 이 세부사항을 잘못하면 **수백만 달러의 컴퓨팅 낭비** 가능, 팀들이 전체 학습 실행 전 광범위한 소규모 실험 수행  
- ## 후학습(Post-training)  
  - 학습에서 나온 기본 모델("사전학습" 모델)은 **문서 완성기**이지 챗봇이 아님  
  - ChatGPT로 만드는 과정은 두 단계:  
    - **SFT(지도 미세조정)**: 문서를 큐레이션된 대화로 교체하고 학습 계속, 알고리듬적으로 변화 없음  
    - **RL(강화학습)**: 모델이 응답 생성 → 점수 부여(인간, "심판" 모델, 알고리듬) → 피드백으로 학습  
  - 근본적으로 여전히 문서에 대해 학습하나, 이제 문서가 **모델 자체에서 나온 토큰**으로 구성  
- ## 추론  
  - 수백만 사용자에게 모델 서빙에 자체 **엔지니어링 스택** 필요: 요청 배칭, KV 캐시 관리 및 페이징(vLLM 등), 속도를 위한 **추측적 디코딩**, 메모리 감소를 위한 **양자화**(int8/int4로 실행), 여러 GPU에 모델 분산  
  - 근본적으로 여전히 시퀀스의 다음 토큰을 예측하나 **더 빠르게 만드는 엔지니어링**에 많은 노력  
  
### FAQ  
- ## 모델이 무언가를 "이해"하는가?  
  - 철학적 질문이나 기계적으로: 마법은 일어나지 않음  
  - 모델은 입력 토큰을 다음 토큰에 대한 확률 분포로 매핑하는 **큰 수학 함수**  
  - 학습 중 파라미터는 올바른 다음 토큰을 더 확률 높게 만들도록 조정  
  - "이해"를 구성하는지는 개인에게 달렸으나 **메커니즘은 위 200줄에 완전히 담김**  
- ## 왜 작동하는가?  
  - 모델에 수천 개의 조정 가능한 파라미터가 있고, 옵티마이저가 각 스텝에서 손실을 낮추도록 조금씩 이동  
  - 많은 스텝에 걸쳐 파라미터가 **데이터의 통계적 규칙성을 포착**하는 값으로 안정  
  - 이름의 경우: 자음으로 시작하는 경우 많음, "qu"가 함께 나타나는 경향, 자음 3개 연속은 드묾 등  
  - 모델은 명시적 규칙이 아닌 이를 반영하는 **확률 분포를 학습**  
- ## ChatGPT와 어떤 관련이 있는가?  
  - ChatGPT는 이 동일한 핵심 루프(다음 토큰 예측, 샘플링, 반복)를 **엄청나게 확장**하고 대화형으로 만드는 후학습 추가  
  - 채팅 시 시스템 프롬프트, 사용자 메시지, 응답 모두 **시퀀스의 토큰**일 뿐  
  - 모델은 microgpt가 이름을 완성하는 것과 **동일하게 한 번에 하나의 토큰으로 문서를 완성**  
- ## "환각"은 무엇인가?  
  - 모델은 확률 분포에서 샘플링해 토큰 생성  
  - **진실 개념이 없으며** 학습 데이터에 비추어 통계적으로 그럴듯한 시퀀스만 앎  
  - microgpt가 "karia" 같은 이름을 "환각"하는 것은 ChatGPT가 거짓 사실을 자신 있게 말하는 것과 **동일한 현상**  
  - 둘 다 실제가 아닌 **그럴듯하게 들리는 완성**  
- ## 왜 이렇게 느린가?  
  - microgpt는 순수 Python에서 **한 번에 하나의 스칼라** 처리, 단일 학습 스텝에 수 초 소요  
  - GPU에서 동일한 수학이 **수백만 스칼라를 병렬 처리**해 수 자릿수 더 빠르게 실행  
- ## 더 좋은 이름을 생성하게 할 수 있는가?  
  - 가능: 더 오래 학습(`num_steps` 증가), 모델 크기 증가(`n_embd`, `n_layer`, `n_head`), 더 큰 데이터셋 사용  
  - **대규모에서도 중요한 동일한 조절 요소**  
- ## 데이터셋을 바꾸면?  
  - 모델은 데이터에 있는 **어떤 패턴이든 학습**  
  - 도시 이름, 포켓몬 이름, 영어 단어, 짧은 시 파일로 교체하면 대신 **그것들을 생성하도록 학습**  
  - 나머지 코드는 변경 불필요

## Comments



### Comment 51381

- Author: mhj5730
- Created: 2026-02-19T11:16:59+09:00
- Points: 1

좋은 글 감사합니다.
