Документация

Оптимизация реальной рабочей нагрузки Snake

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

В парном тесте полного цикла поставляемый оптимизированный путь достиг 75.40 ходов/секунду на 2 400 ходах против 70.82 ходов/секунду для eager-вывода в том же тесте: 1.065×, или около 6.5%. У обоих ноль смертей, 2 вмешательства безопасности и идентичные выполненные действия на 2 400/2 400 шагах. Совокупный рост активной памяти MLX после прогрева и очистки кэша составил 0 байт.

Включение

laya-snake --optimize
laya-snake --optimize --max-speed

Общий API предоставляет те же опциональные элементы управления:

import laya_mlx as laya

agent = laya.load(
    "aac6fef/laya-multilingual-mlx",
    compile=True,
    pad_to_multiple=16,
    cache_prompts=True,
)

Все три опции по умолчанию отключены, что сохраняет существующее eager-поведение и конфигурацию бенчмарка. Компиляция специализируется по форме ввода; первое использование и новые формы могут повлечь стоимость компиляции. Создавайте новый Agent после изменения весов или структуры модулей. Дополнение округляет длину последовательности вверх до запрошенной кратности, не превышая настроенный предел контекста. Маски исключают дополненные токены.

cache_prompts=True хранит не более 128 неизменяемых префиксов PreparedQuestion на Agent, включая позиции маркеров. Ключи кэша включают идентичность токенизатора, специальные токены, тип вопроса, упорядоченные отрендеренные варианты, инструкции и бюджет префикса. Состояние очищается и токенизируется один раз на вызов prepare, затем независимо конкатенируется с каждым префиксом вопроса. Изменения вопросов создают или выбирают подходящий префикс. Каждый вопрос всё равно получает полный прямой проход модели.

Абляция формы и подготовки

Это демо задаёт три вопроса на ход: направление, оценку безопасного маршрута и оценку достижимости еды. Поэтому его размер пакета — 3, а не 1. По 32 выборочным реальным записанным полям:

  • Многоязычные длины последовательностей были 59, 61, 63 и 64. Кратность в 16 токенов помещает их все в бакет 64 токена.
  • Английские длины последовательностей были 66, 68, 69 и 70, отображаясь в бакет 80 токенов.
  • Дополнение многоязычного ввода с 64 до 96 добавляет 50% к работе по токенам; это не небольшое изменение с 93 до 96, которое предполагает отдельная фикстура API для короткого текста.

Кандидаты запускались в чередующемся порядке внутри каждого идентичного состояния, после однократного обхода каждой измеряемой формы. Таблица содержит синхронизированную задержку Agent.predict, включая токенизацию и преобразование вывода, и исключает работу планировщика/UI и начальный прогрев формы.

Вариант Многоязычный p50 / p95 (ms) Английский p50 / p95 (ms)
Eager 9.12 / 10.21 21.83 / 26.73
Только переиспользование префикса 8.95 / 9.75 21.60 / 25.23
Скомпилированный, фактическая длина 8.67 / 9.66 21.27 / 25.99
Скомпилированный, дополнен до 96 10.92 / 11.72 25.66 / 29.88
Скомпилированный + переиспользование префикса 8.66 / 9.21 21.03 / 23.97
Скомпилированный, бакет рабочей нагрузки 8.66 / 9.55 21.78 / 26.12
Скомпилированный + бакет + переиспользование префикса 8.56 / 9.29 21.51 / 24.16

Все семь кандидатов совпали с предложенными и выполненными направлениями eager на 32/32 полях на чекпойнт. Максимальное различие в отображаемых вероятностях и оценках с четырьмя знаками составило 0 в этих выборках. Это согласие округлённого вывода на конечной выборке, а не заявление о бит-идентичных внутренних тензорах с плавающей точкой.

Абляция использовала ограниченные обёртки подготовки префиксов для отбора дизайнов. Тест полного цикла ниже использует фактическую поставляемую реализацию API compile, pad_to_multiple и cache_prompts. Его тесты корректности дополнительно сравнивают подготовленные ID и маркеры при усечении состояния, изменении критериев, очистке маски и вытеснении из кэша.

