1. Введение: Что такое нейросеть?
Аналогия с мозгом Нейросеть — это математическая модель, имитирующая работу мозга. Как человек учится отличать «1» от «7» по визуальным шаблонам, так и алгоритм учится находить закономерности в данных, выделяя главные признаки и игнорируя шум.
Упрощенная модель Весь процесс работы делится на 3 этапа:
-
Входные данные: то, что алгоритм «видит» (в нашем случае — пиксели картинки).
-
Обработка (веса): математические вычисления. Входные данные проходят через формулы, где умножаются на веса — числовые коэффициенты. Веса определяют важность каждого сигнала. Обучение нейросети — это просто автоматический подбор правильных весов.
-
Предсказание: итоговый ответ алгоритма (например, классификация: «это цифра 7»).

Наша цель Написать нейросеть на Python с абсолютного нуля (используя только базовую математику) и научить её распознавать рукописные цифры.
2. Подготовка инструментов
Почему именно Python? Python — абсолютный лидер в мире искусственного интеллекта. Его главное преимущество для нас — простой синтаксис, который читается почти как обычный английский текст. Это значит, что мы не будем отвлекаться на сложный код, а сосредоточимся на том, как мыслит наша нейросеть.
Наши главные инструменты (библиотеки) Мы немного схитрим и возьмем три готовых инструмента, которые упростят рутинную работу:
-
numpyВнутри нейросети постоянно происходят тысячи умножений и сложений. Обычный Python справляется с этим медленно. Библиотека NumPy создана для мгновенной работы с огромными таблицами чисел (матрицами). Она будет выполнять всю тяжелую математику под капотом, пока мы будем управлять логикой. -
matplotlibДля компьютера любая картинка — это просто длинный список чисел. Чтобы мы, люди, могли посмотреть, какую именно цифру сейчас пытается угадать наш ИИ (и нарисовать красивые графики его обучения), нам нужен инструмент для визуализации. -
sklearnВообще, это мощная библиотека с уже готовыми алгоритмами машинного обучения. Но мы не будем использовать её «мозги», ведь мы пишем свои! Мы используемsklearnисключительно как кладовку — из неё мы всего одной строчкой кода достанем тот самый набор данных (датасет) с тысячами картинок рукописных цифр.
Как это будет выглядеть в коде:
import numpy as npimport matplotlib.pyplot as pltfrom sklearn import datasets
Инструменты готовы, дальше мы посмотрим, с какими именно данными нам предстоит работать.
3. Знакомство с данными (Dataset)
Где взять данные? Чтобы научить нашу сеть, ей нужно показать примеры. Мы загрузим встроенный набор данных digits из библиотеки sklearn. Это коллекция из почти 1800 картинок, где люди от руки написали разные цифры.
В коде это выглядит очень просто:
digits = datasets.load_digits()images = digits.images # Сами картинки (входные данные)labels = digits.target # Правильные ответы (чтобы сеть знала, где ошиблась)

