Это мой первый пост на Хабре, так что не судите строго :-)

Текст ниже - это слегка отредактированная версия чата с моими друзьями, где я вызвался объяснить, что же именно происходит в мозгах «электронного болвана». Так получилось, что в конце 2025 — начале 2026 я смог, наконец, удовлетворить собственное любопытство относительно внутреннего устройства современных нейросетей. Правда, не до конца — сейчас уже почти все переходшли на архитектуру MoE, но насколько я вижу — это скорее оптимизация, нежели что‑то кардинально новое. Трансформер так и остаётся в центре всего этого технологического чуда, что мы наблюдаем.

Надеюсь, текст кому-нибудь поможет продвинуться дальше в его собственном пути к пониманию LLM.


О каких сетях речь

Рассказ будет касаться только нейросетей, удовлетворяющих 4 условиям:

  1. Transformer architecture

  2. Single headed

  3. Dense (не MoE)

  4. LLM

Все четыре ограничения одновременно. Однако,

  1. практически все сети, про которые ходят новости — это трансформеры. По крайней мере qwen, chat gpt, gemini и прочие

  2. multihead — это просто оптимизация, так получается выжать больше из сети того же размера. Нет таких задач, с которыми multihead может справиться, а singlehead — нет. При условии бесконечных ресурсов, разумеется

  3. Вообще говоря, все крупные игроки за последние 12 месяцев уже перешли на MoE (Mixture of Experts). Насколько я могу судить — это потому, что MoE быстрее на порядок. Но похоже, что нет таких задач, которые MoE мог бы решить, а dense не мог бы. В MoE на раннем этапе генерации принимается решение, какая часть сети сейчас важна и все остальные части просто отключаются, чтобы не тратить вычислительные ресурсы

  4. здесь мы говорим про генерацию текста, а не про звук, не про картинки, не про что‑то ещё. Только текст. Так что — только LLM

Архитектура в целом

Сеть состоит из, условно, 6 кусков:

  1. Перевод текста в токены

  2. Перевод токенов во внутренний формат (embedding)

  3. Собственно, трансформер

  4. Языковая модель (она же LM, она же генерация логитов, она же unembedding - много разных названий)

  5. Переход от логитов к токену. Это самый тупой этап - "подбрасывается монетка" чтобы решить, какой токен будет следующим. Это также единственный этап, где в LLM используются случайные числа

  6. Декодинг токена обратно в текст.

Все этапы кроме третьего (кроме трансформера) "магии" не содержат. Там всё предельно просто, пусть и приходится работать с гигабайтами данных. Тупая числодробилка, приводящая входные данные к формату, пригодному для трансформера, а также потом интерпретирующая результат.

Токены

Токены — это куски текста. Грубо можно считать, что 1 токен = 1 слово. Если слово длинное — то оно может состоять из 2–3 токенов. Цифры, знаки препинания и прочее тоже представлены отдельными токенами. Это просто такой способ кодирования. Обратное преобразование тоже элементарное. Заменяем токены на куски текста, которые они представляют и получаем опять обычный текст.

"Обвязка" трансформера

Embedding/unembedding преобразует токены из "внешнего" формата во внутренний.

Внешний формат это просто номера. У каждого токена есть свой номер и можно в табличке посмотреть, что это за слово.

Внутренний формат это набор чисел с плавающей запятой. Набор этот фиксированный для каждой сетки. Например в qwen3:8b это наборы по 4096 чисел. Тут можно провести примерно следующую аналогию: нейронная сеть нашла сама для себя 4096 разных характеристик слов. И каждое слово, какое только существует, классифицировала.

Поэтому если "внешний формат" - это "слово номер 5273", то внутренний "слово на 83% грустное, на 23% солёное, на 1% зелёное, ..." и т.д. - по всем 4096 характеристикам.

В конце процесса, на этапе LM, токен опять преобразуется из набора характеристик в "просто номер", который можно найти в табличке.

