И собственно всё это было сделано год назад ребятами из ByteDance. Они что-то пообучали, где-то у них получилось лучше, но шума не было, и, насколько мне известно, никто этим не пользовался в реальных больших моделях. DeepSeek нашли, почему это может плохо работать с масштабированием. Всё дело как раз в этой матрице 4x4, которая указывает, из каких труб куда и сколько воды переливать. Никаких ограничений на это не ставилось, и могло происходить так, что нарушалось свойство identity из residual stream. Вот у нас была формула `X_4 = X_3 + F(X_3)`, а теперь стало так: `X_4 = странная_штука(X_3) + F(X_3)`. Если `странная_штука` будет выдавать очень большие значения, то это приведёт к перетягиванию градиентов на себя, и F будет плохо учиться. А если будет давать очень маленькие значения, то тогда все предыдущие слои в модели (в данном случае 3 слоя) почти не будут учиться. Старая-добрая проблема затухания и взрывов градиентов. При этом `странная_штука` — это всё ещё просто одна маленькая матрица, задающая веса смешивания 4 разных потоков информации. И DeepSeek предлагают сделать очень простую вещь, чтобы решить проблему: использовать алгоритм Синхорна-Кноппа 1967-го года для энтропийной проекции на многогранник Биркгофа. 😑 вот такими сложными словами УЧЬЁНЫЕ говорят: да просто давайте матрицу поменяем так, чтобы сумма по всем столбцам и строкам была нормирована к единице. Такие матрицы называются дважды стохастическими, все элементы которых неотрицательны, и их множество как раз и называют «Многогранником Биркгофа» — отсюда такие сложности. Алгоритм Синхорна-Кноппа работает тоже очень просто: мы итеративно нормируем поочередно столбцы и строки к единице. То есть сначала суммируем каждый столбик и делим каждое число на сумму (получилось, что сумма равна единице). Потом делаем то же самое для строчек, тем самым ломая логику столбиков. Но этот процесс ходится к тому, что на выходе после нескольких повторений и будет матрица, в которой строки и столбцы суммируются в 1. На практике это означает, что мы контролируем, что не будет перекосов, когда какие-то стримы получают очень большой или очень маленький вес, который препятствует обучению. При сравнении своей модификации с вариантом от ByteDance считают максимальное произведение весов, которые были даны какому-то сигналу (эмбеддингу): раньше было 3000 (затмевал всё), теперь 1.6. У DeepSeek в теории должно быть 1, но так как Алгоритм Синхорна-Кноппа итерационный, и его делают всего 20 раз, то иногда занчения могут быть чуть выше единицы. А 1.01 ^ 100 (1% отклонения на протяжении 100 слоёв) — это 2.7, и именно поэтому нормировка важна Как всегда, DeepSeek написали много про технические оптимизации, как это всё заставить работать быстро. Ключевое — это что Алгоритм Синхорна-Кноппа работает полностью в регистрах GPU (самая быстрая память, с которой напрямую общаются CUDA-ядра).