ПРЕДУПРЕЖДЕНИЕ: Автору 14 лет, он плохо разбирается в технологиях и программировании, но основную теорию проекта придумал сам. Очень хотелось бы услышать конструктивную критику

Всем здравствуйте, я Titled и я создал форк llama.cpp, где реализовал все свои заветные мечты. Сейчас расскажу, что это было и почему я написал такой длинный заголовок.

Сначала стоило бы пройтись по терминам вообще, потому что без них читать эту статью будет не так интересно. Основная речь пойдет о движке запуска нейросети, в который вшиты все архитектуры, и вы можете сами его скачать и запустить любую нейросеть. Его название — llama.cpp, и как принято, все делают форки успешных проектов. Я не стал исключением и создал свой форк, но с нестандартной идеей.

Что помогает нейросети так думать?

Я решил использовать рекуррентность — очень интересный и гипернедооценённый инструмент, который я пытаюсь продвинуть уже очень много времени. Если кратко объяснять, как это работает, то легче показать это наглядно.

Рисовал от руки, так что простите, но здесь наглядно видно, что мы получаем вход, проходим через слои и получаем выход. Чтобы добавить больше ума, нам нужно добавить больше слоев, но тогда будет больше вычислений. Из-за ограниченных возможностей моей видеокарты я физически не смог поставить больше слоев дообучением. Тогда появилась идея: я буду зацикливать слой! Ладно, идея не моя — я украл её из OpenMythos но, в отличие от них я применил это на реальных моделях. И это не всё: я модифицировал систему!

Так происходит на OpenMythos. Это странно, ведь они зацикливают один слой, который может технически отвечать за что-то неважное. Поэтому я подумал и решил делать сразу 3 слоя, которые я буду зацикливать. Хардкод здесь не поможет, и я придумал (попросил дипсик и обговорил с ним) формулу адаптивной выборки слоёв!

Для умных людей я просто оставлю эту формулу здесь, а для нормальных поясню короче:
Она делит все на 4 блока, и один блок выкидывает, зацикливает средние слои. Сумма циклов всегда равна параметру D, а чтобы выбрать слой — параметр эффективности S от 1 до 100.

формула

1. Разбиение на 4 блока

  • N — всего слоёв.

  • k = ⌊N/4⌋, r = N mod 4.

  • Размеры блоков: [k, k, k, k+r].

  • Стартовые индексы: 0, k, 2k, 3k.

2. Выбор слоя в каждом блоке (параметр S ∈ [0,100])

  • Для блока i:
    offset_i = ⌊ S/100 · (size_i − 1) ⌋
    L_i = start_i + offset_i

  • L₁ — отбрасывается (используется только для начального «понимания»).

3. Рекуррентные слои и циклы

  • Активные слои: L₂, L₃, L₄.

  • Общая глубина D (число циклов).
    Распределение по весам (1: 3: 2):

text

c₂ = round(D · 1/6)
c₃ = round(D · 3/6)
c₄ = D − c₂ − c₃

Итог: слой L₂ повторяется c₂ раз, L₃c₃, L₄c₄.
При D=12 получаем (2, 6, 4), при D=16(3, 8, 5) и т.д.

Вот разобрались с формулой, но что нам делать, если мы просто так зациклим слои? Два варианта: или получится бред, или прироста не будет, или мы взорвёмся (градиенты, имеется в виду). В общем, мы должны юзать вот такую имбу: -

Эйлерово масштабирование

  • Вдохновлено численным решением ОДУ:
    h_{t+1} = h_t + (1/iters) · f(h_t)

  • Мы применяем это как адаптивный шаг внутри цикла:
    cur = alpha cur + (1 - alpha) inpSA, где alpha = 1.0 / iters.

  • Это не даёт сигналу взорваться и сохраняет баланс residual-потоков, даже при большом D.

Идёт коррекция: с каждой последующей итераций цикла получаются меньшие величины.

KV КЕШ В ДВЕНАДЦАТЬ РАЗ БОЛЬШЕ ЧТОООО?!?!?!?!?

Звучит пугающе, но для этого мы взяли крутую штуку — это KV-декапплинг (отвязка кеша от рекуррентности). То есть кеш не связан с рекуррентностью. Я могу вам объяснить это сам. Конечно же, а давайте я это и сделаю!

Если кратко: запись кеша доступна только на первой итерации, на всех остальных — только чтение. Но зачем это, кроме веса? Всё из-за того, что на каждой итерации перезапись ключей/значений (KV) ломала внимание. Это было неприятно, но легко чинится. Но это не конец: идём далее.

