LLMs في لغة C/CUDA بسيطة ونقية دون الحاجة إلى 245 ميجابايت من PyTorch أو 107 ميجابايت من cPython. ينصب التركيز الحالي على التدريب المسبق، ولا سيما إعادة إنتاج المسلسلات الصغيرة GPT-2 وGPT-3، إلى جانب تنفيذ مرجع PyTorch المتوازي في Train_gpt2.py. ستتعرف على هذا الملف على أنه ملف nanoGPT معدل قليلاً، وهو مشروع سابق لي. حاليًا، يعد llm.c أسرع قليلًا من PyTorch Nightly (بحوالي 7%). بالإضافة إلى التعليمات البرمجية الرئيسية التي تنزف في Train_gpt2.cu، لدينا تطبيق مرجعي بسيط لوحدة المعالجة المركزية fp32 في حوالي 1000 سطر من التعليمات البرمجية النظيفة في ملف واحد Train_gpt2.c. أرغب في أن يحتفظ هذا الريبو فقط برمز C و CUDA. نرحب بشدة بالمنافذ إلى لغات أو مستودعات أخرى، ولكن يجب أن يتم ذلك في مستودعات منفصلة، ويسعدني الارتباط بها أدناه في قسم "الشوكات البارزة". يتم تنسيق المطورين في المناقشات وعلى Discord، إما على قناة #llmc
على قناة Zero to Hero، أو على #llmdotc
على GPU MODE Discord.
أفضل مقدمة لمستودع llm.c اليوم هي إعادة إنتاج نموذج GPT-2 (124M). مناقشة رقم 481 خطوات من خلال هذا بالتفصيل. يمكننا إعادة إنتاج نماذج أخرى من سلسلتي GPT-2 وGPT-3 في كل من llm.c وفي التنفيذ الموازي لـ PyTorch. قم بإلقاء نظرة على البرامج النصية 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) نموذج GPT-2 124M المحفوظ في fp32، في bfloat16، 2) "حالة التصحيح" المستخدمة في اختبار الوحدة (دفعة صغيرة من البيانات وعمليات التنشيط والتدرجات المستهدفة)، 3) رمز GPT-2 المميز و 3) مجموعة بيانات tinyshakespeare المميزة. وبدلاً من ذلك، بدلاً من تشغيل البرنامج النصي .sh، يمكنك إعادة إنشاء هذه العناصر يدويًا كما يلي:
pip install -r requirements.txt
python dev/data/tinyshakespeare.py
python train_gpt2.py
قسم "أنا فقير جدًا في وحدة معالجة الرسومات لدرجة أنني لا أملك حتى وحدة معالجة رسومات واحدة". لا يزال بإمكانك الاستمتاع برؤية قطار llm.c! ولكنك لن تذهب بعيدا جدا. تمامًا مثل إصدار fp32 أعلاه، يعد إصدار وحدة المعالجة المركزية بمثابة نقطة تفتيش سابقة في تاريخ llm.c، عندما كان مجرد تطبيق مرجعي بسيط في لغة C. على سبيل المثال، بدلاً من التدريب من الصفر، يمكنك ضبط GPT- 2 صغير (124 ميجا) لإخراج نص يشبه شكسبير، على سبيل المثال:
chmod u+x ./dev/download_starter_pack.sh
./dev/download_starter_pack.sh
make train_gpt2
OMP_NUM_THREADS=8 ./train_gpt2
إذا كنت تفضل تجنب تشغيل البرنامج النصي لحزمة البداية، فكما هو مذكور في القسم السابق، يمكنك إعادة إنتاج نفس ملفات .bin والعناصر عن طريق تشغيل python dev/data/tinyshakespeare.py
ثم python train_gpt2.py
.
الأسطر أعلاه (1) تقوم بتنزيل مجموعة بيانات tinyshakespeare المميزة بالفعل وتنزيل أوزان GPT-2 (124M)، (3) init منها في C والتدريب على 40 خطوة على tineshakespeare باستخدام AdamW (باستخدام حجم الدفعة 4، طول السياق 64 فقط )، وتقييم فقدان التحقق من الصحة، وأخذ عينة من النص. بصراحة، ما لم يكن لديك وحدة معالجة مركزية قوية (ويمكنك زيادة عدد سلاسل OMP في أمر التشغيل)، فلن تصل إلى هذا الحد في دورات 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
هي المسؤولة عن تنزيل الرموز المميزة وحفظها في ملفات .bin، والتي يمكن قراءتها بسهولة من لغة C. لذلك، على سبيل المثال، عند تشغيل:
python dev/data/tinyshakespeare.py
نقوم بتنزيل مجموعة بيانات شكسبير الصغيرة ورمزها. يبدو إخراج هذا كما يلي:
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. تتوفر المزيد من مجموعات البيانات في /dev/data
.
أقوم أيضًا بإرفاق اختبار وحدة بسيط للتأكد من أن كود C الخاص بنا يتوافق مع كود PyTorch. على وحدة المعالجة المركزية كمثال، قم بالتجميع والتشغيل باستخدام:
make test_gpt2
./test_gpt2
يؤدي هذا الآن إلى تحميل ملف gpt2_124M_debug_state.bin
الذي تتم كتابته بواسطة Train_gpt2.py، وتشغيل تمريرة أمامية، ومقارنة السجلات والخسارة مع تطبيق PyTorch المرجعي، ثم إجراء 10 تكرارات للتدريب مع Adam والتأكد من تطابق الخسائر مع 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، الطبقة المعيارية. هذه نقطة بداية جيدة لفهم كيفية تنفيذ الطبقات في لغة C.
اهتمام فلاش . اعتبارًا من 1 مايو 2024، نستخدم Flash Attention من cuDNN. نظرًا لأن cuDNN يزيد وقت الترجمة من بضع ثوانٍ إلى ~ دقيقة، ويكون مسار التعليمات البرمجية هذا جديدًا جدًا الآن، ويتم تعطيله افتراضيًا. يمكنك تمكينه عن طريق تجميع مثل هذا:
make train_gpt2cu USE_CUDNN=1
سيحاول هذا التجميع مع cudnn وتشغيله. يجب أن يكون لديك cuDNN مثبتًا على نظامك. ستتولى تعليمات تثبيت cuDNN مع apt-get المجموعة الافتراضية من حزم cuDNN. للحصول على الحد الأدنى من الإعداد، تكون حزمة cuDNN dev كافية، على سبيل المثال في Ubuntu 22.04 لـ CUDA 12.x:
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 عنه حاليًا إما في الدليل الرئيسي أو الدليل الحالي. إذا كنت قد وضعته في مكان آخر، فأضف CUDNN_FRONTEND_PATH=/path/to/your/cudnn-frontend/include
إلى سطر أوامر make
.
تأكد من تثبيت MPI وNCCL، على سبيل المثال على Linux:
sudo apt install openmpi-bin openmpi-doc libopenmpi-dev
بالنسبة لـ NCCL، اتبع التعليمات الواردة من الموقع الرسمي (على سبيل المثال، أداة تثبيت الشبكة)
وثم:
make train_gpt2cu
mpirun -np < number of GPUs > ./train_gpt2cu
أو ببساطة قم بتشغيل أحد البرامج النصية لدينا ضمن ./scripts/
.
تأكد من تثبيت 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).لا شيء من هذه الطرق الثلاث متفوق، نحن نقدم لك فقط خيارات حتى تتمكن من العمل في بيئتك المحددة.
تمامًا كمثال لعملية اجتياح معدلات التعلم على جهاز مزود بـ 4 وحدات معالجة رسوميات على TinyStories. قم بتشغيل البرنامج النصي لـ Shell 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 جلسات شاشة ويقوم بتشغيل الأوامر الأربعة باستخدام LRs مختلفة. يؤدي هذا إلى كتابة ملفات السجل stories$i.log
مع جميع الخسائر، والتي يمكنك رسمها كما يحلو لك في Python. يوجد مثال سريع لكيفية تحليل ملفات السجل هذه وتخطيطها في dev/vislog.ipynb.
بضع كلمات أخرى حول ما أريد أن يكون عليه هذا الريبو:
أولاً، أريد أن يكون llm.c
مكانًا للتعليم. على سبيل المثال، يعد مجلد dev/cuda
الخاص بنا مكانًا لمكتبة النوى لجميع الطبقات المكتوبة يدويًا والموثقة جيدًا، بدءًا من النوى البسيطة جدًا وصولاً إلى النوى الأكثر تعقيدًا/الأسرع. إذا كان لديك نواة جديدة بمقايضات مختلفة ومختلفة، فلا تتردد في المساهمة بها هنا.
ومع ذلك، أريد أيضًا أن يكون llm.c
سريعًا جدًا أيضًا، وحتى مفيدًا عمليًا لتدريب الشبكات. على سبيل المثال، في البداية، يجب أن نكون قادرين على إعادة إنتاج النسخة التدريبية الكبيرة GPT-2 (1.6B). وهذا يتطلب أن ندمج أيًا من أسرع النوى الموجودة، بما في ذلك استخدام المكتبات مثل cuBLAS، وcuBLASlt، وCUTLASS، وcuDNN، وما إلى ذلك. وأعتقد أيضًا أن القيام بذلك يخدم غرضًا تعليميًا لإنشاء حد أعلى خبير، ووحدة قياس، على سبيل المثال، يمكنك القول أن النواة المكتوبة يدويًا تبلغ 80% من سرعة cuBLAS، وما إلى ذلك. وبعد ذلك يمكنك اختيار إجراء تشغيل فائق السرعة، أو يمكنك اختيار "السحب والإفلات" أيًا كان الدليل. النوى التي ترغب في استخدامها، وتشغيلها.
ومع ذلك، كقيد، أريد أن أبقي الخط الرئيسي llm.c
في المجلد الجذر بسيطًا وسهل القراءة. إذا كان هناك علاقات عامة تعمل على تحسين الأداء بنسبة 2٪ على سبيل المثال ولكنها "تكلف" 500 سطر من كود C المعقد، وربما تبعية غريبة لطرف ثالث، فقد أرفض العلاقات العامة لأن التعقيد لا يستحق كل هذا العناء. كمثال ملموس - جعل cuBLAS لـ matmuls هو الإعداد الافتراضي في حلقة التدريب الجذرية هو أمر لا يحتاج إلى تفكير: فهو يجعل كود الخط الرئيسي أسرع بكثير، وهو عبارة عن سطر واحد من التعليمات البرمجية القابلة للتفسير، وهي تبعية شائعة جدًا. على جانب هذا، يمكن أن يكون لدينا تطبيقات يدوية يمكنها التنافس مع cuBLAS في dev/cuda
.
أخيرًا، سأكون أكثر حساسية للتعقيد في المجلد الجذر للمشروع، والذي يحتوي على الملفات الرئيسية/الافتراضية للمشروع. بالمقارنة، يعد مجلد dev/
بمثابة مساحة أولية بالنسبة لنا لتطوير مكتبة من النوى أو الفئات ومشاركة التعليمات البرمجية المفيدة أو ذات الصلة أو التعليمية، ويمكن أن تكون بعض هذه التعليمات البرمجية معقدة (محليًا).
دعم AMD
ج#
كودا سي ++
C++/كودا
ويب جي بي يو سي ++
سي ++
يذهب
جافا
معدن
موجو
OpenCL
الصدأ
سويفت
منعرج
هافانا غاودي2
نيم
طرق تنظيم التنمية:
#llmc
جديدة على قناتي Zero to Hero Discord. معهد ماساتشوستس للتكنولوجيا