Как видит компьютер? (Визуализация) Если мы выведем одну картинку на экран, то увидим размытую цифру размером всего 8 на 8 пикселей. Но для компьютера это не изображение. Компьютер видит матрицу — квадратную таблицу из 64 чисел. Каждое число означает яркость конкретного пикселя (например, 0 — это белый фон, а 16 — максимально черный след от ручки).
Преобразование (Flattening): Зачем ломать картинку? Здесь кроется важный секрет устройства базовых нейросетей. Наш входной слой не умеет смотреть на квадратную картинку целиком, как это делает человеческий глаз. Вспомните схему из первой части: у сети есть просто ряд независимых входов (кружочков).
Поэтому перед тем, как отдать картинку нейросети, нам нужно сделать Flattening (сплющивание). Мы берем наш квадрат 8×8 и «вытягиваем» его в одну длинную цепочку. Мы берем первую строчку пикселей, приклеиваем к ней вторую, затем третью и так далее.
В итоге вместо квадрата мы получаем длинный «поезд» из 64 вагонов-пикселей (вектор). Это и есть наши 64 сигнала (от до
), которые отправятся в нейросеть.
4. Архитектура нашей сети
Теперь, когда наши данные превратились в удобную цепочку из 64 чисел, пора построить для них ту самую «фабрику по принятию решений». Наша нейросеть будет состоять из трех этажей (слоев).
1. Входной слой: Наши 64 пикселя Это зона приема данных. Здесь нет никакой математики, это просто 64 «датчика», каждый из которых принимает яркость одного конкретного пикселя нашей картинки. Если пиксель белый, датчик передает ноль. Если черный — передает число побольше. Можно представить, что это 64 провода, по которым бежит ток разной силы.
2. Скрытый слой Сигнал от датчиков идет дальше — в скрытый слой. Он называется «скрытым», потому что мы (пользователи) не видим его работу напрямую, он спрятан внутри программы. Здесь находятся внутренние нейроны. Вы можете создать их сколько угодно: 15, 64 или 100. Чем их больше, тем умнее может стать сеть, но тем дольше она будет думать. В этой «комнате» нейроны пытаются найти закономерности. Один нейрон может научиться реагировать на кружочки (важно для цифр 8, 9, 0), другой — на вертикальные палочки (важно для 1 или 4).
3. Выходной слой После того как скрытый слой поискал закономерности, он передает свои выводы на последний этаж. Здесь у нас строго 10 нейронов — ровно по количеству цифр (от 0 до 9). Каждый из этих десяти нейронов — это детектор одной конкретной цифры. Они работают как жюри на конкурсе. В конце вычислений каждый нейрон выдает свою оценку (уверенность). Если громче всех «кричит» нейрон под номером 7, значит, нейросеть решила, что на картинке нарисована семерка.

Что такое веса () и смещения (
)? Объясняем на пальцах
Как именно сигнал проходит от одного слоя к другому? По связям. И у каждой связи есть свои настройки.
-
Веса (
— Weights): Настройка важности. Представьте пульт звукорежиссера с кучей ползунков громкости. Вес (
) — это такой ползунок на каждом проводе между нейронами. Если черный пиксель в самом центре картинки очень важен для определения цифры «8», нейросеть в процессе обучения выкрутит этот ползунок на максимум (сделает вес большим). А если черный пиксель в самом углу обычно означает случайную кляксу и только мешает, нейросеть сделает этот вес нулевым (выключит звук), чтобы игнорировать этот пиксель.
-
Смещение (
— Bias): Базовый уровень. Иногда нейрону нужна дополнительная помощь, чтобы «включиться» или, наоборот, остаться выключенным. Смещение (
) — это внутреннее настроение нейрона. Представьте, что это дополнительный грузик на весах. Он позволяет нейросети сказать: «Даже если сигналы от пикселей слабоваты, я всё равно добавлю немного от себя, потому что я склонен верить, что это цифра 1».
Обучение нейросети — это, по сути, просто бесконечное кручение этих ползунков () и подбор грузиков (
) до тех пор, пока выходные нейроны не начнут выдавать правильные ответы!
5. Математика (Основные функции)
Внутри нейросети нет никакой магии — только умножение и сложение. Давайте посмотрим, как именно цифры бегут по проводам нашей фабрики.
Прямое распространение (Forward Propagation): От входа к выходу Это процесс, когда данные просто идут слева направо: от входных пикселей к финальному ответу. Представьте один нейрон. К нему по проводу приходит сигнал от пикселя (назовем его ). На проводе висит «вес» — настройка важности (
). Внутри самого нейрона есть базовое смещение (
).
Математика прямого распространения для одного сигнала выглядит так:
Сигнал нейрона =
(Вход умножить на вес, плюс смещение)
Если в нейрон приходит сразу 64 сигнала от всех пикселей, он просто умножает каждый на свой вес и складывает их все вместе в одну большую кучу. Получается одно число.
Функция активации: Зачем нам «нелинейность»? Проблема в том, что число, которое получилось после сложения сигналов, может быть любым: ,
или
. С такими дикими цифрами сети будет сложно работать. Нам нужен «фейсконтроль» (или переключатель), который решит: пропускать этот сигнал дальше или нет. Это и есть функция активации.
В современных нейросетях чаще всего используют две:
-
ReLU (Rectified Linear Unit) — Жесткий охранник: Работает элементарно: «Если число отрицательное — превращаем его в
. Если положительное — оставляем как есть». Это убивает ненужные (отрицательные) сигналы и оставляет только важные. Именно ReLU обычно ставят в скрытых слоях.
-
Sigmoid (Сигмоида) — Плавный сжиматель: Она берет любое число и плавно сжимает его в диапазон строго от
до
. Это идеально подходит для выходного слоя, ведь мы хотим получить от сети уверенность в процентах (например,
— это уверенность
, что перед нами цифра 7).

Функция потерь (Loss Function): Работа над ошибками Итак, сигнал прошел до конца. Нейросеть выдала ответ: «Я думаю, что это цифра 1 (уверенность 80%), а не цифра 7». Но мы-то знаем правильный ответ!
Здесь на сцену выходит Функция потерь. Это строгий учитель, который оценивает ошибку. Он берет предсказание сети ( для единицы) и сравнивает с идеалом (должно быть
, ведь это семерка!). Функция вычисляет математическую разницу — штрафной балл.
-
Если сеть угадала идеально — штраф равен
.
-
Если сеть сильно ошиблась — штраф огромный.
6. Обучение: Обратное распространение (Backpropagation)
В прошлой части наша нейросеть сделала предсказание и получила от Функции потерь «штрафной балл» за ошибку. Теперь ей нужно сделать работу над ошибками и как-то подкрутить свои веса (настройки важности), чтобы в следующий раз ошибиться меньше.
Этот процесс называется Обратным распространением ошибки (Backpropagation). Сигнал об ошибке идет с самого конца (от ответа) обратно к началу (к пикселям), по пути меняя настройки каждого тумблера. Но как сеть понимает, в какую именно сторону нужно крутить каждый вес: увеличивать его или уменьшать?
Метод градиентного спуска: Спуск с горы в тумане
Чтобы понять, как это работает, представим классическую аналогию.
Представьте, что вы стоите на склоне горы с завязанными глазами (или в густом тумане). Ваша цель — спуститься в самый низ, в долину. Высота горы — это размер вашей ошибки (Функция потерь). Чем вы ниже, тем точнее работает ваша нейросеть. Самая нижняя точка долины — это идеальные настройки весов, при которых ошибка равна нулю.
Как вы будете спускаться, если ничего не видите?
-
Вы нащупываете ногой землю вокруг себя.
-
Вы понимаете, в какую сторону склон уходит круче всего вниз.
-
Вы делаете один шаг в этом направлении.
-
Снова нащупываете склон и делаете следующий шаг.
В математике этот «уклон» называется градиентом. Нейросеть с помощью производных (не пугайтесь, Python посчитает их за нас) вычисляет, куда направлен склон для каждого отдельного веса, и делает небольшой математический «шаг» вниз.
Обновление весов: Размер шага имеет значение
Этот шаг называется Скоростью обучения (Learning Rate). Это очень важная настройка:
-
Если вы будете делать слишком маленькие шаги, вы будете спускаться с горы целую вечность (программа будет обучаться слишком долго).
-
Если вы будете делать слишком огромные прыжки, вы можете случайно перепрыгнуть самую нижнюю точку долины и оказаться на другом склоне горы (нейросеть «сойдет с ума» и не сможет обучиться).
Эпохи обучения: Повторение — мать учения
Нейросеть не может стать умной за один раз. Она прогоняет через себя все 1800 картинок с цифрами, считает общую ошибку, делает один «шаг» вниз по горе (немного меняет все веса) и начинает заново. Один такой полный проход всех картинок называется Эпохой (Epoch).
С каждой новой эпохой веса становятся всё точнее, нейросеть спускается всё ниже в долину ошибок, а её предсказания становятся всё более уверенными. В логах программы это обычно выглядит так:
Эпоха 1: Ошибка 4.5 … Точность 12% Эпоха 50: Ошибка 1.2 … Точность 65% Эпоха 200: Ошибка 0.1 … Точность 96%
7. Пишем код (Step-by-Step)
Пора надеть шляпу программиста. Вся наша теория, слои, математика и данные объединяются в один рабочий скрипт. Вам не нужно устанавливать тяжелые программы — этот код можно запустить в любой среде (например, PyCharm, VS Code или Google Colab).
В этом коде есть один очень важный секрет профессионалов: обратите внимание на строку, где мы создаем стартовые веса (W1 и W2). Мы умножаем случайные числа на 0.1. Зачем? Если стартовые веса будут слишком большими, наша функция активации (Сигмоида) «ослепнет», процесс обучения остановится, и точность навсегда зависнет на 20%. Это называется «затуханием градиента». Уменьшая стартовые веса, мы помогаем сети начать учиться бодро и без запинок!
Вот полный, готовый к запуску код нашей нейросети. Просто скопируйте его и нажмите «Run»:
import numpy as npfrom sklearn import datasets# ==========================================# 1. ПОДГОТОВКА ДАННЫХ# ==========================================# Загружаем картинки и "сплющиваем" их в цепочки по 64 пикселяdigits = datasets.load_digits()X = digits.images.reshape((len(digits.images), -1)) / 16.0 # One-Hot Encoding: превращаем правильный ответ (например, "3") # в список детекторов [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]Y_true = digits.targetY = np.zeros((len(Y_true), 10))for i in range(len(Y_true)): Y[i, Y_true[i]] = 1# ==========================================# 2. МАТЕМАТИЧЕСКИЕ ФУНКЦИИ# ==========================================# Плавный переключатель (от 0 до 1)def activation(x): return 1 / (1 + np.exp(-x))# Уклон нашей "горы" для шага назадdef derivative(x): return x * (1 - x)# ==========================================# 3. НАСТРОЙКИ СЕТИ# ==========================================input_size = 64 # 64 пикселя на входеhidden_size = 15 # 15 нейронов в "тайной комнате"output_size = 10 # 10 детекторов цифр на выходеnp.random.seed(42) # Фиксируем случайность для стабильности# Инициализируем веса. Умножаем на 0.1, чтобы избежать "паралича" сети!W1 = np.random.randn(input_size, hidden_size) * 0.1 W2 = np.random.randn(hidden_size, output_size) * 0.1learning_rate = 0.1 # Размер шага при спуске с горыepochs = 200 # Количество полных циклов обучения# ==========================================# 4. ЦИКЛ ОБУЧЕНИЯ (TRAINING LOOP)# ==========================================print("🚀 Запускаем обучение нейросети...\n")for epoch in range(epochs): # --- ШАГ 1: ПРЯМОЕ РАСПРОСТРАНЕНИЕ --- # Сигналы от картинок бегут вперед к финалу hidden_layer = activation(np.dot(X, W1)) output_layer = activation(np.dot(hidden_layer, W2)) # --- ШАГ 2: ОЦЕНКА ОШИБКИ --- # Насколько предсказание сети отличается от идеала error = Y - output_layer # --- ШАГ 3: ОБРАТНОЕ РАСПРОСТРАНЕНИЕ --- # 1. Считаем сигнал ошибки на самом выходе delta_output = error * derivative(output_layer) # 2. Считаем сигнал ошибки, который дошел обратно до скрытого слоя delta_hidden = delta_output.dot(W2.T) * derivative(hidden_layer) # 3. Вычисляем градиенты (в какую сторону крутить веса) d_W2 = hidden_layer.T.dot(delta_output) d_W1 = X.T.dot(delta_hidden) # --- ШАГ 4: ОБНОВЛЕНИЕ ВЕСОВ --- # Делаем шаг вниз по горе W2 += learning_rate * d_W2 W1 += learning_rate * d_W1 # --- ШАГ 5: ВЫВОД ЛОГОВ --- # Каждые 10 эпох смотрим, насколько поумнел наш ИИ if epoch % 10 == 0: # Сеть выбирает нейрон с самым сильным сигналом predictions = np.argmax(output_layer, axis=1) # Считаем процент правильных ответов accuracy = np.mean(predictions == Y_true) * 100 print(f"Эпоха {epoch:3d}: точность {accuracy:.1f}%")print("\n✅ Обучение завершено!")
Как это будет выглядеть на экране?
Когда вы запустите этот скрипт, вы буквально увидите, как программа становится умнее с каждой секундой. В вашей консоли появится примерно такой отчет:
🚀 Запускаем обучение нейросети...Эпоха 0: точность 10.1%Эпоха 10: точность 46.2%Эпоха 20: точность 68.5%...Эпоха 100: точность 91.3%Эпоха 190: точность 95.8%✅ Обучение завершено!
Всего за 200 проходов наша самодельная математическая фабрика научилась распознавать почерк с точностью почти 96%!
8. Проверка результата (Экзамен для ИИ)
Когда на экране красуется точность 95%, велик соблазн решить, что задача выполнена. Но есть один нюанс: а что, если нейросеть просто «зазубрила» конкретные картинки из тренировочного набора, но так и не поняла, как на самом деле выглядят цифры?
В машинном обучении это называется переобучением (Overfitting). Чтобы проверить ИИ, мы должны устроить ему экзамен на данных, которые он никогда не видел.
Тестирование на новых данных В идеале мы делим наш датасет на две части: 80% — для учебы, 20% — для проверки. После завершения всех циклов обучения мы просим сеть предсказать цифры для «контрольной группы».
Если на учебных данных точность 99%, а на тестовых — 50%, значит, наш ИИ — зубрила. Если же показатели близки — поздравляю, вы создали настоящий интеллект!
Матрица ошибок (Confusion Matrix) Даже самый умный ИИ иногда ошибается. Но важно понимать — как именно. Для этого мы рисуем «Матрицу ошибок». Это таблица, где:
-
Строки — это то, что было нарисовано на самом деле.
-
Столбцы — это то, что предсказала нейросеть.
Если цифра «8» на пересечении со столбцом «3» имеет число больше нуля, значит, наш ИИ путает восьмерку с тройкой. Взгляните на них: обе цифры состоят из округлостей. ИИ «видит» их сходство, и его ошибка — логична. Это доказывает, что сеть действительно ищет закономерности, а не просто гадает.
Код для визуализации ошибок
Чтобы увидеть, где именно ваш ИИ «косячит», добавьте этот блок после цикла обучения:
import matplotlib.pyplot as pltfrom sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay# Получаем финальные предсказания# output_layer - это результат работы нашей нейросетиfinal_predictions = np.argmax(output_layer, axis=1)# Строим матрицу ошибокcm = confusion_matrix(Y_true, final_predictions)disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=range(10))# Рисуем графикfig, ax = plt.subplots(figsize=(8, 8))disp.plot(cmap='Blues', ax=ax)plt.title("Где ошибается наш ИИ? (Confusion Matrix)")plt.show()

На этом графике вы увидите яркую диагональ (правильные ответы) и редкие «пятнышки» ошибок вне её. Именно эти пятнышки — самая интересная часть для исследователя данных!
9. Заключение
Куда двигаться дальше?
То, что мы написали сегодня — это «начальная школа» искусственного интеллекта. Чтобы строить системы, которые рисуют картины или пишут дипломы, стоит изучить:
-
Deep Learning (Глубокое обучение): Это нейросети с десятками и сотнями слоев. Они умеют распознавать лица, голоса и сложные объекты.
-
PyTorch и TensorFlow: Это промышленные стандарты. В них не нужно писать производные вручную — они делают это за тебя, позволяя собирать нейросети как конструктор LEGO.
-
Сверточные сети (CNN): Если хочешь работать с видео и фото на серьезном уровне, это твой следующий шаг.
Анонсы новых статей, полезные материалы, а так же если в процессе у вас возникнут сложности, обсудить их или задать вопрос по этой статье можно в моём Telegram-сообществе. Смело заходите, если что-то пойдет не так, — постараемся разобраться вместе.
ссылка на оригинал статьи https://habr.com/ru/articles/1031568/