Как нам не взорвать градиенты

Надеюсь, объяснять, что такое градиенты, мне не нужно, поэтому просто скажу: они взрываются без инъекций, поэтому мы даём ей лекарство:

  • Добавляем линейную комбинацию:
    h_new = alpha h_cur + beta h_inp, где beta = 1 - alpha.

  • Это якорь, который возвращает состояние к исходному вектору, предотвращая семантический дрейф.

Вот таким образом мы, получается, убеждаемся, что мы всегда меньше 1, а значит, взрыва и брейнрота у нас не будет.

Пруфы

Смотря эту статью, вы зададитесь двумя вопросами: «Почему так кратко?» и «Где пруфы?» На второй я отвечу прямо сейчас:

ВОТ ОН

А чтобы подтвердить всё, я сделал базовый бенчмарк gms8k и получил на маленькой модели впечатляющие результаты, поэтому вот и они:

GSM8K Benchmark Results (N=500)

Evaluating DeepSeek-R1-Distill-Qwen-1.5B-Q4_K_M:

Configuration

GSM8K Accuracy

Correct Answers

Baseline ( D = 0 )

39.20%

196 / 500

Recurrent ( D = 12 )

77.20%

386 / 500

Using Euler step scaling and KV cache decoupling to prevent semantic drift across iterations.

Да это вырезка из README!!

Да, это явно пруфы. Я думаю насчёт второго вопроса: отвечу — я сделаю вторую часть, где объясню больше крутых моментов именно по разработке и переписи кода на ручной C++, а не ИИ-шный. В общем, так я надеюсь, что кто-то найдёт время зайти, посмотреть репозиторий и дать советы по улучшению, и да, по моим тестам данный форк увеличивает скорость где-то на ~10%, так что юзайте на здоровье!

Спасибо за прочтение!

Важное уточнение: в этой работе я не делал дообучение (fine‑tuning) модели. Все изменения касаются только этапа инференса: я модифицировал вычислительный граф, добавив рекуррентное применение слоёв с адаптивным масштабированием и отвязкой KV-кеша. Веса модели остаются неизменными

