Skip to content

ggml-openvino: select the NPU token_embd type with GGML_OPENVINO_NPU_TOKEN_EMBD_QUANT - #359

Merged
ravi9 merged 2 commits into
ravi9:dev_backend_openvinofrom
yzhou51:gather
Oct 27, 2026
Merged

ravi9 merged 2 commits into
ravi9:dev_backend_openvinofrom
yzhou51:gather

Conversation

@yzhou51

@yzhou51 yzhou51 commented Oct 23, 2026

Copy link
Copy Markdown
  1. Optimize gather to fetch row before dequant
  2. add NPU token_embd quantization option

Overview

On NPU, a quantized token_embd is tied to the output projection. It was dequantized in full (about 1.3 GB in f16) on every token, and NPUW then passed the dequantized table between submodels. Decode was slower than with an F16 table.

We do an optimization GET_ROWS now gathers the rows of the quantized constants and their scales first, and dequantizes only those rows. Grouped and channel-wise int4/int8 layouts are handled, with or without zero points. Any other shape falls back to the plain Gather.

Additional information

Switch: GGML_OPENVINO_GATHER_BEFORE_DEQUANT is tri-state. When unset it is on for NPU and off elsewhere, a positive value forces it on, and 0 forces it off.

ggml-openvino-extra.cpp: a new NPU-only option, GGML_OPENVINO_NPU_TOKEN_EMBD_QUANT, with q4_0_128, q4_0_c, or F16 when unset. It applies to a Q6_K token_embd.weight and logs the chosen type once.

ggml-cpu base: llama-perplexity.exe -m Qwen_Qwen3.5-4B-Q4_0.gguf -f wiki.test.raw -c 512 --chunks 20 -dev none -ngl 0 --kl-divergence-base kld-base-wiki.text.raw.chunks20-512.bin
npu base: unset GGML_OPENVINO_GDN_PRESCALE, kld-wiki.text.raw.chunks20-512-base.log

  tg128 Mean KLD
F16 token_embd (default) 10.89 t/s 0.112
q4_0_128 + gather 18.5 t/s 0.128
q4_0_c + gather 18.8 t/s 0.151
q4_0_128 without gather 6.8 t/s  

With an F16 table the gather switch changes neither accuracy nor speed. So, we keep the GGML_OPENVINO_GATHER_BEFORE_DEQUANT on by default.

Requirements

  • I have read and agree with the contributing guidelines
    Yes, The minimal case passed.
  • AI usage disclosure:
    AI help analysis and profile.

@github-actions github-actions Bot added documentation Improvements or additions to documentation OpenVINO ggml labels Oct 23, 2026
@yzhou51

yzhou51 commented Oct 23, 2026

Copy link
Copy Markdown
Author

Hi @cavusmustafa @wine99 Can you help take a review for this? Thanks.

@ravi9
ravi9 force-pushed the dev_backend_openvino branch from c5cd082 to 947be59 Compare October 24, 2026 06:11
yzhou51 and others added 2 commits October 27, 2026 02:41
…table

1. Optimize gather to fetch row before dequant
2. add NPU token_embd quantization option
…TOKEN_EMBD_QUANT

GET_ROWS had two rewrites that gather the rows of a quantized table before
dequantizing them: gather_compressed_rows, which runs on every device, and
gather_before_dequant, enabled on NPU by GGML_OPENVINO_GATHER_BEFORE_DEQUANT.
Both match the int4 and int8 chains built by make_int4_weights() and
make_int8_weights(). Keep gather_compressed_rows and drop the second rewrite
and its switch.

The NPU type of a Q6_K token_embd.weight was set by two booleans,
GGML_OPENVINO_TOKEN_EMBD_I8 and GGML_OPENVINO_TOKEN_EMBD_I4, and by
GGML_OPENVINO_NPU_TOKEN_EMBD_QUANT. Keep only the string variable, with the
values f16 (default), q8_0_c, q4_0_128 and q4_0_c, so the int8 and group-128
int4 settings stay available. An unknown value aborts, as for
GGML_OPENVINO_NPU_REQUANT_POLICY, instead of silently using f16. The variable
replaces the two booleans in the NPU compiled-model cache key.
@ravi9

ravi9 commented Oct 26, 2026

Copy link
Copy Markdown
Owner

FYI: I've resolved the conflicts and am running some basic model validation. Will update this PR soon.

@ravi9
ravi9 force-pushed the dev_backend_openvino branch from 674af4a to 9e01c2f Compare October 26, 2026 21:41
@ravi9 ravi9 changed the title ggml-openvino: Gather rows before dequantizing a quantized embedding table ggml-openvino: select the NPU token_embd type with GGML_OPENVINO_NPU_TOKEN_EMBD_QUANT Oct 26, 2026
@ravi9

ravi9 commented Oct 26, 2026

Copy link
Copy Markdown
Owner

Rebased onto the updated dev_backend_openvino. dev already gathers the packed rows before dequantizing (gather_compressed_rows in get_rows.cpp), so I dropped the duplicate gather_before_dequant path and GGML_OPENVINO_GATHER_BEFORE_DEQUANT. GGML_OPENVINO_NPU_TOKEN_EMBD_QUANT now replaces GGML_OPENVINO_TOKEN_EMBD_I8 and GGML_OPENVINO_TOKEN_EMBD_I4. It takes one of f16 (default), q8_0_c, q4_0_128 or q4_0_c, and any other value aborts at model load. Your commit is kept, rebased with the conflicts resolved toward dev. My changes are in one commit on top.

@ravi9
ravi9 merged commit 0974aef into ravi9:dev_backend_openvino Oct 27, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation ggml OpenVINO

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants