text-to-image · 177.3M параметров · одна RTX 4080

UDiT — пирамидальный U-трансформер

Ширина растёт к низу: 192 → 512 → 1024 → 1536. Свёртки на мелком уровне, внимание на грубом, текст на всех уровнях. Декодер готового автоэнкодера работает хвостом-рендерером, поэтому тело считает 32 числа на клетку 8×8, а не пиксели.

177.3Mпараметров всего
97 мсшаг обучения · bs8 · 256²
20.4GFLOP forward у тела
0.647детали (hf) против AE 0.859
8.1 ГБпик памяти из 16
оригинал, реконструкция AE и две генерации

слева направо: оригинал · реконструкция AE (потолок 0.859 hf) · две генерации модели на 30k шагов с разными сидами

тело · 143.3M

пирамида 192/512/1024/1536, поток в латентном пространстве

текст · 10.0M

Ettin-150M заморожен, обучается только выбор слоёв

хвост · 23.9M

декодер AE, дообучается как flow по пикселям

UDiT · архитектура1 / 12

три части

Модель не считает пиксели — только 32 числа на клетку 8×8

шум 32 × h/8 × w/8 при 256²: 32×32 ТЕЛО · пирамида 143.3M · 20.4 GFLOP 4–8 шагов Эйлера · CFG 1.5 ÷1 · 192 ÷2 · 512 ÷4 · 1024 · ÷8 · 1536 латент 32 × h/8 × w/8 x0-предсказание ХВОСТ · декодер AE 23.9M · 4 шага flow PixelShuffle ×3 → 3 канала условие: z0 + ошибка тела обучен заранее, как декодер AE дообучается вместе с телом px 3×H×W ТЕКСТ · Ettin-150M (768, заморожен) + SliceMixer 10.04M · кросс-внимание в теле на всех четырёх уровнях

Латент вместо пикселей

Один токен = 32 числа на клетку 8×8. При 256² это 1024 токена против 196 608 пикселей.

Декодер уже обучен

Хвост наследует декодер AE: телу не нужно учиться рисовать текстуру с нуля.

Текст не экономим

Кросс-внимание в каждом блоке до самого мелкого уровня: +2.5M, «switch» 0.43 → 0.78.

UDiT · три части2 / 12

почему пирамида

Плоский стек ширины 1024 платит за каждый токен по полной

было: 12 блоков × ширина 1024 все блоки на одном разрешении токенов на блоке: 1024 · ширина: 1024 · уровней: 1 232 GFLOP · 196 мс/шаг · hf 0.18 нет уровня, где вся картинка — это 16 токенов
стало: 192 → 512 → 1024 → 1536 ÷1 · 1024 токена · ширина 192 · свёртки ÷2 · 256 токенов · 512 ÷4 · 64 · 1024 ÷8 · 16 · 1536 энкодер вверх, декодер вниз, аддитивный скип на каждом уровне 20.4 GFLOP · 97 мс/шаг · hf 0.54 → 0.65 широкий низ: 16 токенов видят всю картинку целиком
метрикаплоский 1024пирамидачто это значит
GFLOP на forward (тело)23220.4в 11 раз меньше арифметики при том же числе параметров
шаг обучения, bs8 · 256²196 мс97 мсвдвое больше шагов за то же время
детали: hf(gen)/hf(AE)21%51–75%и это при 3–6 кратном меньшем числе шагов обучения

Стоимость слоя ≈ токены × ширина². Мы держим ширину там, где токенов мало, и снимаем с мелкого уровня 28-кратный перерасход — эти же деньги уходят в глубину и разрешение.

UDiT · сравнение3 / 12

лестница

Ширина растёт там, где токенов мало — стоимость уровней сбалансирована

уровеньтокенов 256²токенов 512²ширинаблокимеханика
L0 ÷1102440961926 enc / 4 dec + self-attnсвёртки + текст
L1 ÷225610245124 / 3трансформер
L2 ÷46425610243 / 2трансформер
L3 ÷8166415362 (боттлнек)трансформер

энкодер поднимается по лестнице, декодер спускается; на каждом уровне прибавляется скип

стоимость уровня ≈ токены × ширина² 37.7 · L0 67.1 · L1 67.1 · L2 37.7 · L3 для сравнения: 1024 на всех уровнях 1073 · L0 при ширине 1024 (в 28 раз дороже) параметры уезжают вниз, где токенов 16, а не 1024
UDiT · бюджет уровней4 / 12