Комментарии (24)


  1. TomskDiver
    29.07.2026 07:29

    Все не любят нейрослоп, но для данной статьи он был бы спасением:)) Вы ненавидите запятые? Попросите ИИ проставить знаки препинания, вернуть потерянные буквы и поправить орфографию.


    1. WenTech
      29.07.2026 07:29

      Для этого и Word 6.0 хватило бы, не надо ИИ.

      А вот практическую часть ждём - пусть аффтырь напугает нас тестами! )))

      =============================================================

      PS: 29 июля 2026 года автору 14 лет.

      ПРЕДУПРЖДЕНИЕ : Автору 14 лет 

      А 8 апреля 2025 года ему было 11 лет.

      В этом вашем IT год за 3 идет, как в полярных войсках? Срочно запретить IT!!! :)))


      1. SimpleTitled Автор
        29.07.2026 07:29

        В реальности мне 13 день рождение 17 мая просто я увеличиваю возраст чтобы люди не думали что я малолетка


        1. WenTech
          29.07.2026 07:29

          В инете возраст так-то вообще значения не имеет, и более того...

          ...«В интернете никто не знает, что ты кот» (с) ;)


        1. Sinclear
          29.07.2026 07:29

          Я как 40 летний преподаватель и человек который занимается наукой скажу:

          1. Все кто тыкает пальцем на возраст при проведении исследований - шли по дальше

          2. Занимайся дальнейшими исследованиями

          3. Не забывай что у тебя юность и побей крапиву палкой


    1. SimpleTitled Автор
      29.07.2026 07:29

      Извините, в следубщей статье буду более старательно ставить запятые сам заметил что получилось таксебе


      1. SER_26
        29.07.2026 07:29

        Лучше уже эту отредактировать через Word. Я так просто её не смог читать:-(
        Да и ошибки типа "в следубщей ", как выше, объясняются просто тем, что текст даже не прочитан автором после печати, а не банальной плохой грамотностью. Не очень такой подход вежлив по отношению к читателям.


  1. vazir
    29.07.2026 07:29

    для получения 77.20% - на сколько дольше модель стала думать?


    1. SimpleTitled Автор
      29.07.2026 07:29

      на 10% быстрее довольно странный результат но это правда вы можете сами скачать и проверить я сам в шоке


  1. RomanVelichkin
    29.07.2026 07:29

    Чтобы добавить больше ума, нам нужно добавить больше слоев, но тогда будет больше вычислений. Из-за ограниченных возможностей моей видеокарты я физически не смог поставить больше слоев дообучением.

    Дообучение не добавляет слои. Оно обновляет веса на уже имеющихся слоях - все или только части слоев.

    Конечно, можно дообучать и с добавлением новых слоев. Но это скорее частный случай.


    1. SimpleTitled Автор
      29.07.2026 07:29

      Да, спасибо что поправили наверное правильно было сказать что чтобы сделать умнее надо брать большую модель.


  1. RomanVelichkin
    29.07.2026 07:29

    Вообще крутая штука, но до сих пор не могу понять, как она работает, поэтому спросите ИИ-чат-бота, он вам поможет, а я перейду далее.

    Идёт коррекция: с каждой последующей итераций цикла получаются меньшие величины


    1. SimpleTitled Автор
      29.07.2026 07:29

      Спасибо


  1. RomanVelichkin
    29.07.2026 07:29

    GSM8K Benchmark Results (N=500)

    Непонятно на каких данных дообучалась модель. Если на данных этого бенчмарка, тогда такой результат неудивителен - модель просто "узнала" тестовые данные. А этого нельзя делать, модель не должна видеть тестовые данные. Иначе она их "запомнит" вместо понимания закономерностей.

    Необходимо отделять тренировочные данные от тестовых.


    1. SimpleTitled Автор
      29.07.2026 07:29

      Это одинкаовая модель суть была в том что модель прогоняет это у себя в голове


  1. RomanVelichkin
    29.07.2026 07:29

    DeepSeek-R1-Distill-Qwen-1.5B-Q4_K_M

    Вы тренировали дистиллированную модель. Это по-умолчанию делает задачу по дообучению бессмысленной. Дистиллированные модели не обучают.

    Дистиллированные модели получают посредством "передачи знаний" от старшей большой модели к меньшей модели. От учителя ученику. При этом передача происходит с минимальной потерей знаний.

    Но дистиллированные модели нельзя дообучать. Их размер слишком маленький, и они не могут самостоятельно получить тот же уровень знаний, что они унаследовали от "учителя". Дообучение неизбежно приведёт к деградации и падению эффективности.


    1. SimpleTitled Автор
      29.07.2026 07:29

      В статье не было ничего про обучение моделей пожалуйста перечитайте статью

      Ведь форк llama.cpp это движок по запуску моделей


      1. RomanVelichkin
        29.07.2026 07:29

        Хм, ну ладно


  1. Gamefin
    29.07.2026 07:29

    Хочешь признания и реального интереса к своей идее? Сделай тоже самое с qwen 27b/32b и vllm, эту связку используют в работе многие компании для локального инференса по документации. Если на этой связке получишь прирост, то тебя будут ждать в кремниевой долине


    1. SimpleTitled Автор
      29.07.2026 07:29

      Вторая статья уже в процессе и прирост есть в ущерб скорости но ущерб всего 10% при этом агент смог сделать намного больше чем базовый


      1. Gamefin
        29.07.2026 07:29

        Подписался, буду ждать с нетерпением


  1. DanielBobrov
    29.07.2026 07:29

    Я правильно понимаю, что ты ничего не дообучал, а просто в претрене зациклил некоторые слои? Почему именно эти? Вообще сам уже давно хочу рекурентный трансформер сделать, но железа нет :( только я дообучать хочу еще, просто претрена не хватит точно. Но направление у вас явно верное, очень интересно, если даже без дообучения уже есть приросты! Надо еще как-то поэкспериментировать с выбором слоев, мб добавить какой-нибудь маленький слой промежуточный, той же лорой его обучить. Но железа надо много для хороших метрик в любом случае, это меня и останавливает до сих пор. Вам удачи, жду вторую часть!


    1. SimpleTitled Автор
      29.07.2026 07:29

      Нет не претрен прямо во время запуска модели инференса я выбирал по своей чуйке если честно мне показалось что важнее всего гдето серединка там вся умность и так просто протестировал разные варианты сейчас тестирую на 32b и она думает как 70b вобщем позже опубликую статью об этом


      1. MrYuiryMr
        29.07.2026 07:29

        https://github.com/mudler/apex-quant а вот тут ребята считают что в модели можно сжать середину, оставив края менее квантоваными.