چیت‌شیت

دیباگ آموزش شبکه عصبی

Debugging Neural Network Training

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

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

نشانه، علت، اولین راهکار

عیب‌یابی
  • گیر کردن تابع زیان روی -log(1/num_classes)

    علت
    مدل توزیع یکنواخت پیش‌بینی می‌کند
    راه‌حل
    پایپ‌لاین داده و برچسب‌ها را بررسی کنید
  • NaN شدن تابع زیان پس از چند گام

    علت
    نرخ یادگیری بیش از حد بالاست
    راه‌حل
    کاهش نرخ یادگیری به میزان 10x
  • NaN شدن بلافاصله‌ی تابع زیان

    علت
    log(0) یا تقسیم بر صفر
    راه‌حل
    افزودن اپسیلون به لگاریتم و تقسیم
  • نوسان شدید تابع زیان

    علت
    نرخ یادگیری بسیار بالا یا دسته بسیار کوچک
    راه‌حل
    کاهش نرخ یادگیری، افزایش اندازه‌ی دسته
  • کاهش تابع زیان و سپس رسیدن به حالت یکنواخت

    علت
    نرخ یادگیری برای فاز فاین‌تیونینگ زیادی بالاست
    راه‌حل
    افزودن برنامه‌ی کاهش کسینوسی یا پله‌ای
  • دقت آموزش بالا، دقت آزمون پایین

    علت
    بیش‌برازش
    راه‌حل
    افزودن دراپ‌اوت، کاهش وزن، داده‌ی بیشتر
  • دقت آموزش = دقت آزمون = شانس تصادفی

    علت
    مدل چیزی یاد نمی‌گیرد
    راه‌حل
    اجرای آزمون بیش‌برازش روی یک بچ
  • صفر بودن همه‌ی گرادیان‌ها

    علت
    نورون‌های مرده‌ی ReLU یا گراف جداشده
    راه‌حل
    تغییر به LeakyReLU، بررسی .requires_grad

باگ‌های متداول PyTorch

عیب‌یابی
  • نوسان تابع زیان، تجمع گرادیان‌ها

    علت
    عدم استفاده از optimizer.zero_grad()
    راه‌حل
    فراخوانی آن قبل از loss.backward()
  • تغییر دقت آزمون بین اجراهای مختلف

    علت
    عدم استفاده از model.eval() حین آزمون
    راه‌حل
    افزودن model.eval() و torch.no_grad()
  • نتایج نادرست بدون خطا

    علت
    برادکستینگ خاموش ابعاد
    راه‌حل
    چاپ ابعاد بعد از هر عملیات
  • RuntimeError: expected CUDA tensor

    علت
    عدم تطابق CPU و GPU
    راه‌حل
    استفاده از .to(device) هم برای مدل و هم داده
  • رشد نامحدود گراف، OOM

    علت
    تنسورها جدا (detach) نشده‌اند
    راه‌حل
    استفاده از .detach() یا with torch.no_grad()
  • RuntimeError: modified by in-place operation

    علت
    عملیات درجا مانع مشتق‌گیری خودکار می‌شود
    راه‌حل
    جایگزینی x += 1 با x = x + 1
  • گیر کردن تابع زیان در سطح شانس تصادفی

    علت
    ورودی‌ها نرمال‌سازی نشده‌اند
    راه‌حل
    نرمال‌سازی ورودی‌ها به میانگین 0 و انحراف معیار 1
  • انتظار Long در آنتروپی متقاطع و دریافت Float

    علت
    dtype نامناسب برچسب‌ها
    راه‌حل
    تغییر نوع برچسب‌ها: labels.long()

عدم کاهش تابع زیان: ترتیب بررسی

