Косинус между соседними скоростями в многошаговом сэмплере flow matching даёт бесплатную оценку кривизны траектории. Предыдущая скорость уже лежит в памяти сэмплера, поэтому угол между векторами достаётся без единого дополнительного вызова нейросети. Из этого угла собирается оценка локальной ошибки шага Эйлера E = (h/2)·|v|·θ, и на модели Anima она предсказывает реальную ошибку с медианным отношением 0,80-0,84 и корреляцией логарифмов 0,91-0,92.
Дальше начинается интересное. Хорошая локальная метрика не превращается автоматически в хороший адаптивный контроллер: вариант «шаг по косинусу» проигрывает стандартному расписанию ComfyUI из-за слепого первого шага. Зато статическая сетка с равным углом поворота на шаг, посчитанная заранее, снижает ошибку по латенту на 30-43% при том же числе вызовов сети. Ниже разбор того, что подтверждается цифрами, а что не сработало.
Это разбор исследовательской работы, опубликованной на Habr, а не результаты собственных тестов редакции. Все числа ниже взяты из источника и из связанных публикаций.
Что такое сигнал кривизны и почему он бесплатный
Многошаговый сэмплер вроде Адамса-Башфорта и так хранит предыдущую скорость, чтобы посчитать следующий шаг. Косинус между старой и новой скоростью берётся из этих двух векторов: ни одного дополнительного вызова сети (NFE) не нужно. Отсюда и слово «бесплатный»: сигнал появляется как побочный продукт работы сэмплера. Описание экспериментов и код
Косинус измеряет поворот скорости. Изменение её длины он не видит вообще. Квадрат разности двух векторов раскладывается точно:
|v_n - v_(n-1)|² = (s_n - s_(n-1))² + 4·s_n·s_(n-1)·sin²(θ/2)
где s_n и s_(n-1) - длины скоростей, θ - угол между ними. Первое слагаемое отвечает за изменение длины, второе - за поворот. На Anima вклад изменения длины в энергию ускорения на большей части траектории составляет 0,3-0,4%. В первых и последних 5% времени он вырастает до 8-9%, а в отдельных точках до 23%. Практический смысл: в середине траектории косинус описывает почти всё изменение скорости, на концах картина заметно неполная.
Второе ограничение - шум. Anima работает в bf16 с classifier-free guidance, и угловой шум скорости там около 1,7°. Всё, что меньше этого угла, тонет в вычислительном шуме и сигналом не считается.
Два примера, где косинус обманывает ожидания. Гауссиана: скорость меняет знак в минимуме дисперсии, косинус между соседними скоростями равен -1, а локальная ошибка при этом маленькая. Прямой поток, который разгоняется вдоль линии: направление не меняется совсем, косинус равен 1, а ошибка шага растёт вместе со скоростью. Угол даёт большую часть картины, но не всю.
Оценка E = (h/2)·|v|·θ: как из косинуса получается предсказание ошибки шага Эйлера
Локальная ошибка одного шага Эйлера на интервале h пропорциональна h² и модулю ускорения вдоль траектории: примерно (h²/2)·|dv/dt|. Угол θ за шаг h даёт оценку скорости поворота θ/h, а значит |dv/dt| ≈ |v|·θ/h. Подстановка приводит к E = (h/2)·|v|·θ. Формулу стоит читать как обоснованную эвристику: строгой теоремы за ней нет, зато есть эмпирическая проверка.
В формуле три множителя: h (размер шага), |v| (длина скорости) и θ (угол поворота между соседними скоростями в радианах). Ошибка растёт линейно с шагом, линейно со скоростью и линейно с кривизной. Логика простая: быстрый поток при сильном повороте уводит шаг Эйлера дальше всего от истинной траектории.
Слабое место - тот же слепой участок. θ не содержит информации об изменении длины скорости. На концах траектории, где вклад длины доходит до 8-9%, оценка систематически недооценивает ошибку. Для отбраковки явно плохих шагов этого достаточно, для точного предсказания на краях интервала - нет.
Насколько хорошо оценка предсказывает реальную ошибку: цифры валидации
Проверка шла на 12 юнитах: 4 промпта × 3 сида, модель Anima, шаги в диапазоне от 0,01 до 0,12 интервала времени. Медианное отношение оценки к истинной ошибке составило 0,80-0,84, корреляция логарифмов между юнитами 0,91-0,92. Таблицы с результатами
Медианное отношение 0,80-0,84 значит, что оценка систематически занижает истинную ошибку примерно на 16-20%. Постоянный множитель лечится одной калибровочной константой. Важнее другое: порядок шагов оценка выстраивает правильно.
Корреляция логарифмов 0,91-0,92 между юнитами значит, что ранжирование переносится с картинки на картинку. Переобучать коэффициент под каждый промпт и сид не нужно, достаточно откалибровать его один раз на нескольких юнитах.
Границы применимости обозначены прямо: одна модель, 12 юнитов, шаги до 0,12 интервала времени. За пределами диапазона поведение не проверено, а на другой архитектуре калибровку придётся повторять с нуля.
Почему адаптивный контроллер шага проигрывает стандартному расписанию
Логично ожидать обратного: если E хорошо предсказывает локальную ошибку, контроллер, выравнивающий E по шагам, должен обыгрывать фиксированное расписание ComfyUI. В описанной реализации контроллер «шаг по косинусу» проиграл.
Причина в первом шаге. На старте предыдущей скорости ещё нет, косинус не определён, и контроллер выбирает размер первого шага без сигнала. Дальше он идёт по уже испорченной траектории: бюджет вызовов потрачен, ошибка накоплена, компенсировать её нечем. Один слепой шаг в начале стоит дороже, чем экономия на всех остальных.
Вывод жёсткий и без смягчений: адаптивный контроллер в такой реализации не работает. Локальная метрика описывает шаг, а не политику распределения шагов, и в точке, где метрики нет, политика принимает решение наугад.
Что реально работает: статическая сетка по равному углу поворота
Выигрыш приносит заранее посчитанная сетка, в которой на каждый шаг приходится примерно одинаковый угол поворота скорости. Против стандартного расписания ComfyUI она даёт на 30-43% меньшую ошибку по латенту при том же числе вызовов сети. С учётом профиля распространения ошибки разрыв доходит до 41-50%. Готовые списки сигм для Anima
| Подход | Ошибка по латенту | Дополнительные вызовы сети |
|---|---|---|
| Стандартное расписание ComfyUI | базовый уровень | нет |
| Сетка по равному углу | на 30-43% меньше | нет |
| Сетка по равному углу с учётом профиля ошибки | на 41-50% меньше | нет |
| Адаптивный «шаг по косинусу» | хуже базового | нет |
Почему статика обходит адаптив: сетка строится один раз по усреднённой кривизне на калибровочном наборе, и слепого первого шага в ней нет. Равномерность по углу задана заранее, а не выясняется на лету по шумному сигналу в момент, когда предыдущей скорости ещё не существует.
В репозитории к работе лежат код, тесты и готовые списки сигм для Anima при 8, 12, 16 и 24 вызовах сети. Ноды для ComfyUI там нет: сигмы подставляются вручную или через существующие механизмы расписаний. Для пользователя ComfyUI это означает ручную возню, для разработчика - воспроизводимый набор чисел, который можно перепроверить.
Подстройка сетки под конкретную картинку и противоречие LPIPS
Идея подгонять сетку под конкретное изображение выглядит заманчиво: раз кривизна зависит от промпта и сида, почему бы не посчитать шаги индивидуально. На практике подстройка под картинку не добавила измеримого выигрыша. Усреднённая сетка работала не хуже и стоила дешевле.
Отдельная история - метрики. На текстурном промпте LPIPS дал результат, противоположный метрике по латенту. Объяснение лежит в природе метрики: LPIPS сравнивает перцептивные признаки и чувствителен к текстурам, поэтому траектория, которая лучше сохраняет латентную близость, может дать чуть другую текстуру и проиграть по LPIPS.
Практический вывод: метрику выбирают под задачу. Если важна верность латента (img2img, дальнейшая обработка, пайплайны с несколькими проходами), смотрите на латент. Если важен вид картинки для человека, нужен перцептивный набор, и лучше не один.
Как это соотносится с CAT-Flow, Optimal Stepsize Distillation и другими работами
Адаптивный шаг без обучения и без дополнительных вызовов сети для flow matching уже существует. CAT-Flow (Li и др., arXiv 2609.01746) предлагает два training-free алгоритма, CAT-OV и CAT-OT, которые адаптируют размер шага на инференсе, опираясь на связь сэмплинга flow matching с градиентным потоком. Препринт CAT-Flow
Разница между алгоритмами в том, что именно оценивается. CAT-OT считает кривизну по времени через конечно-разностную аппроксимацию производной векторного поля. CAT-OV аппроксимирует кривизну по пространству состояний через градиент поля. Авторы заявляют, что на четырёх моделях text-to-image flow matching оба алгоритма обходят существующие эвристики шага по метрикам качества изображения и сокращают число шагов генерации до 40%. Сравнение с эвристиками шага
Важная деталь для честной оценки: автор разбираемого измерительного исследования нашёл CAT-Flow уже после своих экспериментов, прочитал аннотацию и введение и напрямую с ней не сравнивался. Утверждение «адаптивный шаг не работает» относится к конкретной реализации через косинус, а не ко всем адаптивным схемам.
Второй соседний класс - статические расписания, подобранные под модель. Optimal Stepsize Distillation (arXiv 2503.21774) извлекает теоретически оптимальные расписания шагов из эталонных траекторий методами динамического программирования. Optimal Stepsize Distillation Bespoke Solvers (arXiv 2310.19075) идут с другой стороны: строят кастомный ODE-солвер под ODE конкретной предобученной flow-модели. Bespoke Solvers Align Your Steps - ещё один пример статических расписаний, подобранных под модель или эталонные траектории.
Место разбираемой работы в этом поле скромное и полезное. Она не претендует на SOTA-адаптив. Её вклад в другом: дешёвый сигнал кривизны годится прежде всего для построения статической сетки и для диагностики того, насколько удачно выбраны шаги.
Ограничения и что делать, если у вас другая модель
Ограничения без прикрас:
- Ноды для ComfyUI нет, списки сигм подставляются вручную.
- Готовые сигмы посчитаны только для Anima при 8, 12, 16 и 24 вызовах сети.
- Для другой модели нужны свои эталонные траектории: без них сетку по равному углу не построить.
- bf16 и classifier-free guidance дают угловой шум около 1,7°, поэтому мелкие повороты скорости неотличимы от вычислительного шума.
- На концах траектории вклад изменения длины скорости доходит до 8-9%, в отдельных точках до 23%, и там косинус описывает кривизну хуже всего.
- Проверка ограничена 12 юнитами и шагами 0,01-0,12 интервала времени.
Чек-лист для своей модели:
- Проверьте, что сэмплер хранит предыдущую скорость. Одношаговые схемы сигнал не дают в принципе.
- Откалибруйте константу: посчитайте медианное отношение E к истинной ошибке на нескольких промптах и сидах.
- Сравнивайте с базовым расписанием по латенту, а не только по LPIPS.
- Держите число вызовов сети одинаковым, иначе сравнение расписаний ничего не значит.
- Измерьте угловой шум на своей модели. Если он сопоставим с типичными углами между шагами, сигнал бесполезен.
Сигнал кривизны - дешёвый диагностический инструмент и основа для статической сетки шагов. Заменой нормальному адаптивному сэмплеру он не становится: для этого нужны аналитические схемы вроде CAT-Flow или дистилляция расписаний из эталонных траекторий. Начните с готовых сигм для Anima, если работаете с этой моделью, и с калибровки на своих юнитах, если модель другая.