You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Quantized matmul dispatch skips rank-1 (single-token decode) activations, falls through to broken matmulGeneric #993
chooseQuantizedMatmulHeap (skainet-backend-cpu/src/commonMain/.../DefaultCpuOps.kt) and chooseQuantizedMatmul (skainet-backend-cpu/src/jvmMain/.../DefaultCpuOpsJvm.kt) both gate on a.shape.rank >= 2, returning null (i.e. "not a case I handle, fall through") for a rank-1 activation. In practice, a real forward pass produces a rank-1 hidden-state vector for every incremental decode step once it moves past the initial batched prefill (which is rank-2+). That rank-1 case then falls all the way through to matmulGeneric's untyped per-element TensorData.get() access, which — for a packed-quant weight (including one wrapped by SKaiNET-transformers' PreTransposedWeight marker types, e.g. PreTransposedQ4_K) — returns the raw packed byte rather than a dequantized Float, throwing:
java.lang.ClassCastException: class java.lang.Byte cannot be cast to class java.lang.Float
at sk.ainet.exec.tensor.ops.DefaultCpuOpsBase.matmulGeneric$lambda$1(DefaultCpuOps.kt:755)
at sk.ainet.exec.tensor.ops.DefaultCpuOpsBase.matmulGeneric(DefaultCpuOps.kt:704)
at sk.ainet.exec.tensor.ops.DefaultCpuOpsBase.matmul(DefaultCpuOps.kt:623)
at sk.ainet.lang.nn.transformer.LinearProjectionKt.linearProject(LinearProjection.kt:40)
at sk.ainet.lang.nn.transformer.MultiHeadAttention.attentionImpl(MultiHeadAttention.kt:298)
...
Related to #991 / #992 (same dispatch functions, same crash signature) but a distinct root cause: #991/#992 was about the activation operand's TensorData subtype being too strict (FloatArrayTensorData-only) for a rank-2 input; this one is about rank, and reproduces even after #991/#992's fix is applied.
Repro
End-to-end against a real Llama-3.2-1B-Instruct-Q4_K_M.gguf via SKaiNET-transformers' KLlamaJava.loadGGUF (DIRECT mode): the first forward pass (prefill, rank-2 batched input) succeeds; the crash hits on the first post-prefill decode step, where the runtime passes a rank-1 [hidden_dim] activation.
Fix
Pushed as an additional commit to #992 (fix/q6k-memseg-matmul-dispatch), since it touches the exact same dispatch functions:
Both guards changed from a.shape.rank < 2 to a.shape.rank < 1 — the existing leading-dim-flattening logic (added for rank>2 attention batches) already generalizes correctly to rank-1 (empty leading dims, flatBatch=1, [in] promotes to [1, in], result squeezes back to [out]) with no further changes needed.
matmulGeneric hardened as defense in depth: a lazily-materialized copyToFloatArray() fallback if a TensorData's generic get() ever returns something other than the tensor's own dtype, instead of an unconditional unsafe as Float cast.
New regression test: rank-1 FP32 activation against a Q4_K-packed weight, asserting no throw and finite output.
Verified fixed on develop: both guards are a.shape.rank < 1 now (DefaultCpuOps.kt:574, DefaultCpuOpsJvm.kt:586, with the rank-1→[1,in]→squeeze promotion the issue proposed, and the comment at DefaultCpuOpsJvm.kt:595 narrating exactly this change) — the fix pushed via #992 landed. Beyond that, the decode path has since moved to view-keyed KernelDispatch (SKEEP-003 §5), where operand rank/format/layout are part of the key rather than an is-ladder, which is the structural fix for this class of bug. Closing; reopen with a repro if any rank-1 case still falls through.
Activity
michalharakal commentedon Aug 27, 2026
Verified fixed on develop: both guards are
a.shape.rank < 1now (DefaultCpuOps.kt:574,DefaultCpuOpsJvm.kt:586, with the rank-1→[1,in]→squeeze promotion the issue proposed, and the comment at DefaultCpuOpsJvm.kt:595 narrating exactly this change) — the fix pushed via #992 landed. Beyond that, the decode path has since moved to view-keyedKernelDispatch(SKEEP-003 §5), where operand rank/format/layout are part of the key rather than an is-ladder, which is the structural fix for this class of bug. Closing; reopen with a repro if any rank-1 case still falls through.