Глава 1. Почему не сработал Brute Force?
Любая архитектура рождается не из желания сделать новую архитектуру.
Она рождается потому, что старое решение перестаёт укладываться в ограничения.
Это, пожалуй, главный принцип всей книги.
Мы не начнём со свёрток.
Мы начнём с попытки, которая должна была сработать — и не сработала.
Именно из этого краха выросла вся современная компьютерная визуализация.
1.1. Проклятие размерности: считаем параметры
Представьте, что сейчас начало 2010-х.
Вам дают задачу, которая звучит почти обидно просто:
На входе — изображение.
На выходе — один ответ: «кошка» или «собака».
У вас уже есть инструмент: полносвязная нейронная сеть.
Каждый вход связан с каждым нейроном следующего слоя. Универсально. Честно. Без предположений о структуре данных.
Кажется, осталось только подать картинку.
Что значит «подать картинку»
Изображение для компьютера — это не картинка. Это массив чисел.
Возьмём скромный кадр:
640 × 480 × 3 (RGB) = 921 600 чисел
Почти миллион входов.
Ещё не Full HD. Ещё не 4K. Уже почти миллион.
Теперь подключим первый скрытый слой — скажем, из 1000 нейронов.
Каждый нейрон получает вес на каждый вход:
921 600 × 1 000 ≈ 921 миллиона параметров
Только на первом слое.
Ещё bias. Ещё следующие слои. Ещё оптимизатор, который хранит моменты.
Память заканчивается раньше, чем начинается обучение.
Даже если память найдётся, возникает второй вопрос — уже не про железо, а про статистику.
Чтобы оценить почти миллиард свободных параметров, нужны данные.
Много данных. На порядки больше, чем «несколько тысяч размеченных фото».
Иначе модель не учит понятие «кошка». Она запоминает конкретные комбинации пикселей из обучающей выборки.
Это и есть проклятие размерности в инженерной формулировке:
Чем выше размерность входа при полной связности,
тем быстрее растёт число степеней свободы —
и тем быстрее заканчиваются и память, и данные.
Brute force здесь не «глупый». Он просто не масштабируется.
1.2. Проблема пространственной амнезии
Допустим, мы каким-то чудом обучили полносвязную сеть на крошечных картинках 28×28.
MNIST. Цифры. Работает.
Теперь сдвинем ту же цифру на один пиксель вправо.
Для человека ничего не изменилось.
Для полносвязной сети изменилось всё.
Потому что после flatten пиксель (x, y) и пиксель (x+1, y) — это просто два разных индекса в длинном векторе. У них разные веса. Никакой связи «это сосед» в архитектуре нет.
Сеть страдает пространственной амнезией:
- она не знает, что соседние пиксели связаны;
- она не знает, что сдвиг объекта — это тот же объект;
- она вынуждена заново учить «кошку слева», «кошку справа», «кошку чуть выше» как почти независимые случаи.
Можно возразить: «Ну так аугментируем данные — будем сдвигать картинки при обучении».
Это помогает. Но это лечение симптома данными, а не болезни архитектурой.
Мы заставляем модель запомнить инвариантность, вместо того чтобы встроить её в структуру вычислений.
Инженерный вывод уже здесь:
Если свойство мира устойчиво (локальность, сдвиг),
его выгоднее заложить в архитектуру,
чем надеяться, что оптимизатор сам его откроет из сырых весов.
1.3. Отсутствие иерархии
Есть ещё одна трещина в brute force — менее очевидная, но не менее важная.
Полносвязный слой смотрит на весь вход сразу.
У него нет понятия «сначала края, потом глаза, потом лицо».
А реальный мир устроен иерархически:
Классификатору «лицо / не лицо» бессмысленно начинать с глобальной статистики всех пикселей.
Сначала нужны локальные строительные блоки. Потом — сборка.
Brute-force сеть может в теории выучить иерархию внутри своих весов.
На практике она делает это крайне неохотно: слишком много свободы, слишком мало давления структуры.
Получается третья проблема:
| Что нужно миру | Что даёт Dense |
|---|---|
| Локальные признаки | Глобальные связи сразу |
| Повторное использование одного детектора края | Отдельные веса в каждом месте кадра |
| Сборка от простого к сложному | Один плоский скачок «пиксели → ответ» |
1.4. Три гипотезы, которые напрашиваются сами
Остановимся.
Мы ещё не знаем слова «свёртка». Мы только зафиксировали симптомы.
flowchart TD
A[Задача: картинка → класс] --> B[Гипотеза A: Bigger Dense]
A --> C[Гипотеза B: Уменьшить вход]
A --> D[Гипотеза C: Использовать структуру изображения]
B --> B1[Больше слоёв / нейронов]
B1 --> B2[Память и данные не масштабируются]
C --> C1[Resize до 32×32]
C1 --> C2[Мелкие объекты и детали умирают]
D --> D1[Соседи важнее дальних пикселей]
D1 --> D2[Один фильтр — во всех местах кадра]
D2 --> E[Путь к локальным операциям]
Гипотеза A — «просто сделаем сеть больше».
Добавим нейронов. Купим память. Соберём больше данных.
Иногда это работает в других областях. Здесь упираемся в комбинаторику раньше, чем в интеллект модели.
Гипотеза B — «сожмём картинку заранее».
Приведём всё к 32×32 и забудем про проблему.
Для цифр — ок. Для фото с улицы — выбрасываем именно то, что потом понадобится детекции: мелкие объекты, границы, текстуру.
Гипотеза C — «изображение — не мешок чисел».
Соседние пиксели коррелируют. Один и тот же паттерн может встретиться в любом углу кадра. Значит, операция должна быть локальной и переиспользуемой.
Гипотеза C выглядит скромнее двух других.
Именно она окажется плодотворной.
1.5. Что именно сломалось: карта отказов
Сведём крах brute force в одну схему — так проще держать в голове, зачем вообще понадобится следующая глава.
Почему brute force умер
| Симптом | Корень |
|---|---|
| Миллиарды параметров | Полная связность на каждом пикселе |
| Плохая обобщаемость | Нет встроенной инвариантности к сдвигу |
| Нужна гора данных | Слишком много степеней свободы |
| Нет «частей» объекта | Нет иерархии локальных признаков |
| Медленно даже читать | Dense плохо ложится на локальность GPU |
Важно: мы не доказали, что полносвязные сети «плохи».
Мы доказали более узкую и полезную вещь:
Для естественных изображений полная связность на сырых пикселях —
неправильный обмен. Мы платим универсальностью за масштаб,
которого у нас нет.
В инженерии это нормальная смерть идеи.
Не «ошибка автора», а несовпадение допущений модели с устройством данных.
1.6. Компромисс, который ещё предстоит найти
Если честно сформулировать задачу заново, она звучит так:
Нужна операция, которая
1) смотрит локально,
2) одинаково работает в любом месте кадра,
3) резко сокращает число параметров,
4) оставляет возможность строить иерархию признаков.
Мы пока не называем её.
Мы только понимаем, какими свойствами она должна обладать — иначе снова упрёмся в память, данные и пространственную амнезию.
Это и есть правильная точка старта для архитектора:
не «какой слой модно вставить»,
а «какое ограничение мира мы готовы встроить в вычисления».
Если бы вы были автором статьи…
Представьте: вы в 2010–2012 годах. Brute force на изображениях вас уже разочаровал. Запишите три гипотезы — не гугля «правильный ответ».
-
Как сократить параметры, не убивая способность видеть детали?
Можно ли переиспользовать одни и те же веса в разных местах кадра? Чем вы за это платите? -
Какое свойство реальных фото вы готовы считать аксиомой?
Например: «пиксель сильнее связан с соседями, чем с противоположным углом кадра». Что будет, если аксиома окажется неверной для вашей задачи? -
Где проходит граница между “умной архитектурой” и “просто уменьшили вход”?
Придумайте критерий: когда resize — инженерный приём, а когда — капитуляция.
В следующей главе мы возьмём гипотезу C всерьёз и доведём её до конкретной операции.
Окажется, что математика для неё уже существовала пару веков — просто компьютерное зрение ещё не сформулировало задачу достаточно жёстко.