چیت‌شیت

آموزش و بارگذاری یک GPT از صفر

Train and Load a GPT from Scratch

ساخت GPT با 124M پارامتر، آموزش آن با AdamW و گرم‌کردن کسینوسی، بارگذاری وزن‌های GPT-2، گیت‌بندی پایپ‌لاین.

  • ۱۲ بخش
  • ۵ درس مرتبط
  • کد و دستورها عیناً از دوره‌ی اصلی
فهرست مطالب
  1. اجرای درس‌ها
  2. پیش‌فرض‌های GPTConfig (مدل 124M)
  3. فرآیند پیش‌رو (forward) در GPTModel
  4. ساخت، شمارش و نمونه‌گیری
  5. یک گام آموزش
  6. هسته‌ی حلقه‌ی آموزش
  7. اعداد زمان‌بندی و ابعاد
  8. نگاشت نام‌های GPT-2 به نام‌های محلی
  9. بارگذاری وزن‌های safetensors
  10. عیب‌یابی
  11. گیت‌های ارزیابی پایپ‌لاین
  12. پرسش و پاسخ

اجرای درس‌ها

دستورها
دستورکارکرد
`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_size50257ردیف‌های جدول توکن
context_length1024ردیف‌های جدول موقعیت
d_model768عرض امبدینگ
num_heads12d_model باید بر آن بخش‌پذیر باشد
num_layers12دوازده ماژول TransformerBlock
mlp_expansion4بخش پنهان MLP برابر با 4 برابر d_model است
dropout0.1دموی کوچک 0.0 تنظیم می‌کند
weight_tyingTruelm_head با tok_embed مشترک است

فرآیند پیش‌رو (forward) در GPTModel

معماری
شناسه‌ها0 تا T-1وزن مشترک (tied)شناسه‌های توکنشکل B, Ttok_embed50257, 768pos_embed1024, 768 یادگرفته‌شدهجمعembed_dropout12 بلوکTransformerBlock با Pre-LNfinal_lnLayerNormlm_headلاجیت‌های B, T, 50257

ساخت، شمارش و نمونه‌گیری

کد
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:]  # پنجره‌ی لغزان

یک گام آموزش

گام‌به‌گام
  1. make_batchesهدف، ورودی است که یک موقعیت شیفت داده شده.
  2. Scheduleتابع cosine_with_warmup مقدار group["lr"] را در هر گروه پارامتر تنظیم می‌کند.
  3. calc_loss_batchفرآیند پیش‌رو، مسطح‌سازی به (batch * seq, vocab)، انتروپی متقاطع.
  4. Backwardاجرای loss.backward()، سپس clip_grad_norm_ در max_norm=1.0.
  5. AdamWاجرای optimizer.step() با betas=(0.9, 0.95).
  6. Logافزودن {"step", "train_loss", "lr"} به losses.jsonl.
  7. 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.weighttok_embed.weight
امبدینگ موقعیتwpe.weightpos_embed.weight
مقیاس LayerNorm 1h.N.ln_1.weightblocks.N.ln1.scale
بخش QKV ادغام‌شده، ترانهادهh.N.attn.c_attn.weightblocks.N.attn.qkv.weight
خروجی اتنشن، ترانهادهh.N.attn.c_proj.weightblocks.N.attn.out_proj.weight
بخش fc1 در MLP، ترانهادهh.N.mlp.c_fc.weightblocks.N.mlp.fc1.weight
بخش fc2 در MLP، ترانهادهh.N.mlp.c_proj.weightblocks.N.mlp.fc2.weight
LayerNorm نهاییln_f.weight، ln_f.biasfinal_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 بنویسید و مقادیر مرزی را تست کنید

گیت‌های ارزیابی پایپ‌لاین

پیش‌فرض‌ها
تنظیمپیش‌فرضنکته
mmlu65.0حداقل باید این مقدار باشد
humaneval40.0حداقل باید این مقدار باشد
truthfulqa50.0حداقل باید این مقدار باشد
safety_refusal_rate0.05حداکثر باید این مقدار باشد
kl_from_reference25.0حداکثر باید این مقدار باشد
cost_total_usd50000.0حداکثر باید این مقدار باشد
budget_usd50000.0توقف اجرا در صورت فراتر رفتن از بودجه
seed42فیلد مانیفست

پرسش و پاسخ

پرسش و پاسخ
چرا ترانهاده هنگام بارگذاری؟
ماژول‌های c_attn، c_proj و c_fc از چیدمان conv1d استفاده می‌کنند. nn.Linear ترانهاده‌ی آن را می‌خواهد.
چرا حین آموزش یک نمونه چاپ می‌شود؟
تابع زیان (loss) یک اسکالر است. یک نمونه نشان می‌دهد آیا مدل روی یک توکن قفل کرده یا نه.
چرا دسته‌های ارزیابی فقط یک بار برش می‌خورند؟
دسته‌های یکسان باعث می‌شوند تابع زیان (loss) ارزیابی در بین دفعات اجرا قابل مقایسه باشد.
زمان‌بندی گام خود را از کجا می‌خواند؟
از global_step در چک‌پوینت، نه از یک شمارنده‌ی محلی.