단일 CPU에서 8.24GB RAM만으로 2.78조 매개변수 Kimi K3 추론을 실행하는 이식 가능한 C99 엔진입니다.
이식 가능한 C99로 구현한 Kimi K3 추론입니다.
BLAS 없음. 프레임워크 없음. GPU 없음.
2.78T
매개변수1.56 TB
디스크의 체크포인트8.24 GB
측정된 최대 RSS176 KB
전체 엔진0
GPU
동일한 2.78조 매개변수 모델과 동일한 답변을, 보유한 어떤 장비에서도 실행합니다.
메모리를 더 주면 속도만 빨라집니다.
| 보유 장비 | RAM | 토큰당 시간 | 동작 방식 |
|---|---|---|---|
| 일반 노트북 | 8 GB | 26.5 s | 매 단계마다 전체 모델을 디스크에서 스트리밍 |
| 고성능 노트북 | 32 GB | 24.2 s | 모델 일부가 이제 메모리에 상주 |
| 데스크톱 | 64 GB | 19.8 s | 더 많은 부분이 메모리에 상주 |
| 고사양 워크스테이션 | 128 GB+ | 5.6 s | 모델 전체가 메모리에 들어가 디스크 대기가 사라짐 |
모든 크기에서 같은 짧은 프롬프트를 사용하며, 가장 작은 장비부터 가장 큰 장비까지 출력은 바이트 단위로 동일합니다. 바뀌는 것은 시간뿐입니다. 124코어와 빠른 NVMe 드라이브를 갖춘 한 장비에서, 처음 세 행은 여전히 매 단계 모델을 디스크에서 읽으므로 더 느린 드라이브에서는 더 느립니다. 반면 128 GB+ 행은 모든 것을 메모리에 유지하므로 더는 디스크를 기다리지 않습니다. 같은 장비에서 v1.0.0은 토큰당 연산을 약 8× 줄이고, 대화의 후속 질문을 3.9× 빠르게 했으며, 긴 프롬프트 비용을 약 절반으로 낮췄습니다. 토큰은 대략 짧은 단어 조각이며, 아래의 실행 가능한 두 데모는 더 느린 드라이브에서 원래 캡처한 것이므로 시간이 조금 더 큽니다. 전체 데이터는 docs/data/에 있습니다.
저는 AI 연구 직무와 박사 과정 자리를 찾고 있습니다. 이력서.
macOS, Windows, NEON 포트, 채팅 모드, ultra 프리셋, 더 빠른 MXFP4 커널 및 수많은 파서 수정은 아래 사람들의 기여로 이루어졌습니다. 기여 내역.
$ ./bin/k3 ~/k3model --trunk ~/k3trunk --preset laptop
--tok ~/k3model --prompt "The capital of France is" --gen 8 --incremental
--- generated text --- Paris.",
8 tokens in 261.5 s, 32.69 s/token average PEAK RSS for the whole run: 8.24 GB
1.56 TB 체크포인트에서 읽어 오면서도 8.24 GB에서 느리지만 올바르게 답합니다. 이 배치 명령은 의도적으로 원시 연속 생성을 요청합니다. 공식 Kimi K3 체크포인트는 채팅도 지원합니다. 답변과 다중 턴 기록이 필요하면 아래 XTML REPL을 사용하세요. 같은 배치 요청에 메모리를 더 주어도 답은 변하지 않으며 시간만 바뀝니다.
$ ./bin/k3 ~/k3model --trunk ~/k3trunk --preset server
--tok ~/k3model --prompt "def fibonacci(n):" --gen 28 --incremental
28 tokens in 299.3 s, 10.69 s/token average PEAK RSS for the whole run: 127.92 GB
이 문서의 모든 수치는 docs/data/에 있는 측정 출력에서 가져왔습니다.
고밀도 트렁크는 선택한 깊이까지 메모리에 유지하고 나머지는 스트리밍합니다. 1.45 TB의 라우팅 전문가들은 절대 상주하지 않으며 압축된 4비트 형식에서 바로 곱셈을 수행합니다. 결과적으로 동일 모델이 8 GB와 224 GB에서 실행되고, 그 사이의 모든 예산에서 바이트 단위로 동일한 출력을 만듭니다.
바이트가 어디에 상주하는지에 관한 네 가지 결정으로 클러스터에서 노트북까지 내려갈 수 있으며, 맨 아래의 답은 맨 위의 답과 같습니다.
파트 II에서는 두 다이어그램의 모든 상자를 구성 요소별로 처음부터 만듭니다.
관문은 스토리지입니다. 체크포인트는 1.56 TB입니다. 나머지는 평범합니다.
| 운영체제 | Linux, x86-64(참조); macOS/arm64와 Windows/x86-64도 빌드되며 모든 게이트를 통과 | O_DIRECT, posix_memalign, getrusage 사용 — Windows는 MSYS2의 MinGW-w64로 포팅됨(src/io/k3_portable_io.h 참고) |
| CPU | x86-64에서는 AVX2 + FMA, arm64에서는 NEON | AVX-512는 불필요. x86-64의 make portable은 범용 AVX2 대상 |
| RAM | 8 GB 이상 | 모든 프리셋이 작동하며, 메모리가 많으면 더 빠를 뿐 결과는 같음 |
| 스토리지 | 약 1.7 TB 여유 공간 | 1.56 TB 체크포인트 + 109 GB 패킹 트렁크, 이상적으로 빠른 로컬 디스크 |
| 도구 체인 | GCC ≥ 9 또는 Clang ≥ 10 | GNU make 또는 CMake |
| Python | 3.9+ | 다운로드, 패킹, 분석 도구용이며 make test에는 불필요 |
토크나이저와 구성 읽기 도구는 이식 가능한 C99이며 어디서나 빌드됩니다. 체크포인트 없이도 빠른 시작의 모든 작업을 수행할 수 있습니다.
복제하고, 빌드하고, 전체 테스트 모음을 실행하세요. 체크포인트 없음, 네트워크 없음, Python 없음. 전체 과정은 약 1분이 걸립니다.
git clone https://github.com/FareedKhan-dev/kimi-k3-in-c.git cd kimi-k3-in-c
make -j # 몇 초. C 파일 일곱 개, 컴파일러 및 OpenMP make test # 1분 이내
다음과 같이 끝나야 하며, 그렇지 않으면 실패한 것입니다.
GATE 1 teacher forcing : 32/32 positions match tf_pred
generated span : 20/20 <- must be exact
GATE 2 greedy decode : 20/20 generated tokens match full_ids
GATE 3 incremental : 20/20 generated tokens match full_ids <- KV cache + carried KDA state
VERDICT: ENGINE MATCHES THE REFERENCE EXACTLY
ALL WEIGHTLESS TESTS PASSED
이것이 전체 엔진입니다. 모든 커널, 스트리밍 캐시, safetensors 읽기 도구, 구성 읽기 도구, 토크나이저, 그리고 저장소에 커밋된 픽스처의 PyTorch 참조와 비교해 확인하는, 릴리스 모델과 같은 텐서 그래프로 만들어진 13레이어 모델에 대한 종단 간 오라클이 포함됩니다.
한 공개 측정값도 전체 93레이어 실행 중 기록한 추적에서 즉시 재현할 수 있습니다. 이 작업에는 Python 3.9+와 numpy가 필요합니다.
python3 tools/sim_cache.py tests/fixtures/expert_trace.bin
100,096개 전문가 요청을 expert-cache-capacity.txt의 용량 표로 다시 출력합니다.
빈 디렉터리에서 생성 텍스트까지 여섯 단계입니다. 느린 것은 4단계뿐입니다.
./scripts/k3-doctor.sh는 어느 시점에나 실행할 수 있습니다. 도구 체인을 확인하고, RAM 크기에 맞는 프리셋을 정하며, 스토리지를 측정하고, 다음에 실행할 정확한 명령을 출력합니다.
git clone https://github.com/FareedKhan-dev/kimi-k3-in-c.git cd kimi-k3-in-c
약 45 MB이며, 대부분은 다이어그램과 테스트 픽스처입니다.
./scripts/k3-doctor.sh
엔진이 읽는 방식으로 디스크를 측정하므로 약 1분이 걸립니다. 장비가 모델을 전혀 실행할 수 없으면 0이 아닌 값으로 종료합니다.
make -j
몇 초면 됩니다. 의존성은 C99 컴파일러, libm, OpenMP뿐입니다. CMake도 작동합니다.
cmake -B build && cmake --build build -j && ctest --test-dir build
make test
1.56 TB 다운로드에 시간을 투자하기 전에 할 가치가 있습니다. 엔진이 같은 텐서 그래프의 모델에서 참조 구현과 일치함을 증명하며, 저장소 외에는 아무것도 필요하지 않습니다.
1.56 TB이므로 몇 분이 아니라 몇 시간이 걸립니다. huggingface.co/settings/tokens에서 토큰을 받으세요.
export HF_TOKEN=hf_your_token_here # 환경에서 읽으며 절대 출력하지 않음 ./scripts/download-model.sh ~/k3model # 재개 가능, 계속하려면 다시 실행
스크립트는 샤드 개수와 정확한 전체 바이트 수를 검증한 뒤, 공개된 수치와 각 샤드의 개별 크기까지 모두 검증합니다.
verifying…
shards : 96 (expect 96)
bytes : 1560936091448 (expect 1560936091448)
shards : all 96 match their published sizes individually
RESULT : byte-exact match
부분 다운로드는 크게 실패하지 않고 잘못된 토큰을 냅니다. 여기서 FAIL은 중단 신호로 취급하세요. 샤드별 확인은 “1.56 TB를 다시 내려받기”를 “이 17 GB 파일 하나를 다시 내려받기”로 바꾸며, 전체 크기로는 잡을 수 없는 경우, 즉 두 샤드의 오류가 같은 양만큼 반대 방향으로 발생한 경우도 잡아냅니다.
./scripts/pack-trunk.sh ~/k3model ~/k3trunk
한 번만 약 4분이 걸립니다. 93개의 고밀도 레이어를 레이어 _L_이 알려진 오프셋에 있고 한 번의 호출로 읽을 수 있는 109 GB 파일 하나로 다시 씁니다. 이것이 메모리 요구량을 다이얼로 바꾸는 작업입니다. 출력은 보유한 가장 빠른 디스크에 두세요.
./bin/k3 ~/k3model --trunk ~/k3trunk --preset workstation
--tok ~/k3model --prompt "The capital of France is" --gen 8 --incremental
토크나이저는 체크포인트와 함께 제공되므로 --tok는 모델 디렉터리를 가리킵니다.
kimi-k3-in-c/ ~45 MB 소스, 문서, 이미지 및 bin/k3
~/k3model/ 1.56 TB 96개 샤드 · config.json · tiktoken.model · tokenizer_config.json
~/k3trunk/ 109 GB trunk.bin · trunk.json, 보유한 가장 빠른 디스크에 배치
어떤 실행이든 첫 토큰은 디스크에서 고정 레이어 전체를 불러옵니다. server 프리셋에서는 약 108 GB이므로 안정 상태 속도보다 훨씬 오래 걸립니다. 이 비용은 토큰마다가 아니라 실행마다 한 번 지불합니다.
k3 <model_dir> [prompt] [memory] [generation] [diagnostics]
<model_dir>은 .safetensors 샤드를 보관하는 디렉터리입니다. 모든 실행에 필요하지만 --help, --version, --list-presets는 이것 없이 동작합니다.
./bin/k3 --help ./bin/k3 --version ./bin/k3 --list-presets
--chat 외에서는 다음 중 정확히 하나가 필요합니다. 하나도 전달하지 않거나 둘 이상 전달하면 사용 오류입니다(종료 2).
| 플래그 | 인수 | |
|---|---|---|
--prompt | TEXT | TEXT를 토큰화해 실행합니다. --tok가 필요합니다. |
--prompt-file | PATH | 파일의 바이트를 토큰화합니다. --tok가 필요합니다. 셸은 argv를 다시 인코딩하지만 파일은 그대로 읽으므로 ASCII 이외의 모든 입력에는 이 방식을 권장합니다. |
--ids | 1,2,3 | 토큰 식별자를 직접 전달합니다. 토크나이저를 전혀 불러오지 않으므로 토크나이저 파일이 없는 장비에서도 작동합니다. 테스트에서 사용하는 재현 가능한 채널입니다. |
./bin/k3 ~/k3model --tok ~/k3model --prompt "The capital of France is" ...
printf 'La capitale de la France est' > /tmp/p.txt ./bin/k3 ~/k3model --tok ~/k3model --prompt-file /tmp/p.txt ...
./bin/k3 ~/k3model --ids 1008,10484,318,15383,387 ...
| 플래그 | 인수 | 기본값 | |
|---|---|---|---|
--preset | NAME | 없음 | laptop · desktop · workstation · server · max. 아래 두 예산을 모두 설정합니다. |
--trunk | DIR | 꺼짐 | 5단계의 패킹된 트렁크 디렉터리입니다. 이 옵션이 스트리밍을 활성화합니다. 없으면 트렁크 전체가 약 113.5 GB로 상주 로드됩니다. |
--trunk-gb | X | 16 | 고정 레이어와 스트리밍 링 예산 |
--cache-gb | X | 64 | 라우팅 전문가 LRU 캐시 예산 |
--trunk-ring | N | 2 | 스트리밍 링 슬롯입니다. 한 레이어를 계산하는 동안 나머지는 읽기가 진행됩니다. 추가 슬롯 하나마다 RAM 슬롯 하나가 들며, 맞지 않으면 예산이 우선합니다. |
--threads | N | 물리 코어 | OpenMP 스레드입니다. Linux에서는 SMT 장비에서 여기서는 더 느린 논리 CPU당 한 스레드 대신 물리 코어 수가 기본입니다. 설정되어 있다면 OMP_NUM_THREADS를 따릅니다. |
--ultra-low-memory | 없음 | 꺼짐 | 정확한 임베딩 행과 lm_head 청크를 스트리밍하며, 전체 재계산도 하나의 순환 상태 슬롯을 재사용합니다. --trunk가 필요합니다. |
ultra 프리셋은 2.5 GB 트렁크 링과 0.31 GB 전문가 캐시로 --ultra-low-memory를 선택합니다. 8 GB급 장비를 위한 동작 증명 경로이지 대화형 속도 프리셋이 아닙니다. 모델 정밀도, Top-K 라우팅, 93개 레이어는 모두 변경되지 않습니다.
--preset과 두 -gb 플래그는 같은 두 숫자를 설정하므로 프리셋은 단축 표현일 뿐입니다. 섞어 쓰면 순서가 중요합니다. 뒤의 플래그가 이기므로 --preset server --cache-gb 40은 서버 트렁크 예산과 40 GB 캐시를 제공합니다.
--trunk없이--preset을 사용하면 유용한 일을 하지 않습니다. 모든 프리셋은 트렁크가 스트리밍된다고 가정합니다.--trunk을 생략하면 요청한 예산과 무관하게 엔진은 전체 113.5 GB를 상주 로드합니다.
| 플래그 | 인수 | 기본값 | |
|---|---|---|---|
--gen | N | 8 | 생성할 토큰 수입니다. 최대 4096이며 프롬프트는 최대 32768 토큰입니다. --gen 0 --incremental --save-state PATH는 사전 채우기만 수행하고 정확한 상태를 저장하므로 접두사를 한 번 준비해 여러 번 재개할 수 있습니다. |
--stop-id | N | 꺼짐 | 모델이 식별자 N을 내보내면 즉시 멈춥니다. 최대 8개까지 반복할 수 있습니다. 릴리스된 체크포인트는 서로 다른 두 종료 식별자(config.json의 163586, tokenizer_config.json의 163585)를 선언하며 둘 다 내보내므로 둘 다 전달하세요. |
--incremental | 없음 | 꺼짐 | 전체 접두사를 매번 다시 실행하는 대신 토큰 사이에 KV 캐시와 순환 상태를 유지합니다. |
--tok | DIR | 없음 | tiktoken.model과 tokenizer_config.json이 있는 디렉터리입니다. |
길이가 있는 생성에는 --incremental을 전달하세요. 이것이 없으면 각 단계가 전체 접두사를 다시 실행하므로 입니다. 있으면 0단계가 프롬프트 비용을 부담하고 이후 각 단계는 같은 고정 비용만 듭니다. 두 경로는 동일한 토큰을 생성해야 통과하도록 게이트되어 있으므로 순수한 속도 선택입니다.
K3는 채팅을 지원합니다. --chat은 공식 XTML 세그먼트와 토크나이저 제어 토큰을 사용하며 ChatML이나 손으로 작성한 일반 프롬프트로 대체하지 않습니다. 버전 하나는 텍스트 전용입니다. 도구, 이미지, 서버, 컨텍스트 압축은 없습니다.
./bin/k3 ~/k3model --trunk ~/k3trunk --preset desktop --tok ~/k3model
--chat --system "You are a helpful assistant."
--history my-session.jsonl --incremental
REPL은 일반 텍스트와 /help, /reset, /exit를 받습니다. <think>…</think>와 <response>…</response>를 포함한 완전한 표준 레코드를 출력합니다. --history가 제공되면 다음과 같은 이식 가능하고 사람이 읽을 수 있는 JSONL 파일을 씁니다.
{"role":"system","content":"You are a helpful assistant."} {"role":"user","content":"Explain cache locality."} {"role":"assistant","content":"…","reasoning_content":"…"}
이 파일은 모든 사용자 메시지와 완전한 어시스턴트 추론 기록을 포함할 수 있으므로 민감한 것으로 취급하세요. K3가 대화를 충실하게 계속하려면 이것이 필요합니다. 재시작하면 엔진은 전사본을 검증하고, 다시 렌더링하고, 다시 사전 채웁니다. 불투명한 KV, MLA, KDA 상태는 의도적으로 직렬화하지 않습니다. 한 세션에서 --incremental을 사용하면 턴이 만든 상태는 유지되며, 렌더링된 전사본이 그 상태에 공급된 식별자로 정확히 시작할 때 다음 턴은 새 꼬리만 사전 채웁니다(REPL은 재사용한 위치 수를 출력합니다). /reset 또는 다른 모든 불일치는 처음부터 다시 시작합니다. 제공된 --system은 기존의 초기 시스템 레코드와 정확히 일치해야 합니다. 사용자 메시지의 리터럴 제어 마커 텍스트는 XTML 제어 토큰이 아니라 일반 텍스트로 인코딩됩니다.
채팅은 기본적으로 --gen 4096을 사용하며 배치 생성처럼 탐욕 디코딩을 사용합니다. --temperature, --top-p, --seed 중 하나를 전달하면 샘플링이 켜집니다(명시하지 않은 경우 temperature 1.0, top-p 0.95). --greedy는 이 경우에도 argmax를 강제합니다. 샘플링은 PCG32를 사용합니다. --seed N은 어시스턴트 턴마다 하나의 스트림을 결정론적으로 파생하므로, 같은 전사본을 같은 시드로 재생하면 재현 가능합니다. 32K 프롬프트 및 4096 생성 제한은 새 채팅 제한이 아니라 기존 엔진 제한입니다. 컨텍스트 또는 안전한 KV 할당 한계에 도달하면 채팅은 명확히 실패하고 기록을 유지합니다.
사고 기능은 기본적으로 켜져 있으며 thinking_effort=max입니다. 이는 체크포인트 자체의 토크나이저에서 apply_chat_template에 아무것도 주지 않을 때와 정확히 같습니다. --thinking-effort low 또는 high는 그 설정만 바꿉니다. --no-think는 인코더의 thinking=False입니다. 사고 노력 시스템 메시지가 없고, 이전 어시스턴트 턴은 사고 채널 없이 렌더링되며, 생성 프롬프트가 응답 채널을 직접 열기 때문에 모델은 즉시 답하고 REPL은 <think> 블록을 출력하지 않습니다. 스트리밍 트렁크에서는 이것이 가장 큰 속도 조절 장치입니다. 실제 체크포인트 실행에서 다섯 단어 답변의 150토큰 중 119토큰이 사고 블록이었습니다. 전사본에 이미 저장된 추론은 유지되고 다음에 사고를 켠 채 대화를 실행하면 다시 렌더링됩니다. 두 플래그 모두 tests/unit/test_chat.c에서 공식 토크나이저와 바이트 및 식별자 단위로 정확히 일치합니다.
채팅은 배치 모드와 같은 CPU 전용 스트리밍 트렁크 및 라우팅 전문가 캐시를 사용합니다. --preset, --trunk-gb, --cache-gb는 기존과 정확히 같은 의미를 유지합니다. 어떤 전문가도 미리 로드되지 않고, 기존 메모리 플래그가 다르게 요청하지 않는 한 트렁크는 디스크 스트리밍 상태로 남습니다.
| 플래그 | 인수 | |
|---|---|---|
--config | PATH | 모델 구성입니다. 기본값은 <model_dir>/config.json입니다. |
--layers | N | 부분 샤드 집합용으로 첫 N개 레이어만 바인딩합니다. |
--out | FILE | JSON 결과입니다(기본값 k3_run.json). |
--dump-logits | PATH | 원소별 비교를 위한 첫 단계의 float32 로짓입니다. |
--dump-cache-trace | DIR | tools/sim_cache.py가 재생하는 expert_hist.json과 expert_trace.bin을 씁니다. |
0 | 성공 |
1 | 텐서 바인딩 또는 순방향 패스 실패 |
2 | 사용 오류 또는 확신을 갖고 읽을 수 없는 구성. 엔진은 추측을 거부합니다. |
3 | 실행은 끝났지만 --out 파일을 쓸 수 없어 하니스가 읽을 결과가 없습니다. |
4 | 실행은 끝났지만 적어도 하나의 라우팅 전문가를 불러오지 못해 출력 식별자를 신뢰할 수 없습니다. 프로세스는 그 외에는 성공했으며, 침묵하는 수치 손상을 잡기 위한 코드이므로 1과 구별됩니다. |
5 | Ctrl-C로 일찍 중지됨. 진행 중인 단계는 마쳤고 상태 파일, --out, 보고서도 모두 썼지만 토큰 목록은 요청보다 짧습니다. 두 번째 Ctrl-C는 대신 프로세스를 종료합니다. |
| 변수 | 사용처 | |
|---|---|---|
HF_TOKEN | download-model.sh | 환경에서 읽고 절대 출력하지 않는 HuggingFace 토큰 |
OMP_NUM_THREADS | 엔진 | 스레드 수. 이것과 --threads가 모두 없으면 Linux는 물리 코어 수를 기본값으로 사용합니다. |
K3_TOK_FILES | 토크나이저 도구 및 CI | 기본 위치에 없을 때 tiktoken.model이 있는 디렉터리 |
K3_MODEL_DIR | tools/budget.py | 인수로 제공하지 않았을 때의 체크포인트 디렉터리 |
./bin/k3 ~/k3model --trunk ~/k3trunk --preset ultra
--tok ~/k3model --prompt "The capital of France is" --gen 1
./bin/k3 ~/k3model --trunk ~/k3trunk --preset laptop
--tok ~/k3model --prompt "Hello! My name is" --gen 16 --incremental
./bin/k3 ~/k3model --trunk ~/k3trunk --preset server
--tok ~/k3model --prompt "def fibonacci(n):" --gen 28 --incremental
./bin/k3 ~/k3model --trunk ~/k3trunk --trunk-gb 110 --cache-gb 13
--tok ~/k3model --prompt-file prompt.txt --gen 32 --incremental
./bin/k3 ~/k3model --trunk ~/k3trunk --preset desktop
--ids 1008,10484,318,15383,387 --gen 8 --incremental --out run.json
./bin/k3 ~/k3model --trunk ~/k3trunk --preset workstation
--ids 1008,10484,318,15383,387 --gen 8 --incremental
--dump-cache-trace /tmp/trace
python3 tools/sim_cache.py /tmp/trace/expert_trace.bin
./bin/k3 ~/k3model --trunk ~/k3trunk --preset server
--ids 3,4,5,6,7 --gen 1 --dump-logits /tmp/c_logits.bin
python3 tools/cmp_logits.py /tmp/c_logits.bin ref_logits.json
./bin/k3 ~/k3model --trunk ~/k3trunk --layers 8
--ids 1,2,3 --gen 1
systemd-run --scope --user -q -p MemoryMax=8G -p MemorySwapMax=0
./bin/k3 ~/k3model --trunk ~/k3trunk --trunk-gb 2.5 --cache-gb 0.5
--ids 1008,10484,318,15383,387 --gen 8 --incremental
$ ./bin/k3 --list-presets presets (trunk / expert-cache, in GB): ultra 2.50 / 0.31 ~3 GB planned: streamed model tables, one state slot. Slow. laptop 3.00 / 1.00 8.2 GB peak RSS. The ordinary-path floor. desktop 16.00 / 10.00 31.9 GB peak RSS. workstation 60.00 / 30.00 95.5 GB peak RSS; the expert cache starts to matter here. server 110.00 / 13.00 ~128 GB peak RSS; 90 of 93 trunk layers pinned. Fastest. max 110.00 / 109.00 ~224 GB peak RSS; trunk pinned and a large expert cache.
All presets stream the trunk, so they need --trunk <packed_dir>. Run scripts/k3-doctor.sh to see which one this machine fits.
경계는 측정된 사다리에서 왔으며, doctor는 MemTotal 대신 MemAvailable을 사용합니다.
if [ "$AVAIL_GB" -ge 192 ]; then PRESET=server; EXPECT="~6 s/token" elif [ "$AVAIL_GB" -ge 96 ]; then PRESET=workstation; EXPECT="~6-20 s/token" elif [ "$AVAIL_GB" -ge 32 ]; then PRESET=desktop; EXPECT="~24 s/token" elif [ "$AVAIL_GB" -ge 10 ]; then PRESET=laptop; EXPECT="~27 s/token" else PRESET=""; fi
선택 전 알아둘 두 가지입니다.
max는 server보다 빠르지 않습니다. 추가 96 GB는 노이즈 바닥 밖에서 아무것도 사지 못합니다.server는 128이 아니라 대략 135 GB의 가용 메모리가 필요합니다.
엔진은 메모리 계획을 출력하고 생성 토큰별로 한 줄을 출력한 다음 요약을 출력합니다. 다음은 workstation 실행에서 발췌한 것입니다.
cache [final step]
requests : 1472 hits 1472 (100.00%) misses 0 evictions 729
TRUE resident hit rate 50.48%
I/O share of wall clock: 71.1% (trunk 62.4 s + experts 34.2 s of 135.8 s)
trunk [final]
pinned 48/93 layers, ring 1 slots
read 368.65 GB in 62.40 s (5908 MB/s)
PEAK RSS for the whole run: 94.74 GB <- quote this, not the plan
세 숫자가 의미를 전달합니다.
TRUE resident hit rate: RAM에서 제공된 전문가 비율입니다. 원시 hits 카운터는 프리페처가 잠시 전 디스크에서 가져온 전문가도 세므로 모든 캐시 크기에서 100%로 보입니다. 상주 수치는 그 아래에 출력됩니다.I/O share of wall clock: 전체 실행 디스크 시간을 전체 시간과 비교한 것입니다. 사다리 전체에서 41%~61%로 측정됐습니다.PEAK RSS: 실행 후 getrusage에서 얻습니다. 이것이 메모리 수치입니다. 초기 계획은 이보다 약간 높게 나옵니다.
작은 프리셋에서도 메모리가 113 GB 근처에 있습니다. --trunk를 생략했습니다. 패킹된 트렁크 디렉터리가 없으면 전체 트렁크가 상주 로드되며, 모든 프리셋은 스트리밍을 가정합니다.
ASCII가 아닌 프롬프트가 이상하게 토큰화됩니다. 셸이 argv를 다시 인코딩하므로 엔진은 입력한 것과 다른 바이트를 받습니다. 파일에 프롬프트를 넣고 그대로 읽는 --prompt-file을 사용하세요.
--prompt/--prompt-file need --tok DIR. 토크나이저는 체크포인트와 함께 제공되므로 --tok ~/k3model을 추가하세요. 엔진은 어휘가 어디에 있는지 추측하지 않고 종료합니다. 토크나이저를 완전히 건너뛰려면 --ids로 토큰 식별자를 전달하세요.
처리량이 표보다 크게 낮습니다. 거의 항상 스토리지 때문입니다. python3 tools/devbw.py <file-on-that-disk>는 dd와 달리 큐 깊이 1 및 16에서 큰 무작위 O_DIRECT 읽기로 엔진이 읽는 방식대로 디스크를 측정합니다. 네트워크 볼륨은 로컬 NVMe보다 몇 배 느립니다. ~/k3trunk를 로컬에 두세요.
KV 캐시 때문에 실행 시작이 거부됐습니다. 컨텍스트는 예산과 무관하게 위치당 약 2.37 MB가 들며, 엔진은 한 시간 뒤에 발견하는 대신 미리 계산합니다. 요청을 줄이거나 KV 캐시를 전혀 유지하지 않는 전체 재계산 방식으로 전환하려면 --incremental을 빼세요.
전체 1.56 TB가 필요한가요? 생성에는 그렇습니다. 개발에는 아닙니다. make test는 아무것도 필요 없고 --layers N은 부분 샤드 집합으로 실행됩니다. scripts/download-model.sh <dest> --layers N은 해당 레이어가 필요한 샤드만 가져옵니다. N=1에서는 약 7 GB, N=8에서는 125 GB입니다. 작은 디스크에서 파이프라인을 시험하기 위한 것이며, 레이어 접두사는 모델이 아니므로 모델 출력을 생성하지 않습니다.
왜 BLAS가 없나요? 여기의 모든 행렬 곱은 모든 장비에서 같은 비트를 내야 하기 때문입니다. 테스트 모음은 허용 오차가 아니라 정확히 PyTorch 참조와 엔진을 비교합니다. 각 내적의 합산 순서가 고정되고 알려져 있어야만 가능합니다. BLAS 라이브러리는 자체 블로킹과 축소 순서를 택하며, 버전, 공급업체(OpenBLAS, MKL, Accelerate), 같은 장비의 스레드 수에 따라 달라질 수 있습니다. 각각 수치적으로는 올바르지만 비트 단위로는 서로 일치하지 않습니다. src/core/k3_ops.c의 커널은 그 순서를 고정하기 위해 존재합니다. AVX2와 NEON 경로는 스칼라 축소를 정확히 재현하며 test_ops가 이를 확인합니다. 또한 병목이 아닌 커널에 플랫폼마다 다르게 설치되는 의존성을 추가하지 않습니다. 실행은 연산이 아니라 트렁크와 전문가를 디스크에서 얼마나 빨리 읽느냐에 제한됩니다.
Kimi K3는 2.78조 매개변수를 가지며 배포 상태에서 1.56테라바이트입니다. 소비자 장비 어느 것도 이를 담을 수 없고, 벽은 속도가 아니라 용량이므로 더 나은 하드웨어를 기다려도 해결되지 않습니다.
하지만 이것은 전문가 혼합 모델이므로 주어진 토큰에 대해 레이어당 896개 전문가 중 16개만 활성화되고 나머지는 디스크에서 잠들어 있습니다. 항상 활성인 부분을 메모리에 두고 잠자는 전문가를 스트리밍하면, GPU 없이 CPU 하나에서 8.24기가바이트에 들어맞습니다.
순진한 요구량은 모든 매개변수 수가 암시하는 값입니다.
따라서 이겨야 할 수치는 5.56테라바이트입니다.
Kimi K3에는 93개 레이어가 있습니다. 레이어 0은 평범한 고밀도 피드포워드 레이어이므로 나머지 92개 레이어가 라우팅하며, 각 레이어는 896개 중 상위 16개 전문가를 고릅니다.
주어진 토큰에 활성인 매개변수는 2.78조 중 약 1040억 개, 즉 3.7%입니다. 나머지 96.3%도 접근 가능한 어딘가에는 존재해야 하지만 RAM에 있을 필요는 없습니다.
추측하지 않고 디스크의 실제 바이트를 세면 다음과 같습니다.
=== shard census: what the 1.56 TB actually is ===
shards : 96
total bytes : 1560936091448 (1.56 TB)
--- routed experts (the part that is streamed, never resident) ---
experts total : 82,432 (896 routed x 92 MoE layers)
bytes per expert : 17,547,264 exactly
= 33,030,144 params x 0.53125 bytes
= 0.5 bytes/nibble + 1/32 byte for the shared E8M0 scale
routed expert set : 82,432 x 17,547,264 = 1.447 TB
라우팅 전문가 82,432개가 있으며 각각은 정확히 17,547,264바이트를 차지합니다. 합쳐서 전체 체크포인트의 93%인 1.447테라바이트입니다. 나머지(어텐션 프로젝션, 라우터, 정규화, 임베딩)는 나머지 7%입니다.
이 조사가 한 장의 그림으로 보여 주는 전체 전략입니다. 1.447테라바이트를 접근 가능하지만 비상주 상태로 만들 수 있다면, 커널을 하나도 작성하기 전에 메모리 문제는 한 자릿수 이상 줄어듭니다.
남는 것은 56,743,648,000개 매개변수, 즉 bfloat16에서 113.49기가바이트입니다. 이 중 108.81 GB는 레이어별 고밀도 트렁크이고, 4.70 GB는 임베딩 테이블과 출력 헤드입니다.
처음부터 끝까지 bfloat16 모델 대비 675×, 배포 체크포인트 대비 189× 축소입니다. 근사한 것은 없고 버린 가중치도 없습니다. 이 사다리 맨 아래의 출력은 맨 위의 출력과 바이트 단위로 같습니다. 문서 맨 위의 차트는 이 장부를 실제 크기로 그린 것입니다.
여기의 모든 측정은 한 워크스테이션에서 나왔습니다. SMT 없는 124코어 듀얼 소켓 AMD EPYC 7763, RAM 228 GB, NVMe 3.2 TB입니다. NVIDIA L40 GPU 네 개도 있지만 이 엔진은 GPU 경로가 없으므로 전체 측정 기간 동안 완전히 유휴 상태였습니다.
--- ISA (note: AVX2 present, AVX-512 ABSENT) ---
avx avx2 fma sse4_2
--- memory ---
Mem: 228Gi 5.1Gi 207Gi 3.1Mi 18Gi 223Gi
MemTotal: 239308464 kB
MemAvailable: 233961008 kB
Hugepagesize: 2048 kB
AVX-512는 없습니다. 엔진은 AVX2와 FMA만 필요하며, 이는 지난 10년 모든 데스크톱 CPU에 있는 명령어 집합입니다.
CPU 수치보다 스토리지 수치가 더 중요하며, 그중 하나는 예상과 반대입니다.
--- storage bandwidth, measured ---
O_DIRECT cold : 3.2 GB/s (dd bs=4M iflag=direct after drop_caches)
buffered warm : 2.3 GB/s
engine, trunk : 5373-6064 MB/s sustained during runs
NOTE O_DIRECT is FASTER than buffered here. That is the opposite of the usual
expectation, and it is why the engine opens the trunk O_DIRECT.
페이지 캐시를 완전히 우회하는 O_DIRECT 읽기가 여기서는 캐시를 통한 읽기보다 더 빠릅니다. 이 한 번의 측정이 전체 I/O 설계를 결정했습니다.
로드된 장비는 잘못 측정하기 쉬우므로, 한 가지 측정 위생 규칙이 있습니다.
--- measurement hygiene ---
unattended-upgrades: STOPPED and DISABLED before measurement (was using ~63% of a
core during the smoke run).
apt-daily.timer and apt-daily-upgrade.timer: DISABLED
코어 대부분을 먹는 백그라운드 패키지 업데이터는 대부분의 최적화보다 더 크게 시간을 바꾸므로, 무엇을 측정하기 전에 꺼야 합니다.
엔진에는 실제로 메모리가 얼마나 필요할까요? 구성 값을 손으로 곱하면 유익한 방식으로 잘못된 답이 나오므로 tools/budget.py가 존재합니다.
def classify(name: str) -> str: if ".block_sparse_moe.experts." in name: return "routed_expert" # streamable: only 16 of 896 per token if ".block_sparse_moe.shared_expert" in name: return "shared_expert" # RESIDENT: runs on every token if ".self_attn." in name: return "attention" # resident if "embed_tokens" in name or "lm_head" in name: return "embedding" # resident return "other" # norms, router gates, biases: resident
두 공유 전문가는 모든 토큰에서 실행되므로, 텐서 이름이 라우팅 전문가 옆에 있어도 상주 집합에 속합니다. 이를 잘못 계산하면 바닥값이 실제보다 작아 보이며, 그것이 가장 위험한 오류 방향입니다.
하나의 바이너리로 컴파일되는 C 파일 여섯 개입니다. BLAS, PyTorch, ONNX 런타임, GPU 라이브러리가 없습니다. 의존성은 libm과 OpenMP뿐입니다.
include/k3/
k3.h # 공개 헤더: 구성, 가중치, 모든 커널 프로토타입
k3_cfg.h # 구성 읽기 도구, 헤더 전용, 기본값 대입 거부
src/
core/k3_ops.c # 모든 수치 커널: RMSNorm, KDA, MLA, MoE, MXFP4 matmul
io/k3_st.c # safetensors 읽기 도구, 직접 작성한 JSON 스캔, O_DIRECT 읽기
io/k3_load.c # 샤드 내부 한 전문가 바이트 찾기
io/k3_trunk.c # 고밀도 트렁크 스트리밍, 고정 접두사와 링 슬롯
cache/k3_cache.c # 라우팅 전문가 LRU 캐시와 배치 프리페치
model/k3_bind.c # 체크포인트 텐서 이름을 커널 인수에 바인딩
tokenizer/k3_tok.h# tiktoken.model에서 불러오는 바이트 수준 BPE
cli/k3_run.c # k3 바이너리: 메모리 계획, 디코드 루프, 보고
tools/ # python: 트렁크 패킹, 캐시 재생, torch 대비 검증
benchmarks/ # cgroup 메모리 사다리와 분할 스윕
tests/ # 픽스처, 작은 오라클, 93레이어 적합성 실행
CFLAGS = -O3 -std=gnu99 -Wall -Wextra -Wpointer-arith -Wshadow -Wvla
-march=native -fopenmp -ffp-contract=off
LDFLAGS = -lm -fopenmp
특이해 보이는 플래그는 -ffp-contract=off입니다. 기본적으로 컴파일러는 곱셈과 덧셈을 하나의 FMA로 융합할 수 있으며, 이는 반올림을 바꿉니다. 보통은 좋지만 여기서는 문제가 됩니다. 스칼라 경로, OpenMP 경로, AVX2 경로가 비트 단위로 동일한 결과를 내야 하므로 성능 변경이 조용히 정확도 변경이 되어서는 안 됩니다.
1. build, warnings are failures
-> clean build, no diagnostics
test_ops 97784 bytes
k3_model 89392 bytes
k3_run 179736 bytes
전체 추론 엔진은 179,736바이트, 즉 1.56테라바이트 모델을 실행하는 176킬로바이트 바이너리입니다.
중간 단계는 같은 텐서 그래프를 가진 작은 모델입니다. 13개 레이어, 은닉 크기 128, 어휘 256입니다.
왜 다섯 개가 아니라 열세 개인가요? 어텐션 잔차는 열두 개 레이어 블록으로 작동하며, 두 블록이 완료되고 세 번째 블록이 진행되기 전에는 실패 양상이 나타날 수 없기 때문입니다. 다섯 레이어 모델은 경계 논리를 전혀 실행하지 않습니다.
3. full-model oracle gates on the 13-layer reference
checkpoint: 628 tensors loaded
layer map (0-based): KKKMKKKMKKKMM (M=MLA, K=KDA; dense layer = 0)
attn_res boundaries at: 0 3 6 9 12
prompt_ids 12, full_ids 32, tf_pred 32
all layer weights bound
GATE 1 teacher forcing : 32/32 positions match tf_pred
generated span : 20/20 <- must be exact
GATE 2 greedy decode : 20/20 generated tokens match full_ids
GATE 3 incremental : 20/20 generated tokens match full_ids <- KV cache + carried KDA state
VERDICT: ENGINE MATCHES THE REFERENCE EXACTLY
서로 다른 세 실행 경로가 동일한 토큰 식별자를 냅니다. 이산 argmax에는 작은 오류라는 것이 없으므로 셋 모두 정확해야 합니다.
그리고 바로 아래에 있어야 할 주의 사항입니다.
The strongest-sounding line in gates.txt is about a toy model. "VERDICT: ENGINE
MATCHES THE REFERENCE EXACTLY" refers to the 13-layer, hidden-128, vocab-256 oracle
- NOT the 2.8T checkpoint.
모든 픽스처는 그럴듯한 특정 잘못된 구현을 실패시키도록 설계되었습니다. 라우터 픽스처는 여섯 행 중 다섯 행에서 상위 두 전문가의 순서를 바꾸므로 라우팅 편향을 무시하는 구현은 실패합니다. SiTU-GLU 픽스처는 입력 0.1에서 1000까지를 포괄합니다. 거의 선형인 영역에서는 제한된 tanh가 항등 함수와 구별되지 않기 때문입니다. 그럴듯한 버그가 살아남을 수 있는 테스트는 테스트가 아닙니다.
두 가지 질문이 남습니다. 93개 레이어 각각이 올바르게 연결되었는가, 그리고 전체 스택이 올바른 수치를 생성하는가입니다.
tol = 1.2e-7 * math.sqrt(width) * 50
L87 KDA PASS 3 stages worst 0.00x budget 44s
L88 KDA PASS 3 stages worst 0.00x budget 46s
L89 KDA PASS 3 stages worst 0.00x budget 43s
L90 KDA PASS 3 stages worst 0.00x budget 45s
L91 MLA PASS 3 stages worst 0.00x budget 46s
L92 MLA PASS 3 stages worst 0.00x budget 49s
==============================================================================
LAYERS 0..92 93 passed, 0 failed (69 KDA, 24 MLA) 5639 s total
worst stage across all passing layers: 0.00x of its rounding budget
==============================================================================
VERDICT: ALL LAYERS CONFORM
마지막 두 행을 보세요. L91과 L92는 둘 다 MLA입니다. 처음에 구성이 알렸던 아키텍처 특성이 이제 검증 출력에서 보입니다.
두 번째 질문을 위한 독립 구현의 전체 순방향 패스입니다.
===== ELEMENTWISE LOGIT COMPARISON =====
prompt cross-check : both sides ran [3, 4, 5, 6, 7]
vocab : 163840
C argmax : 2494 (logit 15.021946)
reference argmax : 2494 (logit 15.021948)
top-10 overlap : 10/10
max |diff| : 7.867813e-06
relative to max|ref| : 5.237545e-07 (budget 5.1e-04)
mean |diff| : 1.231738e-06
correlation : 1.000000000
VERIFIED: the C engine's logits match the torch reference over the FULL 93-layer
stack on the released checkpoint, elementwise, and the argmax token agrees.
163,840개 값 전체에서 가장 큰 불일치는 7.87 × 10⁻⁶으로, 허용 예산의 약 천분의 일이며 상관계수는 1.000000000으로 출력됩니다.
prompt ids : 1008,10484,318,15383,387
prompt txt : The capital of France is
generated ids : 17374,20829,10,427,414,1008,606,142957
generated txt : Paris.",~+ "The Eiffel~
(~ marks a newline)
The first two tokens are 17374 = ' Paris' and 20829 = '."' - the model answers
the question CORRECTLY.
파리. 몇 기가바이트 RAM의 CPU에서 실행되는 2.78조 매개변수 모델이 처음 낸 토큰은 올바른 답입니다. 뒤따르는 따옴표와 “The Eiffel” 연속은 결함이 아닙니다. 이 원시 연속 생성 테스트는 XTML 채팅 턴을 제공하지 않으므로 모델은 텍스트를 계속 생성합니다. 모델은 자신이 프랑스에 대한 문장 JSON 목록 안에 있다고 판단하고 그 목록을 이어 갑니다.
메모리 제한은 반드시 강제해야 합니다. 228 GB 장비에서 엔진에 8 GB를 사용하라고만 말하는 것은 아무것도 측정하지 못합니다. 더 사용하지 못하게 막는 것이 없기 때문입니다.
systemd-run --scope --user -q
-p MemoryMax=${TOT}G -p MemorySwapMax=0
./bin/k3 "$MODEL" --ids "$IDS" --gen "$GEN"
--trunk "$TRUNK" --trunk-gb "$TR" --cache-gb "$CA" --incremental
--out "$OUT/$tag.json" > "$OUT/$tag.log" 2>&1
=== LADDER COMPLETE ===
total_gb pin_layers cache_gb s_per_tok trunk_hit gb_read peak_rss_gb
8 0 0.49 32.69 0.0 25.83 8.24
12 0 2.79 31.41 0.0 25.83 10.53
16 3 4.39 32.21 2.8 25.83 16.00
24 7 7.58 31.85 6.6 25.83 23.95
32 11 10.80 31.44 10.3 25.83 31.90
48 19 17.19 29.76 17.9 25.83 47.80
64 27 23.59 28.60 25.4 25.83 63.71
96 43 36.39 24.40 40.5 18.11 95.51
128 60 49.19 29.40 56.5 17.51 128.18
160 76 61.99 26.31 71.5 17.28 159.98
192 90 77.00 21.32 84.7 16.65 191.83
224 90 108.98 19.21 84.7 14.53 223.82
ids, every row: 17374,20829,10,427,414,1008,606,142957
마지막 줄부터 읽으세요. 모든 단계가 바이트 단위로 동일한 출력을 생성했습니다. 28배 범위의 열두 예산에서 토큰 식별자는 모두 같습니다.
원시 데이터: docs/data/memory-ladder.tsv.
8 GB에서 224 GB로 가면 32.69 s/token이 19.21로 내려갑니다. 이는 메모리 28배로 속도 1.70배입니다. 하드웨어를 선택한다면 8 GB에서 64 GB로의 증가는 14%를 제공합니다. 속도는 메모리에 있지 않습니다.
모든 단계에서 전체 시간의 40.9%에서 60.6%를 디스크 대기에 씁니다. 따라서 같은 바이너리도 서로 다른 두 장치에서는 서로 다른 두 엔진입니다.
로컬 NVMe에서 31.71 s/token인 실행과 네트워크 볼륨에서 70.62인 실행은 2.2배 차이이며, 그중 어느 것도 소스에 귀속할 수 없습니다. 두 구성 간 비교는 장치를 고정해야 하며, 그렇지 않으면 장치를 측정하는 것입니다.
--greedy를 추가합니다.config.json에 27개 레이어로 완전히 명시되어 있지만 여기에는 코드가 전혀 없습니다. 이 없는 인코더는 체크포인트의 0.057%이며 따로 내려받을 수 있으므로, 1.56 TB 작업이 아니라 0.9 GB 작업입니다.다음 우선순위 작업은 ROADMAP.md에 있습니다.
bfloat16의 모든 매개변수는 5.56 TB입니다. 전문가는 이미 가중치당 0.53125바이트로 제공되므로 디스크에서는 1.56 TB가 됩니다. 라우팅은 레이어마다 896개 중 16개 전문가만 활성화한다는 뜻이므로, 그중 1.45 TB는 메모리에 있을 필요가 전혀 없고 113.49 GB가 남습니다. 트렁크를 한 번에 한 레이어씩 스트리밍하면 마지막 하한이 다이얼이 되며, 다이얼은 측정 기준 8.24 GB까지 내려갑니다.
핵심은 결코 속도가 아니었습니다. 8 GB에서는 토큰당 약 30초가 걸리며, 다른 척하는 것은 어리석습니다. 핵심은 모델이 들어맞는다는 것, 8 GB에서나 224 GB에서나 같은 토큰을 생성한다는 것, 그리고 “데이터센터가 필요하다”와 “데스크톱이 필요하다” 사이의 간극이 모델 자체의 변경이 아니라 바이트가 어디에 상주하는지에 대한 네 가지 결정이었다는 것입니다.
QUICKSTART.md | 위 설정을 명령으로 압축한 문서 |
ARCHITECTURE.md | 모델이 코드에 대응되는 방식 |
PERFORMANCE.md | 노이즈 바닥을 포함한 측정된 메모리 사다리 |
TUNING.md | 예산과 분할 선택 방법 |
BENCHMARKING.md | 자신을 속이지 않고 측정하는 방법 |
TESTING.md | 각 게이트가 확립하는 내용 |
API.md | 엔진 임베딩을 위한 C 인터페이스 |
ROADMAP.md | 범위와 다음 작업 |
docs/data/ | 측정 출력. 위의 모든 수치는 여기에서 전사됨 |
docs/images/ | 모든 다이어그램과 방정식, 그리고 이를 생성하는 mermaid 및 Python 소스 |
kimi-k3-tech-report.pdf | 모델의 기술 보고서 |
make test # 계속 통과해야 하는 게이트. 가중치, 네트워크, Python 불필요 make help # 문서화된 대상 make asan # AddressSanitizer 및 UBSan make portable # -march=native 없는 범용 AVX2
CI는 같은 게이트를 실행합니다. -Werror의 GCC 및 Clang 매트릭스, 파서와 캐시의 새니타이저, 전체 가중치 없는 모음, 그리고 차단 검사인 ruff 및 shellcheck입니다. 픽스처는 PyTorch 참조에서 생성되어 커밋됩니다. tests/fixtures/README.md는 각 픽스처가 적대적인 이유와 재생성 방법을 기록합니다. 시작할 곳은 CONTRIBUTING.md입니다.
Apache 2.0입니다. LICENSE를 참고하세요. 포함된 제3자 구성 요소와 수정 사항은 NOTICE에 선언되어 있습니다.
Kimi K3는 Moonshot AI가 자체 라이선스에 따라 만들고 릴리스했습니다. 이 저장소에는 모델 가중치가 없으며 가중치에 대한 어떤 권리도 부여하지 않습니다. 기술 보고서는 참고용으로 포함되며 저자의 재산으로 남습니다.
1조 매개변수 모델이 1조 달러짜리 랙을 요구해서는 안 된다는 명제를 위해 만들었습니다.