роли уровней

Каждый уровень отвечает за свой масштаб — как у художника

16 токенов

L3 · «прищур»

Вся картинка — 16 токенов. Полное внимание: все видят всех. Здесь решается композиция и симметрия.

64 токена

L2 · крупные формы

Тело, крылья, общая раскраска. Ширина 1024 — запас «смысла» на грубое описание.

256 токенов

L1 · средние детали

Форма крыла, крупный рисунок, где тёмное и где светлое. Ширина 512.

1024 токена

L0 · текстура

Жилки, кромки, крапинки. Здесь свёртка 3×3, а не внимание: текстура локальна, а свёртка в 20 раз дешевле.

Внимание на грубом уровне стоит копейки: 16 токенов × 16 = 256 пар. Внимание на мелком — 1024 × 1024 = миллион пар. Поэтому «прищур» мы делаем вниманием, а текстуру — свёрткой.

UDiT · роли уровней5 / 12

путь и скипы

Энкодер поднимается к смыслу, декодер возвращается к деталям — помня эскиз

L0 · 1024 токена · 192 6 блоков enc · 4 dec L1 · 256 · 512 4 enc · 3 dec L2 · 64 · 1024 3 enc · 2 dec L3 · 16 · 1536 2 блока · полное внимание pool 2× pool 2× pool 2× up 2× up 2× up 2× скип: на каждом уровне выход энкодера прибавляется ко входу декодера того же уровня (аддитивно, без проекций)

Почему аддитивные

Ширина входа и выхода уровня совпадает, проекции не нужны — так делают U-Net’ы SD.

Почему pool, а не stride

Среднее 2×2 плюс линейный слой: сжатие учится и не ломает фазу позиционного кодирования.

Что это даёт

Тонкая структура строится на своём уровне, а не вытягивается вниманием с одного масштаба.

UDiT · путь и скипы6 / 12

текст

Подпись не «берётся из последнего слоя» — модель сама выбирает, какие слои читать

норма растёт с глубиной в 10 раз — без пер-слойной нормировки ранние слои не влияют слой 2слой 5слой 8 слой 11слой 14слой 17 слой 20 52 548 7 срезов → LN на каждый → внимание по срезам → Linear(7→1) → + среднее «проектор слоёв»: какие слои читать, решает обучение, а не догадка

SliceMixer · 10.04M обучаемых · идея из moss/adapter (0.8B + 158M голова вместо 9B-энкодера)

Два входа текста в каждый блок

  • кросс-внимание: каждый токен-клетка спрашивает «что в подписи про моё место?»
  • модуляция: общий вектор «t + усреднённый текст» настраивает shift/scale/gate фильтров
что сделалиценаэффект
кросс-внимание и на L0+2.5M+9 мс
«switch» (один шум, два капшена)—0.43 → 0.78
детали (hf) не пострадали—0.44 → 0.65

«switch» — насколько латент меняется от смены подписи при том же шуме

UDiT · текст7 / 12

хвост и сэмплинг

Тело ведёт латент, готовый декодер рисует пиксели

шум тело: x0-предсказание 8 шагов · CFG 1.5 латент z 32 × h/8 × w/8 хвост: декодер AE 4 шага flow пиксели 3 × H × W
на каком латенте учить хвостчто видит рендерерчто происходит
только z0 (чистый латент)идеальный латентна сэмплинге встречает ошибку тела, к которой не привык
только предсказание теламусор в начале обученияучится «исправлять мусор» и разучивается рисовать: 29.6 → 21.3 дБ
z0 + (ошибка тела).detach()реальную ошибкувидит промах, но градиент через него не идёт; 24.7–25.9 дБ стабильно

Сэмпл: 8 шагов тела + 4 шага декодера ≈ 35 мс на 4080 при 256². CFG 1.5 — выше 2 при недоученной безусловной ветви ухудшает латент (замерено 0.19 → 0.28). Метрика tail(z0) в каждом логе ловит деградацию рендерера.

UDiT · хвост8 / 12

результат на узком домене

Бабочки: детали растут с шагами и не насыщаются

шагиhf / AEmse_lathighswitch
4 0000.446 · 52%0.210.420.43
10 0000.436 · 51%0.1640.320.68
20 0000.540 · 63%0.1070.190.78
30 0000.647 · 75%0.0720.1140.78

