Почему обычная нейросеть не видит фракталы
Возьмите простой многослойный перцептрон. Дайте ему координаты пикселя (x, y). Попросите предсказать цвет. Обучите на фрактале Мандельброта. Что получите?
Размытое пятно. Нечто среднее между кофейной гущей и плохой акварелью. Никаких бесконечно сложных границ. Никаких самоподобных структур.
Нейросеть не глупая. Она страдает от спектрального смещения - той же болезни, что мешает ей видеть физику дефектов пленки, а не просто размывать шум. Сеть предпочитает низкочастотные функции. Гладкие изменения. А фрактал - это сплошные высокие частоты. Резкие переходы. Бесконечная детализация.
Спектральное смещение - не баг, а фича. Нейросеть оптимизирована для реального мира, где резкие переходы редки. Но фрактальный мир играет по другим правилам.
Фрактал как детерминированный кошмар
Мандельброт - математический объект. Для каждой точки (x, y) алгоритм escape-time дает точное значение итераций. Нет вероятности. Нет неопределенности. Либо точка внутри множества (бесконечные итерации), либо сбежала на определенном шаге.
Попробуйте обучить обычный MLP на таких данных. Сеть увидит паттерн: "близкие точки должны иметь похожие цвета". Это работает в реальных изображениях. Но граница множества Мандельброта нарушает все правила. Две точки на расстоянии 0.0001 могут требовать 1000 итераций разницы.
Gaussian Fourier Features: волшебная палочка для высоких частот
В 2020 году исследователи из Google и Стэнфорда предложили простую, но гениальную идею. Вместо того чтобы подавать в сеть сырые координаты, сначала пропустите их через синусоидальное преобразование со случайными частотами.
1 Случайные частоты как ключ к детализации
Возьмите вектор координат v = [x, y]. Сгенерируйте матрицу B размера m×2, где каждый элемент взят из нормального распределения N(0, σ²). Умножьте: v' = B·v. Теперь примените синус и косинус к каждому элементу: γ(v) = [sin(2πv'), cos(2πv')].
Что это дает? Каждая случайная частота в B становится осью в расширенном пространстве признаков. Синусы и косинусы создают осцилляции. Много осцилляций - много возможностей аппроксимировать высокочастотные паттерны.
| Параметр | Значение | Влияние на результат |
|---|---|---|
| m (размерность B) | 256-512 | Больше m = больше частот = лучше детализация |
| σ (стандартное отклонение) | 10-30 | Выше σ = выше частоты = более резкие переходы |
| Активация в MLP | ReLU или SiLU | ReLU проще, SiLU плавнее |
2 Почему именно Гауссово распределение?
Можно было бы взять равномерное распределение. Или задать частоты вручную. Но Гауссово распределение работает лучше по той же причине, по которой генеративный ИИ без магии использует нормальные шумы. Оно обеспечивает хороший баланс между низкими, средними и высокими частотами. Большинство значений концентрируется вокруг среднего (низкие/средние частоты), но есть и длинные хвосты (высокие частоты).
Фрактал Мандельброта требует всего спектра. Плавные градиенты внутри множества (низкие частоты). Резкие переходы на границе (высокие частоты). Сложные самоподобные структуры (все частоты сразу).
Архитектура сети: что работает, а что нет
С Gaussian Fourier Features подготовка данных решена. Теперь сама сеть.
Стандартный MLP - и почему он проваливается
Берете 8 слоев по 256 нейронов. ReLU активации. Adam оптимизатор. Обучаете 5000 эпох. Результат? Все еще размыто. Меньше, чем без Fourier Features, но все равно не фрактал.
Проблема в том, что сеть слишком "глупая" для такой задачи. Она пытается найти простые паттерны в сложных данных. Нужно заставить ее учить более сложные представления.
Residual connections - обязательный элемент
Добавьте skip-connections как в ResNet. Не просто слои друг за другом, а блоки вида: output = layer(input) + input. Почему это важно для фракталов?
Фрактал Мандельброта имеет иерархическую структуру. Большие детали состоят из меньших деталей, те - из еще меньших. Residual connections позволяют сети строить такие иерархические представления. Каждый блок добавляет новую детализацию к существующему представлению.
Без residual connections сеть пытается заново изобретать представление на каждом слое. С ними - постепенно уточняет. Для фракталов второй подход работает в разы лучше.
Синусоидальные активации - спорный выбор
Есть соблазн использовать SIREN (синусоидальные активации). Теория говорит: раз Fourier Features используют синусы, то и активации должны быть синусами. Практика показывает: для фракталов это избыточно.
SIREN отлично работает на гладких сигналах. Но фрактал - не гладкий. Это дискретный escape-time алгоритм. ReLU или SiLU справляются лучше, потому что они кусочно-линейны. А фрактальная граница - это множество разрывов.
Пошаговый план: от данных до обученной модели
1 Генерация данных - не так просто, как кажется
Создайте сетку 512×512 точек в области x ∈ [-2.5, 1.0], y ∈ [-1.25, 1.25]. Для каждой точки запустите алгоритм escape-time с максимумом 1000 итераций. Получите матрицу значений от 0 до 1000.
Теперь нормализуйте. Просто поделить на 1000? Нет. Значения распределены не равномерно. Большинство точек сбегают быстро (малые значения). Некоторые точки внутри множества (значение 1000). Нужно логарифмическое масштабирование: log(iterations + 1).
2 Подготовка Fourier Features
Выберите m = 256, σ = 10. Сгенерируйте матрицу B один раз и сохраните. При обучении используйте одну и ту же B для всех эпох. Если будете генерировать заново каждый раз, сеть не сможет выучить стабильные паттерны.
Нормализуйте координаты в диапазон [-1, 1] перед применением B. Иначе большие значения координат дадут огромные аргументы синуса.
3 Архитектурные решения
- Входной слой: принимает Fourier Features размерности 2×m (синусы + косинусы)
- 5 residual блоков по 256 нейронов каждый
- Активация: SiLU (Swish) - плавнее ReLU, лучше для градиентов
- Выходной слой: 1 нейрон (значение итерации)
- Dropout: 0.1 между блоками (предотвращает переобучение на шум)
4 Обучение с учетом специфики фрактала
MSE loss - плохой выбор. Почему? Ошибка в 10 итераций для точки с значением 10 и для точки с значением 1000 - разная значимость. Используйте относительную ошибку: |pred - true| / (true + 1). Или Huber loss.
Learning rate: начните с 1e-3, уменьшайте на плато. Используйте Cosine annealing - он хорошо работает для таких задач.
Батч размер: 1024 или больше. Фрактал - детерминированная функция. Большие батчи дают более стабильные градиенты.
Не пытайтесь обучить сеть на всем фрактале сразу. Сначала сфокусируйтесь на интересующей области (например, границе множества). Потом дообучите на всей области. Это как хакнуть активации нейросети - заставить ее смотреть туда, куда нужно.
Ошибки, которые гарантированно испортят результат
Использовать слишком маленькое σ
σ = 1 даст только низкие частоты. Сеть будет видеть фрактал как размытое пятно. Начните с σ = 10, пробуйте до 30. Слишком большое σ (100+) тоже плохо - сеть будет учить шум вместо структуры.
Игнорировать нормализацию координат
Координаты в диапазоне [-2.5, 1.25] после умножения на B дадут огромные значения. Синус от 1000 - это бессмысленно. Всегда нормализуйте в [-1, 1] или [0, 1].
Обучать на сырых значениях итераций
Значения от 0 до 1000 имеют экспоненциальное распределение. Большинство точек - малые значения (быстро сбежали). Несколько точек - 1000 (внутри множества). Без логарифмирования сеть будет оптимизировать ошибку на малых значениях, игнорируя границу.
Забыть про overfitting на детализации
Сеть с Fourier Features может выучить тренировочные данные идеально. Но попробуйте увеличить масштаб в 10 раз - и она не сможет экстраполировать. Всегда оставляйте часть данных для валидации на другом масштабе.
Зачем все это нужно? Практическое применение
Казалось бы, зачем учить нейросеть рисовать фрактал, если есть прямой алгоритм? Есть несколько причин.
Сжатие представления
Прямой алгоритм требует вычислений для каждой точки. Нейросеть - одна прямая операция. Обученная сеть весом 2 МБ может представлять фрактал любого разрешения. Нужно 8K изображение? Подайте сетку координат, получите результат за миллисекунды.
Интерполяция и анимация
Обучите сеть на нескольких фракталах с разными параметрами. Затем интерполируйте веса сети. Получите плавную анимацию перехода между фракталами. С прямым алгоритмом это потребовало бы пересчета каждого кадра.
Тест-бенчмарк для архитектур
Фрактал Мандельброта - идеальный тест для оценки способности сети аппроксимировать сложные функции. Если архитектура справляется с фракталом, она, скорее всего, справится и с реальными задачами высокой сложности. Это как тест на человеческое зрение для ИИ, но для аппроксимации функций.
Что делать, если все равно не работает
Вы все сделали по инструкции. Fourier Features, residual connections, правильная loss функция. А результат все равно похож на абстрактное искусство, а не на фрактал.
Проверьте распределение частот
Визуализируйте матрицу B. Постройте гистограмму значений. Убедитесь, что есть и низкие, и высокие частоты. Если все значения близки к нулю - увеличьте σ.
Увеличьте размерность признаков
m = 256 может быть недостаточно для сложных областей фрактала. Попробуйте 512 или 1024. Каждое удвоение m дает примерно на 30% лучшее качество, но требует больше памяти.
Измените функцию потерь
MSE не видит разницы между ошибкой на гладкой области и на границе. Используйте perceptual loss: предварительно обучите маленький CNN на различии "похоже на фрактал" / "не похоже". Или добавьте градиентный penalty.
Следующий шаг: от фракталов к реальному миру
Техника Gaussian Fourier Features не ограничивается фракталами. Ту же проблему спектрального смещения вы встретите в любой задаче, где нужно учить высокочастотные паттерны:
- Реконструкция 3D-сцен из изображений
- Стилизация изображений с сохранением мелких деталей
- Анализ медицинских снимков с микроскопическими структурами
- Обработка сигналов с резкими переходами
Фрактал Мандельброта - это полигон. Идеальная тестовая задача. Если ваша архитектура и метод обучения справляются с ним, они, скорее всего, справятся и с реальными задачами высокой сложности.
Спектральное смещение - не приговор. Это вызов. Gaussian Fourier Features - один из ответов. Но не единственный. Продолжайте экспериментировать. Может быть, следующий прорыв в обучении нейросетей сложным паттернам придет от того, кто просто захотел научить MLP рисовать красивые картинки.