Распознавание цифр из пикселей
MNIST — «hello world» компьютерного зрения: 70 000 рукописных цифр 28×28. На этой задаче проще всего понять, как картинка превращается в вектор чисел, а классификатор — в набор «шаблонов», которые можно буквально увидеть.
Интуиция
Для компьютера картинка — это таблица яркостей. Изображение 28×28 пикселей — просто 784 числа от 0 (чёрный фон) до 1 (белый штрих). Вытянем таблицу в один длинный вектор x ∈ ℝ⁷⁸⁴ — и задача «узнать цифру» превращается в знакомую задачу классификации: по вектору признаков выбрать один из 10 классов.
Самый простой классификатор — линейный: у каждого класса свой набор из 784 весов и bias. Считаем score каждого класса как скалярное произведение:
Скалярное произведение — это мера совпадения: score велик, когда яркие пиксели картинки попадают на большие положительные веса класса. Поэтому вектор весов wk можно развернуть обратно в картинку 28×28 — и увидеть «шаблон» (template) класса: у нуля это светлое кольцо, у единицы — вертикальная полоса. Линейный классификатор — это буквально сопоставление с шаблонами (template matching), которые он сам выучил из данных.
Как это работает: пайплайн
- Нормировка пикселей: делим яркости на 255 (и часто центрируем) — градиентному спуску проще жить, когда входы в одном масштабе.
- Скоры → вероятности: 10 скоров пропускаем через softmax — получаем распределение вероятностей по классам.
- Лосс: кросс-энтропия (cross-entropy) — штраф за низкую вероятность правильного класса: L = −log pверный.
- Оптимизация: обычный мини-батчевый градиентный спуск по весам всех 10 классов сразу.
Параметров у такой модели всего 784×10 + 10 = 7850 — обучается за секунды даже на CPU.
Почему линейного классификатора мало
Обученный на MNIST линейный классификатор даёт около 92% точности. Звучит неплохо, пока не вспомнишь, что это 8 ошибок на каждые 100 цифр — почтовый индекс из 6 цифр будет прочитан верно лишь в ~60% случаев. Проблема фундаментальная: у класса всего один шаблон, а семёрку люди пишут десятком способов (с перекладиной и без, под разным наклоном). Все стили усредняются в один размытый шаблон, и границы классов остаются прямыми плоскостями в пространстве пикселей.
Иерархия решений выглядит так:
- Линейный классификатор — ~92%: один шаблон на класс.
- MLP (полносвязная сеть со скрытыми слоями, см. перцептрон и MLP) — ~98%: скрытые нейроны выучивают штрихи и их комбинации, границы становятся кривыми.
- CNN (свёрточные сети) — 99%+: свёртки дают устойчивость к сдвигам и учат локальные признаки — то, чего вытянутому в вектор изображению отчаянно не хватает.
Кстати, «вытягивание» картинки в вектор — само по себе преступление против данных: соседние пиксели перестают быть соседями, и модель должна переоткрывать 2D-структуру заново. CNN эту структуру сохраняют.
Зачем MNIST сегодня
В продакшене цифры давно распознают не так, но MNIST остался идеальной песочницей: на нём за минуты проверяют, что пайплайн жив (данные → лосс → градиенты → метрика), отлаживают новые идеи и учатся читать ошибки модели — смотреть глазами на картинки, где она путает 4 и 9. Правило «сначала заведи простейший линейный бейзлайн, потом усложняй» — одна из самых полезных привычек ML-инженера, и родом она именно отсюда.
- «Сколько параметров у линейного классификатора MNIST?» — 784×10 весов + 10 bias = 7850. Умение быстро посчитать параметры проверяют постоянно.
- «Что увидим, если визуализировать веса как картинки?» — размытые шаблоны цифр: положительные веса там, где обычно проходит штрих класса.
- «Почему softmax + кросс-энтропия, а не MSE?» — кросс-энтропия даёт сильный градиент при уверенной ошибке и правильно работает с вероятностями классов.
- «Зачем нормировать пиксели?» — единый масштаб входов ускоряет и стабилизирует градиентный спуск; сами предсказания идеальной модели от масштаба бы не изменились.