hf — энергия высоких частот (лапласиан). AE-реконструкция того же вида: 0.859, оригинал 0.913. «high» — ошибка на высоком шуме, то есть «какую особь рисовать»; она упала в 3.7 раза.

Три сида дают три разные особи: 0.642 / 0.646 / 0.654 — модель не сколлапсировала в один мод.

Четыре вида бабочек, сгенерированные моделью

генерации на 30k шагов: Delias, Cepora, Troides, Catasticta — вид задаётся подписью из 16 токенов

UDiT · результат9 / 12

цена

177.3M параметров, 97 мс на шаг, 8.1 ГБ — обучение на одной карте

Параметры по частям

143.3 M · тело 10.0 M · текст 23.9 M · хвост всего 177.3M · чекпойнт 709 МБ

Арифметика на forward

20.4 · пирамида 232 · плоский 1024 + хвост ≈ 29 GFLOP итого ≈ 50 против ≈ 262 та же карта, в 5 раз больше шагов

Скорость и память

97 мс · пирамида 196 мс · плоский 8.1 ГБ из 16 (bs8, 256²) 8-битный AdamW: −1 ГБ состояний эффективность ~1.6 TFLOPS — упор в память

Почему хватает 16 ГБ

Память ест не модель (2.5 ГБ весов и состояний), а активации: они ~ токены × ширина × блоки. Пирамида держит широкие слои на 16–64 токенах, поэтому активации маленькие.

Где запас

Шаг упирается в память, а не в счёт. Запас есть на батч 16 (14.8 ГБ с хвостом) и на 512² с батчем 1–2 — то есть на разрешение, где деталь физически возможна.

UDiT · цена10 / 12

следующий прогон

FLUX-Reason: 2 эпохи по 1.5M картинок, поток без кэша

параметрзначение
датасетLucasFang/FLUX-Reason-6M, часть Aesthetics-Part01 (415 шардов, ~250 ГБ)
разрешение / батч256² · bs16
подписьcaption_entity → caption_composition (40–400 симв.), иначе caption_detail
бюджет2 эпохи = 187 500 шагов ≈ 12.5 ч
оптимизаторAdamW8bit, прогрев 500, cosine до 10%
дропаутыподпись 10% (CFG) · слова 5%
стартвеса бабочек (30k шагов)

Что уже видно (шаг 800)

mse_lat общий и по зонам шума 0.33 0.037 low (t<0.3): 0.037 high (t>0.7): 0.70 241 мс/шаг · 66 картинок/с 9.5 ГБ · skip 0

«high» здесь в 6 раз выше, чем на бабочках: 1.5M разных сцен, «какую именно рисовать» по подписи не угадать — это нормальный старт, а не поломка.

Смотреть

tmp/flux/log.csv · tmp/flux/samples/latest.png (лиса, стеклянный город, неон, импрессионист)

Остановить / продолжить

kill процесса · тот же запуск с --resume --out tmp/flux

Честно про «2 эпохи»

эпоха по Part01 = 1.5M картинок; все 4 части ≈ 1 ТБ, а на диске 352 ГБ

UDiT · FLUX-Reason11 / 12

правила

Всё, что ниже — вывод из замеров, а не из вкуса

1 Ширина растёт к низу. Плоский 1024 на всех уровнях: 196 мс и hf 0.18. Пирамида: 97 мс и 0.54.

2 Текст не экономим. Кросс-внимание на самом мелком уровне: +2.5M и +9 мс, «switch» 0.43 → 0.78.

3 Хвост учится на z0 + ошибка тела. Только z0 — не видит реальных ошибок; только предсказания тела — деградация 29.6 → 21.3 дБ.

4 Бакеты кратны 64. Три даунсэмпла требуют латента, кратного 8. Аспект — центр-кроп, не растяжение.

5 Метрики вместо впечатлений. mse_lat (общий, low, high), mse_pix, switch, tail(z0), hf(gen)/hf(AE), skip.

6 Никаких костылей. Фиксированный шум, клип латента, «mix» латентов — выброшены: они прячут то, что мы измеряем.

Дальше

дожать FLUX-Reason до 2 эпох по Part01

Потом

люди: 5749 фото, 256² — лица и кисти

Затем

512² на людях: деталь физически разрешима

Только потом

ёмкость: ширина боттлнека и число блоков L0

UDiT · правила12 / 12