nn.Module и слой nn.Linear

Знакомимся с фундаментом моделей PyTorch: классом nn.Module и полносвязным слоем nn.Linear.

nn.Module — базовый класс для всех слоёв и моделей; он автоматически отслеживает обучаемые параметры внутри себя.

Зачем нужен модуль torch.nn

В разделе про autograd мы складывали модель из голых тензоров с requires_grad=True. Для большой сети это неудобно: пришлось бы вручную создавать и хранить десятки тензоров весов. Модуль torch.nn даёт готовые слои — объекты, которые сами создают свои веса, сами включают им requires_grad и сами применяют forward. Из таких кирпичиков собирают сеть.

nn.Linear — полносвязный слой

Самый базовый слой — nn.Linear(in_features, out_features). Он реализует знакомую операцию y = x @ W.T + b: умножение входа на матрицу весов плюс bias. Это тот самый «линейный слой» из теории нейросетей.

import torch
import torch.nn as nn

layer = nn.Linear(3, 2)   # принимает вектор из 3, выдаёт из 2

x = torch.randn(4, 3)     # батч из 4 примеров, у каждого 3 признака
y = layer(x)              # применяем слой
print(y.shape)            # torch.Size([4, 2]) — 4 примера, по 2 числа

Обратите внимание на форму: вход (4, 3), выход (4, 2). Первая размерность — это батч (4 примера), она проходит насквозь. Слой превращает каждый 3-мерный вектор в 2-мерный. Внутри лежат матрица весов формы (2, 3) и вектор bias длины 2 — PyTorch создал их сам и инициализировал случайными числами.

Слой вызывают как функцию

Важная идиома: к слою применяют данные через вызов объектаlayer(x), а не layer.forward(x). Под капотом это вызывает forward, но через __call__ PyTorch делает дополнительную служебную работу (хуки, режимы). Поэтому правило: всегда вызывайте модель как model(x).

Заглянем внутрь слоя

Веса слоя — это обычные тензоры (точнее, nn.Parameter), их видно и можно потрогать:

layer = nn.Linear(3, 2)

print(layer.weight.shape)   # torch.Size([2, 3]) — матрица W
print(layer.bias.shape)     # torch.Size([2])    — вектор b
print(layer.weight.requires_grad)  # True — это обучаемый параметр

Видно главное: веса уже помечены requires_grad=True. Это значит, что autograd из прошлого раздела будет считать по ним градиенты, а оптимизатор — двигать их. Слой избавил нас от ручного создания параметров.

Какие ещё бывают слои

СлойНазначение
nn.Linearполносвязный слой (взвешенная сумма + bias)
nn.Conv2dсвёрточный слой для изображений
nn.Embeddingтаблица векторов для слов/категорий
nn.Dropoutрегуляризация — случайно гасит часть нейронов
nn.BatchNorm1dнормализация активаций внутри батча

Все они — наследники nn.Module и применяются одинаково: создал, вызвал на входе. В следующем уроке мы соберём из таких слоёв полноценную сеть.

Итог

  • nn.Module — база всех слоёв и моделей; он сам отслеживает обучаемые параметры.
  • nn.Linear(in, out) делает y = x @ W.T + b и сам создаёт веса с requires_grad=True.
  • Первая размерность входа — батч, она проходит насквозь; слой меняет размер признаков.
  • Слой/модель вызывают как функцию: model(x), а не model.forward(x).
Проверьте себя
1. Что вычисляет слой nn.Linear(in, out)?
AПоэлементное произведение входа на веса
BВзвешенную сумму входа плюс bias: y = x @ W.T + b
CСвёртку входного изображения
DТолько функцию активации
2. Как правильно применить слой к данным x?
Alayer.forward(x)
Blayer.apply(x)
Clayer(x) — вызов объекта как функции
Dlayer.run(x)
3. Какое значение requires_grad у layer.weight сразу после nn.Linear(3, 2)?
AFalse, пока не вызван backward
BTrue — это обучаемый параметр
CNone до первого forward
DЗависит от устройства
Поддержать проект