Поставляемый оптимизированный путь также прошёл полную матрицу валидации реального чекпойнта: 63/63 согласия по выбранному ответу для каждого из трёх чекпойнтов в FP32 и FP16 (378/378 всего). Ошибки калиброванных вероятностей остались в пределах существующих допусков. Каждая конфигурация прошла 10 дополнительных конечных детерминированных повторных вызовов с 0 байт измеренного роста активной памяти. Данные оптимизированной валидации. Результаты исходного eager-пути со 100 повторами на конфигурацию остаются в исходном отчёте о бенчмарке.

Для английского компиляция с фактической длиной последовательности оказалась лучше принудительного использования более крупного бакета в этой выборке. Демо по умолчанию использует многоязычный вариант; пользователи общего API могут оставить pad_to_multiple=None, включив компиляцию и переиспользование префикса.

Парный тест полного цикла

Четыре seed по 600 ходов каждый, с чередованием порядка кандидатов по seed. Рендеринг включает композицию Rich истинного цвета и сериализацию ANSI и исключает отрисовку эмулятора терминала. Каждый ход выполняет свежее предсказание. Результаты — из одного локального парного запуска.

Seed Eager ходов/с Оптимизированные ходов/с Счёт (оба) Согласие действий
101 68.60 78.04 20 600
102 70.07 78.62 24 600
103 76.75 85.62 23 600
104 68.50 63.15 16 600

Оптимизированный путь был медленнее на одном seed. Следовательно, 6.5% — это совокупное улучшение в этом измеренном запуске, а не гарантированное улучшение для каждого эпизода или машины. Более ранний широкий свип скорости и этот поздний парный тест — разные запуски; их абсолютные частоты нельзя вычитать, чтобы заявить ускорение. Полные данные цикла.

Выбор модели по геймплею, а не только по задержке

Оба чекпойнта прошли 20 парных seed × 300 ходов, с чередованием порядка чекпойнтов на каждом seed. Каждый эпизод использовал одно и то же начальное состояние, seed RNG для еды, компактные описания признаков и щит цикла. Горизонт фиксирован; это счета после 300 ходов, а не полные игры, заканчивающиеся смертью или заполненным полем. В это сравнение моделей не входил терминальный рендеринг.

Чекпойнт Выжил / эпизодов Ходов Медиана / средний счёт Вывод p50 / p95 (ms) Вмешательства
laya 20 / 20 6000 7.0 / 6.9 23.15 / 28.21 0
multilingual 20 / 20 6000 10.0 / 9.9 9.38 / 14.38 2

Multilingual добился большего прогресса к еде и был быстрее на этой рабочей нагрузке, поэтому он остаётся чекпойнтом демо по умолчанию. Результат оценивает эту политику с вспомогательными признаками, а не общее качество рассуждений или модель Snake без помощи. Каждый эпизод и вывод.

Воспроизведение

uv run --extra demo python -m experiments.snake_runtime \
  --output artifacts/snake/runtime-multilingual.json
uv run --extra demo python -m experiments.snake_runtime \
  --model models/hub/laya-mlx --bucket 80 \
  --output artifacts/snake/runtime-english.json
uv run --extra demo python -m benchmarks.snake_optimized \
  --output artifacts/snake/optimized-paired.json
uv run --extra demo python -m benchmarks.snake_models \
  --episodes 20 --steps 300 --output artifacts/snake/models.json

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

Более раннее сравнение компактного и подробного промпта чередовало порядок промптов на 64 состояниях и обнаружило 11.80 → 9.29 ms медианы после отбрасывания первых 8 итераций прогрева. Его исходная ad-hoc запись не хранила снимки поля, поэтому это вспомогательное свидетельство, а не первичная воспроизводимая абляция. python -m benchmarks.snake_prompt предоставляет воспроизводимую версию, которая хранит состояния, seed, полные решения и метод.

Реализация следует официальному руководству по компиляции MLX: использовать долгоживущий скомпилированный вызываемый объект и обычную специализацию по форме. Она не использует shapeless=True на зависящем от формы Python-коде модели. Текущая документация была проверена через официальный сайт после того, как запросы Context7 CLI завершились сетевыми ошибками.