چیتشیت
آموزش و بارگذاری یک GPT از صفر
Train and Load a GPT from Scratch
ساخت GPT با 124M پارامتر، آموزش آن با AdamW و گرمکردن کسینوسی، بارگذاری وزنهای GPT-2، گیتبندی پایپلاین.
فهرست مطالب
اجرای درسها
دستورها| دستور | کارکرد |
|---|---|
`python3 code/main.py` (35) | شمارش 124M پارامتر، تولید متن با یک پیکربندی کوچک |
`python3 code/main.py` (36) | آموزش یک مدل کوچک، ثبت در outputs/losses.jsonl |
`python3 code/main.py` (37) | نوشتن outputs/gpt2-stub.safetensors و بارگذاری آن |
`python3 code/main.py` (44) | 20 گام، نرخ یادگیری و نُرم گرادیان در هر گام، نمودار متنی |
python code/main.py plan | اعتبارسنجی مانیفست، تخمین هزینه، چاپ DAG |
python code/main.py run | اجرای مراحل، نوشتن manifest.out.yaml |
python code/main.py gate | اعمال گیتهای ارزیابی. چاپ SHIP یا HOLD |
build_param_groups(model, weight_decay) | گروههای AdamW، تفکیک کاهش وزن (decay) |
پیشفرضهای GPTConfig (مدل 124M)
پیشفرضها| تنظیم | پیشفرض | نکته |
|---|---|---|
vocab_size | 50257 | ردیفهای جدول توکن |
context_length | 1024 | ردیفهای جدول موقعیت |
d_model | 768 | عرض امبدینگ |
num_heads | 12 | d_model باید بر آن بخشپذیر باشد |
num_layers | 12 | دوازده ماژول TransformerBlock |
mlp_expansion | 4 | بخش پنهان MLP برابر با 4 برابر d_model است |
dropout | 0.1 | دموی کوچک 0.0 تنظیم میکند |
weight_tying | True | lm_head با tok_embed مشترک است |
فرآیند پیشرو (forward) در GPTModel
معماریساخت، شمارش و نمونهگیری
کدpython
ref_model = GPTModel(GPTConfig()) # مرجع 124M
count_parameters(ref_model) # پارامترهای منحصربهفرد، یکبار مشترکشده
GPTModel(GPTConfig(weight_tying=False)) # vocab_size * d_model را اضافه میکند
self.lm_head.weight = self.tok_embed.weight # بهاشتراک بگذارید، هرگز کپی نکنید
generate(tiny_model, prompt, max_new_tokens=12,
temperature=0.8, top_k=20, seed=42) # دما (temperature) باید مثبت باشد
top_k_filter(logits, top_k) # بقیه به -inf
window = tokens[:, -model.cfg.context_length:] # پنجرهی لغزان
یک گام آموزش
گامبهگام- make_batchesهدف، ورودی است که یک موقعیت شیفت داده شده.
- Scheduleتابع
cosine_with_warmupمقدارgroup["lr"]را در هر گروه پارامتر تنظیم میکند. - calc_loss_batchفرآیند پیشرو، مسطحسازی به
(batch * seq, vocab)، انتروپی متقاطع. - Backwardاجرای
loss.backward()، سپسclip_grad_norm_درmax_norm=1.0. - AdamWاجرای
optimizer.step()باbetas=(0.9, 0.95). - Logافزودن
{"step", "train_loss", "lr"}بهlosses.jsonl. - Probeهر
eval_everyگام اجرایevaluate_modelوgenerate_and_print_sample.
هستهی حلقهی آموزش
کدpython
optimizer = torch.optim.AdamW(
build_param_groups(model, cfg.weight_decay), # تفکیک کاهش وزن (decay)
lr=cfg.max_lr, betas=(0.9, 0.95))
for step in range(cfg.num_steps):
lr = cosine_with_warmup(step, cfg.warmup_steps, cfg.num_steps, cfg.max_lr, cfg.min_lr)
for group in optimizer.param_groups:
group["lr"] = lr
inputs, targets = next(train_loader)
optimizer.zero_grad(set_to_none=True)
loss = calc_loss_batch(model, inputs, targets) # انتروپی متقاطع مسطح
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=cfg.grad_clip)
optimizer.step()
اعداد زمانبندی و ابعاد
مفهومها- Warmup
- به میزان
lr_max * step / warmup_stepsتاwarmup_steps. - Cosine
- مقدار
lr_min + 0.5 * (lr_max - lr_min) * (1 + cos(pi * progress)). - Floor
- پس از
total_steps، نرخ یادگیری رویlr_minمیماند. - طول Warmup
- کسری از کل گامها. معمولاً 1 تا 3 درصد است.
- حداقل نرخ یادگیری (Floor)
- تنظیم
lr_minروی 10 درصدlr_maxیادگیری بهینهساز را زنده نگه میدارد. - Weight Tying
- صرفهجویی در 50257 در 768 = 38 میلیون پارامتر.
- مقداردهی اولیه بازمانده (Residual)
- مقیاسبندی تصویرهای خروجی با
1 / sqrt(2 * num_layers). - FLOPs پیشآموزش
- 6 × پارامترها × توکنها.
نگاشت نامهای GPT-2 به نامهای محلی
مقایسه| عامل | فایل GPT-2 | مدل محلی |
|---|---|---|
| امبدینگ توکن | wte.weight | tok_embed.weight |
| امبدینگ موقعیت | wpe.weight | pos_embed.weight |
| مقیاس LayerNorm 1 | h.N.ln_1.weight | blocks.N.ln1.scale |
| بخش QKV ادغامشده، ترانهاده | h.N.attn.c_attn.weight | blocks.N.attn.qkv.weight |
| خروجی اتنشن، ترانهاده | h.N.attn.c_proj.weight | blocks.N.attn.out_proj.weight |
| بخش fc1 در MLP، ترانهاده | h.N.mlp.c_fc.weight | blocks.N.mlp.fc1.weight |
| بخش fc2 در MLP، ترانهاده | h.N.mlp.c_proj.weight | blocks.N.mlp.fc2.weight |
| LayerNorm نهایی | ln_f.weight، ln_f.bias | final_ln.scale، final_ln.shift |
بارگذاری وزنهای safetensors
کدpython
make_stub_safetensors(STUB_PATH, cfg, seed=42) # مجموعهدادهی نمونه آفلاین
model = GPTModel(cfg)
report = load_safetensors(model, STUB_PATH, verbose=False)
report.summary() # loaded= missing= unexpected= shape_mismatch=
report.ok() # بدون missing، بدون shape_mismatch
model.lm_head.weight.data_ptr() == model.tok_embed.weight.data_ptr() # مشترک (tied)
عیبیابی
عیبیابیتابع زیان (loss) نزدیک به صفر است، مدل هیچچیز یاد نمیگیرد
- علت
- عدم شیفت بهاندازهی یک موقعیت
- راهحل
- هدف در موقعیتهای 1..T قرار گیرد
مقیاس LayerNorm صفر میشود
- علت
- کاهش وزن (weight decay) روی ضریب مقیاس اعمال شده
- راهحل
- انتقال مقیاس و بایاس به گروه بدون کاهش وزن (no decay)
یک دستهی نامناسب زحمات ساعتها را نابود میکند
- علت
- گرادیان بسیار بزرگ
- راهحل
clip_grad_norm_قبل ازstep
نمونههای قبل و بعد از بارگذاری یکسانند
- علت
- نگاشت نامها هیچ تنسوری را پیدا نکرده است
- راهحل
- بررسی
LoadReport
shape_mismatchدر گزارش- علت
- ابعاد با پیکربندی مغایرت دارند
- راهحل
- بارگذار چیزی را تخصیص نمیدهد. پیکربندی را اصلاح کنید
خطای یکی اضافه/کم بودن (off by one) نرخ یادگیری در انتهای اجرا
- علت
- زمانبندی سهبخشیِ وصلهپینهشده
- راهحل
- یک تابع روی
stepبنویسید و مقادیر مرزی را تست کنید
گیتهای ارزیابی پایپلاین
پیشفرضها| تنظیم | پیشفرض | نکته |
|---|---|---|
mmlu | 65.0 | حداقل باید این مقدار باشد |
humaneval | 40.0 | حداقل باید این مقدار باشد |
truthfulqa | 50.0 | حداقل باید این مقدار باشد |
safety_refusal_rate | 0.05 | حداکثر باید این مقدار باشد |
kl_from_reference | 25.0 | حداکثر باید این مقدار باشد |
cost_total_usd | 50000.0 | حداکثر باید این مقدار باشد |
budget_usd | 50000.0 | توقف اجرا در صورت فراتر رفتن از بودجه |
seed | 42 | فیلد مانیفست |
پرسش و پاسخ
پرسش و پاسخ- چرا ترانهاده هنگام بارگذاری؟
- ماژولهای
c_attn،c_projوc_fcاز چیدمان conv1d استفاده میکنند.nn.Linearترانهادهی آن را میخواهد. - چرا حین آموزش یک نمونه چاپ میشود؟
- تابع زیان (loss) یک اسکالر است. یک نمونه نشان میدهد آیا مدل روی یک توکن قفل کرده یا نه.
- چرا دستههای ارزیابی فقط یک بار برش میخورند؟
- دستههای یکسان باعث میشوند تابع زیان (loss) ارزیابی در بین دفعات اجرا قابل مقایسه باشد.
- زمانبندی گام خود را از کجا میخواند؟
- از
global_stepدر چکپوینت، نه از یک شمارندهی محلی.