چیت‌شیت

حافظه آموزش، انباشت و چک‌پوینت‌ها

Training Memory, Accumulation and Checkpoints

رفع گام‌های NaN، محدودیت‌های حافظه، مقیاس انباشت و ادامه‌های ناموفق. کلیپ، AMP، باز‌محاسبه، چک‌پوینت‌های اتمیک.

  • ۱۲ بخش
  • ۶ درس مرتبط
  • کد و دستورها عیناً از دوره‌ی اصلی
فهرست مطالب
  1. نشانه‌های آموزش
  2. خطاهای بارگذاری چک‌پوینت
  3. گام امن AMP
  4. انباشت، همگام‌سازی در آخرین مرحله
  5. وظایف در کد
  6. ذخیره‌ی اتمیک شاردبندی‌شده
  7. ذخیره و ادامه از میانه اپوک
  8. اجرای درس‌ها
  9. پیش‌فرض‌ها در کد
  10. اعداد مربوط به حافظه و هزینه
  11. پرسش و پاسخ
  12. نکات

نشانه‌های آموزش

عیب‌یابی
  • صعود عمودی تابع زیان (loss) پس از یک دسته

    علت
    جهش نُرم گرادیان، بدون کلیپ
    راه‌حل
    clip_grad_norm_ در max_norm = 1.0
  • NaN شدن تمام وزن‌ها پس از یک گام

    علت
    سرریز FP16 مقدار Inf و سپس NaN می‌دهد
    راه‌حل
    torch.amp.GradScaler گام را نادیده می‌گیرد
  • فاکتور مقیاس‌بندی هرگز تغییر نمی‌کند

    علت
    عدم وجود scaler.update() در مسیر رد شدن
    راه‌حل
    فراخوانی scaler.update() در هر گام
  • اعمال کلیپ روی گرادیان‌های مقیاس‌شده

    علت
    اجرای کلیپ پیش از unscale
    راه‌حل
    ابتدا scaler.unscale_(optimizer) را صدا بزنید
  • صدها رد شدن (skip) در هر اپوک

    علت
    مدل فراتر از بازه FP16 است
    راه‌حل
    هشدار در صورت نرخ رد شدن بالای 5 درصد
  • گام بهینه‌ساز 16 برابر بزرگ‌تر است

    علت
    تابع زیان (loss) میکروبچ تقسیم نشده است
    راه‌حل
    تقسیم تابع زیان بر accum_steps
  • تفاوت در منحنی تابع زیان (loss) پس از ادامه

    علت
    نبود وضعیت RNG در چک‌پوینت
    راه‌حل
    ذخیره خروجی capture_rng_state()
  • اکتیویشن‌ها در حافظه جا نمی‌شوند

    علت
    پس‌انتشار همه اکتیویشن‌ها را نگه می‌دارد
    راه‌حل
    torch.utils.checkpoint.checkpoint(fn, input)

خطاهای بارگذاری چک‌پوینت

عیب‌یابی
  • world_size mismatch

    علت
    ادامه روی یک اندازه‌ی جهان متفاوت
    راه‌حل
    ادامه روی همان اندازه‌ی جهان
  • sha256 mismatch on rank

    علت
    ناقص شدن شارد حین flush
    راه‌حل
    نوشتن در tmp.، سپس fsync و تغییر نام
  • shard file missing

    علت
    فایل‌های کمتر از رتبه‌ها نسبت به شاردهای مانیفست
    راه‌حل
    بررسی و پیمایش تک‌تک شاردها
  • unknown schema

    علت
    اسکیمای پی‌لود با ckpt آغاز نمی‌شود
    راه‌حل
    انتقال‌های branch بر اساس رشته اسکیما
  • NaN شدن تابع زیان (loss) پس از 100 گام از ادامه

    علت
    شارد ناقص در پشت مانیفست موجود
    راه‌حل
    نوشتن اتمیک به همراه sha256 حین بارگذاری
  • پر شدن دیسک در میانه اجرا

    علت
    عدم وجود گردش چک‌پوینت‌ها
    راه‌حل
    rotate_checkpoints آخرین K مورد را نگه می‌دارد

