nn.Sequential и параметры модели
Учимся собирать сети короче через nn.Sequential и заглядывать в их параметры.
nn.Sequential — контейнер, который прогоняет вход через список слоёв по очереди, избавляя от написания класса.
nn.Sequential: сеть в одну строку
Если сеть — это просто цепочка слоёв «один за другим», писать целый класс необязательно. nn.Sequential сам прогонит данные через слои в порядке их перечисления:
import torch
import torch.nn as nn
model = nn.Sequential(
nn.Linear(784, 128),
nn.ReLU(),
nn.Linear(128, 10),
)
x = torch.randn(16, 784)
out = model(x)
print(out.shape) # torch.Size([16, 10])
Это полный аналог класса Net из прошлых уроков, но компактнее. Sequential хорош для простых линейных пайплайнов. Как только нужна логика (ветвление, повторное использование выхода, несколько входов) — возвращайтесь к классу с forward, там вы управляете потоком данных полностью.
Параметры модели
Все обучаемые веса модели доступны через model.parameters() — это итератор по тензорам. Именно его передают оптимизатору, чтобы он знал, какие тензоры двигать:
for p in model.parameters():
print(p.shape, p.requires_grad)
# torch.Size([128, 784]) True <- W первого слоя
# torch.Size([128]) True <- bias первого слоя
# torch.Size([10, 128]) True <- W второго слоя
# torch.Size([10]) True <- bias второго слоя
Видно, что Sequential сам собрал параметры всех слоёв. Это работает потому, что слои зарегистрированы как подмодули — та же магия nn.Module, что и при присваивании в self.
named_parameters: с именами
Чтобы понять, какой тензор за что отвечает, удобнее named_parameters() — он отдаёт пары «имя, тензор»:
for name, p in model.named_parameters():
print(name, tuple(p.shape))
# 0.weight (128, 784)
# 0.bias (128,)
# 2.weight (10, 128)
# 2.bias (10,)
Числа в именах — это индексы слоёв в Sequential (слой 1 — это ReLU, у неё параметров нет, поэтому она не встречается).
Сколько в модели параметров
Размер модели принято измерять числом обучаемых параметров. Считают так: складывают numel() (число элементов) всех параметров. Идею подсчёта легко показать на чистом Python — этот код запускается:
# имитируем формы параметров сети 784 -> 128 -> 10
shapes = [(128, 784), (128,), (10, 128), (10,)]
def numel(shape):
total = 1
for d in shape:
total *= d
return total
params = sum(numel(s) for s in shapes)
print("всего параметров:", params)
Вывод:
всего параметров: 101770
В реальном PyTorch это пишут одной строкой: sum(p.numel() for p in model.parameters()). Так вы быстро оцениваете «вес» модели — от тысяч у учебных сетей до миллиардов у больших языковых моделей.
Итог
nn.Sequentialпрогоняет вход через слои по очереди — компактная замена классу для простых сетей.- Для ветвлений и сложной логики нужен класс с собственным
forward. model.parameters()отдаёт все обучаемые веса — их передают оптимизатору.- Размер модели = сумма
p.numel()по всем параметрам.