как мы взяли gpt-oss-20b-TurboQuant-MLX-8bit, изменили логику наблюдения и научились точечно исправлять квантованные слои
Введение
В прошлой статье я показывал, что подпись Schnorr / MuSig2 можно рассматривать не как «чёрный ящик», а как систему наблюдаемых affine-структур: через строгий BIP340 membership bridge, семейства скрытых нонсов, compression/connectivity-метрики и protocol-valid линеаризацию MuSig2 partial signatures Хабр. Это меняет саму оптику: вместо «верим протоколу на слово» мы начинаем разбирать его на проверяемые математические блоки.
Следующий шаг оказался неожиданным, но логичным.
Мы перенесли ту же самую методологию в AI.
Не в смысле «взяли LLM и начали её тюнинговать». А в смысле: взяли квантованную MLX-модель и стали исследовать её внутреннюю математику так же, как раньше исследовали подписи.
Объектом эксперимента стал локальный дистрибутив:
gpt-oss-20b-TurboQuant-MLX-8bit
Мы не меняли архитектуру модели, не переписывали attention и не занимались классическим fine-tuning. Мы сделали другое:
-
научились читать
.safetensorsкак точную структуру; -
построили детерминированный calibration cache;
-
начали снимать реальные BF16-активации с конкретных слоёв;
-
свели локальную коррекцию весов к ограниченной задаче целочисленной оптимизации;
-
сделали безопасную запись patch обратно в модель;
-
и добавили smoke-check, который проверяет, совпадает ли offline-математика с реальным runtime MLX.
Главный результат этой статьи звучит так:
мы не «улучшили модель магией», а построили exact AI-forensics pipeline, в котором квантованный слой перестаёт быть чёрным ящиком и становится наблюдаемым, проверяемым и локально корректируемым объектом.
Почему переход от Schnorr к AI вообще естественен
В криптографии всё началось с очень простой идеи: если объект допускает строгую нормализацию, то его можно не только использовать, но и исследовать как геометрию скрытых параметров.
Для подписи Schnorr базовое соотношение имеет вид:
где:
-
— приватный ключ,
-
— nonce,
-
— challenge,
-
— скаляр подписи.
Это уже не «магия подписи», а линейная структура.
В AI мы сделали тот же самый ход.
Мы перестали смотреть на модель как на функцию «промпт текст» и спустились ниже — к тому месту, где живёт её внутренняя линейная алгебра:
-
квантованные коды,
-
scale/bias,
-
входные активации,
-
эталонные выходы линейного слоя.
То есть вопрос поменялся.
Не:
«Модель отвечает хорошо или плохо?»
А:
«Можно ли представить конкретный квантованный слой как точный affine-объект, наблюдать его поведение и локально исправлять без разрушения всей модели?»
Вот это и есть AI-forensics.
Что именно мы взяли
Базой стал MLX-дистрибутив:
gpt-oss-20b-TurboQuant-MLX-8bit
Нас интересовали два конкретных слоя первого блока:
model.layers.0.self_attn.q_proj.weightmodel.layers.0.mlp.router.weight
Почему именно они?
Потому что это хороший тест на два разных сценария:
-
слой, который может оказаться слишком «жёстким» для осмысленного patch без внешнего эталона;
-
слой, который, наоборот, допускает локальную корректировку.
Именно на этом контрасте и проявляется ценность метода.
Что именно мы изменили
Важно сразу зафиксировать: мы не меняли архитектуру модели.
Мы изменили не «мозг модели», а способ работы с ним.
Было
-
.safetensorsкак opaque-контейнер; -
квантованные веса как «что-то внутри рантайма»;
-
оценка модели только по финальному текстовому выходу.
Стало
-
точный доступ к сырому весовому представлению;
-
выделение кодов квантования, scale и bias;
-
runtime-захват входа и выхода конкретного линейного слоя;
-
локальная integer-оптимизация кодов;
-
безопасная обратная запись патча;
-
обязательная проверка, что математика offline не расходится с реальным исполнением.
Проще говоря:
мы превратили квантованный слой из «непрозрачной детали модели» в объект инженерной диагностики.
Шаг 1. Exact bridge к .safetensors
Первое, что пришлось сделать, — написать мост к MLX-квантованию.
Он умеет:
-
находить нужный тензор в модели;
-
читать его raw-представление;
-
извлекать квантованные коды;
-
читать
BF16-масштабы и смещения; -
при необходимости записывать изменённые коды обратно.
Это важный момент.
Пока веса модели воспринимаются как «готовый blob», никакой точной работы с ними не получится. Нужно сначала развернуть этот blob в нормальную математическую структуру.
Шаг 2. Детерминированный calibration cache
Следующий шаг — calibration cache.
Мы заранее собрали стабильный набор примеров:
|
Параметр |
Значение |
|---|---|
|
Всего примеров |
768 |
|
Split |
512 |
|
Split |
256 |
|
Размер шарда |
128 |
|
Политика захвата |
|
|
Тип активаций |
|
Зачем это нужно?
Чтобы каждый следующий эксперимент был воспроизводимым. Не «кажется, стало лучше», а:
-
вот тот же набор,
-
вот тот же слой,
-
вот тот же вход,
-
вот тот же эталонный выход,
-
вот та же метрика ошибки.
Без этого всё быстро превращается в storytelling.
Шаг 3. Захват реальных активаций
После этого мы добавили runtime-capture для конкретных линейных слоёв.
Для каждого выбранного примера сохранялись:
-
pre_linear_input -
linear_output_reference
Причём именно для последнего токена.
Это очень важно.
Мы не симулируем слой отдельно от модели, а снимаем его с живого MLX-runtime. То есть дальше работаем уже не с абстрактной линейной алгеброй, а с данными, которые модель реально порождает сама.
Математическая модель квантованного слоя
Теперь можно записать слой в виде нормальной формулы.
Пусть строка весов разбита на блоки длины . Для строки
и блока
обозначим:
-
— вектор квантованных кодов длины
;
-
— scale;
-
— bias.
Тогда деквантованный блок весов задаётся как
где — вектор из единиц длины
.
Если входной вектор для примера разбит по тем же блокам:
то выход по координате равен
или, после подстановки деквантования,
Вот здесь и появляется главный мост.
Квантованный слой перестаёт быть «набором непонятных байтов» и становится affine-системой над дискретными кодами.
Что именно мы оптимизируем
Для выбранного блока мы ищем новый кодовый вектор , который лучше воспроизводит reference-output, но не уезжает слишком далеко от исходного.
Оптимизационная задача имеет вид:
при ограничениях
и
Здесь:
-
— исходные коды блока;
-
— коэффициент регуляризации;
-
— максимально допустимое изменение одного кода.
В наших экспериментах для router-слоя использовались:
|
Параметр |
Значение |
|---|---|
|
Размер блока |
64 |
|
Ridge lambda |
16 |
|
Max code delta abs |
8 |
То есть patch изначально делался консервативным:
-
не переписывать слой целиком;
-
не менять десятки тысяч параметров без контроля;
-
не уходить далеко от исходной структуры;
-
чинить локально и в ограниченном окне.
Важная теорема: почему без внешнего эталона честного patch не будет
Это ключевая граница метода.
Теорема
Если в качестве цели мы используем текущий же квантованный слой, то любой exact-поиск патча даёт тривиальный оптимум: ничего не менять.
Идея
Пусть исходное состояние слоя задаётся тройкой:
и пусть функционал ошибки имеет вид
где:
-
для любой допустимой конфигурации;
-
;
-
ноль достигается только в точке
.
Тогда минимум уже достигнут в исходном состоянии, потому что меньше нуля уйти нельзя.
Следовательно, если мы пытаемся «улучшить» слой, используя как цель сам этот слой, то лучшая стратегия — ничего не менять.
Вывод
Чтобы non-identity patch был математически осмысленным, нужен внешний эталон:
-
реальные runtime-активации;
-
reference-output;
-
отдельный holdout.
Именно поэтому в нашей системе pipeline строится вокруг capture и holdout, а не вокруг самосравнения модели с самой собой.
Что показал аудит q_proj
Первым тестовым кандидатом был слой
model.layers.0.self_attn.q_proj.weight
Мы прогнали по нему exact-аудит.
Структурная картина
|
Метрика |
Значение |
|---|---|
|
Total rows |
4096 |
|
Decoded width |
2880 |
|
Blocks per row |
45 |
|
Total blocks |
184320 |
|
Unique rows |
4096 |
|
Repeated rows |
0 |
|
Unique blocks |
184320 |
|
Repeated blocks |
0 |
|
Exact equal adjacent block pairs |
0 |
Это очень показательная таблица.
Слой оказался структурно «жёстким»:
-
без тривиальных повторов;
-
без клонов блоков;
-
без дешёвых exact-симметрий;
-
без готовой компрессии, которую можно было бы легко использовать для patch.
В результате финальный вывод по q_proj оказался жёстким, но правильным:
|
Итог по |
Значение |
|---|---|
|
Self-target identity optimum |
|
|
External reference required |
|
|
Non-identity patch justified |
|
|
Exact patch candidates found |
|
И это хороший результат.
Потому что система не «придумала улучшение», а доказала границу применимости метода.
Где patch действительно сработал: router
Совсем другая история получилась для слоя
model.layers.0.mlp.router.weight
Для него был построен полный pipeline:
-
calibration cache,
-
runtime activation capture,
-
blockwise LWO-оптимизация,
-
holdout validation,
-
safe patch,
-
smoke-check.
Параметры эксперимента
|
Параметр |
Значение |
|---|---|
|
Модель |
|
|
Слой |
|
|
Train shard |
|
|
Holdout shard |
|
|
Train sample count |
4 |
|
Holdout sample count |
4 |
|
Block size |
64 |
|
Ridge lambda |
16 |
|
Max code delta abs |
8 |
Результат на train
На train-shard улучшение получилось почти идеальным.
|
Метрика |
Значение |
|---|---|
|
Baseline MSE |
|
|
Patched MSE |
|
|
MSE gain |
|
|
Changed blocks |
571 |
|
Changed codes total |
9067 |
На этом месте легко было бы сказать: «готово, мы вылечили слой».
Но это был бы неправильный вывод.
Train почти всегда можно улучшить. Главный вопрос — переносится ли эффект дальше.
Проверка на holdout
Вот здесь начинается самое интересное.
|
Метрика |
Значение |
|---|---|
|
Baseline MSE |
|
|
Patched MSE |
|
|
MSE gain |
|
|
Transfer ratio |
|
|
Holdout improves |
|
|
Overfit suspected |
|
То есть improvement почти полностью перенёсся на отдельный shard.
Можно записать это совсем кратко:
Это уже не похоже на случайное попадание или подгонку под четыре точки. Это означает, что система действительно нашла локальную корректировку, которая несёт устойчивый эффект.
Safe patch: почему это не просто красивый отчёт
После вычисления патча его нужно было ещё записать обратно в модель.
Для этого был реализован safe patch workflow:
-
сохранить backup;
-
упаковать новые коды в
U32; -
записать их в
.safetensors; -
перечитать и проверить exact match.
Результат записи
|
Метрика |
Значение |
|---|---|
|
Changed blocks |
571 |
|
Changed codes total |
9067 |
|
Raw |
3335 |
|
Write applied |
|
|
Readback exact match |
|
То есть система умеет не только посчитать патч, но и корректно внедрить его в реальный модельный файл.
Именно здесь начинается инженерия, а не просто исследование на бумаге.
Самая честная часть всей истории: smoke-check
После записи патча был выполнен runtime smoke-check.
И вот здесь система показала, зачем вообще нужна строгая проверка.
Smoke-check: General
|
Метрика |
Значение |
|---|---|
|
Input exact rows |
|
|
Output exact rows |
|
|
Input runtime vs reference MSE |
|
|
Output runtime vs reference MSE |
|
|
Output changed raw BF16 values |
|
Smoke-check: Logic
|
Метрика |
Значение |
|---|---|
|
Input exact rows |
|
|
Output exact rows |
|
|
Input runtime vs reference MSE |
|
|
Output runtime vs reference MSE |
|
|
Output changed raw BF16 values |
|
Что это значит?
Очень просто:
-
вход в слой воспроизводится идеально;
-
а вот реальный runtime-output после записи не совпал с offline-reference, несмотря на сильный результат в solver-отчётах.
На первый взгляд это выглядит как плохая новость. На самом деле — наоборот.
Это означает, что система умеет обнаруживать расхождение между:
-
offline-моделью деквантования,
-
и реальной семантикой исполнения в MLX runtime.
То есть она не просто «генерирует патчи», а умеет поймать момент, когда красивая математика перестаёт совпадать с реальностью исполнения.
Это очень важная способность.
Что мы реально изменили в модели
Чтобы не перегибать с формулировками, зафиксирую аккуратно.
Мы не меняли:
-
архитектуру модели;
-
число слоёв;
-
механизм attention;
-
tokenizer;
-
high-level inference pipeline.
Мы изменили логику работы с её внутренними квантованными слоями:
-
добавили точное чтение кодов;
-
добавили разбор по блокам;
-
добавили BF16 activation capture;
-
добавили constrained integer patching;
-
добавили safe write-back;
-
добавили post-patch reality check.
То есть фактически мы превратили MLX-дистрибутив из «готовой коробки» в систему, которую можно инструментировать, диагностировать и хирургически править.
Что теперь умеет наша система
Если собрать всё вместе, получается уже довольно сильный capability map.
1. Exact audit квантованных слоёв
Система умеет разбирать внутреннее представление веса на уровне:
-
U32-кодов, -
uint8-декодирования, -
BF16scale/bias, -
block geometry.
2. Runtime capture живой модели
Она умеет снимать реальные входы и выходы линейного слоя на настоящем MLX-runtime, а не на симуляторе.
3. Локальную integer-коррекцию
Она умеет искать ограниченный patch для конкретных блоков без разрушения всего слоя.
4. Safe patching
Она умеет записывать корректировку обратно в .safetensors с контролем readback.
5. Holdout validation
Она умеет отличать реальное улучшение от переобучения на крошечном calibration-shard.
6. Runtime mismatch detection
Она умеет обнаружить, что offline-патч красив, но среда исполнения интерпретирует его иначе.
И вот это, пожалуй, одна из самых сильных возможностей системы на текущем этапе.
Что мы пока не заявляем
Чтобы статья оставалась инженерной, а не рекламной, зафиксирую и ограничения.
Мы пока не утверждаем, что:
-
любой слой можно исправлять одинаково успешно;
-
q_projуже улучшен — нет, там система честно упёрлась в границу метода; -
runtime-семантика MLX уже полностью раскодирована;
-
AI-ветка уже усиливает криптоаналитический recovery end-to-end;
-
вся lattice-ветка для AI уже production-ready.
Но мы вполне можем утверждать другое:
построена рабочая exact AI-forensics инфраструктура для квантованной MLX-модели.
И это уже немало.
Почему это интереснее обычного fine-tuning
Обычный fine-tuning отвечает на вопрос:
как сделать модель в среднем лучше на задаче?
Наш подход отвечает на другой вопрос:
что делает конкретный квантованный слой, как он устроен в exact-представлении, и можно ли изменить его локально, не теряя контроля над каждым шагом?
Это другой уровень доступа.
Не «подкрутить поведение модели», а разобрать её внутреннюю линейную механику до уровня кодов квантования.
Именно поэтому эта AI-ветка выросла у нас не из MLOps, а из криптоанализа.
Потому что и там, и здесь задача одна и та же:
перестать верить чёрному ящику и заменить веру наблюдаемой структурой.
Итог
Если сформулировать совсем коротко, то произошло следующее.
Мы взяли gpt-oss-20b-TurboQuant-MLX-8bit и добавили к нему не «ещё один AI-скрипт», а целую exact-инфраструктуру:
-
bridge к
.safetensors, -
calibration cache,
-
BF16 activation capture,
-
constrained blockwise optimization,
-
safe patch,
-
holdout validation,
-
runtime smoke-check.
Подтверждённый итог на текущем этапе двойной:
-
router-слой действительно допускает осмысленную локальную коррекцию, причём эффект переносится на holdout;
-
offline-модель патча и реальная MLX runtime-семантика ещё не совпадают полностью, и система это умеет честно обнаруживать.
А значит, сегодня наша система уже умеет делать не только криптографическую forensics-диагностику, но и то же самое внутри квантованной нейросети:
выделять слой, формализовать его как affine-объект, локально исправлять и проверять, не обманывает ли нас сама среда исполнения.
Именно в этом месте AI перестаёт быть «магией модели» и становится объектом точной инженерной диагностики.
Короткое послесловие
Эта работа не про «волшебное улучшение LLM». Она про другое: как перенести дисциплину криптоанализа в AI и научиться работать с квантованной моделью так же строго, как мы работаем с протоколами подписи.
То есть не «верить, что внутри что-то происходит», а видеть, измерять, патчить и проверять.
И это, похоже, только начало.
ссылка на оригинал статьи https://habr.com/ru/articles/1026340/