Трансформер, "день": сбор рассказов

Первый (из двух) этапов - это обмен информацией. Я назову это "день". Токенам разрешают поболтать друг с другом - и они делают это, опираясь на 4 набора правил:

  1. Key. Насколько каждый токен считает себя интересным для окружающих. По каждому из 4096 параметров - с точки зрения этого токена

  2. Query. Какие характеристики этому токену интересны самому. Опять же - по каждому из 4096.

  3. Value. Что токен способен рассказать о себе, когда им интересуются другие токены.

  4. Output. Что токен думает о рассказах других.

В процессе применения этого набора правил каждый токен смотрит на все остальные и оценивает, кто и насколько ему интересен. У токена есть набор его собственных интересов (Query) и есть его личность, которой интересуются другие (Key). Кроме того, у него есть некоторый «рассказ о себе» — что говорить соседу, если тот спросит (Value), а также что думать о том, что ему понарассказывали (Output).

Также в суть (в набор характеристик) токенов входит их место в тексте — поэтому каждый токен может отличать ближних соседей от дальних. Эта информация закладывается в токены один единственный раз — при переходе от номеров токенов к их характеристикам. А дальше уже токены вольны эту информацию хранить и преобразовывать, как им вздумается.

В‑общем, в результате приложения маски Query@Key каждый токен получает набор коэффициентов — по одному на каждый токен в тексте. Лучше всего это сравнить с прозрачностью в Фотошопе. Каждый токен сам для себя создаёт маску — что ему в окружающем тексте интересно и насколько. Этот процесс называется self‑attention.

Кроме того есть мелкий нюанс — маска прозрачности искуственно модифицируется так, чтобы каждый токен интересовался только теми, кто стоит в тексте до него. Это ещё одна оптимизация — поскольку LLM занята генерацией текста — ей запрещают «подглядывать» в будущее на этапе обучения. Иначе предсказание будущего перестаёт быть предсказанием. Потому что какое же это предсказание, если ты и так точно знаешь, что будет.

В целом процесс «дневной» трансформации выглядит так:

  1. каждый токен составляет «рассказ о себе» с помощью матрицы Value

  2. эти рассказы фильтруются сквозь маски self‑attention (q@v) — каждый токен фильтрует один раз для себя

  3. отфильтрованнные рассказы складываются вместе (с помощью математической операции «плюс»). Поэтому каждый токен получает некое усреднённое звучание всего текста.

  4. сложенные вместе расказы интерпретируются с помощью матрицы Output.

Строго говоря, преобразование x' = x+Output(∑(q@k * v)) (то есть пункты 1 и 4) тоже является некоторой оптимизацией. Сеть очевидно работает лучше, когда Value и Output делают свою работу. Они тоже являются частью общей логики модели. Но, если их выкинуть, то есть перейти к x' = x+∑(q@k * x), то будет работать и так. Хуже, да, но будет (я пробовал). Выкидывание Output оказывает меньшее влияние (да и неудивительно - есть же ещё "ночь"), выкидывание Value - большее. Но основное в трансформере - это всё таки q и k, без них нормально работать не будет.

И чтобы пояснить, что стоит за буквами:

  • x - это значение токена (4096 чисел) на предыдущем этапе

  • q = x@Q, где Q - это матрица 4096x4096 для данного шага

  • k = x@K, где K - тоже матрица 4096x4096

  • v = x@V, аналогично

  • Output(y) = y@Output

  • @ - операция матричного умножения

  • x' - результирующее значение токена "в конце дня"

Итак, этап "день" можно сформулировать так: токен прожил 1 день своей жизни, поговорил с соседями, накопил новую информацию, составил некоторое первичное мнение о том, что происходит.

Трансформер: "ночь", осмысление.

После трудного дня токен должен осмыслить свой вновь приобретённый опыт. Математически это выглядит так: свои 4096 характеристик (составленные из его прошлого + вновь обретённого опыта) путём матричного преобразования раздуваются в 3 раза (до 12288 параметров), потом фильтруются - слишком яркие впечатления притупляются - как позитивные, так и негативные, а потом опять же, путём матричного преобразоваются "сдуваются" снова в 3 раза до исходных 4096.

Этот процесс я бы сравнил с какой-то маленькой, но всё же не крошечной и при этом предельно жёсткой компьютерной программой. В ней записано, из каких характеристик происходят какие. Грубо - "если сложить бумагу и нагрев - будет огонь". Токен делает свой собственный малюсенький вывод, с точки зрения его индивидуального опыта, что же происходит в тексте.

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

"Следующие дни"

Собственно, история на этом не оканчивается. В типичной "глубокой" нейросети не один слой, а очень даже много. Даже в тривиальных сетях зачастую делают 2-3 слоя. А в qwen3:8b, который мы взяли для примера, их 36. Сценарий каждого следующего дня идентичен предыдущему - сначала токены общаются между собой, а потом каждый токен индивидуально осмысливает свой персональный опыт.

Вот только матрицы Q, K, V, O каждый день новые. Поэтому наша аналогия с токенами как с личностями тут начинает несколько трещать по швам. "Личный опыт" токена переходит изо дня в день, а вот интересы токенов, то, как они рассказывают свои истории и как они интерпретируют истории других - меняются. Как если бы каждый день было новое правило "сегодня все косплеим муравьёв". А потом - жучков. А потом - червячков. Потом - мышек, и так далее - по возрастающей - до слона. Каждый день (в каждом слое сети), токены будут проявлять всё более глобальные интересы, охватывая всё более сложные концепты, которые только может охватить процесс мышления.

На выходе же каждый токен преобразуется в тот, что, по его мнению, должен следовать за ним.
Например, если исходно была фраза "Ты бросила пить коньяк по утрам", а нейросеть наша настолько совершенна, что читает наши мысли и обладает 100% точностью, то токен "Ты" после 36 дней мытарств предскажет токен " бросила". Токен " бросила" предскажет токен " пить" - и так далее. В итоге токен " утрам" предскажет вопросительный знак. Правда, настолько точных сетей нет - потому что токен "Ты" является самым первым и с этого слова может начинаться огромное множество фраз, откуда же ему знать, что у нас Карлсон на уме.

И что в итоге?

После 36 дней, после того как каждый токен прошёл весь путь от муравьишки до слона, последний токен в цепочке предсказывает нам что же идёт после него. Зачастую он не совсем уверен, что именно там будет и предлагает несколько вариантов, на выбор. Мы волевым усилием (бросанием монетки) берём только один из предложенных вариантов, дописываем его в конец последовательности и весь процесс повторяется заново.

Так нейросеть думает или нет?

Да. Думает. Этот процесс мышления необязательно тот же, что и у людей. Тут можно спорить о терминологии, но суть в том, что предсказание следующего токена складывается из усилий всех предыдущих токенов.

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

Поэтому процесс генерации вполне себе — «обдумывание». Текст непрерывно нарастает «с конца». Это программа, которая непрерывно сама себя пишет, становясь всё сложнее и сложнее. И непрерывно выполняется. Если предположить, что в изначальном промпте была поставлена некая задача, то поиск решений (генерация идей) как раз и состоит из создания новых токенов. Все эти токены явно (не скрыто) указывают на какие‑то феномены и нюансы, которые вроде бы и так были известны — у каждого токена в его маленьких ганглиях было «смутное ощущение чего‑то такого», но не были проявлены раньше.

Нейросеть постепенно создаёт «журнал мыслей». Отмечает интересные моменты, создаёт инструкции для себя самой, следует им, принимает решения перестать следовать некоим инструкциям, которые в результате анализа оказались ложными.

Иллюстрация

