Add TML Inkling architecture - #25731
danielhanchen wants to merge 26 commits into
Conversation
|
Hi @danielhanchen, thanks for your contribution! Per our contribution guidelines, the automated PR checker found the following issue(s) that need your attention:
Please note that maintainers reserve the right to make final decisions on PRs. If you believe there is a mistake, please comment below. |
d5f48c4 to
1cb0374
Compare
50cde5d to
a015409
Compare
Merge upstream PR ggml-org#25731: TML Inkling architecture (+ upstream master sync)
4d8798a to
f47a88c
Compare
Hybrid attention model: 55 sliding-window plus 11 global layers, banded content-dependent relative position bias instead of RoPE, per-layer short convolution state, fine-grained MoE (256 experts top-6 plus 2 shared), attention log-scaling past 128K, 1M context. Includes the GGML_OP_FLASH_ATTN_EXT_BANDED operator (CPU and CUDA, fused into the MMA flash attention kernel with an fp16 accumulator overflow guard), HF to GGUF conversion, chat template with typed content block parsing (interleaved thinking, narration and tool calls), mmproj vision and audio support, and backend op tests at production shapes.
f47a88c to
ce16fff
Compare
|
First: thank you for day-0 support, and it works. We ran inkling UD-Q4_K_XL (587GB) fully resident across two cloud VMs (4x A100 80GB each, 8 total) split over the RPC backend on ordinary Ethernet, and output is coherent and correct (it first-shot passed our hardest structured Terraform generation task). Text only, audio/vision untested here. We also profiled it, and the data below may be useful for the "might need to redesign some parts later" list. Decode runs at roughly 25 percent of what the hardware gives comparable MoEs, and the evidence points at per-token graph rebuild and launch overhead, not compute. Numbers (all this PR at ce16fff, same boxes, sustained single-stream, ctx 8192)
Decode is flat from empty context to 2.2k depth (6.2 to 6.6), so it is not KV/attention scaling. Single box, inkling runs at ~80 percent of the comparable resident MoE. Over RPC it drops to ~27 percent. Where the time goesPer token at 6.45 t/s = 155 ms. During decode:
perf record on llama-server during decode gives a maximally flat profile: 1,783 distinct symbols, top entry 3.5 percent. Named entries in the top 20: cudaStreamSynchronize / ggml_backend_cuda_synchronize, pthread_mutex_lock under cuLaunchKernel, ggml_backend_sched_split_graph, ggml_gallocr_alloc_graph, and ggml-rpc add_tensor + get_alloc_size (the whole graph re-serialized to the worker every token, which is the 5.5 MB). So the shape looks like: a ~9k-node graph rebuilt, re-split, re-allocated, re-serialized and launched node by node every token while the GPUs idle. Our guess is the banded rel-bias / shortconv path defeats the llama-side graph reuse, and the node count does the rest. If graph reuse engages for this arch, the RPC number should improve several-fold on its own. Happy to re-run any branch of this PR on the 2-node A100 cluster or the single box and report the same measurements. Full logs, perf.data and exact commands available on request. |
# Conflicts: # ggml/src/ggml-cuda/mmq.cuh # src/llama-model-saver.cpp # src/llama-vocab.h
…#39) Both pins pointed at commits that no longer merge onto the selected upstream base, so the nightly full release build failed while resolving the PR set. ggml-org#24523 was pinned to 66f43aa6, which was not even the PR head at the time (the resolver logged that the head had moved to 0b78558a). That commit conflicts in common/chat.cpp against both b10107 and b10133. The PR has since been rebased onto current master, so the pin now points at its new head a58a7fa6, which merges cleanly. ggml-org#25731 was pinned to ce16fff, which conflicts on its own in ggml/src/ggml-cuda/mmq.cuh, src/llama-model-saver.cpp and src/llama-vocab.h. This never surfaced in the log because the resolver stops at the first failing entry. Its current head 453c438 merges cleanly by itself. Note that ggml-org#24523 and ggml-org#25731 still conflict with each other in common/chat.cpp and src/llama-arch.h: both append a new llm_arch enum value immediately before LLM_ARCH_UNKNOWN and both add a chat parser in the same region. Reordering does not help, since whichever entry is applied second hits the same conflict. Resolving that needs a decision about which of the two to carry, so it is left alone here. Requires a base of b10133 or newer: b10107 predates the rename of common_chat_params::thinking_end_tag to thinking_end_tags, which the rebased ggml-org#24523 depends on. Co-authored-by: Daniel Han <unslothai@gmail.com>
|
Performance data on gfx1151 (Strix Halo, ROCm) — decode degrades linearly with context depth. Ran a depth sweep with Setup: AMD Ryzen AI Max+ 395 (gfx1151), 128 GB LPDDR5-8000, Ubuntu 26.04 (in-tree amdgpu), ROCm 7.14.0 in container, built from 1e6f9e4 with
The decode slope is constant — roughly 15.5 us of added latency per token of context: So it's O(n), not O(n^2) — but the constant seems high for this architecture. With Possibly Practical impact: a 19.8k-token prompt with ~2k output takes about 18.5 min end-to-end on this hardware. Two other notes for anyone testing on Strix Halo:
Happy to run additional configurations if useful. |
|
Three findings from testing on gfx1151 (Strix Halo, ROCm) that may be useful — in particular, the Setup: AMD Ryzen AI Max+ 395 (gfx1151), 128 GB LPDDR5-8000, Ubuntu 26.04 (in-tree amdgpu), ROCm 7.14.0 in a container, built from 1e6f9e4 with 1.
|
| test | -fa 1 | -fa 0 |
|---|---|---|
| tg32 | 20.96 | — |
| tg32 @ d4096 | 8.86 | — |
| tg32 @ d16384 | 3.36 | 13.85 |
| pp512 @ d16384 | 75.10 | 118.39 |
With FA on, the decode slope is roughly 15.5 us of added latency per token of context, and it is linear:
0 -> 4096 : +65.2 ms / 4096 = 15.9 us/token
4096 -> 16384 : +184.7 ms / 12288 = 15.0 us/token
So O(n), not O(n^2), but the constant looks high. With sliding_window = 512 on most layers I'd expect only the global layers to scale with depth. Rough estimate: even if all 42 layers read their full KV window each step, that's under 1 us/token at this memory bandwidth — so the cost looks compute-bound inside the banded bias rather than bandwidth-bound. Possibly GGML_OP_FLASH_ATTN_EXT_BANDED isn't using rel_extent_swa to bound per-layer work?
Real-world, 8421-token prompt via /v1/chat/completions:
-fa 1 : prompt 102.2 t/s, decode 5.36 t/s
-fa 0 : prompt 111.3 t/s, decode 16.04 t/s
3. But -fa 0 degrades output quality noticeably
This part is subjective, so treat it accordingly — but the difference was consistent and large enough to report.
Same 8421-token prompt, same seed-free sampler settings, same preset except flash-attn. Task: summarise a document into a structured factual account. With -fa 1 the output covered the central facts. With -fa 0 the same prompt produced output that:
- omitted five of the six key facts present in the input (including the one uncontested admission, the date of the event, and the named witness),
- was ~40% shorter in substance,
- in one run, invented a witness who does not appear in the input, along with a fabricated relationship and a paragraph of testimony,
- in the reasoning trace, hallucinated an input detail ("broken glass") that isn't in the prompt and then built the whole analysis around contradicting it.
I don't have a numerical benchmark for this — no perplexity runs — so it may be worth someone reproducing on CUDA before drawing conclusions. But if the non-FA path is numerically diverging rather than just being a different code path, that seems worth knowing, since -fa 0 is currently the only way to get usable decode speed at depth on this hardware.
Also, for anyone else testing on Strix Halo: --load-mode none (or --no-mmap) is required, otherwise loading stalls badly past ~64 GB — looks like #15018.
Happy to run additional configurations or provide full logs if useful.
Prebuilt: repin ggml-org#25731 and unslothai#70 onto post-squash heads
# Conflicts: # ggml/include/ggml-rpc.h # ggml/src/ggml-backend-meta.cpp # ggml/src/ggml-cuda/ggml-cuda.cu # src/llama-model-saver.cpp # tests/test-llama-archs.cpp
Prebuilt: repin ggml-org#24423 and ggml-org#25731 onto carry branches
# Conflicts: # src/llama-model.cpp
# Conflicts: # ggml/src/ggml-rpc/ggml-rpc.cpp
Resolves the two conflicts left by upstream ggml-org#27764 (chat parsers split into common/parsers) and ggml-org#26675 (ggml_prec rework): - common_chat_params_init_inkling moves to common/parsers/inkling.cpp, registered in parsers.h and sources.cmake; chat.cpp keeps only the template detection branch. - GGML_PREC_F32_PEDANTIC joins the new ranked ggml_prec scale at 5, below GGML_PREC_F32, since it is the stricter contract; ggml_flash_attn_ext_banded keeps its declaration next to the flash attention API.
…C_F32_PEDANTIC Every caller of the deprecated ggml_mul_mat_set_prec / ggml_flash_attn_ext_set_prec now uses ggml_prec_set_acc (the macOS prebuilt leg builds with LLAMA_FATAL_WARNINGS, so the deprecation would be fatal there), and ggml_prec_set_acc accepts GGML_OP_FLASH_ATTN_EXT_BANDED. With the enum ranked, the CUDA cuBLAS compute-type gate and the CPU, spacemit and Vulkan flash-attention accumulator checks compare by rank instead of equality with GGML_PREC_F32, so a pedantic request never falls through to a lower-precision path. The CUDA mul_mat_id slice carries the acc and src precision slots, and ggml_cuda_mul_mat_id_needs_sync applies the same pedantic gate as ggml_cuda_mul_mat_id so a pedantic F32 expert matmul cannot trip its assertion.
…master (#209) The nightly on b10865 (run 34287079907) stopped in resolve: the pinned commit no longer merged after upstream ggml-org#27764 moved the chat parsers into common/parsers and ggml-org#26675 reworked ggml_prec. The PR branch now carries a merge of upstream master with both conflicts resolved, so the mix merges again on b10865 and b10870 with only the usual additive add/add merges.
|
Heads up, #29042 makes the saver write the SWA pattern, so once it lands this architecture no longer needs to be excluded from llama_model_saver_supports_arch and can get the test-llama-archs roundtrip. |
Adds support for the Inkling architecture, a Python safetensors-to-GGUF converter, the graph build, and the kernel changes needed for correct and deterministic inference.
int64_ton some ops since large MoEs would go out of indexI tried to keep changes unbreaking - might need to redesign some parts later.
Used AI for kernels, but hand verified and checked everything carefully.