← Назад к вопросам

Как работает механизм backpropagation?

2.0 Middle🔥 121 комментариев
#Машинное обучение

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как работает механизм backpropagation?

Backpropagation (обратное распространение ошибки) — это алгоритм, который позволяет обучать нейронные сети, эффективно вычисляя градиенты функции потерь по всем параметрам.

Суть идеи

Backpropagation работает в два шага:

  1. Forward pass (прямой проход): данные идут через сеть, вычисляется предсказание и функция потерь
  2. Backward pass (обратный проход): градиенты вычисляются в обратном направлении от выхода к входу, используя цепное правило (Chain Rule)

Математическая основа: Цепное правило

Если y = f(g(x)), то:
dy/dx = (dy/dg) * (dg/dx)

Это правило позволяет разложить сложную функцию и вычислить производные.

Пример: простая нейронная сеть

Архитектура:

x (входные данные)
    ↓
z1 = x*W1 + b1 (скрытый слой)
    ↓
a1 = ReLU(z1) (активация)
    ↓
z2 = a1*W2 + b2 (выходной слой)
    ↓
Loss = MSE(z2, y)

Forward Pass:

def forward(X):
    z1 = np.dot(X, W1) + b1
    a1 = np.maximum(0, z1)  # ReLU
    z2 = np.dot(a1, W2) + b2
    return z2, a1, z1

Backward Pass (Backpropagation):

def backward(X, y, output, a1, z1):
    m = X.shape[0]
    
    # Шаг 1: Градиент по выходу
    dz2 = (output - y) * 2 / m
    
    # Шаг 2: Градиенты для W2 и b2
    dW2 = np.dot(a1.T, dz2)
    db2 = np.sum(dz2, axis=0, keepdims=True)
    
    # Шаг 3: Градиент по скрытому слою
    da1 = np.dot(dz2, W2.T)
    
    # Шаг 4: ReLU backward
    dz1 = da1 * (z1 > 0)
    
    # Шаг 5: Градиенты для W1 и b1
    dW1 = np.dot(X.T, dz1)
    db1 = np.sum(dz1, axis=0, keepdims=True)
    
    # Обновляем параметры (Gradient Descent)
    W1 -= learning_rate * dW1
    b1 -= learning_rate * db1
    W2 -= learning_rate * dW2
    b2 -= learning_rate * db2

Вычислительный граф

              x
             / \
            /   \
          W1    b1
           \    /
            z1 = x*W1 + b1
             |
           ReLU
             |
            a1
           / \
          /   \
        W2    b2
         \    /
          z2 = a1*W2 + b2
           |
        Loss(z2, y)

Backpropagation идёт в обратном направлении:
Loss → z2 → a1 → z1 → W1, b1
        ↓
      W2, b2

Пошаговый пример

Forward:
x = [2, 3]
z1 = [2, 3] * W1 + b1 = [1.3, 0.8]
a1 = ReLU([1.3, 0.8]) = [1.3, 0.8]
z2 = [1.3, 0.8] * W2 + b2 = [1.06]
Loss = (1.06 - 5)^2 = 15.68

Backward:
dL/dz2 = 2 * (1.06 - 5) = -7.88
dW2 = a1.T * dL/dz2 = [1.3, 0.8] * (-7.88)
dz1 = dL/dz2 * W2.T * (z1 > 0)
dW1 = X.T * dz1

Backpropagation в PyTorch (автоматический)

import torch
import torch.nn as nn

class SimpleNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(2, 10)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(10, 1)
    
    def forward(self, x):
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        return x

# Создаём данные
X = torch.randn(100, 2)
y = (X[:, 0] ** 2 + X[:, 1] ** 2).reshape(-1, 1)

# Обучение
model = SimpleNN()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
loss_fn = nn.MSELoss()

for epoch in range(100):
    output = model(X)
    loss = loss_fn(output, y)
    
    # Backpropagation!
    optimizer.zero_grad()
    loss.backward()  # Вычисляет все градиенты автоматически
    optimizer.step()  # Обновляет параметры

Эффективность Backpropagation

Численное дифференцирование (неэффективно):

# Нужно n forward passes для n параметров
# Сложность: O(n) forward passes

def numerical_gradient(f, x, epsilon=1e-5):
    grad = np.zeros_like(x)
    for i in range(x.size):
        x_plus = x.copy()
        x_plus.flat[i] += epsilon
        grad.flat[i] = (f(x_plus) - f(x)) / epsilon
    return grad

# Для 1M параметров: 1M forward passes!

Backpropagation (эффективно):

- 1 forward pass
- 1 backward pass
- Все градиенты вычисляются за ~O(1) от количества параметров
- Для 1M параметров: всё за 2 passes!

Проблемы и решения

1. Vanishing Gradient Problem

Градиенты могут исчезать при propagation через слои (например, сигмоид: d(σ)/dz ≤ 0.25).

Решение: используйте ReLU вместо сигмоида.

2. Exploding Gradient Problem

Градиенты могут расти экспоненциально.

Решение: Gradient Clipping

torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)

3. Мертвые нейроны

ReLU даёт 0 для отрицательных значений, нейрон перестаёт обновляться.

Решение: используйте LeakyReLU.

Ключевые выводы

  1. Backpropagation — это применение цепного правила в обратном направлении через сеть

  2. Два этапа: Forward pass (вычисляем loss), Backward pass (вычисляем градиенты)

  3. Эффективность: все градиенты за 1 обратный проход, в отличие от O(n) численного дифференцирования

  4. Автоматизация: в PyTorch/TensorFlow это делается автоматически через .backward()

  5. Вычислительный граф: позволяет эффективно вычислять производные сложных функций

  6. Проблемы: vanishing gradients, exploding gradients, мертвые нейроны (всё имеет решения)

  7. На практике: используйте готовые фреймворки, но понимайте математику!