چیتشیت
مفاهیم ضروری PyTorch
PyTorch Essentials
تنسورها، مشتقگیری خودکار، nn.Module، حلقه آموزش، DataLoader و دستگاهها، از درسها.
فهرست مطالب
وظایف
کار و کد| وظیفه | کد |
|---|---|
| انتخاب یک دستگاه | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") |
| ساخت یک تنسور روی آن | x = torch.randn(3, 4, device=device) |
| انتقال مدل و دسته | model = model.to(device) |
| شمارش پارامترها | sum(p.numel() for p in model.parameters()) |
| ذخیره وزنها | torch.save(model.state_dict(), "model.pt") |
| بارگذاری وزنها | model.load_state_dict(torch.load("model.pt", weights_only=True)) |
| ارزیابی بدون گراف | `model.eval()` then `with torch.no_grad():` |
| بررسی GPU | torch.cuda.get_device_name(0) |
گام آموزش
گامبهگام- DataLoaderیک دسته از ورودیها و اهداف را تحویل میدهد.
- دستگاه
inputs.to(device), targets.to(device)دسته را منتقل میکند. - بهینهساز
optimizer.zero_grad()گرادیانهای قبلی را پاک میکند. - مدل
outputs = model(inputs)گذر رو به جلو را اجرا میکند. - تابع زیان (loss)
criterion(outputs, targets)یک مقدار اسکالر برمیگرداند. - مشتقگیری خودکار
loss.backward()نوار را به صورت معکوس بازپخش میکند. - بهینهساز
optimizer.step()پارامترها را بهروزرسانی میکند.
پایپلاین آموزش
معماریآموزش و ارزیابی
کدpython
criterion = nn.CrossEntropyLoss() # لاجیتهای خام را میگیرد
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
for epoch in range(num_epochs):
model.train() # دراپاوت و نرمالسازی دسته روشن است
for inputs, targets in train_loader:
inputs, targets = inputs.to(device), targets.to(device)
optimizer.zero_grad() # گرادیانها جمع میشوند
outputs = model(inputs) # گذر رو به جلو
loss = criterion(outputs, targets)
loss.backward() # محاسبه گرادیانها
optimizer.step() # بهروزرسانی وزنها
model.eval() # حالت ارزیابی (eval) برای تست
with torch.no_grad(): # بدون گراف، حافظه کمتر
outputs = model(images)
داده و دقت ترکیبی
کدpython
class MNISTDataset(Dataset):
def __len__(self):
return len(self.labels) # تعداد نمونهها
def __getitem__(self, idx):
return self.images[idx], self.labels[idx] # one sample
loader = DataLoader(dataset, batch_size=64, shuffle=True, num_workers=4)
scaler = GradScaler() # از torch.amp
for inputs, targets in loader:
with autocast(device_type="cuda"): # گذر رو به جلو با float16
outputs = model(inputs)
loss = criterion(outputs, targets)
scaler.scale(loss).backward() # پسانتشار مقیاسشده
scaler.step(optimizer)
scaler.update()
optimizer.zero_grad()
عملیات تنسور
دستورها| دستور | عملکرد |
|---|---|
x.view(2, 12) | تغییر شکل. تنسور باید پیوسته در حافظه باشد |
x.reshape(6, 4) | تغییر شکل. همیشه کار میکند |
x.permute(2, 0, 1) | تغییر ترتیب ابعاد |
x.unsqueeze(0) | افزودن یک بُعد، (1, 2, 3, 4) |
x.squeeze() | حذف ابعاد با اندازه 1 |
`x.to("cuda")` / `x.cpu()` | انتقال تنسور بین دستگاهها |
.detach() | جدا کردن تنسور از گراف |
labels.long() | تبدیل نوع برچسبها برای آنتروپی متقاطع |
ماژولها
دستورها| دستور | عملکرد |
|---|---|
nn.Linear(in, out) | $Wx + b$، پارامترهای in*out + out |
nn.Conv2d(in_ch, out_ch, k) | کانولوشن دوبعدی |
nn.BatchNorm1d(features) | نرمالسازی اکتیویشنها، features * 2 |
nn.LayerNorm(dim) | نرمالسازی به ازای هر نمونه، dim * 2 |
nn.Dropout(p) | صفر کردن تصادفی، 0 پارامتر |
nn.ReLU() | $\max(0, x)$ |
nn.Embedding(vocab, dim) | جدول جستجو، vocab * dim |
nn.Sequential(...) | اجرای ماژولها به ترتیب |
پیشفرضها و اعداد
پیشفرضها| تنظیم | پیشفرض | نکته |
|---|---|---|
Tensor dtype | float32 | دقت پیشفرض آموزش |
LLM training dtype | bfloat16 | بازه float32، دقت کمتر |
Adam learning rate | 1e-3 | نقطه شروع پیشفرض |
SGD start learning rate | 1e-2 | یا 1e-1، طبق درس دیباگ |
DataLoader batch_size | 64 | لودر آموزش در درس |
num_workers | 4 | فرایندهای موازی بارگذاری |
Dropout in MNIST MLP | 0.2 | بعد از هر ReLU پنهان |
fp16 bytes per parameter | 2 | حافظه GPU را بر 2 تقسیم کن، حاشیه نگه دار |
مفاهیم کلیدی
مفهومها- تنسور
- آرایهای دارای شکل، dtype و دستگاه.
- قانون دستگاه یکسان
- همه عملیاتها نیاز دارند تمام تنسورها روی یک دستگاه باشند.
- مشتقگیری خودکار
- عملیاتها را روی یک نوار ضبط کرده، سپس معکوس بازپخش میکند.
- تنسور برگ
- فقط برگهای با
requires_grad=Trueگرادیانها را انباشته میکنند. - انباشت
- گرادیانها بهطور پیشفرض جمع میشوند. در هر گام
zero_gradرا صدا بزنید. - ثبت
- ماژولها و
nn.Parameterتنظیمشده در__init__توسطparameters()پیدا میشوند. - state_dict
- نگاشت نامها به تنسورها. قابل انتقال با وجود تغییرات کد.
- دقت ترکیبی
- گذر رو به جلو و پسانتشار با float16، وزنهای اصلی با float32.
عیبیابی
عیبیابیRuntimeError: expected CUDA tensor- علت
- مدل و داده روی دستگاههای متفاوتند
- راهحل
- اجرای
.to(device)روی مدل و داده
RuntimeError: modified by in-place operation- علت
- عملیات درجا مشتقگیری خودکار را مختل میکند
- راهحل
- جایگزینی
x += 1باx = x + 1
نوسان تابع زیان (loss)
- علت
- عدم استفاده از
optimizer.zero_grad() - راهحل
- صدا زدن آن قبل از
loss.backward()
تغییر دقت تست بین اجراهای مختلف
- علت
- عدم استفاده از
model.eval()در زمان تست - راهحل
- افزودن
model.eval()وtorch.no_grad()
اتمام حافظه (OOM)
- علت
- آزاد نشدن گراف
- راهحل
.detach()یاtorch.no_grad()
خطای dtype در آنتروپی متقاطع
- علت
- برچسبها Float هستند
- راهحل
- تبدیل نوع با
labels.long()
گرادیانهای اشتباه، بدون خطا
- علت
- ارسال خروجی سافتمکس به
CrossEntropyLoss - راهحل
- ارسال لاجیتهای خام
پرش تابع زیان (loss) به NaN
- علت
- انفجار گرادیان
- راهحل
torch.nn.utils.clip_grad_norm_یا کاهش نرخ یادگیری
پروبهای دیباگ
کار و کد| وظیفه | کد |
|---|---|
| یافتن عملیاتی که باعث NaN شد | with torch.autograd.detect_anomaly(): |
| بررسی تابع زیان (loss) برای NaN | torch.isnan(loss) |
| خواندن نرم گرادیان | torch.nn.utils.clip_grad_norm_(model.parameters(), float("inf")) |
| خواندن حافظه GPU | torch.cuda.memory_allocated() / 1e9 |
نکات
نکتهها- اول آزمون بیشبرازش روی یک بچ را اجرا کن. اگر شکست بخورد، ستاپ مشکل دارد.
- قبل از گشتن دنبال باگهای دیگر، 3 نرخ یادگیری با اختلاف 10 برابری را امتحان کن.
- شکلها را بعد از هر عملیات چاپ کن. برادکستینگ باگهای ابعاد را پنهان میکند.
- ورودیها را به میانگین 0 و انحراف معیار 1 نرمال کن.
- گیر کردن تابع زیان (loss) روی -log(1/num_classes) به معنی پیشبینیهای یکنواخت است.
- برای دادههای وابسته به دیسک از
num_workersاستفاده کن. میتواند سرعت را دوبرابر کند.