PyTorch

PyTorch — фреймворк глубокого обучения от Meta: динамический граф вычислений, автоградиция и гибкость исследовательского пайплайна. И выбор №1 для естественных языков и картинок.

Уровень: средний 19 разделов ⏱ 4–5 часов

1. Что такое PyTorch

PyTorch нацелен на гибкость: граф вычислений строится «на лету» (dynamic), поэтому исследовать и отлаживать модели просто. Экосистема: torchvision (картинки), torchtext (тексты), Hugging Face Transformers, Lightning (обёртка обучения).

В науке и индустрии NLP PyTorch — фактически стандарт.

2. Установка

pip install torch torchvision

Проверь CUDA перед GPU-обучением:

import torch
print(torch.__version__)
print(torch.cuda.is_available())

3. Тензоры

x = torch.tensor([[1., 2.], [3., 4.]])
print(x.shape)                 # torch.Size([2, 2])
y = torch.randn(3, 4)
z = x @ x.mT                  # умножение матриц
a = torch.zeros(2, 3, dtype=torch.float32)

# обмен с NumPy
import numpy as np
arr = x.numpy()
back = torch.from_numpy(arr)

Как ndarray из NumPy, но с поддержкой GPU и автоградиции.

4. Autograd — автоматическое дифференцирование

x = torch.tensor(3.0, requires_grad=True)
y = x ** 2 + 5 * x
y.backward()
print(x.grad)   # dy/dx = 2*3 + 5 = 11

requires_grad=True включает отслеживание; backward() считает градиенты.

5. Модуль nn.Module

import torch.nn as nn
import torch.nn.functional as F

class Net(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(784, 128)
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        return F.log_softmax(self.fc2(x), dim=1)

model = Net()
print(model)

6. Цикл обучения

import torch.optim as optim

optimizer = optim.Adam(model.parameters(), lr=1e-3)
loss_fn = nn.CrossEntropyLoss()

for epoch in range(10):
    for xb, yb in train_loader:
        optimizer.zero_grad()
        out = model(xb)
        loss = loss_fn(out, yb)
        loss.backward()
        optimizer.step()

Пять шагов цикла: zero_grad → forward → loss → backward → step — основа всего обучения в PyTorch.

7. DataLoader

from torch.utils.data import Dataset, DataLoader

class MyData(Dataset):
    def __init__(self, X, y):
        self.X = torch.tensor(X, dtype=torch.float32)
        self.y = torch.tensor(y, dtype=torch.long)

    def __len__(self):
        return len(self.X)

    def __getitem__(self, i):
        return self.X[i], self.y[i]

loader = DataLoader(MyData(X, y), batch_size=32, shuffle=True)

DataLoader перемешивает данные, делит на батчи, работает с многопроцессностью.

8. Обучение на GPU

device = 'cuda' if torch.cuda.is_available() else 'cpu'
model = model.to(device)

for xb, yb in train_loader:
    xb, yb = xb.to(device), yb.to(device)
    # остальной цикл как раньше
GPU ускоряет умножение матриц; для маленьких сетей CPU может быть почти не медленнее из-за накладных расходов копирования.

9. CNN на PyTorch

class CNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(1, 32, 3),
            nn.ReLU(),
            nn.MaxPool2d(2))
        self.fc = nn.Linear(32 * 13 * 13, 10)

    def forward(self, x):
        x = self.conv(x)
        x = x.view(x.size(0), -1)
        return self.fc(x)

10. Сериализация

torch.save(model.state_dict(), 'model.pth')

loaded = Net()
loaded.load_state_dict(torch.load('model.pth'))
loaded.eval()

state_dict — веса и буферы; model.eval() переключает в режим инференса (выключает dropout).

11. Экосистема и тенденции

Не забывай model.eval() и with torch.no_grad() при инференсе — иначе dropout и autograd сломают результат и съедят память.

12. Оптимизаторы и планировщики

Вид оптимизатора сильно влияет на сходимость. Самые распространённые в PyTorch:

optimizer = torch.optim.AdamW(model.parameters(),
                              lr=1e-4, weight_decay=1e-2)

Планировщики меняют lr по ходу обучения:

scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=30)
# каждый шаг или эпоху:
scheduler.step()
Начинай с lr в окне 3e-4…1e-3 для Adam и 1e-3…3e-3 для SGD; дивергенция — уменьшай вдвое.

13. Регуляризация

Приёмы, которые снижают переобучение:

# Dropout в PyTorch
self.dropout = nn.Dropout(0.3)
x = self.dropout(F.relu(self.fc1(x)))

# weight_decay внутри оптимизатора
optimizer = torch.optim.AdamW(model.parameters(), weight_decay=1e-2)
Забывший model.eval() получит случайные активации на инференсе — метрики «плывут» нестабильно.

14. Трансформеры через Hugging Face

Библиотека transformers даёт предобученные модели одной строкой:

from transformers import pipeline

clf = pipeline("sentiment-analysis")
print(clf("Курс отличный!")[0])
# дообучение BERT под свою классификацию
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained(
    "bert-base-uncased", num_labels=2)

Внутри — архитектура «красной» группы: энкодер, эмбеддинги, слои внимания. Метрики модели растут с данными и удачной тонкой настройкой.

Тренируй на GPU при возможности: инференс трансформера на CPU медленный даже для коротких текстов.

15. Экспорт и инференс: ONNX / TorchScript

