Нейронные сети: как устроены, как обучаются и какие бывают

Нейронные сети: как устроены, как обучаются и какие бывают Полезное

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

Ниже — устройство нейрона и слоев, обучение сети, основные виды и две маленькие сети на Python с NumPy с воспроизводимым выводом.

Мини-словарь

Термин Что это
Вес Число, на которое умножается вход; показывает, насколько вход влияет на ответ
Смещение (bias) Слагаемое, которое сдвигает порог срабатывания нейрона независимо от входов
Функция активации Нелинейное преобразование суммы: сигмоида, ReLU, tanh и др.
Слой Группа нейронов, получающих одни и те же входы
Функция потерь (loss) Число, которое показывает, насколько ответы сети далеки от правильных
Эпоха Один проход по всем обучающим примерам

Два термина часто смешивают. Обратное распространение ошибки (backpropagation) только вычисляет градиенты — на сколько и в какую сторону каждый вес влияет на ошибку. Градиентный спуск (SGD, Adam и др.) использует эти градиенты, чтобы обновить веса. Первое — способ посчитать, второе — способ шагнуть.

Как работает один нейрон

Нейрон делает три действия: умножает входы на веса, складывает и прибавляет смещение, пропускает результат через функцию активации. Для входов x1, x2, x3 это y = f(w1*x1 + w2*x2 + w3*x3 + b).

Задача: четыре примера из трех нулей и единиц, правильный ответ совпадает с первым числом. Эту закономерность нейрон должен найти сам по примерам.

import numpy as np

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

# 4 обучающих примера: выход совпадает с первым входом
X = np.array([[0, 0, 1],
              [1, 1, 1],
              [1, 0, 1],
              [0, 1, 1]])
y = np.array([[0, 1, 1, 0]]).T

rng = np.random.default_rng(42)
w = rng.normal(size=(3, 1))   # веса
b = 0.0                       # смещение
lr = 1.0                      # шаг обучения

for step in range(2000):
    z = X @ w + b             # взвешенная сумма
    p = sigmoid(z)            # активация
    err = p - y               # ошибка предсказания
    grad = err * p * (1 - p)  # градиент потерь (p-y)^2/2 по z
    w -= lr * X.T @ grad / len(X)
    b -= lr * grad.mean()

print("предсказания:", p.ravel().round(3))
print("новый пример [1, 0, 0]:", sigmoid(np.array([1, 0, 0]) @ w + b).round(3))

Результат под сидом 42 (проверено с NumPy 2.0):

предсказания: [0.041 0.964 0.968 0.035]
новый пример [1, 0, 0]: [0.99]

Ответы близки к 0 и 1, но не равны им: сигмоида выдает число от 0 до 1, которое удобно читать как уверенность. На примере [1, 0, 0], которого не было в обучении, нейрон ответил 0.99 — он выучил правило «смотри на первый вход», а не запомнил таблицу.

В цикле grad учитывает ошибку и наклон сигмоиды p * (1 - p), а веса сдвигаются против градиента. Сид фиксирует стартовые веса, чтобы вывод повторялся.

Зачем нужны слои: пример с XOR

Один нейрон с сигмоидой проводит между классами одну прямую (в многомерном случае — плоскость). Задача XOR так не решается: ответ 1, когда входы разные, и 0, когда одинаковые, и одной прямой эти точки не разделить. Именно на это ограничение однослойного перцептрона указывали Минский и Пейперт в 1969 году.

Сначала покажем, что происходит без скрытого слоя (тот же сид 0 и те же данные, что в рабочем примере ниже):

import numpy as np
def sigmoid(x): return 1/(1+np.exp(-x))
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]); y = np.array([[0, 1, 1, 0]]).T
rng = np.random.default_rng(0)
w = rng.normal(size=(2, 1)); b = 0.0
for epoch in range(5001):
    p = sigmoid(X @ w + b)
    g = (p - y) * p * (1 - p)
    w -= X.T @ g; b -= g.sum()
print("loss =", round(float(np.mean((p - y) ** 2)), 4), "| XOR:", p.ravel().round(2))
loss = 0.25 | XOR: [0.5 0.5 0.5 0.5]

Сеть сдалась: на все входы ответ 0.5, ошибка 0.25 — как у угадывания «посередине». Исправление — добавить скрытый слой из нескольких нейронов и обучать всю цепочку обратным распространением ошибки.

import numpy as np

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([[0, 1, 1, 0]]).T   # XOR

rng = np.random.default_rng(0)
W1 = rng.normal(size=(2, 4)); b1 = np.zeros(4)   # скрытый слой: 4 нейрона
W2 = rng.normal(size=(4, 1)); b2 = np.zeros(1)   # выходной нейрон
lr = 1.0

for epoch in range(5001):
    # прямой проход
    h = sigmoid(X @ W1 + b1)
    p = sigmoid(h @ W2 + b2)
    loss = np.mean((p - y) ** 2)
    if epoch % 2500 == 0:
        print(f"эпоха {epoch}: loss = {loss:.4f}")
    # обратный проход: ошибка идет от выхода к входу
    d2 = (p - y) * p * (1 - p)
    d1 = (d2 @ W2.T) * h * (1 - h)
    W2 -= lr * h.T @ d2;  b2 -= lr * d2.sum(axis=0)
    W1 -= lr * X.T @ d1;  b1 -= lr * d1.sum(axis=0)

print("XOR:", p.ravel().round(2))
эпоха 0: loss = 0.3430
эпоха 2500: loss = 0.0008
эпоха 5000: loss = 0.0003
XOR: [0.01 0.98 0.98 0.02]

