245MB의 PyTorch 또는 107MB의 cPython이 필요 없는 단순하고 순수한 C/CUDA의 LLM입니다. 현재 초점은 사전 훈련, 특히 train_gpt2.py의 병렬 PyTorch 참조 구현과 함께 GPT-2 및 GPT-3 미니시리즈를 재현하는 데 있습니다. 이 파일은 내 이전 프로젝트인 nanoGPT를 약간 수정한 파일이라는 것을 알 수 있을 것입니다. 현재 llm.c는 PyTorch Nightly보다 약간 빠릅니다(약 7%). train_gpt2.cu의 최첨단 메인라인 코드 외에도 train_gpt2.c 파일 하나에 ~1,000줄의 깔끔한 코드로 간단한 참조 CPU fp32 구현이 있습니다. 이 저장소에서 C 및 CUDA 코드만 유지하고 싶습니다. 다른 언어 또는 저장소로의 포팅은 매우 환영하지만 별도의 저장소에서 수행되어야 하며 아래의 "주요 포크" 섹션에 해당 포트에 대한 링크를 제공하게 되어 기쁩니다. 개발자 조정은 토론과 Discord, Zero to Hero 채널의 #llmc
채널 또는 GPU MODE Discord의 #llmdotc
에서 이루어집니다.
오늘 llm.c 저장소에 대한 가장 좋은 소개는 GPT-2(124M) 모델을 재현하는 것입니다. 토론 #481에서는 이에 대해 자세히 설명합니다. llm.c와 PyTorch의 병렬 구현 모두에서 GPT-2 및 GPT-3 시리즈의 다른 모델을 재현할 수 있습니다. README 스크립트를 살펴보세요.
디버깅 팁: make
명령을 실행하여 바이너리를 빌드할 때 -O3
-g
로 바꾸어 수정하면 즐겨 사용하는 IDE(예: vscode)에서 코드를 단계별로 실행할 수 있습니다.
여러 노드에서 훈련하지 않고 혼합 정밀도에 관심이 없으며 CUDA 학습에 관심이 있는 경우 fp32(레거시) 파일이 흥미로울 수 있습니다. 이는 llm.c의 역사 초기에 "체크포인트"되어 시간이 지나면서 동결된 파일입니다. 더 간단하고 이식성이 뛰어나며 이해하기도 더 쉽습니다. 다음과 같이 1 GPU, fp32 코드를 실행합니다.
chmod u+x ./dev/download_starter_pack.sh
./dev/download_starter_pack.sh
make train_gpt2fp32cu
./train_gpt2fp32cu
download_starter_pack.sh 스크립트는 시작하는 빠르고 쉬운 방법이며, 시작하는 데 도움이 되는 여러 .bin 파일을 다운로드합니다. 여기에는 1) bfloat16의 fp32에 저장된 GPT-2 124M 모델, 2) 단위 테스트에 사용되는 "디버그 상태"(소규모 데이터 배치, 대상 활성화 및 그라데이션), 3) GPT-2 토크나이저가 포함됩니다. , 3) 토큰화된 Tinyshakespeare 데이터 세트. 또는 .sh 스크립트를 실행하는 대신 다음과 같이 이러한 아티팩트를 수동으로 다시 생성할 수 있습니다.
pip install -r requirements.txt
python dev/data/tinyshakespeare.py
python train_gpt2.py
"저는 GPU가 너무 부족해서 GPU가 하나도 없습니다" 섹션. 여전히 llm.c 기차를 보는 것을 즐길 수 있습니다! 그러나 당신은 너무 멀리 가지 않을 것입니다. 위의 fp32 버전과 마찬가지로 CPU 버전은 C의 단순한 참조 구현이었던 llm.c 역사의 훨씬 이전 체크포인트입니다. 예를 들어 처음부터 훈련하는 대신 GPT를 미세 조정할 수 있습니다. 예를 들어, 셰익스피어와 같은 텍스트를 출력하기 위한 작은 크기(124M) 2개:
chmod u+x ./dev/download_starter_pack.sh
./dev/download_starter_pack.sh
make train_gpt2
OMP_NUM_THREADS=8 ./train_gpt2
스타터 팩 스크립트를 실행하지 않으려는 경우 이전 섹션에서 언급한 대로 python dev/data/tinyshakespeare.py
실행한 다음 python train_gpt2.py
실행하여 정확히 동일한 .bin 파일 및 아티팩트를 재현할 수 있습니다.
위의 줄은 (1) 이미 토큰화된 Tinyshakespeare 데이터 세트를 다운로드하고 GPT-2(124M) 가중치를 다운로드합니다. (3) C에서 초기화하고 AdamW를 사용하여 Tineshakespeare에서 40단계 동안 훈련합니다(배치 크기 4 사용, 컨텍스트 길이 64만 사용). ), 유효성 검사 손실을 평가하고 일부 텍스트를 샘플링합니다. 솔직히, 강력한 CPU가 없으면(그리고 실행 명령에서 OMP 스레드 수를 늘릴 수 없다면) CPU 교육 LLM에서 그렇게까지 얻을 수는 없지만 좋은 데모/참조가 될 수 있습니다. 내 MacBook Pro(Apple Silicon M3 Max)에서 출력은 다음과 같습니다.
[GPT-2]
max_seq_len: 1024
vocab_size: 50257
num_layers: 12
num_heads: 12
channels: 768
num_parameters: 124439808
train dataset num_batches: 1192
val dataset num_batches: 128
num_activations: 73323776
val loss 5.252026
step 0: train loss 5.356189 (took 1452.121000 ms)
step 1: train loss 4.301069 (took 1288.673000 ms)
step 2: train loss 4.623322 (took 1369.394000 ms)
step 3: train loss 4.600470 (took 1290.761000 ms)
... (trunctated) ...
step 39: train loss 3.970751 (took 1323.779000 ms)
val loss 4.107781
generating:
---
Come Running Away,
Greater conquer
With the Imperial blood
the heaviest host of the gods
into this wondrous world beyond.
I will not back thee, for how sweet after birth
Netflix against repounder,
will not
flourish against the earlocks of
Allay
---
/dev/data/(dataset).py
내부의 데이터 파일은 C에서 쉽게 읽을 수 있는 .bin 파일에 토큰을 다운로드, 토큰화 및 저장하는 역할을 합니다. 예를 들어 다음을 실행하면:
python dev/data/tinyshakespeare.py
우리는 Tinyshakespeare 데이터 세트를 다운로드하고 토큰화합니다. 이것의 출력은 다음과 같습니다:
writing 32,768 tokens to ./dev/data/tinyshakespeare/tiny_shakespeare_val.bin
writing 305,260 tokens to ./dev/data/tinyshakespeare/tiny_shakespeare_train.bin
.bin 파일에는 짧은 헤더(1024바이트)와 uint16 형식의 토큰 스트림이 포함되어 있으며 GPT-2 토크나이저의 토큰 ID를 나타냅니다. /dev/data
에서 더 많은 데이터 세트를 사용할 수 있습니다.
또한 C 코드가 PyTorch 코드와 일치하는지 확인하기 위한 간단한 단위 테스트를 첨부합니다. 예를 들어 CPU에서 다음을 사용하여 컴파일하고 실행합니다.
make test_gpt2
./test_gpt2
이제 train_gpt2.py에 의해 작성된 gpt2_124M_debug_state.bin
파일을 로드하고, 정방향 패스를 실행하고, 로짓과 손실을 PyTorch 참조 구현과 비교한 다음, Adam을 사용하여 10번의 훈련 반복을 수행하고 손실이 PyTorch와 일치하는지 확인합니다. GPU 버전을 테스트하려면 다음을 실행합니다.
# fp32 test (cudnn not supported)
make test_gpt2cu PRECISION=FP32 && ./test_gpt2cu
# mixed precision cudnn test
make test_gpt2cu USE_CUDNN=1 && ./test_gpt2cu
이는 fp32 경로와 혼합 정밀도 경로를 모두 테스트합니다. 테스트를 통과하고 overall okay: 1
.
여기에 doc/layernorm/layernorm.md에 아주 작은 튜토리얼을 첨부했습니다. 이는 GPT-2 모델의 단일 레이어인 layernorm 레이어를 구현하는 방법에 대한 간단한 단계별 가이드입니다. 이는 C에서 레이어가 어떻게 구현되는지 이해하는 좋은 출발점입니다.
플래시 주의 . 2024년 5월 1일부터 cuDNN의 Flash Attention을 사용합니다. cuDNN은 컴파일 시간을 몇 초에서 ~분까지 늘리고 이 코드 경로는 현재 매우 새로운 것이므로 기본적으로 비활성화되어 있습니다. 다음과 같이 컴파일하여 활성화할 수 있습니다.
make train_gpt2cu USE_CUDNN=1
그러면 cudnn으로 컴파일하고 실행하려고 시도합니다. 시스템에 cuDNN이 설치되어 있어야 합니다. apt-get을 사용한 cuDNN 설치 지침은 기본 cuDNN 패키지 세트를 가져옵니다. 최소 설정의 경우 cuDNN dev 패키지로 충분합니다(예: CUDA 12.x용 Ubuntu 22.04).
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb
sudo dpkg -i cuda-keyring_1.1-1_all.deb
sudo apt-get update
sudo apt-get -y install libcudnn9-dev-cuda-12
게다가 cuDNN 프런트엔드가 필요하지만 이는 헤더 파일일 뿐입니다. 저장소를 디스크에 복제하기만 하면 됩니다. Makefile은 현재 홈 디렉터리나 현재 디렉터리에서 해당 파일을 찾습니다. 다른 곳에 저장한 경우 make
명령줄에 CUDNN_FRONTEND_PATH=/path/to/your/cudnn-frontend/include
추가하세요.
예를 들어 Linux에서는 MPI 및 NCCL을 설치해야 합니다.
sudo apt install openmpi-bin openmpi-doc libopenmpi-dev
NCCL의 경우 공식 웹사이트(예: 네트워크 설치 프로그램)의 지침을 따르세요.
그런 다음:
make train_gpt2cu
mpirun -np < number of GPUs > ./train_gpt2cu
또는 ./scripts/
아래에서 스크립트 중 하나를 실행하세요.
다중 GPU 섹션의 지침에 따라 NCCL
설치했는지 확인하세요.
다중 노드 교육을 실행할 수 있도록 현재 지원되는 세 가지 방법이 있습니다.
./scripts/multi_node/run_gpt2_124M_mpi.sh
스크립트를 참조하세요../scripts/multi_node/run_gpt2_124M_fs.sbatch
스크립트를 참조하세요../scripts/multi_node/run_gpt2_124M_tcp.sbatch
스크립트를 참조하세요.메모:
slurm-wlm
이 PMIx 지원을 중단한 경우 일반적인 상황이라고 가정) FS(2) 또는 TCP(3) 접근 방식을 사용해야 합니다. . slurm이 PMIx를 지원하는지 테스트하려면: srun --mpi=list
실행하고 출력에 pmix
나오는지 확인하세요.mpirun
- MPI(1)를 사용하여 다중 노드 실행을 시작할 수 있습니다.이 3가지 방법 중 어느 것도 더 우수하지 않습니다. 우리는 단지 귀하의 특정 환경에서 실행할 수 있도록 옵션을 제공할 뿐입니다.
TinyStories에서 4개의 GPU가 있는 머신의 학습 속도를 스윕하는 프로세스의 예와 같습니다. 쉘 스크립트 sweep.sh
실행하십시오(물론 chmod u+x sweep.sh
이후).
#! /bin/bash
learning_rates=(3e-5 1e-4 3e-4 1e-3)
for i in {0..3} ; do
export CUDA_VISIBLE_DEVICES= $i
screen -dmS " tr $i " bash -c " ./train_gpt2cu -i data/TinyStories -v 250 -s 250 -g 144 -l ${learning_rates[$i]} -o stories $i .log "
done
# you can bring these down with
# screen -ls | grep -E "tr[0-3]" | cut -d. -f1 | xargs -I {} screen -X -S {} quit
이 예에서는 4개의 화면 세션을 열고 서로 다른 LR을 사용하여 4개의 명령을 실행합니다. 그러면 모든 손실이 포함된 로그 파일 stories$i.log
기록되며 Python에서 원하는 대로 플롯할 수 있습니다. 이러한 로그 파일을 구문 분석하고 구성하는 방법에 대한 간단한 예는 dev/vislog.ipynb에 있습니다.
이 저장소가 무엇인지에 대해 몇 마디 더 말씀드리겠습니다.
첫째, 저는 llm.c
교육을 위한 장소가 되기를 바랍니다. 예를 들어 dev/cuda
폴더는 매우 간단한 커널부터 시작하여 더 복잡하고 빠른 커널에 이르기까지 수동으로 직접 작성하고 잘 문서화한 모든 레이어에 대한 커널 라이브러리를 위한 장소입니다. 다양한 장단점이 있는 새로운 커널이 있다면 여기에 자유롭게 기여해 주세요.
즉, 나는 또한 llm.c
매우 빠르기를 원하며 심지어 네트워크를 훈련시키는 데 실질적으로 유용할 수도 있습니다. 예를 들어 시작하려면 대규모 GPT-2(1.6B) 훈련 실행을 재현할 수 있어야 합니다. 이를 위해서는 cuBLAS, cuBLASLt, CUTLASS, cuDNN 등과 같은 라이브러리의 사용을 포함하여 가장 빠른 커널을 통합해야 합니다. 또한 그렇게 하는 것이 전문가의 상한선과 측정 단위를 설정하는 교육적 목적에 도움이 된다고 생각합니다. 예를 들어 수동으로 작성된 커널이 cuBLAS 속도의 80%라고 말할 수 있습니다. 그런 다음 초고속 실행을 선택하거나 사용하려는 수동 커널을 "드래그 앤 드롭"하여 다음과 같이 실행할 수 있습니다. 저것들.
그러나 제약 조건으로 루트 폴더의 메인라인 llm.c
간단하고 읽기 쉽게 유지하고 싶습니다. 예를 들어 성능을 2% 향상시키는 PR이 있지만 500줄의 복잡한 C 코드가 "비용"이 들고 이상한 제3자 종속성이 있는 경우 복잡성이 그만한 가치가 없기 때문에 PR을 거부할 수 있습니다. 구체적인 예로 matmuls용 cuBLAS를 루트 훈련 루프의 기본값으로 만드는 것은 당연한 일입니다. 이는 메인라인 코드를 훨씬 빠르게 만들고, 해석 가능한 코드 한 줄이며, 매우 일반적인 종속성입니다. 이 측면에서 우리는 dev/cuda
에서 cuBLAS와 경쟁할 수 있는 수동 구현을 가질 수 있습니다.
마지막으로 프로젝트의 기본/기본 파일이 포함된 프로젝트 루트 폴더의 복잡성에 훨씬 더 민감하겠습니다. 이에 비해 dev/
폴더는 커널 또는 클래스 라이브러리를 개발하고 유용하거나 관련되거나 교육적인 코드를 공유하기 위한 스크래치 공간에 가깝습니다. 이 코드 중 일부는 (로컬적으로) 복잡해도 괜찮을 수 있습니다.
AMD 지원
기음#
쿠다 C++
C++/쿠다
웹GPU C++
C++
가다
자바
금속
모조
오픈CL
녹
스위프트
급격한 변경
하바나 가우디2
님
개발을 조직하는 방법:
#llmc
채널을 만들었습니다. MIT