گام‌به‌گام
  1. نرخ یادگیریاگر زیاد باشد، تابع زیان نوسان کرده یا منفجر می‌شود. اگر کم باشد، به‌سختی تغییر می‌کند.
  2. نرخ یادگیریسه نرخ با فاصله‌ی 10x را امتحان کنید؛ مثلاً 1e-2، 1e-3، 1e-4.
  3. گرادیان‌هاصفر بودن همه یعنی نورون مرده‌ی ReLU یا محوشدگی گرادیان.
  4. گرادیان‌هاNaN یا Inf یعنی انفجار گرادیان.
  5. پایپ‌لاین دادهبُر خوردن اشتباه برچسب‌ها دقت را در حد شانس تصادفی نگه می‌دارد.
  6. پایپ‌لاین دادهباگ پیش‌پردازش باعث یادگیری نویز توسط مدل می‌شود.
  7. معماریمدل بسیار کوچک دچار کم‌برازش می‌شود؛ مدل بیش از حد عمیق سخت بهینه‌سازی می‌شود.

توابع عیب‌یابی

کار و کد
وظیفهکد
ابعاد، dtype، دستگاه، و NaN بودن تنسورdebug_print(name, tensor)
نگاشت ابعاد تمام لایه‌هاcheck_shapes(model, sample_input)
یافتن گرادیان‌های NaN یا Infdetect_nan(model, loss, step)
یافتن تنسورهای روی دستگاه دیگرcheck_devices(model, *tensors)
نُرم کلی، گرادیان‌های بزرگ یا صفرcheck_gradient_health(model)
اثبات توانایی یادگیری حلقه آموزشoverfit_one_batch(model, x_batch, y_batch, criterion)
پیمایش نرخ یادگیریfind_learning_rate(model, x_data, y_data, criterion)
مقایسه پس‌انتشار با تفاضل متناهیgradient_check(model, x, y, criterion, eps=1e-4)

متصل کردن دیباگر با هوک به مدل

کد
python
debugger1 = NetworkDebugger(model1)    # هوک زدن به Linear، Conv2d، ReLU، LeakyReLU
debugger1.record_loss(loss.item())     # یک بار فراخوانی در هر گام
debugger1.print_report()               # بررسی‌های تابع زیان، اکتیویشن و گرادیان
debugger1.remove_hooks()
with torch.autograd.detect_anomaly():  # تشخیص توکار NaN و Inf
    loss.backward()

آستانه‌های مورد استفاده در بررسی‌ها

پیش‌فرض‌ها
تنظیمپیش‌فرضیادداشت
fraction_zero> 0.5نورون‌های مرده. استفاده از LeakyReLU یا نرخ یادگیری پایین‌تر
Activation `std`< 1e-6فروپاشی اکتیویشن‌ها
Gradient `abs_mean`< 1e-7محوشدگی گرادیان در آن لایه
Gradient `abs_mean`> 100انفجار گرادیان در آن لایه
First / last grad ratio> 100محوشدگی گرادیان در عمق شبکه
rel_diff< 1e-5تأیید بررسی گرادیان. بالاتر از 1e-3 باگ است
Overfit `final_loss`> 0.1ناموفق: مدل یا حلقه آموزش خراب است
start_lr1e-7پیمایش ابزار LR finder تا end_lr=10

مقداردهی اولیه بر اساس اکتیویشن

مفهوم‌ها
مقداردهی صفر
همه نورون‌ها یکسان می‌مانند. عملاً یک نورون مؤثر در هر پهنا.
قاعده واریانس
$\mathrm{Var}(z) = \text{fan}_{\text{in}} \cdot \mathrm{Var}(w) \cdot \mathrm{Var}(x)$
Xavier
$\mathrm{Var}(w) = 2/(\text{fan}_{\text{in}} + \text{fan}_{\text{out}})$ برای sigmoid و tanh.
Kaiming
$\mathrm{Var}(w) = 2/\text{fan}_{\text{in}}$ برای ReLU، Leaky ReLU، GELU و Swish.
مقیاس‌بندی باقیمانده
مقیاس لایه‌های باقیمانده با $1/\sqrt{2N}$ برای $N$ لایه.
تصادفی N(0,1)
تا لایه 5 منفجر می‌شود. N(0,0.01): تا لایه 10 محو می‌شود.
بررسی
بزرگی اکتیویشن‌ها در تمام لایه‌ها بین 0.5 و 2.0 باقی بماند.
PyTorch
مقدار پیش‌فرض nn.Linear(512, 256) توزیع Kaiming uniform است.

