From: opencoti Subject: [PATCH 0087] DCA: wire --dca-yarn-factor into build_dca_rope mscale (bug-740 / #550) --dca-yarn-factor was fully plumbed (arg.cpp -> params -> cparams.dca_yarn_factor, public C API, TS adapter) but never READ by the rope path, so the flag was inert (bug-740). build_dca_rope now composes it into the attention scaling: dca_attn_factor = attn_factor * cparams.dca_yarn_factor and passes that to both ggml_rope_multi (MROPE) and ggml_rope_ext (NEOX) in place of the bare attn_factor. This is the YaRN mscale piece of the DCA+YaRN composition: DCA already keeps q-k distances in-distribution via the per-regime chunk remap, so only the softmax temperature (mscale) needs stretching for ctx past the chunk grid -- freq_scale / freq_base stay the model's baked values. Host-only (graph construction); the existing CUDA rope kernel reads attn_factor from op_params unchanged, so no DSO rebuild. Default 1.0 => dca_attn_factor == attn_factor exactly (x1.0f is bit-identity for finite floats), so the flag-unset path is byte-identical to upstream -- the fix only makes a previously-inert flag live; it cannot regress default behavior. Empirical characterization (Qwen3-4B, native 40960, DCA chunk 16384, RULER 5-needle substring under ignore_eos; NOT greedy-first-token): f16 KV @ 2.4x native: yarn 1.0->5/5 1.25->4/5 1.5->1/5 2.0->0/5 (monotonic: flag live) q8_0 KV ladder yarn=1.0: 2.4x->4 4.0x->5 5.0x->3 6.0x->4 (plain-DCA holds deep) q8_0 KV @ 6.0x native: yarn 1.0->4 1.1->4 1.25->4 (flat; 1.18 = principled mscale, no win) Verdict: the mscale lever has NO beneficial regime for DCA retrieval -- it only over-sharpens already-concentrated attention. DEFAULT 1.0 IS CORRECT. Ships as a power-user knob (raising it degrades retrieval); documented in docs/evaluations/context.md. diff --git a/llama.cpp/src/dca.cpp b/llama.cpp/src/dca.cpp --- a/llama.cpp/src/dca.cpp +++ b/llama.cpp/src/dca.cpp @@ -164,15 +164,23 @@ // Rope the DCA per-regime Q (or insert-K) faithfully for the arch. `pos` must be the width // build_attn_inp_dca allocated: 4*n_tokens for MROPE (section split below), n_tokens for NEOX. ggml_tensor * llm_graph_context::build_dca_rope(ggml_tensor * x, ggml_tensor * pos, const dca_rope & rp) const { + // opencoti-hook: dca-yarn-factor (bug-740 / #550) — compose a YaRN mscale stretch with DCA. + // cparams.dca_yarn_factor (1.0 = none; set by --dca-yarn-factor) multiplies the attention scaling + // (mscale / attn_factor) so the extending-regime softmax is re-tempered for ctx past the chunk grid + // (the final 2-4x of the DCA+YaRN sub-native extension recipe; see docs/features/gemma4_dca.md). DCA + // already keeps q-k distances in-distribution via the per-regime chunk remap, so only the mscale needs + // stretching — freq_scale/freq_base stay the model's baked values. Default 1.0 => this rope call is + // byte-identical to upstream (inert unless the flag is set). + const float dca_attn_factor = attn_factor * cparams.dca_yarn_factor; if (dca_is_mrope(rope_type)) { int sections[GGML_MROPE_SECTIONS] = { rp.sections[0], rp.sections[1], rp.sections[2], rp.sections[3] }; return ggml_rope_multi(ctx0, x, pos, rp.freq_factors, rp.n_rot, sections, rope_type, n_ctx_orig, rp.freq_base, rp.freq_scale, - ext_factor, attn_factor, beta_fast, beta_slow); + ext_factor, dca_attn_factor, beta_fast, beta_slow); } return ggml_rope_ext(ctx0, x, pos, rp.freq_factors, rp.n_rot, rope_type, n_ctx_orig, rp.freq_base, rp.freq_scale, - ext_factor, attn_factor, beta_fast, beta_slow); + ext_factor, dca_attn_factor, beta_fast, beta_slow); } // opencoti F5 dca #444 (DCA all-KV C1): dequant-on-lift a cached K/V tensor to f16 for the f16-only