Строка d1 = (d2 @ W2.T) * h * (1 - h) и есть обратное распространение: ошибка выходного нейрона раскладывается по скрытым нейронам пропорционально весам, которые их связывают. Остальное — градиентный спуск по полученным градиентам.

Граница примера: это учебная сеть на четырех точках. В реальных задачах берут фреймворки (PyTorch, JAX, Keras), где градиенты считаются автоматически.

Если не получилось

  • ModuleNotFoundError: No module named 'numpy' — установите библиотеку: python -m pip install numpy.
  • Числа отличаются от приведенных — проверьте сид и что используется default_rng, а не np.random.seed: это разные генераторы.
  • Loss XOR застыл около 0.25 со скрытым слоем — попробуйте другой сид или больше нейронов: маленькая сеть иногда застревает в плохой точке.

Как сеть обучается: три шага

  1. Прямой проход. Данные идут от входа к выходу, сеть выдает ответ.
  2. Подсчет потерь. Функция потерь сравнивает ответ с правильным. Для регрессии (предсказать число) обычно берут среднеквадратичную ошибку, для классификации — кросс-энтропию. В примерах выше MSE взята ради простоты формул.
  3. Обратный проход и шаг оптимизатора. Backprop считает градиенты, оптимизатор обновляет веса. Простейший вариант — SGD; на практике часто по умолчанию используют Adam или AdamW, но лучший выбор зависит от задачи и проверяется экспериментом.

Гиперпараметры (шаг обучения, число слоев и нейронов, размер батча) сеть сама не учит — их подбирают отдельно.

Функции активации

Функция Формула Где встречается
Сигмоида 1 / (1 + e^-x) Выход бинарной классификации; в глубоких скрытых слоях редко (затухание градиента)
ReLU max(0, x) Скрытые слои
Softmax e^xi / сумма e^xj Выход многоклассовой классификации

Без нелинейной активации любая глубина схлопывается в одно линейное преобразование — поэтому она нужна в скрытых слоях.

Виды нейронных сетей

Вид Как устроен Типичные задачи
Полносвязная (MLP, перцептрон) Каждый нейрон слоя связан со всеми нейронами следующего Табличные данные, простая классификация
Сверточная (CNN) Небольшие фильтры скользят по входу и ищут локальные признаки Изображения, иногда звук
Рекуррентная (RNN, LSTM, GRU) Скрытое состояние передается от шага к шагу последовательности Временные ряды, небольшие задачи с текстом и речью
Трансформер Механизм внимания связывает все элементы последовательности сразу Языковые модели, перевод, код, также изображения и звук

Есть и другие семейства — автокодировщики, GAN, диффузионные и графовые сети; в современных моделях блоки разных типов часто комбинируют.

Как выбрать для учебной задачи: табличные данные — начать с MLP и сравнить с градиентным бустингом, который на таблицах нередко не уступает нейросети; картинки — CNN или готовая предобученная модель; текст — предобученный трансформер.

Краткая история

Год Событие
1943 Мак-Каллок и Питтс описывают формальную модель нейрона
1958 Розенблатт публикует модель перцептрона
1969 Минский и Пейперт показывают ограничения однослойного перцептрона (в том числе XOR)
1974 Вербос описывает обратное распространение ошибки в диссертации
2012 Сверточная сеть AlexNet выигрывает конкурс ImageNet, начинается бум глубокого обучения
2017 Статья «Attention Is All You Need» вводит архитектуру трансформера

Ограничения

  • Нужно много размеченных данных; при их нехватке сеть переобучается — запоминает примеры, а не закономерность.
  • Обучение больших моделей требует GPU и заметных затрат.
  • Решения трудно объяснить: веса не читаются как правила.
  • Сеть может уверенно ошибаться на данных, непохожих на обучающие.

Выводы

  • Нейрон — это взвешенная сумма входов плюс смещение, пропущенная через нелинейную функцию активации.
  • Один нейрон разделяет классы только прямой, поэтому XOR он не решает; скрытый слой снимает это ограничение.
  • Обучение = прямой проход, подсчет потерь, обратное распространение ошибки (градиенты) и шаг оптимизатора (обновление весов).
  • Основные виды: полносвязные, сверточные, рекуррентные сети и трансформеры; выбор определяется типом данных.

Где применяется / связь с практикой

Нейросети решают задачи классификации, регрессии, распознавания изображений и речи, генерации текста. Чтобы применять их на практике, нужна база классического машинного обучения: подготовка данных, метрики, валидация, борьба с переобучением.

Освойте тему на практике

Эту базу вместе с первыми нейросетями на Python дает курс «Machine Learning. Basic». Посмотреть формат занятий и разобрать отдельные темы можно на бесплатных открытых уроках.

FAQ

Чем нейросеть отличается от машинного обучения в целом?
Нейросети — одно из семейств моделей машинного обучения. Рядом существуют линейные модели, деревья решений, градиентный бустинг, и на табличных данных они часто работают не хуже.

Сколько нужно данных, чтобы обучить нейросеть?
Универсального числа нет: оно зависит от сложности задачи и размера модели. Когда данных мало, обычно дообучают готовую предобученную модель вместо обучения с нуля.

Можно ли писать нейросети не на Python?
Да, библиотеки есть для C++, Java, JavaScript и других языков, но основная экосистема обучения моделей — на Python.

OTUS Журнал
Скидка 5% 12-19 октября на курсы (popup)
Бесплатные открытые уроки (поп-ап)