Тренировочная модель для продакшена переводится в компактные форматы:

dummy = torch.randn(1, 3, 224, 224)
torch.onnx.export(model, dummy, "model.onnx",
                  input_names=["input"], output_names=["out"])

TorchScript фиксирует граф и исполняется без Python:

traced = torch.jit.trace(model, dummy)
traced.save("model.pt")

ONNX удобен, когда сервер работает на другом рантайме — Triton, TensorRT, Python-бэкенды. Все оптимизации проверяй метриками на задержку и точностной тест.

Проверяй экспортированную модель теми же тензорными выходами, что и PyTorch: сравнение max-ошибки ловит потерю точности.

16. Трансферное обучение и fine-tuning

Тренировать сеть с нуля дорого. Загрузи предобученную модель и обучай «поверх» неё:

from torchvision.models import resnet18

model = resnet18(weights="IMAGENET1K_V1")
for p in model.parameters():        # заморозили базу
    p.requires_grad = False
model.fc = nn.Linear(512, 10)       # новая голова

# кастуй вход под 224x224 — нормализация ImageNet
Transfer learning экономит часы и данные. Начни без хитростей: голову + Adam lr=1e-3, потом тонкая настройка.

17. Скорость: AMP и torch.compile

Mixed precision (AMP) в 2–3 раза ускоряет тренировку на GPU без потери точности; torch.compile — компиляция графа в runtime:

scaler = torch.cuda.amp.GradScaler()

with torch.autocast(device_type="cuda", dtype=torch.float16):
    out = model(x)
scaler.scale(loss).backward()
scaler.step(opt); scaler.update()

# или одной строкой при сборке модели
model = torch.compile(model)
FP16 не для всех операций: overflow на маленьких значениях лечится скалером, но это не отменяет валидации метрик после перехода.

18. Аугментации и баланс классов

Хорошие данные важнее архитектуры. Конструктор torchvision.transforms подключает аугментации «на лету»:

from torchvision import transforms as T

train_tf = T.Compose([
    T.RandomResizedCrop(224, scale=(0.8, 1.0)),
    T.RandomHorizontalFlip(),
    T.ColorJitter(brightness=0.2, contrast=0.2),
    T.ToTensor(), T.Normalize(MEAN, STD),
])
Если val-accuracy растёт, а train-падает — это переобучение; если оба падают — проблема данных или сходимости, а не аугментаций.

19. Мониторинг и воспроизводимость

Нейросетевой проект без логов — чёрный ящик. Добавь метрики в TensorBoard и фиксируй сид:

from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter("runs/exp1")
writer.add_scalar("loss/train", loss.item(), step)
writer.add_histogram("weights", model.fc.weight, step)

# воспроизводимость
torch.manual_seed(42)          # + seed для random/numpy
for epoch in range(epochs):
    avg, acc = one_epoch(...)
    print(f"{epoch:03d} loss={avg:.4f} acc={acc:.3f}")
Полный мониторинг метрик с Prometheus/Grafana пригодится, когда модель переходит в продакшен.

20. Обработка текста: токенизация и эмбеддинги

Для начала работы с текстовыми данными важно понимать разницу между токенизацией и эмбеддингами:

from transformers import AutoTokenizer, AutoModel

tok = AutoTokenizer.from_pretrained("sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2")
ids = tok("Привет, мир!", return_tensors="pt")["input_ids"]
ТерминЧто этоКогда нужно
Токенизацияразбиение на токены (слова/субслова)вход для любой model
Эмбеддингвекторное представление текстапоиск, классификация, кластеризация
pos/nerчасти речи, именованные сущностиизвлечение имен/дат из текста
Хорошее метрическое сравнение текстов — косинусная близость эмбеддингов, а не Jaccard по стоп-словам.

21. Обучение на CPU: стратегии для учебных задач

Процессоры медленнее GPU, но для учебных задач это не приговор — правильно ограничивай нагрузки:

model.to("cpu")
# меньше батчи, дробный lr, больше итераций
for x, y in loader:
    x, y = x.to("cpu"), y.to("cpu")
Если на CPU идёт > 10 минут на эпоху — бери 1–2 эпохи на полном наборе или случайную подвыборку.
Не сравнивай скорость CPU и GPU «лоб в лоб»: разная математика и память. Сравнивай только результат (loss/accuracy).

22. Чекпойнты: полный цикл сохранения

Сохранять нужно не только веса, но и всё, что нужно для продолжения обучения:

torch.save({
    "model": model.state_dict(),
    "optimizer": optim.state_dict(),
    "epoch": epoch,
    "val_acc": best_acc
}, f"ckpt_{epoch}.pt")
Валидируй: загрузи чекпойнт в чистом процессе и прогони — убедись, что числа воспроизводятся.

23. Отладка: потеря, NaN и застрявшее обучение

Когда метрики не сходятся, ищи в порядке: данные, потеря, сходимость.

# три причины NaN: градиент, lr, деление на ноль
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
Не лечи NaN «автоматически перезапусти и посмотрим»: всегда записывай seed и воспроизводи эксперимент — иначе отладка превращается в лотерею.
Заведи сводную таблицу экспериментов: lr, batch, seed, результат — быстро найдёшь лучшее решение.

Что дальше

Работа с данными — Pandas/NumPy, классика — Scikit-Learn. Удобная альтернатива пайплайна — TensorFlow+Keras.

← Вернуться к курсам