گام امن AMP

کد
python
optimizer.zero_grad(set_to_none=True)         # تبدیل گرادیان‌ها به None
with torch.amp.autocast(device_type="cuda"):  # گذر رفت FP16
    loss = loss_fn(model(inputs), targets)
if not torch.isfinite(loss).all().item():     # بررسی پیش از پس‌انتشار
    return skip("non_finite_loss")            # بدون scaler.update در اینجا
scaler.scale(loss).backward()                 # پس‌انتشار مقیاس‌شده
scaler.unscale_(optimizer)                    # unscale پیش از کلیپ
if has_non_finite_grad(model.parameters()):
    scaler.update()                           # فاکتور را نصف می‌کند
    return skip("non_finite_grad")
pre, post = clip_global_l2_norm(params, max_norm)
scaler.step(optimizer)
scaler.update()                               # دو برابر یا نصف می‌کند

انباشت، همگام‌سازی در آخرین مرحله

کد
python
accum_steps = len(micro_batches)
zero_grads(model)
for i, (x, y) in enumerate(micro_batches):
    is_last = i == accum_steps - 1
    if no_sync_until_last and not is_last:
        with no_sync_context(model):  # DDP عملیات all-reduce را رد می‌کند
            loss = loss_scaled_for_accum(model(x), y, accum_steps, loss_fn)
            loss.backward()           # گرادیان‌ها به param.grad افزوده می‌شوند
    else:
        loss = loss_scaled_for_accum(model(x), y, accum_steps, loss_fn)
        loss.backward()               # یک همگام‌سازی به ازای هر گام مؤثر
optimizer.step()                      # یک‌بار به ازای هر دسته‌ی مؤثر

وظایف در کد

کار و کد
وظیفهکد
کلیپ بر اساس نرم L2 سراسریclip_grad_norm_(parameters, max_norm)
ثبت لاگ فاکتور مقیاس‌بندیscaler.get_scale()
مقیاس‌بندی تابع زیان (loss) میکروبچloss_scaled_for_accum(logits, target, accum_steps, loss_fn)
باز‌محاسبه یک قطعه در پس‌انتشارcheckpoint(fn, input)
ذخیره کامل وضعیت به صورت اتمیکsave_checkpoint(model, optimizer, scheduler, state, out_path)
بارگذاری یک فایل غیرقابل اعتمادtorch.load(path, map_location="cpu", weights_only=True)
ذخیره و بارگذاری شاردهای به ازای هر رتبهsave_sharded(per_rank_state, dest_dir, step)
ادامه آموزش و راستی‌آزمایی هر شاردload_sharded(src_dir, expected_world_size)

ذخیره‌ی اتمیک شاردبندی‌شده

معماری
sha256sha256ادامهوضعیت رتبه 0شارد پارامتر و بهینه‌سازوضعیت رتبه 1یک فایل به ازای هر رتبهrank0.bin.tmpنوشتن، flush، سپس fsyncrank1.bin.tmpنوشتن، flush، سپس fsyncmanifest.json.tmpworld_size، گام، شاردهاos.replaceابتدا شاردها، در آخر مانیفستload_shardedبررسی sha256 برای هر شارد

ذخیره و ادامه از میانه اپوک

گام‌به‌گام
  1. save_checkpointبسته‌بندی مدل، بهینه‌ساز، اسکژولر، شمارنده‌ها و RNG.
  2. atomic_saveیک فایل موقت می‌نویسد، سپس os.replace را صدا می‌زند.
  3. load_checkpointاجرای torch.load با weights_only=True.
  4. restore_rng_stateبازگردانی RNG در پایتون، NumPy و torch.
  5. حلقه آموزشادامه از batch_in_epoch. تفاوت‌های بازنگری زیان زیر 1e-4.

