Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ that share the [Qwen3.5/3.8 executor](../src/models/qwen3_5/native/), which acce
single prompts and bounded packed prefill. Cua-S1 and Open-Jev-9B use
single-prompt calls; Open-Jev-27B-v1.1 packs candidates within one request for
input and gate/up GEMMs while preserving per-sequence mixers and output/down GEMM
shapes.
shapes. The executor can also run prompts that share token prefixes, each prefix
once (below); no worker uses that yet.
[Laya's native worker](../src/models/laya/README.md)
uses a separate Hopper CUDA backend for one complete padded request. All three
coordinate independent processors and executors through
Expand All @@ -32,6 +33,24 @@ Graph captures Encoder/Decision; gather, scorer/action head and synchronized
readback remain outside capture. Native Metal remains planned; Python workers
retain their documented reference/serving roles.

The Qwen executor's `forward_shared` takes a request prefix, group prefixes and
branches, ends each prefix at its last multiple of 64 tokens, and returns one final
hidden state per branch in order
([#85](https://github.com/ThinkFlowLab/system1-omni/issues/85)). It runs on the
prefix continuation that JEV-VL's cache uses: each prefix is captured once (per
linear-attention layer the float32 recurrent state and the last three conv inputs,
per full-attention layer the prefix keys and values), and each branch then runs as
its own pass from that state. The two prefix states persist across calls and grow only for a
longer prefix; their contents are valid only within one call, which runs eagerly and
synchronizes its stream before returning, also on error. Its GEMMs keep one
algorithm per weight shape, so on GPUs where that keeps rows independent of M
(checked by `fixed_gemm_rows_do_not_depend_on_m`, so far on sm_89) each result equals
`forward_fixed` on the full prompt bit for bit; it differs from `forward` by
rounding. Both take merged weights with the default numerics only, and refuse an
unmerged adapter, reference numerics or FP32 GDN before any device work. Each
prefix state takes about 50 MiB on Qwen3.5-4B and 9B, plus 32 KiB per position of
its prefix rounded up to 1,024 positions, and the GEMM handle a 32 MiB workspace.

## Native worker boundaries

The native workers separate `processing.rs` from `executor.rs`; their worker
Expand Down
5 changes: 4 additions & 1 deletion src/backends/cuda/qwen3_5/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ entry points. Open-Jev uses this path within requests; Cua-S1 keeps single-promp

Prefix continuation retains full-attention KV, three convolution input rows,
and FP32 Gated DeltaNet state at 64-token chunk boundaries. It is used by the
experimental JEV-VL worker; existing full-prefill callers keep their own paths.
experimental JEV-VL worker and by the shared executor's `forward_shared`, which
runs prompts that share prefixes once per prefix with the fixed-algorithm GEMM
handle ([#85](https://github.com/ThinkFlowLab/system1-omni/issues/85)); existing
full-prefill callers keep their own paths.
ABI 6 adds mandatory copy and prefix entry points after ABI 5 native vision,
and ABI 9 adds the fixed-algorithm GEMM handle.
Rebuild the library and **all** Qwen worker binaries together; older libraries
Expand Down
4 changes: 4 additions & 0 deletions src/models/qwen3_5/native/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@ path = "../../../../tests/qwen3_5/kernels.rs"
[[test]]
name = "device_features"
path = "../../../../tests/qwen3_5/device_features.rs"

[[test]]
name = "prefix"
path = "../../../../tests/qwen3_5/prefix.rs"
Loading
Loading