Классификация MNIST пошагово

Урок проводит через полный проект: распознавание рукописных цифр MNIST в Keras от данных до точности.

MNIST — классический учебный набор из 70 000 чёрно-белых картинок рукописных цифр 0–9 размером 28×28 пикселей; «Hello, World» компьютерного зрения.

На MNIST удобно собрать первую настоящую сеть: данные маленькие, задача понятная, а результат — узнаваемая точность около 98%. Пройдём все пять шагов конвейера на реальном коде.

Шаг 1–2: данные и нормализация

Картинки — это пиксели 0–255; их делят на 255, чтобы привести к диапазону 0–1 (так сеть учится стабильнее). Код требует TF:

import tensorflow as tf

(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()

x_train = x_train / 255.0   # нормализация в [0, 1]
x_test = x_test / 255.0

print(x_train.shape)  # (60000, 28, 28)
print(y_train[:5])    # метки-цифры, например [5 0 4 1 9]

Шаг 3: модель

Flatten разворачивает картинку 28×28 в вектор из 784 чисел, дальше идут Dense-слои:

from tensorflow.keras import layers

model = tf.keras.Sequential([
    layers.Flatten(input_shape=(28, 28)),
    layers.Dense(128, activation="relu"),
    layers.Dense(10, activation="softmax"),
])
model.summary()

Шаг 4: компиляция и обучение

model.compile(
    optimizer="adam",
    loss="sparse_categorical_crossentropy",
    metrics=["accuracy"],
)

model.fit(x_train, y_train, epochs=5, validation_split=0.1)

Шаг 5: оценка и предсказание

test_loss, test_acc = model.evaluate(x_test, y_test)
print("Точность на тесте:", test_acc)

import numpy as np
pred = model.predict(x_test[:1])
print("Сеть думает, это цифра:", np.argmax(pred[0]))

Зачем нормализация — проверим эффект

Нормализация приводит пиксели к малому диапазону, чтобы градиенты не «взрывались». Сравним масштаб до и после на stdlib — код запускается:

pixels = [0, 64, 128, 200, 255]
normalized = [round(p / 255, 3) for p in pixels]
print("было:", pixels)
print("стало:", normalized)

Вывод:

было: [0, 64, 128, 200, 255]
стало: [0.0, 0.251, 0.502, 0.784, 1.0]

Как работает под капотом

Сеть видит не «цифру», а 784 числа. Слой Dense(128) выучивает 128 признаков (штрихи, изгибы), а финальный Dense(10, softmax) переводит их в 10 вероятностей. argmax берёт класс с максимальной вероятностью. Уже после 5 эпох такая простая сеть достигает ~98% — потому что MNIST хорошо отделим.

Частые ошибки

  • Забыть нормализацию. Без деления на 255 обучение идёт хуже и медленнее.
  • Не развернуть картинку. Dense ждёт вектор — нужен Flatten (или свёртки, см. далее).
  • Оценивать на train. Точность меряют на x_test, которого сеть не видела.

Итог

  • MNIST — стандартный датасет рукописных цифр для первого классификатора.
  • Пиксели нормализуют делением на 255, картинку разворачивают Flatten.
  • Простая сеть Dense+softmax даёт ~98% точности за 5 эпох.
  • argmax выхода softmax даёт предсказанный класс.
Проверьте себя
1. Зачем пиксели MNIST делят на 255?
AЧтобы уменьшить число картинок
BЧтобы нормализовать значения в диапазон 0–1 и стабилизировать обучение
CЧтобы превратить их в цвета
DЭто требование Flatten
2. Что делает слой Flatten перед Dense?
AНормализует пиксели
BРазворачивает картинку 28×28 в вектор из 784 чисел
CДобавляет dropout
DСчитает softmax
3. Как из выхода softmax получить предсказанную цифру?
AВзять минимум
BВзять argmax — индекс максимальной вероятности
CСложить все вероятности
DПрименить relu