Вот небольшой кусочек дампа тех таблиц, из которых составлен qwen3:8b:

blk.32.attn_k.weight Q4_K [4096 1024]
blk.32.attn_k_norm.weight F32 [128]
blk.32.attn_norm.weight F32 [4096]
blk.32.attn_output.weight Q4_K [4096 4096]
blk.32.attn_q.weight Q4_K [4096 4096]
blk.32.attn_q_norm.weight F32 [128]
blk.32.attn_v.weight F16 [4096 1024]
blk.32.ffn_down.weight Q6_K [12288 4096]
blk.32.ffn_gate.weight Q4_K [4096 12288]
blk.32.ffn_norm.weight F32 [4096]
blk.32.ffn_up.weight Q4_K [4096 12288]
blk.33.attn_k.weight Q4_K [4096 1024]
blk.33.attn_k_norm.weight F32 [128]
blk.33.attn_norm.weight F32 [4096]
blk.33.attn_output.weight Q4_K [4096 4096]
blk.33.attn_q.weight Q4_K [4096 4096]
blk.33.attn_q_norm.weight F32 [128]
blk.33.attn_v.weight F16 [4096 1024]
blk.33.ffn_down.weight Q6_K [12288 4096]
blk.33.ffn_gate.weight Q4_K [4096 12288]
blk.33.ffn_norm.weight F32 [4096]
blk.33.ffn_up.weight Q4_K [4096 12288]
blk.34.attn_k.weight Q4_K [4096 1024]
blk.34.attn_k_norm.weight F32 [128]
blk.34.attn_norm.weight F32 [4096]
blk.34.attn_output.weight Q4_K [4096 4096]
blk.34.attn_q.weight Q4_K [4096 4096]
blk.34.attn_q_norm.weight F32 [128]
blk.34.attn_v.weight F16 [4096 1024]
blk.34.ffn_down.weight Q6_K [12288 4096]
blk.34.ffn_gate.weight Q4_K [4096 12288]
blk.34.ffn_norm.weight F32 [4096]
blk.34.ffn_up.weight Q4_K [4096 12288]
blk.35.attn_k.weight Q4_K [4096 1024]
blk.35.attn_k_norm.weight F32 [128]
blk.35.attn_norm.weight F32 [4096]
blk.35.attn_output.weight Q4_K [4096 4096]
blk.35.attn_q.weight Q4_K [4096 4096]
blk.35.attn_q_norm.weight F32 [128]
blk.35.attn_v.weight F16 [4096 1024]
blk.35.ffn_down.weight Q6_K [12288 4096]
blk.35.ffn_gate.weight Q4_K [4096 12288]
blk.35.ffn_norm.weight F32 [4096]
blk.35.ffn_up.weight Q4_K [4096 12288]

Каждый "блок" (blk) - это параметры трансформера на соответствующем шаге. Они пронумерованы от 0 до 35. Внутри каждого блока хорошо видно два этапа - attention (attn), который содержит k, q, v и output - правила сбора информации и feed forward network (ffn), которая описывает, что делать с собранной информацией. Плюс разные нормализаторы (norm), которые не дают нейросетке "уйти в зашкал" - они отвечают за смещение сигналов опять в центр и их перемасштабирование обратно в диапазон от -1 до 1. Это тоже оптимизация, но без неё нейросеть очень сложно построить так, чтобы она не спотыкалась на ровном месте. Скучная, но необходимая операция. Терморегуляция живого организма, если угодно аналогию.

