С вопроса «как обучается нейросеть» начинается почти любая DL-секция. Нужно уверенно объяснить нейрон, многослойную сеть, прямой и обратный проход и уметь выписать градиенты для одного слоя.
Нейрон и слой
Нейрон считает взвешенную сумму входов, добавляет смещение и применяет нелинейность:
y = f(w·x + b)
Полносвязный слой это много нейронов сразу: y = f(Wx + b). Слой с 784 входами и 128 выходами имеет 784·128 + 128 = 100 480 параметров.
Зачем нелинейность: композиция линейных слоёв это снова линейная функция, W₂(W₁x) = (W₂W₁)x. Без активаций сто слоёв равны одному.
Многослойный перцептрон (MLP) это цепочка таких слоёв. Теорема об универсальной аппроксимации говорит, что даже один скрытый слой достаточной ширины может приблизить любую непрерывную функцию, но ничего не говорит о том, как её обучить и сколько нейронов понадобится. На практике глубина эффективнее ширины.
Прямой проход
def forward(x, W1, b1, W2, b2):
h = [max(0.0, sum(w * xi for w, xi in zip(row, x)) + b) for row, b in zip(W1, b1)]
return [sum(w * hi for w, hi in zip(row, h)) + b for row, b in zip(W2, b2)]
Промежуточные значения (входы слоёв, пре-активации) сохраняются: они понадобятся на обратном проходе.
Обратный проход
Backprop применяет цепное правило от loss к первому слою. Для слоя Y = XW + b (X размера B×d_in) и пришедшего сверху dY:
dW = Xᵀ · dY (d_in × d_out, как W)
db = Σ dY по батчу
dX = dY · Wᵀ (передаём в предыдущий слой)
После ReLU градиент умножается на маску «пре-активация > 0». Поэтому для backward нужно хранить вход каждого слоя, и обучение требует больше памяти, чем инференс.
Пример для сети h = ReLU(W1·x + b1), ŷ = w2·h + b2, L = (ŷ - y)²:
- dL/dŷ = 2(ŷ - y).
- dw2 = dL/dŷ · h, db2 = dL/dŷ.
- dh = dL/dŷ · w2, dz = dh там, где z > 0, иначе 0.
- dW1 = dz · xᵀ, db1 = dz.
Шаг обучения
- Взять мини-батч.
- Прямой проход и loss.
- Обратный проход.
- Шаг оптимизатора.
- Обнулить градиенты (в PyTorch они копятся).
Если loss усредняется по батчу, величина градиента в среднем не зависит от размера батча, меняется только шум. При reduction="sum" градиент растёт с батчем.
Инициализация и симметрия
Если все веса слоя одинаковы, все нейроны получают одинаковые градиенты и остаются копиями: симметрия не разрушается никогда. Поэтому веса инициализируют случайно с правильным масштабом (тема модуля про инициализацию).
Мёртвые нейроны
Если из-за большого шага пре-активация нейрона с ReLU стала отрицательной для всех данных, его градиент навсегда нулевой. Лечат меньшим learning rate, инициализацией, LeakyReLU или GELU.
Перцептрон и XOR
Классический перцептрон с пороговой активацией находит разделяющую прямую, если классы линейно разделимы (AND, OR). Для XOR такой прямой нет, и это исторический аргумент в пользу скрытых слоёв.
Частые ошибки
- Забыть, что для dW нужен вход слоя, а не его выход.
- Путать dW и dX.
- Инициализировать веса нулями.
- Не обнулять градиенты между шагами.
Что спросят на собесе
- Что считает нейрон и зачем нелинейность.
- Как работает backprop, формулы градиентов полносвязного слоя.
- Сколько параметров у слоя, почему обучение требует больше памяти.
- Почему нельзя инициализировать веса одинаково, что такое мёртвые нейроны.