اجرای درس‌ها

دستورها
دستورکارکرد
python3 code/main.pyدرس 45: 20 گام، ردیف‌های برچسب‌خورده با STEP یا SKIP
--num-steps 100درس 46: پیمایش طولانی‌تر برای رسم منحنی
--accum-grid 1,2,4,8,16درس 46: گام‌های انباشت جهت پیمایش
--total-steps 24 --interrupt-at 10درس 47: پنجره دمو برای ادامه کار
python3 code/main.pyدرس 80: 4 شارد به علاوه مانیفست، بارگذاری مجدد بایت‌به‌بایت برابر
python3 code/main.pyدرس 81: 20 گام، 4 رتبه، RESUME VERIFIED

پیش‌فرض‌ها در کد

پیش‌فرض‌ها
تنظیمپیش‌فرضنکته
DEFAULT_MAX_NORM1.0آستانه کلیپ در AmpTrainState
`amp_dtype` on cputorch.bfloat16torch.float16 روی cuda
window1000گام‌ها در rolling_skip_rate
k4لایه‌ها به ازای هر قطعه چک‌پوینت
attention_fraction0.15سهم باز‌محاسبه، حالت گزینشی
keep_last5چک‌پوینت‌هایی که rotate_checkpoints نگه می‌دارد
CHECKPOINT_SCHEMAckpt.v1رشته اسکیما در پی‌لود
CHECKPOINT_STEP10گام ذخیره شاردبندی‌شده درس 81

اعداد مربوط به حافظه و هزینه

مفهوم‌ها
اکتیویشن‌ها به ازای هر لایه
حدود 12 * B * L * d عدد اعشاری.
d=8192, L=8192, B=1
حدود 1.6 گیگابایت به ازای هر لایه در BF16. شصت و چهار لایه حدود 103 گیگابایت.
چک‌پوینت‌گیری کامل
حدود 33٪ فلاپس بیشتر. یک گام به‌جای 3 واحد، 4 واحد است.
چک‌پوینت‌گذاری گزینشی
فقط باز‌محاسبه اتنشن. حدود 5٪ سربار.
قاعده sqrt(L)
یک چک‌پوینت به ازای هر sqrt(L) لایه. 8 چک‌پوینت برای L=64.
دسته‌ی مؤثر
micro_batch * accum_steps ضربدر اندازه‌ی جهان موازی‌سازی داده.
حافظه بهینه‌ساز ZeRO-1
معادل 12P/N بایت به ازای هر رتبه.

پرسش و پاسخ

پرسش و پاسخ
چرا GradScaler پردازنده کاری انجام نمی‌دهد؟
تبدیل خودکار CPU از BF16 استفاده می‌کند؛ نیازی به مقیاس‌بندی تابع زیان ندارد.
فاکتور چه زمانی تغییر می‌کند؟
پس از توالی‌های موفق دو برابر می‌شود. با هر رد شدن (skip) نصف می‌شود.
آیا انباشت زمان را ذخیره می‌کند؟
خیر. دو برابر کردن accum_steps زمان واقعی هر گام را دو برابر می‌کند.
چرا weights_only=True؟
فایل .pt یک پیکل است. پیکل‌گشایی کد اجرا می‌کند. از torch نسخه 2.6 یا جدیدتر استفاده کنید.
چرا یک فایل به ازای هر رتبه؟
پهنای باند نوشتن مقیاس‌پذیر می‌شود. 4 ساعت روی 1 رتبه، روی 64 رتبه 4 دقیقه است.

نکات

نکته‌ها
  • دستگاه autocast را با دستگاه بهینه‌ساز مطابقت دهید.
  • به جای assert از ValueError استفاده کنید؛ فلگ python -O گزاره‌های assert را حذف می‌کند.
  • در صورت جهش تابع زیان (loss) به بیش از 2 برابر، به چک‌پوینت قبلی بازگردید.