ترتیب گام‌های برش و مقیاس‌بندی

معماری
متناهیبدون خطاگذر رو به جلو با autocastتابع زیان با فرمت FP32زیان متناهی است؟خیر: رد کردن گامscale(loss).backwardگرادیان‌های FP16unscale_ بهینه‌سازگرادیان‌های واقعیگرادیان NaN یا Inf است؟بله: رد کردن، نصف شدن مقیاس در به‌روزرسانیclip_grad_norm_حداکثر نُرم 1.0scaler.stepگام بهینه‌سازscaler.updateدو برابر یا نصف شدن

یک گام آموزش AMP

کد
python
self.optimizer.zero_grad(set_to_none=True)
with torch.amp.autocast(device_type=self.device_type, dtype=self.amp_dtype):
    loss = self._loss_fn(self.model(inputs), targets)
if not torch.isfinite(loss).all().item():  # رد شدن، بدون اجرای scaler.update()
    ...
self.scaler.scale(loss).backward()
self.scaler.unscale_(self.optimizer)       # پیش از برش
if has_non_finite_grad(self.model.parameters()):
    self.scaler.update()                   # نصف کردن مقیاس
pre_clip, post_clip = clip_global_l2_norm(list(self.model.parameters()), self.max_norm)
self.scaler.step(self.optimizer)
self.scaler.update()                       # در هر گام
scale = self.scaler.get_scale()            # ثبت کنار lr و نُرم

پروفایل و بازرسی

دستورها
دستورعملکرد
python -m cProfile -s cumtime train.pyهر فراخوانی تابع، مرتب‌شده بر اساس زمان تجمعی
kernprof -l -v train.pyزمان خط‌به‌خط برای توابع @profile
python -m memory_profiler your_script.pyمصرف حافظه خط‌به‌خط
tracemalloc.take_snapshot()حافظه CPU خط‌به‌خط بعد از tracemalloc.start()
torch.cuda.memory_summary()حافظه GPU تخصیص‌یافته و کش‌شده
tensorboard --logdir=runsمنحنی‌های زیان، هیستوگرام‌های وزن و گرادیان
breakpoint()توقف در pdb. بررسی با p outputs.shape، ادامه با c، خروج با q
python3 code/main.pyدموی برش و AMP. حداقل یک ردیف SKIP است

اعدادی که باید زیر نظر داشت

پرسش و پاسخ
رفتار طبیعی مقیاس GradScaler چگونه است؟
با توان‌های 2 تا حدود 2^17 یا 2^18 بالا می‌رود.
چه زمانی نرخ رد کردن هشداردهنده است؟
بالای 5 درصد در یک پنجره متحرک 1000 گامی.
مقیاس اصلاً تغییر نمی‌کند؟
مسیر رد شدن scaler.update() را فراموش کرده است.
بارگذاری داده 60٪ زمان را می‌گیرد؟
مقدار num_workers > 0 را در DataLoader تنظیم کنید.
خطای کمبود حافظه (OOM)؟
ابتدا اندازه‌ی دسته را کم کنید. سپس از torch.cuda.empty_cache() استفاده کنید.
دقت آزمون 99٪ است؟
نشت داده را بررسی کنید. اول تفکیک داده، سپس پیش‌پردازش.
کاهش زیان آموزش همزمان با افزایش زیان اعتبارسنجی؟
مدل دچار بیش‌برازش شده است.

چک‌لیست قبل از آموزش کامل

نکته‌ها
  • اجرای آزمون بیش‌برازش روی یک بچ؛ در صورت عدم موفقیت، متوقف شوید.
  • چاپ خلاصه‌ی مدل؛ بررسی تعداد پارامترها.
  • اجرای یک گذر رو به جلو با داده تصادفی؛ بررسی ابعاد خروجی.
  • آموزش برای 5 دوره (epoch)؛ اطمینان از کاهش تابع زیان.
  • بررسی آماره‌های اکتیویشن و جریان گرادیان.
  • چاپ 5 نمونه تصادفی همراه با برچسب‌ها.
  • ثبت لاگ تابع زیان، نرخ یادگیری و نُرم گرادیان حین آموزش.