Нейронная сеть — это модель машинного обучения из множества простых вычислительных элементов (искусственных нейронов), соединенных в слои: каждый нейрон считает взвешенную сумму входов и пропускает ее через нелинейную функцию, а сами веса подбираются по данным в ходе обучения. От мозга здесь только идея: искусственный нейрон — это формула, а не модель биологической клетки.
Содержание
Ниже — устройство нейрона и слоев, обучение сети, основные виды и две маленькие сети на 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 со скрытым слоем — попробуйте другой сид или больше нейронов: маленькая сеть иногда застревает в плохой точке.
Как сеть обучается: три шага
- Прямой проход. Данные идут от входа к выходу, сеть выдает ответ.
- Подсчет потерь. Функция потерь сравнивает ответ с правильным. Для регрессии (предсказать число) обычно берут среднеквадратичную ошибку, для классификации — кросс-энтропию. В примерах выше MSE взята ради простоты формул.
- Обратный проход и шаг оптимизатора. 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.



