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
5 changes: 3 additions & 2 deletions .github/script/ci/changes.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,11 @@
("qwen3_8mtp", "qwen3_8_mtp"): ("qwen3.8-mtp",),
("gemma", "gemma3"): ("gemma3",),
("gemma_text", "gemma3_text"): ("gemma3-text",),
# Gemma4e_Flash and Gemma4e_DFlash derive from Gemma4e and their engines include gemma4e_npu.
("gemma4e",): ("gemma4e", "gemma4e-flash", "gemma4e-dflash"),
# Gemma4e_Flash, Gemma4e_DFlash and Gemma4e_DFlash_Flash derive from Gemma4e and their engines include gemma4e_npu.
("gemma4e",): ("gemma4e", "gemma4e-flash", "gemma4e-dflash", "gemma4e-dflash-flash"),
("gemma4e_flash",): ("gemma4e-flash",),
("gemma4e_dflash",): ("gemma4e-dflash",),
("gemma4e_dflash_flash",): ("gemma4e-dflash-flash",),
("gemma4_12b",): ("gemma4-12b",),
("hunyuan",): ("hunyuan",),
("gpt_oss",): ("gpt-oss",),
Expand Down
1 change: 1 addition & 0 deletions .github/script/npu_test/plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"gemma4e": "gemma4-it:e2b",
"gemma4-12b": "gemma4-it:12b",
"gemma4e-flash": "gemma4e-flash:e2b",
"gemma4e-dflash-flash": None, # same 9 GB nemotron3.5-bolt:e4b package; runs when the change touches it
"gemma4e-dflash": None, # needs the 9 GB nemotron3.5-bolt:e4b package; runs when the change touches it
"qwen3.5": "qwen3.5:0.8b",
"minicpm-v-4.7": "minicpm-v-4.7:1b",
Expand Down
5 changes: 5 additions & 0 deletions docs/docs/benchmarks/flash_results.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ AMD Ryzen™ AI 9 370 (Strix Point) with 32 GB DRAM; performance is comparable t
|-------------------------|-----------|-------:|--------:|--------:|--------:|---------:|
| **gemma4e-flash:e2b** | XDNA2 | 0.20 | 0.22 | 0.36 | 0.73 | 1.53 |
| **gemma4e-flash:e4b** | XDNA2 | 0.33 | 0.34 | 0.62 | 1.20 | 2.57 |
| **nemotron3.5-bolt-dflash-flash:e4b** | XDNA2 | 0.32 | 0.33 | 0.60 | 1.18 | 2.53 |
| **qwen3vl-flash:4b** | XDNA2 | 0.24 | 0.24 | 0.45 | 0.85 | 1.83 |
| **hy-mt2-flash:1.8b** | XDNA2 | 0.13 | 0.14 | 0.23 | 0.43 | 0.84 |

Expand All @@ -44,6 +45,7 @@ Prompt tokens divided by TTFT (TTFT includes generating the first token).
|-------------------------|-----------|-------:|--------:|--------:|--------:|---------:|
| **gemma4e-flash:e2b** | XDNA2 | 322 | 593 | 721 | 705 | 668 |
| **gemma4e-flash:e4b** | XDNA2 | 193 | 373 | 412 | 427 | 398 |
| **nemotron3.5-bolt-dflash-flash:e4b** | XDNA2 | 201 | 392 | 427 | 434 | 405 |
| **qwen3vl-flash:4b** | XDNA2 | 271 | 526 | 570 | 601 | 558 |
| **hy-mt2-flash:1.8b** | XDNA2 | 490 | 923 | 1,093 | 1,197 | 1,214 |

