Как да използвам PyTorch?
За да използваш PyTorch ефективно, ти трябват три неща: правилна инсталация (CPU/GPU), ясна „рамка“ за работа с tensors и устройства (CPU/CUDA/ROCm) и стабилен тренировъчен цикъл (данни → модел → loss → backward → optimizer). PyTorch е най-силен, когато пишеш „нормален“ Python, но измерваш всичко като инженер: скорост, памет и качество. По-долу е практичен път от нулата до първи работещ модел, плюс навици за по-сериозни проекти.
Въведение
PyTorch е deep learning framework, който е удобен за учене и мощен за реални системи. Той работи с tensors (многомерни масиви), автоматични градиенти (autograd) и модулен начин за дефиниране на модели (nn.Module). В 2.x линията PyTorch добави torch.compile, което може да оптимизира изпълнението (особено на GPU) без да пренаписваш модела.
Какво ще научиш:
- как да инсталираш PyTorch правилно
- как да местиш tensors/модел между CPU и GPU
- как се пише training loop, който не „лъже“
- как да запазваш/зареждаш модели и да правиш inference
- как да ускоряваш и дебъгваш
Ако не можеш да повториш резултата си (seed, версии, данни), не си „тренирал модел“, а си направил демо.
Стъпка 1: Подготви среда (venv/conda) и базов проект
Направи си чиста среда, за да не се бориш със зависимости:
- създай
venvили conda env - сложи си
requirements.txtилиpyproject.toml - добави минимална структура:
train.pydata.pymodel.pyeval.py
Това ти спестява хаос още на втория ден.
Стъпка 2: Инсталирай правилния build (CPU, CUDA или ROCm)
Най-сигурният начин е да ползваш selector-а на официалния сайт и да копираш командата за твоята ОС и compute платформа.
Практически сценарии:
- CPU-only (за учене и прототипи): най-лесен, най-малко зависимости.
- CUDA build (NVIDIA GPU): избираш CUDA версията, която съответства на драйвърите/системата.
- ROCm build (AMD GPU): избираш поддържана ROCm версия.
Мини-чек след инсталация:
- импортира ли се
torchбез грешки? - вижда ли GPU?
Стъпка 3: Провери инсталацията и устройството (device)
Пусни:
import torch
print(torch.__version__)
print('cuda available:', torch.cuda.is_available())
if torch.cuda.is_available():
print('gpu:', torch.cuda.get_device_name(0))
После тествай tensor:
x = torch.rand(5, 3)
print(x.shape, x.dtype, x.device)
Основна идея: почти всичко „живее“ или на CPU, или на GPU. Ако входът е на GPU, моделът трябва да е на GPU.
Полезен шаблон:
device = 'cuda' if torch.cuda.is_available() else 'cpu'
model = model.to(device)
X = X.to(device)
Стъпка 4: Научи минималния „език“ на PyTorch (tensors + shapes)
Това са навиците, които спестяват дни дебъг:
- мисли в
shape(напр.batch x featuresилиbatch x channels x height x width) - проверявай
dtype(float32, float16, bfloat16) - знаи къде е tensor-ът:
x.device
Чести операции:
reshape/viewза промяна на размериpermuteза размяна на осиcat/stackза слепване
Пример:
x = torch.randn(32, 100) # batch=32
w = torch.randn(100, 10)
logits = x @ w # (32, 10)
Стъпка 5: Разбери autograd: loss → backward() → optimizer
autograd пази граф на операциите и може да сметне градиенти.
Минимумът:
- дефинираш loss
- извикваш
loss.backward() - optimizer прави
step()
Важно:
- винаги нулирай градиентите:
optimizer.zero_grad(set_to_none=True) - в evaluation използвай
torch.no_grad()
Стъпка 6: Дефинирай модел с nn.Module (и валидирай входа)
Стандартният подход:
- дефинираш
__init__със слоеве - дефинираш
forward
Пример (MLP):
import torch
import torch.nn as nn
class MLP(nn.Module):
def __init__(self, in_dim=100, hidden=256, out_dim=10):
super().__init__()
self.net = nn.Sequential(
nn.Linear(in_dim, hidden),
nn.ReLU(),
nn.Linear(hidden, out_dim)
)
def forward(self, x):
return self.net(x)
Стабилният модел започва със стабилен вход: валидирай размерите и типовете още в началото.
Полезен трик: още в forward понякога е ок да сложиш assert-и при разработка (после ги махаш).
Стъпка 7: Подготви данни с Dataset и DataLoader
Dataset описва как взимаш пример по индекс, а DataLoader управлява batching, shuffle и паралелно зареждане.
Скелет:
from torch.utils.data import Dataset, DataLoader
class MyDataset(Dataset):
def __init__(self):
self.X = ...
self.y = ...
def __len__(self):
return len(self.X)
def __getitem__(self, idx):
return self.X[idx], self.y[idx]
loader = DataLoader(MyDataset(), batch_size=64, shuffle=True, num_workers=2)
Съвети:
- започни с
num_workers=0, после увеличи - за GPU обучение често помага
pin_memory=True - ако данните са изображения, разгледай
torchvision.datasets+transforms
Стъпка 8: Напиши training loop, който е коректен (train/eval + метрики)
Минимален, но реалистичен цикъл:
import torch
import torch.nn as nn
device = 'cuda' if torch.cuda.is_available() else 'cpu'
model = MLP().to(device)
opt = torch.optim.AdamW(model.parameters(), lr=3e-4)
loss_fn = nn.CrossEntropyLoss()
for epoch in range(5):
model.train()
total_loss = 0.0
for X, y in loader:
X, y = X.to(device), y.to(device)
opt.zero_grad(set_to_none=True)
logits = model(X)
loss = loss_fn(logits, y)
loss.backward()
opt.step()
total_loss += loss.item()
model.eval()
with torch.no_grad():
# сметни метрики на validation
pass
print('epoch', epoch, 'loss', total_loss/len(loader))
Правила за здрав разум:
model.train()включва dropout/batchnorm поведениеmodel.eval()+torch.no_grad()за стабилна оценка- пази метрики по епохи (loss, accuracy) и гледай тренд
Стъпка 9: Запази модел и направи inference
Най-чистият навик в PyTorch е да пазиш state_dict:
torch.save(model.state_dict(), 'model.pt')
И да зареждаш така:
model = MLP()
model.load_state_dict(torch.load('model.pt', map_location='cpu'))
model.eval()
За inference:
model.eval()torch.no_grad()- стабилен препроцесинг и постпроцесинг
Стъпка 10: Ускорение (mixed precision и torch.compile)
Mixed precision
На много GPU-и mixed precision дава голям speedup. Подходът е:
torch.cuda.amp.autocast()за forwardGradScalerза стабилни градиенти при fp16
torch.compile
В PyTorch 2.x можеш да компилираш модела с:
model = torch.compile(model)
Документацията описва, че torch.compile използва стека TorchDynamo/TorchInductor и може да ускорява тренировка и inference без промяна на модела. Важно е да знаеш, че поддръжката на най-новите версии на Python може да изостава, затова за production избирай поддържан Python и тествай на реални данни.
Първо направи модела правилен, после го прави бърз. Оптимизация върху грешна задача е загуба на време.
Стъпка 11: Дебъг и стабилизирай обучението
Когато нещо „не учи“:
- провери данните (labels, клас дисбаланс, normalization)
- провери learning rate (често е твърде голям)
- провери дали loss намалява на малък subset (overfit test)
- логвай градиенти и активирания, ако има NaN/inf
Полезен тест: вземи 128 примера и виж дали моделът може да overfit-не. Ако не може, проблемът е в модела/данните/кода.
Съвети за по-добри резултати
- Ползвай
AdamWкато базов optimizer и започни с малък learning rate. - Винаги отделяй validation set и не „пипай“ теста до края.
- Запиши seed и версии (PyTorch, CUDA) за повторяемост.
- Измервай speed: време за епоха, GPU utilization, memory.
- Ако имаш NaN/inf, провери mixed precision, learning rate и данните.
Чести грешки, които да избягваш
- Смесване на устройства: част от tensor-ите са на CPU, моделът е на GPU.
- Грешни
shape-ове (особено при CNN/Transformer входове). - Липса на
model.eval()при оценка, което влошава метриките. - Нулиране на градиентите в грешния момент.
- Липса на логване: не знаеш кога и защо се „чупи“ обучението.
Източници и полезни линкове (проверени 2025–2026)
- PyTorch „Start Locally“ (инсталация и проверка): https://docs.pytorch.org/get-started/locally/
- PyTorch 2.x и
torch.compile(въведение): https://docs.pytorch.org/get-started/pytorch-2.0/ torch.compilerдокументация (обновена 2025): https://docs.pytorch.org/docs/main/user_guide/torch_compiler/torch.compiler.html
Как да направиш проекта повторяем (reproducible)
Повторяемостта е разликата между „случайно се получи“ и инженерство. Минимален чеклист:
- фиксирай seed за Python/NumPy/PyTorch
- логвай версии (PyTorch, CUDA/ROCm, драйвър)
- записвай конфигурацията на експеримента (batch size, lr, архитектура)
- отделяй данните на train/val/test по стабилен начин
Пример за seed (не гарантира 100% детерминизъм, но помага):
import random
import numpy as np
import torch
seed = 42
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
if torch.cuda.is_available():
torch.cuda.manual_seed_all(seed)
Checkpointing: запазвай „най-добрия“ модел, не само последния
Добра практика е да пазиш checkpoint при най-добра validation метрика. Така не губиш време, ако последните епохи започнат да overfit-ват:
best_acc = -1.0
for epoch in range(num_epochs):
# train ...
val_acc = ...
if val_acc > best_acc:
best_acc = val_acc
torch.save({
"epoch": epoch,
"model": model.state_dict(),
"opt": opt.state_dict(),
"best_acc": best_acc,
}, "checkpoint.pt")
Как да избегнеш OOM (out-of-memory) на GPU
Ако ти свършва GPU паметта:
- намали batch size
- включи mixed precision
- ползвай gradient accumulation (симулираш голям batch)
- изключи излишни tensor-и от графа (внимавай с
detach()иno_grad()при оценка) - профилирай
dtype(float32 vs float16/bfloat16)
Практичен подход: първо направи базовия модел да работи стабилно на малък batch, после увеличавай и оптимизирай.
Transfer learning: започни от pretrained модел
В практиката често не тренираш „от нула“. Вместо това взимаш pretrained backbone (например за изображения или текст), замразяваш част от слоевете и дообучаваш само последните. Това дава по-добро качество с по-малко данни и по-малко време. Типичен подход:
- зареди pretrained модел от подходяща библиотека
- замрази параметрите:
p.requires_grad = False - добави нов „head“ (класификатор)
- тренирай само head-а, после размрази част от backbone-а за finetune
Learning rate scheduler (когато обучението „засече“)
Ако loss спре да пада, scheduler често помага. В PyTorch имаш torch.optim.lr_scheduler с готови стратегии (step, cosine, reduce-on-plateau). Важно: логвай текущия learning rate, за да знаеш какво се случва и защо.
Кога да използваш „високо ниво“ библиотека (напр. Lightning)
Когато вече разбираш базовия training loop, high-level библиотека може да ти спести boilerplate (логване, чекпойнти, distributed training). Ползвай я, ако имаш стандартен supervised pipeline и искаш бърза итерация. Ако правиш нетипичен алгоритъм или много custom логика, остани на „чист“ PyTorch, докато стабилизираш идеята.
Бележка: Започни с малък модел, измервай, и итерай системно.