Дополнительные материалы

  1. Очень полезным ресурсом является серия из 10 видео "Zero to hero" от Andrej Karpathy. В ней он начинает с чистого листа и постепенно пишет трансформер, подробно объясняя каждую строчку. Общая продолжительность видео - порядка 20 часов, но реально времени на неё нужно часов 40.

  2. qwen3.c: https://github.com/adriancable/qwen3.c/blob/main/runq.c Это программа на языке C, которая не использует никаких библиотек, но при этом умещает в 1007 строк весь необходимый функционал для запуска qwen3 на процессоре (не на видеокарте). В эти 1007 строк входит всё - загрузка модели с диска, парсинг файлов, вспомогательные функции, вся обвязка, трансформер, интерфейс пользователя и комментарии. Сам трансформер в таком виде понять довольно сложно, но зато прекрасно видна логика всех остальных этапов.

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


  1. DooKoo2
    19.03.2026 10:28

    немного вбок вопрос, но если MoE использует ограниченную часть параметров для ответа на вопрос, то так-ли необходимо грузить в VRAM все веса? По мне так это очень важный аспект, ответ на который может на порядок (именно что в 10 раз, а то и больше) ускорить вычисления.

    На текущий момент ответ на этот вопрос однозначен - да нужно, так как "загрузка/выгрузка" экспертов MoE занимает много времени из RAM в VRAM да через не всегда широкую PCIe шину, если мы говорим про условно-гражданские GPU.

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

    В MoE моделях отлично работает закон парето: 20% экспертов делают 80% работы, остальные прохлаждаются.


    1. snakeru Автор
      19.03.2026 10:28

      Далеко ли у вас ваш внутренний роутер напредсказывает? Предположим, что у вас генерация идёт 20 токенов в секунду (это совсем немного). И какие-то из экспертов используются только 1% времени. Значит примерно раз в пять секунд вам придётся их перегружать в GPU.

      Но! Это и есть та причина, по которой MoE настолько заметно быстрее работают в гибридном режиме - когда в GPU влазит не вся сетка, а только её часть, как раз достаточная для просчёта очередного шага. Для посчёта следующего токена вам, может быть, из уже загруженных экспертов нужно 75%, а значит прогрузить надо только одну четвёртую.


  1. renakdup
    19.03.2026 10:28

    Теперь понятно, почему после долгого общения с ChatGPT мне кажется, что мои собственные мысли кто-то токенизировал и пустил по слоям.
    Пойду проверять, не живу ли я в transformer decodere :D


  1. murkin-kot
    19.03.2026 10:28

    Качественное понимание вопроса. Приятно обнаружить движение в сторону глубины, в отличии от примитивного повторения формул без понимания их сути, как это принято в большинстве других текстов на аналогичную тему.

    Но глубина, к сожалению, пока ещё не велика. Остались за кадром вопросы вроде "а почему именно так?", "а зачем?", ну и т.д.

    И по мелочам:

    Output(y) = y@Output

    У вас здесь y из ниоткуда появился. Поправьте, пожалуйста.


    1. snakeru Автор
      19.03.2026 10:28

      Ну могу разве что исправить на Output(чтото) = чтото@Output. Ну либо на A(B) = B@A. "Игрек" потому и появился, чтобы не вписывать туда целую формулу.

      А насчёт недостаточной глубины - готов ответить на уточняющие вопросы. Почему именно как? Зачем что?


      1. Uint32
        19.03.2026 10:28

        Статья полезная.
        Вот некоторые замечания о местах, на мой взгляд требующих уточнения:

        Поэтому если "внешний формат" - это "слово номер 5273", то внутренний "слово на 83% грустное, на 23% солёное, на 1% зелёное, ..." и т.д. - по всем 4096 характеристикам.

        Следует немного раскрыть механизм образования векторов характиристик и уточнить, что "солёное/грустное" - это условность и прямого соответствия нет.

        свои 4096 характеристик (составленные из его прошлого + вновь обретённого опыта) путём матричного преобразования раздуваются в 3 раза (до 12288 параметров), потом фильтруются - слишком яркие впечатления притупляются - как позитивные, так и негативные, а потом опять же, путём матричного преобразоваются "сдуваются" снова в 3 раза до исходных 4096.

        Как именно работает матричная операция "раздувание"/"сдувание"

        Вот только матрицы Q, K, V, O каждый день новые.

        Как тренеруются матрицы Q, K, V, O


        1. snakeru Автор
          19.03.2026 10:28

          Честно говоря, я бы все три места оставил как есть. Первое кажется мне достаточно очевидным, а я сам не люблю, когда мне предельно "разжёвывают" материал, поэтому предпочту воздержаться от такого.
          А вот второй и третий пункты просто за рамками. Очень соблазнительно всё это объяснить, но всё таки статья не совсем про это. Поэтому ограничусь ответом на коммент здесь, кому интересно - прочитает.
          1. Условность без прямого соответствия? Ну, да, наверное действительно так. "Солёное" - действительно вряд ли, модели не способны ощущать вкус, "зелёное" - тоже, если модель не мультимодальная. А вот грусть они очень даже понимают, поэтому думаю, что такая характеристика там вполне может быть.
          2. Если умножить матрицу размером 1x10 на матрицу размером 10x40 то получим новую, 1x40. Получается, что мы нашу "раздули" в 4 раза. После этого можно применить активацию (притупить положительные и отрицательные эмоции) и можно сдувать обратно домножением на матрицу 40x10
          3. LLM - это, строго говоря, математическая функция. А от функии можно взять производную. Производная, по смыслу своему - градиент. В процессе обучения мы обновляем веса следуя градиентам и из изначального шума (до обучения вся модель состоит из случайных чисел) постепенно проступают осмысленные веса. Вот только осмыслены они с точки зрения модели, а для человека всё ещё зачастую выглядят случайными, пусть в них и прослеживаются иногда некие паттерны.


          1. Flokis_guy
            19.03.2026 10:28

            LLM - это, строго говоря, математическая функция. А от функии можно взять производную.

            Ну, не всегда можно взять производную. Я могу использовать, к примеру, в качестве функции активации функцию вейерштрасса.


      1. murkin-kot
        19.03.2026 10:28

        Ну здрасьте, вроде понимание есть, а названия переменной придумать не можете? Обычно это делают так: представляют себе зачем это значение нужно, что оно делает, какую роль играет, ну и т.д. Далее на этой основе придумывают название. Но часто одним названием не ограничиваются, а пишут что каждое значение в формуле означает. Попробуйте пойти по этому пути, его многие используют.

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

        Но всё же добавлю. "Зачем" и "как" предполагают не просто перечисление операций, но и стоящий за ними смысл. Вы его образно передали, но только на уровне "общения токенов", а как из этого рождается осмысленный текст? То есть нужно двигаться дальше, в векторные пространства и пользу от их преобразований. Как в этом участвуют k,v,q,o? Почему они именно так участвуют? Где по ходу движения рождается смысл текста? Ну и т.д. Обычно про это в аналогичных статьях информация присутствует, а вы же её почему-то упустили. Рано похвалил за глубину?

        Ну и дальше в сторону архитектур надо развиваться. Там та же основа, но без понимания как и почему, туда не попасть.


  1. WhiteBehemoth
    19.03.2026 10:28

    Спасибо за статью, было интересно.

    Споткнулся на ffn объяснении. Если attention блоки было легко сопоставить с описанием выше, но к чему подвязать ffn блоки не понял.

    Каждый "блок" (blk) - это параметры трансформера на соответствующем шаге. Они пронумерованы от 0 до 35. Внутри каждого блока хорошо видно два этапа - attention (attn), который содержит k, q, v и output - правила сбора информации и fast forward network (ffn), которая описывает, что делать с собранной информацией.

    Спросил у Жемини про blk.35.ffn_* строки и направления в них. Оставлю тут, может у кого будет такая же неясность.

    Скрытый текст

    Для понимания этих весов нужно разобраться в архитектуре Feed-Forward Network (FFN), которая идет в каждом слое трансформера (в данном случае Qwen2/Qwen3) сразу после блока Attention.

    В современных моделях (LLaMA, Mistral, Qwen) используется архитектура SwiGLU. В отличие от старых сетей, где было всего два слоя, здесь их три: gate, up и down.

    Что значат эти названия (направления)?

    Представьте, что данные проходят через «бутылочное горлышко», которое сначала расширяется, а потом сужается.

    1. ffn_up (Up-projection):

      • Что делает: Увеличивает размерность вектора.

      • В вашем дампе: из 4096 (скрытая размерность модели) в 12288.

      • Это «расширение» позволяет модели спроецировать данные в пространство более высокой размерности, чтобы извлечь сложные признаки.

    2. ffn_gate (Gate-projection):

      • Что делает: Работает параллельно с up. Это тоже расширение из 4096 в 12288.

      • Результат этого слоя проходит через функцию активации (обычно SiLU). Затем он поэлементно умножается на результат слоя up.

      • Это работает как «фильтр» или «ворота» (gate), определяя, какая информация из up важна, а какая — нет.

    3. ffn_down (Down-projection):

      • Что делает: Сжимает данные обратно в основную размерность модели.

      • В дампе: из 12288 обратно в 4096.

      • Это завершающий этап блока, подготавливающий данные для передачи в следующий слой.

    Разбор ваших строк из дампа:

    • blk.35.ffn_norm.weight F32 [4096]

      • Это параметры нормализации (LayerNorm или RMSNorm) перед входом в FFN. Она стабилизирует числа, чтобы они не «взрывались». Веса хранятся в точности Float32 для стабильности.

    • blk.35.ffn_gate.weight Q4_K [4096 12288] и blk.35.ffn_up.weight Q4_K [4096 12288]

      • Это два огромных слоя расширения. Обратите внимание на тип Q4_K — это 4-битная квантование. Это сделано для экономии памяти, так как это самые «тяжелые» части модели.

    • blk.35.ffn_down.weight Q6_K [12288 4096]

      • Слой сжатия. Здесь используется Q6_K (6 бит). Часто разработчики оставляют чуть больше точности на down-projection, так как ошибки в этом слое сильнее влияют на итоговый результат.

    Итог: зачем это нужно?

    Если Attention отвечает за то, чтобы токены «смотрели» друг на друга и понимали контекст (связи между словами), то FFN (Fast Forward / Feed Forward) — это «база знаний» модели. Именно в этих огромных матрицах (расширение до 12288 и обратно) хранятся фактические знания и логические правила, которые модель применяет к каждому токену по отдельности.

    Почему "Fast Forward"? Скорее всего, в статье или контексте это опечатка или упрощение от Feed-Forward (связь «вперед»). В контексте нейросетей это означает, что сигнал идет строго в одном направлении: вход -> gate/up -> down -> выход.


    1. snakeru Автор
      19.03.2026 10:28

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

      В матричном вычислении есть умножить матрицу размером AxB на матрицу размера BxC то размер результата будет AxC.

      Токен - это вектор значений (некоторое количество чисел с плавающей запятой), в моих примерах его размер был 4096. Поэтому его размер можно записать как 1x4096.
      FFN матрицы имеют размеры 4096x12288 и 12288x4096.

      Поэтому цепочка выглядит так:
      1. токен @ первая матрица -> результат 1x12288 - красочный сон
      2. красочный сон -> притуплённый сон в результате активации (размер сохраняется 1x12288)
      3. притуплённый сон @ вторая матрица -> снова 1x4096, готов к следующему этапу
      Активация на шаге 2 это "ужимание" диапазона в какие-то жёсткие рамки. В результате стольких умножений и сложений каждое из 12288 чисел может иметь очень большие или очень малые значения. После активации это обычно ужато в диапазон -1...+1, а то и ещё меньше. Функций активации много разных, самая простая для понимания - сигмоид, по нему прекрасно видно, как именно сжимается диапазон.