Expand All @@ -55,7 +57,10 @@ Prompt tokens divided by TTFT (TTFT includes generating the first token).
|-------------------------|-----------|-------:|------------|
| **gemma4e-flash:e2b** | XDNA2 | 22.6 | [Gemma 4](../gemma4_results/) (`gemma4-it:e2b`) |
| **gemma4e-flash:e4b** | XDNA2 | 12.6 | [Gemma 4](../gemma4_results/) (`gemma4-it:e4b`) |
| **nemotron3.5-bolt-dflash-flash:e4b** | XDNA2 | 18.2 | [Nemotron Bolt DFlash](../nemotron3.5-bolt-dflash_results/) (`nemotron3.5-bolt-dflash:e4b`) |
| **qwen3vl-flash:4b** | XDNA2 | 19.6 | [Qwen3](../qwen3_results/) (Qwen 3 4B) |
| **hy-mt2-flash:1.8b** | XDNA2 | 52.2 | [Hy-MT2](../hy-mt2_results/) |

> Context is fixed at 1k tokens for every flash model, so 1k is the only applicable decode starting point.
>
> `nemotron3.5-bolt-dflash-flash:e4b` decodes with speculation, so its speed depends on the text: the value above is `flm bench` (about 30 decoded tokens, mean of 3 runs, 15 to 24 tokens/s between runs). Code and structured answers reach 33 to 40 tokens/s, open prose about 20 (see its [model card](../../models/nemotron3.5-bolt-dflash/#-model-card-nvidia-nemotron-35-bolt-e4b--dflash-flash)). The three rows of this model were measured on an AMD Ryzen™ AI MAX+ PRO 395 (Strix Halo) with the same method; on that machine `gemma4e-flash:e4b` gives 0.32 / 0.32 / 0.58 / 1.17 / 2.52 s.
6 changes: 3 additions & 3 deletions docs/docs/instructions/server/openapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ gc.collect()

## ⚡ Example: Flash Models (Single-Turn, Pinned System Prompt)

**Flash** models — `gemma4e-flash:e2b`, `gemma4e-flash:e4b`, `qwen3vl-flash:4b`, and `hy-mt2-flash:1.8b` — trade context length for a much faster time-to-first-token. They are built for high-throughput, short, independent requests: classification, captioning, extraction, routing, translation.
**Flash** models — `gemma4e-flash:e2b`, `gemma4e-flash:e4b`, `nemotron3.5-bolt-dflash-flash:e4b`, `qwen3vl-flash:4b`, and `hy-mt2-flash:1.8b` — trade context length for a much faster time-to-first-token. They are built for high-throughput, short, independent requests: classification, captioning, extraction, routing, translation.

They are **single-turn**: every request starts from a clean KV state, so earlier turns are not carried over. The system prompt is the one exception — it is prefilled once and cached, so keep it fixed and vary only the user message (and, for vision models, the image).

Expand Down Expand Up @@ -571,6 +571,6 @@ gc.collect()
> 📏 Context is **fixed at 1k tokens** for every flash model; context-length overrides are ignored.
> 🔧 **Tool calling is not supported** — any `tools` you pass are dropped.
> 🌐 `hy-mt2-flash` is text-only and has no default system prompt — pin your own translation instruction as the system prompt, or put it in the user message.
> 🖼️ `gemma4e-flash` defaults to the smallest visual token budget (70) and keeps only the **first 30 seconds** of an audio clip. `qwen3vl-flash` always downscales images to a **256 px longer side**.
> 🖼️ `gemma4e-flash` and `nemotron3.5-bolt-dflash-flash` default to the smallest visual token budget (70) and keeps only the **first 30 seconds** of an audio clip. `qwen3vl-flash` always downscales images to a **256 px longer side**.

For the full per-model details, see the [`gemma4e-flash:e2b`](https://fastflowlm.com/docs/models/gemma/#-model-card-gemma-4-e2b-it--flash), [`gemma4e-flash:e4b`](https://fastflowlm.com/docs/models/gemma/#-model-card-gemma-4-e4b-it--flash), [`qwen3vl-flash:4b`](https://fastflowlm.com/docs/models/qwen/#-model-card-qwen3-vl-4b-instruct--flash), and [`hy-mt2-flash:1.8b`](https://fastflowlm.com/docs/models/hy-mt2/) model cards. Performance numbers are on the [Flash benchmarks](https://fastflowlm.com/docs/benchmarks/flash_results/) page.
For the full per-model details, see the [`gemma4e-flash:e2b`](https://fastflowlm.com/docs/models/gemma/#-model-card-gemma-4-e2b-it--flash), [`gemma4e-flash:e4b`](https://fastflowlm.com/docs/models/gemma/#-model-card-gemma-4-e4b-it--flash), [`nemotron3.5-bolt-dflash-flash:e4b`](https://fastflowlm.com/docs/models/nemotron3.5-bolt-dflash/#-model-card-nvidia-nemotron-35-bolt-e4b--dflash-flash), [`qwen3vl-flash:4b`](https://fastflowlm.com/docs/models/qwen/#-model-card-qwen3-vl-4b-instruct--flash), and [`hy-mt2-flash:1.8b`](https://fastflowlm.com/docs/models/hy-mt2/) model cards. Performance numbers are on the [Flash benchmarks](https://fastflowlm.com/docs/benchmarks/flash_results/) page.
2 changes: 1 addition & 1 deletion docs/docs/instructions/server/prefix_cache.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ The other supported models gain the same way. Measured on shorter prompts (about
| Endpoint | `POST /v1/chat/completions` of `flm serve` (what Hermes, Open WebUI and most agents use), streaming or not |
| Not covered | `flm run` (CLI mode) and the Ollama endpoints `/api/chat` and `/api/generate`, which keep the older single-checkpoint reuse. A request on an Ollama endpoint also empties the prefix cache, so a client that mixes both APIs loses its cached prompts. |

Not covered: the single-turn models (`hy-mt2-flash`, `qwen3vl-flash`, `gemma4e-flash`: they take one request and pin their system prompt, so there is nothing to reuse), the developer-preview `*-core` backends, `lfm3`, and the speech, embedding and robotics models. They are unchanged.
Not covered: the single-turn models (`hy-mt2-flash`, `qwen3vl-flash`, `gemma4e-flash`, `nemotron3.5-bolt-dflash-flash`: they take one request and pin their system prompt, so there is nothing to reuse), the developer-preview `*-core` backends, `lfm3`, and the speech, embedding and robotics models. They are unchanged.

It is on by default. Nothing to configure for a single chat or agent.

Expand Down
4 changes: 2 additions & 2 deletions docs/docs/instructions/server/request_parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ A request that sends no sampling fields uses the model's own defaults, which dif
| Models | `presence_penalty` at load |
|---|---|
| `qwen3.5:*`, `qwen3.5-core:*`, `qwen3.6-moe:35b-a3b`, `qwen3.6-moe-core:35b-a3b`, `qwen3.8-mtp:27b`, `minicpm-v-4.7:1b` | 1.5 |
| `gemma4-it:*`, `gemma4-it-core:*`, `gemma4e-flash:*`, `nemotron3.5-bolt:e4b` | 1.0 |
| `gemma4-it:*`, `gemma4-it-core:*`, `gemma4e-flash:*`, `nemotron3.5-bolt:e4b`, `nemotron3.5-bolt-dflash:e4b`, `nemotron3.5-bolt-dflash-flash:e4b` | 1.0 |
| every other model | 0 |

Sending `presence_penalty=0` turns the default off, and it stays off until the model is reloaded (see *Settings stick* above).
Expand Down Expand Up @@ -260,7 +260,7 @@ Before generating, FLM reads the prompt into the model's KV cache. This is the *

| Models | `max_prefill_len` |
|---|---|
| Flash models (`gemma4e-flash:*`, `qwen3vl-flash:4b`, `hy-mt2-flash:1.8b`) | 1024 |
| Flash models (`gemma4e-flash:*`, `nemotron3.5-bolt-dflash-flash:e4b`, `qwen3vl-flash:4b`, `hy-mt2-flash:1.8b`) | 1024 |
| Every other chat model | 4096 |

**`max_prefill_len` is not a limit on the prompt.** A longer prompt just takes more chunks. A 32,000-token prompt on a model with 4096-token chunks is read in eight passes, seven of 4096 tokens and one of 3,328, and the server log shows each one:
Expand Down
1 change: 1 addition & 0 deletions docs/docs/models/flash.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ parent: Models
|---------------|----------|----------------|
| `gemma4e-flash:e2b` | Any-to-Text (image, audio) | [Gemma 4 E2B — Flash](https://fastflowlm.com/docs/models/gemma/#-model-card-gemma-4-e2b-it--flash) |
| `gemma4e-flash:e4b` | Any-to-Text (image, audio) | [Gemma 4 E4B — Flash](https://fastflowlm.com/docs/models/gemma/#-model-card-gemma-4-e4b-it--flash) |
| `nemotron3.5-bolt-dflash-flash:e4b` | Any-to-Text (image, audio), speculative decoding | [Nemotron Bolt E4B — DFlash Flash](https://fastflowlm.com/docs/models/nemotron3.5-bolt-dflash/#-model-card-nvidia-nemotron-35-bolt-e4b--dflash-flash) |
| `qwen3vl-flash:4b` | Image-Text-to-Text | [Qwen3-VL-4B — Flash](https://fastflowlm.com/docs/models/qwen/#-model-card-qwen3-vl-4b-instruct--flash) |
| `hy-mt2-flash:1.8b` | Text-to-Text (Translation) | [Hy-MT2](https://fastflowlm.com/docs/models/hy-mt2/) |

Expand Down
58 changes: 58 additions & 0 deletions docs/docs/models/nemotron3.5-bolt-dflash.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,61 @@ Expected: `1, 2, 3, ..., 40` followed by `done`, at a visibly higher speed than
- Speculation pauses while a tool-call or JSON grammar constrains the output, and whenever it would not be faster (for example at very
long contexts); it resumes by itself.
- `flm remove nemotron3.5-bolt-dflash:e4b` removes only the draft package; `nemotron3.5-bolt:e4b` stays installed.

---

## 🧩 Model Card: [NVIDIA-Nemotron-3.5-Bolt-E4B — DFlash Flash](https://huggingface.co/nvidia/NVIDIA-Nemotron-3.5-Bolt-E4B-4GB)

- **Type:** Any-to-Text (image, audio), single-turn, with speculative decoding
- **What it is:** [`nemotron3.5-bolt-dflash:e4b`](#-model-card-nvidia-nemotron-35-bolt-e4b-with-the-dflash-draft) built for the
[Flash](https://fastflowlm.com/docs/models/flash/) serving style: the fast short-prompt prefill of `gemma4e-flash:e4b` together with
DFlash speculative decoding. Every request starts from a clean state; the system prompt is pinned and reused
([how flash models work in server mode](https://fastflowlm.com/docs/instructions/server/openapi/#-example-flash-models-single-turn-pinned-system-prompt))
- **Time to first token:** the same as `gemma4e-flash:e4b`, about 0.3 s for a short prompt, against 1.2 s for `nemotron3.5-bolt-dflash:e4b`
- **Decode speed:** 33 to 40 tokens/s on code and structured answers, 19 to 21 tokens/s on open prose, against 13 for `gemma4e-flash:e4b`
- **Think / Conversational mode / Vision / Audio:** as `nemotron3.5-bolt:e4b`. Tool calling is not supported (the `tools` field is dropped).
Images default to the smallest visual token budget (70) and only the first 30 seconds of an audio clip are used
- **Packages:** the same two downloads as `nemotron3.5-bolt-dflash:e4b` (`Nemotron-3.5-Bolt-E4B-NPU2`, about 9 GB, and the 0.27 GB draft
`Nemotron-3.5-Bolt-E4B-DFlash-NPU2`). Nothing new to download if you already have that tag
- **Max / Default Context Length:** 1k tokens (fixed, like every flash model)
- **License:** [OpenMDW-1.1](https://openmdw.ai/license/1-1/)
- **FastFlowLM:** 1.0.13 or later

▶️ Run with FastFlowLM in PowerShell:

```shell
flm run nemotron3.5-bolt-dflash-flash:e4b
```

Server mode:

```shell
flm serve nemotron3.5-bolt-dflash-flash:e4b
```

📊 **Measured** (greedy, 18-token pinned system prompt, NPU, quiet machine):

| Prompt length | `gemma4e-flash:e4b` | `nemotron3.5-bolt-dflash:e4b` | `nemotron3.5-bolt-dflash-flash:e4b` |
|---|---|---|---|
| ~50 tokens, time to first token | 0.31 s | 1.24 s | 0.32 s |
| ~140 tokens | 0.57 s | 1.24 s | 0.60 s |
| ~540 tokens | 1.48 s | 1.84 s | 1.49 s |
| ~960 tokens | 2.51 s | 2.15 s | 2.52 s |
| decode, code answer | 13 tokens/s | 38 to 40 tokens/s | 33 to 40 tokens/s |
| decode, prose answer | 13 tokens/s | 17 to 22 tokens/s | 19 to 21 tokens/s |

📝 **Note:**

- Flash prefill is tuned for short prompts: it is the faster choice up to a prompt of roughly 700 tokens. For longer prompts use
`nemotron3.5-bolt-dflash:e4b`, which also has a longer context.
- A long, fixed system prompt (instructions, examples) is where this tag gains most: it is prefilled once and the draft model sees it on
every request, which keeps the speculative steps long. Changing the system prompt between requests discards the pin.
- Sampling, `FLM_DFLASH=0` and the other behaviours of speculation are as on the [`nemotron3.5-bolt-dflash:e4b`](#-model-card-nvidia-nemotron-35-bolt-e4b-with-the-dflash-draft) card.
Greedy output can differ from `nemotron3.5-bolt:e4b` at near-ties.
- Accuracy (50-question samples, XRT and HRX give the same results): GSM8K 92%, the same as `nemotron3.5-bolt-dflash:e4b` and
`gemma4e-flash:e4b`. Document reading (DocVQA, ANLS) is 45, against 76 for `nemotron3.5-bolt-dflash:e4b`: flash models look at an image
with the smallest visual token budget (70 instead of 280), which is enough for captions and simple scenes but not for small text. For
documents and screenshots use `nemotron3.5-bolt-dflash:e4b`.
- Needs 9 of the NPU's 16 hardware contexts (vision and audio included), so other models can still be loaded next to it.
- `flm remove nemotron3.5-bolt-dflash-flash:e4b` removes only the draft package, shared with `nemotron3.5-bolt-dflash:e4b`: remove
both tags' use of it first if you want the space back.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ list(APPEND FLM_ENGINE_LINK_LIBS

list(APPEND FLM_ENGINE_LINK_LIBS gemma4e_flash)
list(APPEND FLM_ENGINE_LINK_LIBS gemma4e_dflash)
list(APPEND FLM_ENGINE_LINK_LIBS gemma4e_dflash_flash)

list(APPEND FLM_ENGINE_LINK_LIBS
gemma4_12b_npu
Expand Down
1 change: 1 addition & 0 deletions src/common/AutoModel/builtin_backends.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ void register_builtin_backends(BackendRegistry& registry) {
RegisterFlm<gemma4e_npu>(registry, "gemma4e");
RegisterFlm<gemma4e_flash>(registry, "gemma4e-flash");
RegisterFlm<gemma4e_dflash>(registry, "gemma4e-dflash");
RegisterFlm<gemma4e_dflash_flash>(registry, "gemma4e-dflash-flash");
RegisterFlm<gemma4_12b_npu>(registry, "gemma4-12b");
RegisterFlm<hunyuan_npu>(registry, "hunyuan");
RegisterFlm<gpt_oss_npu>(registry, "gpt-oss");
Expand Down
4 changes: 3 additions & 1 deletion src/common/AutoModel/modeling_gemma4e.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,9 @@ bool Gemma4e::insert(chat_meta_info_t& meta_info, lm_uniform_input_t& input, std
? this->_shared_insert(meta_info, tokens, is_cancelled, &multi_modal_payload, last_image_token_index)
: this->_shared_insert(meta_info, tokens, is_cancelled, nullptr);

if (this->enable_think) {
// Single-turn (flash): the only checkpoint is the pinned system prefix, which Gemma4e_Flash owns. Taking this one would
// overwrite it with the whole first prompt, and every later request would restore into that stale context.
if (this->enable_think && !this->single_turn) {
checkpoint_his = token_history;
int checkpoint_idx = this->lm_engine->checkpoint();
}
Expand Down
Loading
Loading