Оптимальные настройки llama.cpp + Qwen3.8-Flash-Next на Strix Halo
обновлено:Оптимальная конфигурация для запуска Qwen3.8-Flash-Next (176.94B MoE, архитектура qwen4exp) на MiniPC Strix Halo с AMD Ryzen AI Max+ 395 (128 GiB LPDDR5x, бэкенд Vulkan).
Требования
| Компонент | Описание |
|---|---|
| Оборудование | FEVM FA-EX1 – Ryzen AI Max+ 395, Radeon 8060S (gfx1151), 128 GiB LPDDR5x-8500 (~215 ГБ/с пропускная способность, ~112 GiB GTT на Linux) |
| llama.cpp | strix-halo-llamacpp v0.7.5 (исходник dff60048, Vulkan, включает Mesa 26.3.0-devel) – обязательно |
| Модель | Qwen3.8-Flash-Next-UD-Q4_K_XL (~103.69 GiB, 4 шарда, 176.94B параметров) |
| Модель (меньше) | Qwen3.8-Flash-Next-UD-IQ4_XS (~87.25 GiB, 3 шарда) – помещается больше контекста, качество немного ниже |
| Модель (MTP) | mtp-Qwen3.8-Flash-Next-shared-Q8_0.gguf (~2.6 GiB) – общие MTP-головы для спекулятивного декодирования |
| mmproj | mmproj-BF16.gguf (~0.85 GiB, мультимодальная, опционально) |
| Шаблон | chat_template.jinja v21.3 |
Архитектура модели (qwen4exp): 48 блоков, гибридный SSM (Gated DeltaNet) + полное внимание каждый 4-й слой, индексатор разреженного внимания QSA (top_k=2048, compress_ratio=4 → 12 QSA-слоёв), PLE-слой (16 n-gram голов), MoE 512 экспертов / 10 активных на токен, контекст 262144 токенов.
Почему нужна «специальная сборка»
qwen4exp направляет внимание через индексатор разреженного внимания QSA. В обычном llama.cpp на каждом шаге декодирования индексатор заново пулит весь кэш блочных ключей – O(n_kv) работы на токен, в каждом QSA-слое. По мере роста контекста это доминирует в декодировании, и пропускная способность обваливается.
Исправление (upstream issue ggml-org/llama.cpp#28012, вошло в strix-halo-llamacpp v0.7.5) кэширует пуленные блочные ключи по блокам и пересчитывает только хвост. Замерено на этой машине (Q4_K_XL, глубина 32k, без MTP):
| Сборка | pp512 @ 32k | tg32 @ 32k |
|---|---|---|
сток pr28243 | 215.6 t/s | 20.3 t/s |
| strix-halo-llamacpp v0.7.5 | 321.8 t/s (+49%) | 23.6 t/s (+16%) |
Готовый tarball включает согласованный драйвер Mesa 26.3.0-devel RADV и обёртку _run, которая его подключает – менять системный драйвер не нужно.
Получение сборки
# Prebuilt (recommended) -- self-contained, bundles the Vulkan driver
curl -LO https://github.com/Nathanw1014/strix-halo-llamacpp/releases/download/v0.7.5/strix-halo-llamacpp-vulkan-portable.tar.gz
tar xzf strix-halo-llamacpp-vulkan-portable.tar.gz
# -> vulkan/bin/{llama-server,llama-cli,llama-bench}, vulkan/driver/, vulkan/_runОбёртка _run (или переменные окружения ниже) настраивает входящий в поставку драйвер и флаги производительности:
HERE=/path/to/strix-halo-llamacpp/vulkan
export VK_ICD_FILENAMES="$HERE/driver/radeon_icd.x86_64.json"
export VK_DRIVER_FILES="$VK_ICD_FILENAMES"
export LD_LIBRARY_PATH="$HERE/driver:$HERE/bin"
export GGML_VK_MMID_ROWLISTS=1 GGML_VK_MMID_SMALLN=1 GGML_VK_MMID_BM64=1
export GGML_VK_MMID_WAVE32=1 GGML_VK_MMID_F16B=1 GGML_VK_MMID_M128=1
export GGML_VK_FA_WAVE32=0Базовый запуск (Vulkan)
#!/usr/bin/env bash
HERE=/path/to/strix-halo-llamacpp/vulkan
MODEL=/path/to/Qwen3.8-Flash-Next-UD-Q4_K_XL-00001-of-00004.gguf # all 4 shards auto-loaded
TEMPLATE=/path/to/chat_template.jinja
# (driver env from "Getting the build" above, or just call $HERE/_run)
$HERE/bin/llama-server \
--host 0.0.0.0 \
--port 1234 \
-c 0 \
--n-gpu-layers 999 \
--batch-size 2048 \
--ubatch-size 1024 \
--flash-attn on \
--temp 1.0 \
--top-p 0.95 \
--top-k 20 \
--min-p 0.0 \
--prio 2 \
--cpu-strict 1 \
--threads 16 \
--threads-batch 32 \
--no-warmup \
--jinja \
--chat-template-file ${TEMPLATE} \
-ctk q8_0 \
-ctv q8_0 \
--parallel 1 \
--metrics \
--alias "qwen3.8-flash-next-q4_k_xl" \
-m ${MODEL}Параметры и обоснование
| Параметр | Значение | Почему |
|---|---|---|
-c (контекст) | 0 | Без ограничений (модель поддерживает 262144). KV растёт по мере необходимости; -ctk/-ctv q8_0 держит его компактным |
--n-gpu-layers | 999 | Сгружает всё на iGPU (UMA: «память GPU» – это системная RAM) |
--batch-size | 2048 | Пакет обработки промпта; узкое место – пропускная способность, 2048 достаточно |
--ubatch-size | 1024 | Размер микро-пакета. Тестировали 1024 vs 2048 – разницы нет (MoE упирается в пропускную способность). 1024 держит пик RAM ниже |
--flash-attn | on | FA на входящей в поставку Mesa 26.3 быстрая и стабильная для этой модели |
--temp / --top-p / --top-k | 1.0 / 0.95 / 20 | Это модель рассуждений (режим размышления через шаблон); более свободная сэмплировка уместна |
--min-p | 0.0 | Отключено – не нужно при заданных top-p/top-k |
--prio 2 --cpu-strict 1 | – | Повышенный приоритет ОС + строгая привязка потоков (PLE-слой работает на CPU). --prio требует разрешения на установку nice; безвредное предупреждение при отказе |
--threads / --threads-batch | 16 / 32 | CPU-потоки для PLE-слоя и пакетных работ; соответствует 16 ядрам Strix Halo |
-ctk q8_0 -ctv q8_0 | q8_0 | Сжимает KV-кэш. Обязательно – по умолчанию (f16) префилл падает до ~70 t/s на глубине. q4_0 не даёт выигрыша в скорости и ниже по качеству |
--parallel | 1 | Обязательно. Кэш пула QSA однослотовый; >1 рассинхронизирует индексатор (upstream-баг). Один слот на сервер |
--no-warmup | – | Пропустить прогрев (экономит время загрузки) |
Мульти-модель / по требованию: запускайте роутер вместо одной фиксированной модели:
llama-server --models-preset presets.ini --models-max 2 --host 0.0.0.0 --port 1234и поместите флаги выше в секцию[qwen3.8-flash-next-q4_k_xl]вpresets.ini. Модели загружаются по требованию.
Мультимодальная поддержка (mmproj)
MM=/path/to/mmproj-BF16.gguf
# add to the launch command:
--mmproj ${MM} \Расширенный запуск (спекулятивное декодирование MTP)
MTP использует отдельный черновик с общими головами (mtp-...-shared-Q8_0.gguf) для предсказания нескольких токенов за шаг. На этой машине даёт +33% к декодированию (25.4 → 33.9 ток/с на глубине ~4k) по сравнению с запуском без MTP.
Добавьте к команде базового запуска:
MTP=/path/to/mtp-Qwen3.8-Flash-Next-shared-Q8_0.gguf
--spec-type draft-mtp \
--spec-draft-model ${MTP} \
--spec-draft-n-max 3 \Параметры MTP
| Параметр | Значение | Почему |
|---|---|---|
--spec-type | draft-mtp | Спекулятивное декодирование MTP |
--spec-draft-model | общий Q8_0 | Файл общих MTP-голов (загружается как драфтер) |
--spec-draft-n-max | 3 | До 3 черновых токенов за шаг. Тестировали 3 vs 5 – 5 в пределах шума (33.9 vs 34.7 ток/с), но добавляет накладные расходы на восстановление чекпоинтов. 3 – безопасное значение по умолчанию |
MTP в v0.7.5 использует контекстные чекпоинты (≈112 MB × 48 слоёв на отклонённый раунд). Здесь это чистый выигрыш, но если увидите уход в минус, уменьшите
--spec-draft-n-maxдо 1 или отключите MTP.
Производительность
Замерено (strix-halo-llamacpp v0.7.5, входящая в поставку Mesa 26.3)
Глубина 32768, Q4_K_XL, llama-bench (без MTP):
| Метрика | Значение |
|---|---|
| Обработка промпта (pp512 @ 32k) | ~320 ток/с |
| Декодирование (tg32 @ 32k, без MTP) | ~23.5 ток/с |
| Декодирование (MTP n-max=3) | ~30–34 ток/с (зависит от глубины) |
против стока pr28243 (те же флаги): 15–17 ток/с декодирование, ~216–300 ток/с PP.
Бэкенд HIP / ROCm (альтернатива)
Сборка на Vulkan выше – самый безопасный выбор, но сборка на HIP/ROCm – сильная альтернатива на этой машине. pwilkin/llama.cpp @ strix-halo (b0f31f58, 2026-09-16) собирается против стокового ROCm 10 с собственной парой ROCr/HIP с retained-PM4 (pwilkin/rocm-systems @ ilintar-experiments), которая подставляется во время выполнения через LD_LIBRARY_PATH. Она содержит оба исправления: кэш пула QSA и GPU TOP_K, и показывает ~1.7× быстрее на префилле при паритете декодирования (без MTP).
A/B (Q4_K_XL, глубина 32k, одинаковые флаги)
| тест | HIP (retained-PM4) | Vulkan (v0.7.5) | отношение |
|---|---|---|---|
| pp512 @ 32k | ~540 t/s | 326.97 t/s | ~1.7× |
| tg8 @ 32k (без MTP) | 22.07 t/s | 22.46 t/s | 0.98× |
С MTP (--spec-type draft-mtp, общая Q8_0 голова) декодирование достигает ~43 ток/с (замерено, при контексте ≤2k) – против ~34 ток/с у сборки на Vulkan на глубине 4k; на 8k с реальными кодинг-задачами сообщество сообщает о ~47 ток/с (#27950). Исправление GPU TOP_K (hipCUB / radix, #26592 / #27466) удерживает ggml_top_k индексатора QSA на GPU при ne>1024, тогда как сток HIP откатывается на CPU и декодирование обваливается (перелом – на d1024).
Отличия от сборки на Vulkan
| Аспект | Vulkan (v0.7.5) | HIP (strix-halo) |
|---|---|---|
| Тип KV-кэша | q8_0 (быстрый, маленький) | нужен f16 – q8_0 упирается в GGML_ASSERT в qwen4exp |
| Исправление обвала на глубине | кэш пула QSA #28012 | кэш пула QSA + GPU TOP_K (hipCUB/radix) |
| Префилл @ 32k | ~327 t/s | ~540 t/s |
| Рантайм | входящая Mesa 26.3 RADV | retained-PM4 ROCr/HIP через LD_LIBRARY_PATH |
Сборка (Docker, gfx1151)
Автономный стек (Dockerfile + docker-compose.yaml + build.sh + fetch-sources.sh + .env) компилирует три компонента – ROCr → HIP (clr) → llama.cpp – для gfx1151, затем раздаёт и бенчмаркает с пробросом ROCm GPU. Ключевая идея: llama.cpp компилируется против стокового /opt/rocm; пара ROCr/HIP с retained-PM4 собирается отдельно и подставляется во время выполнения через LD_LIBRARY_PATH.
Dockerfile
ARG BASE_IMAGE=rocm/dev-ubuntu-24.04:10.0.0-full
FROM ${BASE_IMAGE}
# build deps — note the non-obvious ones: xxd (ROCk HSACO->ASCII),
# libgl-dev (clr OpenGL), libelf-dev (ROCk), CppHeaderParser (clr hipamd)
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential cmake ninja-build git pkg-config ccache python3 python3-pip \
xxd perl libdrm-dev libnuma-dev libelf-dev libdwarf-dev \
libgl-dev libegl-dev libglu1-mesa-dev libopenmpi-dev libssl-dev \
&& rm -rf /var/lib/apt/lists/*
RUN pip3 install --break-system-packages --no-cache-dir CppHeaderParser
WORKDIR /work
COPY fetch-sources.sh build.sh ./
RUN ./fetch-sources.sh # clone the two repos at pinned commits (see .env)
RUN ./build.sh # ~1h: ROCr -> HIP(clr) -> llama.cpp (GGML_HIP, gfx1151)
# custom ROCk/HIP (retained-PM4) FIRST so they shadow stock /opt/rocm at load
ENV LD_LIBRARY_PATH=/work/runtime/hip/lib:/work/runtime/rocr/lib:/opt/rocm/lib:/opt/rocm/lib64:/opt/rocm/lib/llvm/lib:/work/build/llama.cpp/bin \
HSA_OVERRIDE_GFX_VERSION=11.5.1 ENABLE_RETAINED_PM4=1 HSA_ENABLE_SDMA=0
ENV PATH=/work/build/llama.cpp/bin:${PATH}build.sh (три компонента)
# 1/3 ROCk (retained-PM4 HSA runtime)
cmake -S src/rocm-systems/projects/rocr-runtime -B build/rocr -G Ninja \
-DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=$RUNTIME/rocr
cmake --build build/rocr -j$(nproc) && cmake --install build/rocr
# 2/3 HIP/clr (retained-PM4). HIP_COMMON_DIR must be the HIP *source* tree
# (has include/hip + cmake + *.cmake.in); stock /opt/rocm lacks the .in templates.
HIP_COMMON_DIR=$SRC/rocm-systems/projects/hip
cmake -S src/rocm-systems/projects/clr -B build/hip -G Ninja \
-DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DCLR_BUILD_HIP=ON -DCLR_BUILD_OCL=OFF \
-DROCM_PATH=$RUNTIME/rocr -DCMAKE_PREFIX_PATH=$RUNTIME/rocr;/opt/rocm \
-DHIP_COMMON_DIR=$HIP_COMMON_DIR -DHIP_PLATFORM=amd \
-DLLVM_BIN=/opt/rocm/lib/llvm/bin -DClang_BIN=/opt/rocm/lib/llvm/bin \
-DCMAKE_INSTALL_PREFIX=$RUNTIME/hip
cmake --build build/hip -j$(nproc) && cmake --install build/hip
# 3/3 llama.cpp (GGML_HIP, gfx1151) — against stock /opt/rocm
cmake -S src/llama.cpp -B build/llama.cpp -G Ninja \
-DCMAKE_BUILD_TYPE=Release -DGGML_HIP=ON -DGGML_HIP_NO_VMM=ON -DGGML_HIP_GRAPHS=ON \
-DGGML_HIP_MMQ_MFMA=ON -DGGML_CUDA_FA=ON -DGGML_NATIVE=ON -DGGML_OPENMP=ON \
-DGPU_TARGETS=gfx1151 -DCMAKE_HIP_COMPILER=/opt/rocm/lib/llvm/bin/clang++
cmake --build build/llama.cpp -j$(nproc)docker-compose.yaml (проброс ROCm GPU + сервер)
x-rocm-gpu: &rocm-gpu
devices: ["/dev/kfd", "/dev/dri"] # ROCm = raw KFD + DRM nodes
security_opt: ["seccomp:unconfined"]
environment:
- HSA_OVERRIDE_GFX_VERSION=11.5.1
- ENABLE_RETAINED_PM4=1
- HSA_ENABLE_SDMA=0
volumes: ["/mnt/local/models:/mnt/local/models:ro"]
services:
server:
build: .
image: strix-pwilkin:gfx1151
<<: *rocm-gpu
ports: ["${SERVER_PORT:-1234}:1234"]
command: >
llama-server
-m $MODEL -md $MTP_DRAFT --mmproj $MM_PROJ
--spec-type draft-mtp --spec-draft-n-max 3
-ngl 999 -fa on -ctk f16 -ctv f16
-t 16 -tb 32 -b 2048 -ub 1024
-c ${CTX:-262144}
--cache-ram 24576 --cache-reuse 1024
--host 0.0.0.0 --port 1234 --jinja
restart: unless-stopped
bench:
image: strix-pwilkin:gfx1151
<<: *rocm-gpu
command: >
llama-bench -m $MODEL -ngl 999 -fa on -p 512 -n 8 -d 32768
-b 2048 -ub 1024 -ctk f16 -ctv f16 -t 16 -r 3
profiles: ["bench"].env (зафиксированные коммиты + модель + ctx)
LLAMA_GIT_SHA=b0f31f5876ef3856b55f5bb88072cc96e5effafe # pwilkin/llama.cpp@strix-halo
ROCM_SYSTEMS_GIT_SHA=7dda3ac6cfe6bbe0b7f08c23a67cfa118d8641a1 # pwilkin/rocm-systems@ilintar-experiments
GPU_TARGETS=gfx1151
CTX=262144
SERVER_PORT=1234
MM_PROJ=/mnt/local/models/.../Qwen3.8-Flash-Next-GGUF/mmproj-BF16.gguf # vision projectorЗапуск
cd strix-pwilkin/
docker compose build # ~1h; bakes /work/build/llama.cpp/bin + /work/runtime/{rocr,hip}
docker compose up -d server # serve: ctx 262144, MTP on, f16 KV, prompt cache, port 1234
docker compose run --rm bench # plain-decode A/B (llama-bench can't see draft flags)Флаги запуска – набор из базового запуска, кроме: используйте -ctk f16 -ctv f16 (не q8_0). --cache-ram 24576 --cache-reuse 1024 включают внутрипроцессный кэш промптов со сдвигом KV; учтите, что f16 KV помещает примерно вдвое меньше токенов, чем q8_0, при том же бюджете RAM, поэтому увеличьте --cache-ram, если переиспользование префиксов критично. --mmproj включает vision, но llama.cpp отключает cache_reuse при загрузке мультимодальной модели (сдвиг KV несовместим с токенами изображений) – так что с --mmproj кэш промптов для повторяющихся префиксов всё ещё работает, но переиспользование со сдвигом KV выключено.
Для других задач
Шаблон включает режим размышления (thinking mode). Выделяйте достаточно max_tokens, чтобы модель завершила рассуждение перед финальным ответом.
Агентные / кодинг-задачи (детерминированные)
--temp 0.3 --top-p 0.5 --top-k 5Творческие тексты
--temp 1.0 --top-p 0.95 --top-k 40Известные проблемы
- Обычный
llama.cppнепригоден на глубине – индексатор QSA заново пулит кэш блочных ключей O(n_kv)/токен. Используйтеstrix-halo-llamacppv0.7.5+ (или сборку с исправлением кэша пула QSA). Это подвох №1. --parallel 1обязателен – кэш пула QSA однослотовый; несколько слотов рассинхронизируют индексатор. Запускайте один сервер на модель (или роутер с одним слотом на каждую).- Тип KV-кэша – по умолчанию (f16) префилл падает до ~70 ток/с при увеличении. Всегда ставьте
-ctk q8_0 -ctv q8_0. - Чат-шаблон обязателен – используйте chat_template.jinja v21.3; шаблон по умолчанию может ломать вызовы инструментов / зацикливания.
- Файлы сохранения слотов привязаны к версии – V-кэш индексатора в v0.7.5 имеет ширину 1 элемент; файлы сохранений из других сборок не восстановятся. Внутрипроцессный кэш промптов не затронут.
- Входящий в поставку драйвер – сборка поставляется с Mesa 26.3.0-devel. Используйте обёртку
_runили задайтеVK_ICD_FILENAMES/LD_LIBRARY_PATH(см. «Получение сборки»); хостовый драйвер (Mesa 26.1) ~7% медленнее на префилле. --prio 2может напечататьPermission denied, если процесс не может установить nice – безвредно, сервер работает со стандартным приоритетом.
Ссылки
- strix-halo-llamacpp – сборка на Vulkan с исправлением кэша пула QSA
- pwilkin/llama.cpp @ strix-halo – сборка HIP/ROCm (retained-PM4, кэш пула QSA + исправление GPU TOP_K)
- pwilkin/rocm-systems @ ilintar-experiments – пара retained-PM4 ROCr/HIP, подставляемая во время выполнения
- Qwen3.8-Flash-Next GGUF (unsloth) – Q4_K_XL, IQ4_XS, общие MTP-головы, mmproj
- upstream issue #28012 – перепулинг индексатора QSA (узкое место декодирования)
- chat_template.jinja v21.3
- llama-bench
- Оптимальные настройки llama.cpp + Qwen3.6 на Strix Halo – рецепт для плотной 27B-модели (дополнение)