cohere-transcribe 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +21 -0
- data/LICENSE.txt +201 -0
- data/NOTICE +5 -0
- data/README.md +265 -0
- data/THIRD_PARTY_NOTICES.md +67 -0
- data/exe/cohere-transcribe +8 -0
- data/exe/cohere-transcribe-doctor +8 -0
- data/ext/cohere_transcribe_native/CMakeLists.txt +262 -0
- data/ext/cohere_transcribe_native/README.md +26 -0
- data/ext/cohere_transcribe_native/audio_abi.cpp +1416 -0
- data/ext/cohere_transcribe_native/audio_exports.macos +5 -0
- data/ext/cohere_transcribe_native/audio_exports.map +10 -0
- data/ext/cohere_transcribe_native/cohere_abi.cpp +1209 -0
- data/ext/cohere_transcribe_native/exports.macos +40 -0
- data/ext/cohere_transcribe_native/exports.map +45 -0
- data/ext/cohere_transcribe_native/extconf.rb +89 -0
- data/ext/cohere_transcribe_native/test/abi_smoke.rb +232 -0
- data/ext/cohere_transcribe_native/test/audio_matrix_smoke.cpp +121 -0
- data/ext/cohere_transcribe_native/test/audio_reliability_smoke.cpp +198 -0
- data/ext/cohere_transcribe_native/test/native_abi_reliability_smoke.cpp +186 -0
- data/ext/cohere_transcribe_native/test/native_batch_projection_probe.rb +81 -0
- data/ext/cohere_transcribe_native/test/native_cancellation_smoke.cpp +194 -0
- data/lib/cohere/transcribe/alignment/ATTRIBUTION.md +23 -0
- data/lib/cohere/transcribe/alignment/LICENSE.ctc-forced-aligner +407 -0
- data/lib/cohere/transcribe/alignment/LICENSE.torchaudio +25 -0
- data/lib/cohere/transcribe/alignment/LICENSE.uroman +26 -0
- data/lib/cohere/transcribe/alignment/aligner.rb +476 -0
- data/lib/cohere/transcribe/alignment/ctc.rb +224 -0
- data/lib/cohere/transcribe/alignment/text.rb +237 -0
- data/lib/cohere/transcribe/alignment/uroman_data.rb +4950 -0
- data/lib/cohere/transcribe/api.rb +173 -0
- data/lib/cohere/transcribe/asr/batching.rb +472 -0
- data/lib/cohere/transcribe/asr/failure_policy.rb +112 -0
- data/lib/cohere/transcribe/asr/native.rb +676 -0
- data/lib/cohere/transcribe/audio/ATTRIBUTION.md +8 -0
- data/lib/cohere/transcribe/audio/LICENSE.auditok +21 -0
- data/lib/cohere/transcribe/audio/decoder.rb +315 -0
- data/lib/cohere/transcribe/audio/ffmpeg_native.rb +248 -0
- data/lib/cohere/transcribe/audio/segmentation.rb +260 -0
- data/lib/cohere/transcribe/cli.rb +727 -0
- data/lib/cohere/transcribe/configuration.rb +282 -0
- data/lib/cohere/transcribe/constants.rb +14 -0
- data/lib/cohere/transcribe/dense_converter.rb +548 -0
- data/lib/cohere/transcribe/doctor.rb +576 -0
- data/lib/cohere/transcribe/errors.rb +57 -0
- data/lib/cohere/transcribe/gguf_writer.rb +268 -0
- data/lib/cohere/transcribe/hub.rb +436 -0
- data/lib/cohere/transcribe/input.rb +110 -0
- data/lib/cohere/transcribe/licenses/crispasr.txt +21 -0
- data/lib/cohere/transcribe/loader.rb +128 -0
- data/lib/cohere/transcribe/model_identity.rb +440 -0
- data/lib/cohere/transcribe/output/publication.rb +1118 -0
- data/lib/cohere/transcribe/output/rendering.rb +105 -0
- data/lib/cohere/transcribe/output/timing.rb +86 -0
- data/lib/cohere/transcribe/python_text.rb +70 -0
- data/lib/cohere/transcribe/pytorch_checkpoint.rb +1180 -0
- data/lib/cohere/transcribe/runtime/engine.rb +1676 -0
- data/lib/cohere/transcribe/runtime/model_provider.rb +390 -0
- data/lib/cohere/transcribe/runtime/precision.rb +57 -0
- data/lib/cohere/transcribe/runtime/preparation.rb +215 -0
- data/lib/cohere/transcribe/runtime/resources.rb +165 -0
- data/lib/cohere/transcribe/runtime/word_pipeline.rb +364 -0
- data/lib/cohere/transcribe/safetensors.rb +579 -0
- data/lib/cohere/transcribe/state/checkpoint.rb +224 -0
- data/lib/cohere/transcribe/state/contracts.rb +141 -0
- data/lib/cohere/transcribe/state/io.rb +727 -0
- data/lib/cohere/transcribe/state/locking.rb +211 -0
- data/lib/cohere/transcribe/state/manifest.rb +155 -0
- data/lib/cohere/transcribe/state.rb +7 -0
- data/lib/cohere/transcribe/types.rb +535 -0
- data/lib/cohere/transcribe/vad/ATTRIBUTION.md +14 -0
- data/lib/cohere/transcribe/vad/LICENSE.faster-whisper +21 -0
- data/lib/cohere/transcribe/vad/LICENSE.silero-vad +21 -0
- data/lib/cohere/transcribe/vad/silero.rb +344 -0
- data/lib/cohere/transcribe/vad/silero_vad_v6.onnx +0 -0
- data/lib/cohere/transcribe/vad/timestamps.rb +219 -0
- data/lib/cohere/transcribe/version.rb +7 -0
- data/lib/cohere/transcribe.rb +26 -0
- data/sig/cohere/transcribe.rbs +250 -0
- data/vendor/crispasr/AUTHORS +510 -0
- data/vendor/crispasr/LICENSE +21 -0
- data/vendor/crispasr/UPSTREAM.md +9 -0
- data/vendor/crispasr/VERSION +1 -0
- data/vendor/crispasr/ggml/AUTHORS +335 -0
- data/vendor/crispasr/ggml/CMakeLists.txt +512 -0
- data/vendor/crispasr/ggml/LICENSE +21 -0
- data/vendor/crispasr/ggml/README.md +49 -0
- data/vendor/crispasr/ggml/cmake/FindNCCL.cmake +36 -0
- data/vendor/crispasr/ggml/cmake/GitVars.cmake +22 -0
- data/vendor/crispasr/ggml/cmake/common.cmake +50 -0
- data/vendor/crispasr/ggml/cmake/ggml-config.cmake.in +191 -0
- data/vendor/crispasr/ggml/ggml.pc.in +10 -0
- data/vendor/crispasr/ggml/include/ggml-alloc.h +85 -0
- data/vendor/crispasr/ggml/include/ggml-backend.h +431 -0
- data/vendor/crispasr/ggml/include/ggml-blas.h +25 -0
- data/vendor/crispasr/ggml/include/ggml-cann.h +123 -0
- data/vendor/crispasr/ggml/include/ggml-cpp.h +39 -0
- data/vendor/crispasr/ggml/include/ggml-cpu.h +151 -0
- data/vendor/crispasr/ggml/include/ggml-cuda.h +50 -0
- data/vendor/crispasr/ggml/include/ggml-hexagon.h +19 -0
- data/vendor/crispasr/ggml/include/ggml-metal.h +61 -0
- data/vendor/crispasr/ggml/include/ggml-opencl.h +26 -0
- data/vendor/crispasr/ggml/include/ggml-openvino.h +37 -0
- data/vendor/crispasr/ggml/include/ggml-opt.h +256 -0
- data/vendor/crispasr/ggml/include/ggml-rpc.h +35 -0
- data/vendor/crispasr/ggml/include/ggml-sycl.h +49 -0
- data/vendor/crispasr/ggml/include/ggml-virtgpu.h +14 -0
- data/vendor/crispasr/ggml/include/ggml-vulkan.h +29 -0
- data/vendor/crispasr/ggml/include/ggml-webgpu.h +19 -0
- data/vendor/crispasr/ggml/include/ggml-zdnn.h +17 -0
- data/vendor/crispasr/ggml/include/ggml-zendnn.h +22 -0
- data/vendor/crispasr/ggml/include/ggml.h +2887 -0
- data/vendor/crispasr/ggml/include/gguf.h +204 -0
- data/vendor/crispasr/ggml/src/CMakeLists.txt +493 -0
- data/vendor/crispasr/ggml/src/ggml-alloc.c +1323 -0
- data/vendor/crispasr/ggml/src/ggml-backend-dl.cpp +48 -0
- data/vendor/crispasr/ggml/src/ggml-backend-dl.h +44 -0
- data/vendor/crispasr/ggml/src/ggml-backend-impl.h +275 -0
- data/vendor/crispasr/ggml/src/ggml-backend-meta.cpp +2145 -0
- data/vendor/crispasr/ggml/src/ggml-backend-reg.cpp +586 -0
- data/vendor/crispasr/ggml/src/ggml-backend.cpp +2437 -0
- data/vendor/crispasr/ggml/src/ggml-common.h +1900 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/CMakeLists.txt +718 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/amx/amx.cpp +249 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/amx/amx.h +8 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/amx/common.h +115 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/amx/mmq.cpp +2512 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/amx/mmq.h +10 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/arm/cpu-feats.cpp +98 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/arm/quants.c +4244 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/arm/repack.cpp +5156 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/loongarch/quants.c +2158 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/powerpc/cpu-feats.cpp +82 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/powerpc/quants.c +2304 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/riscv/cpu-feats.cpp +38 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/riscv/quants.c +4455 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/riscv/repack.cpp +1703 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/s390/cpu-feats.cpp +50 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/s390/quants.c +1465 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/wasm/quants.c +1220 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/x86/cpu-feats.cpp +327 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/x86/quants.c +3970 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/x86/repack.cpp +6407 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch-fallback.h +349 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/binary-ops.cpp +154 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/binary-ops.h +16 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/cmake/FindSIMD.cmake +100 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/common.h +95 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/ggml-cpu-impl.h +539 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/ggml-cpu.c +3791 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/ggml-cpu.cpp +703 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/hbm.cpp +55 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/hbm.h +8 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/kleidiai/kernels.cpp +939 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/kleidiai/kernels.h +90 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/kleidiai/kleidiai.cpp +1513 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/kleidiai/kleidiai.h +17 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/llamafile/sgemm.cpp +4051 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/llamafile/sgemm.h +25 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/ops.cpp +11662 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/ops.h +121 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/quants.c +1288 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/quants.h +103 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/repack.cpp +4836 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/repack.h +245 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/simd-gemm.h +226 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/simd-mappings.h +1329 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/spacemit/ime.cpp +1025 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/spacemit/ime.h +13 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/spacemit/ime1_kernels.cpp +3196 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/spacemit/ime_kernels.h +26 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/traits.cpp +36 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/traits.h +38 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/unary-ops.cpp +336 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/unary-ops.h +35 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/vec.cpp +681 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/vec.h +1606 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/CMakeLists.txt +272 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/acc.cu +61 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/acc.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/add-id.cu +58 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/add-id.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/arange.cu +34 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/arange.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/argmax.cu +91 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/argmax.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/argsort.cu +265 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/argsort.cuh +19 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/binbcast.cu +534 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/binbcast.cuh +12 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/clamp.cu +45 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/clamp.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/col2im-1d.cu +81 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/col2im-1d.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/common.cuh +1489 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/concat.cu +204 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/concat.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/conv-transpose-1d.cu +97 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/conv-transpose-1d.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/conv2d-dw.cu +161 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/conv2d-dw.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/conv2d-transpose.cu +115 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/conv2d-transpose.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/conv2d.cu +166 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/conv2d.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/convert.cu +892 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/convert.cuh +66 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/count-equal.cu +64 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/count-equal.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/cp-async.cuh +57 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/cpy-utils.cuh +217 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/cpy.cu +581 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/cpy.cuh +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/cross-entropy-loss.cu +177 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/cross-entropy-loss.cuh +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/cumsum.cu +307 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/cumsum.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/dequantize.cuh +99 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/diag.cu +77 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/diag.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/diagmask.cu +40 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/diagmask.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fattn-common.cuh +1212 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fattn-mma-f16.cuh +1860 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fattn-tile.cu +57 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fattn-tile.cuh +1309 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fattn-vec.cuh +600 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fattn-wmma-f16.cu +696 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fattn-wmma-f16.cuh +51 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fattn.cu +620 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fattn.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fill.cu +37 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fill.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/gated_delta_net.cu +273 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/gated_delta_net.cuh +4 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/getrows.cu +332 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/getrows.cuh +15 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/ggml-cuda.cu +5580 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/gla.cu +93 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/gla.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/im2col.cu +274 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/im2col.cuh +6 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mean.cu +75 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mean.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mma.cuh +1333 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmf.cu +191 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmf.cuh +908 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmid.cu +164 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmid.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmq.cu +372 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmq.cuh +4175 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmvf.cu +862 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmvf.cuh +14 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmvq.cu +1161 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmvq.cuh +16 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/norm.cu +756 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/norm.cuh +20 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/opt-step-adamw.cu +78 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/opt-step-adamw.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/opt-step-sgd.cu +49 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/opt-step-sgd.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/out-prod.cu +68 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/out-prod.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/pad.cu +106 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/pad.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/pad_reflect_1d.cu +91 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/pad_reflect_1d.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/pool2d.cu +94 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/pool2d.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/quantize.cu +443 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/quantize.cuh +41 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/reduce_rows.cuh +39 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/roll.cu +67 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/roll.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/rope.cu +665 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/rope.cuh +9 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/scale.cu +34 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/scale.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/set-rows.cu +330 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/set-rows.cuh +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/set.cu +39 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/set.cuh +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/softcap.cu +34 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/softcap.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/softmax.cu +472 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/softmax.cuh +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/solve_tri.cu +275 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/solve_tri.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/ssm-conv.cu +197 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/ssm-conv.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/ssm-scan.cu +342 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/ssm-scan.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/sum.cu +41 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/sum.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/sumrows.cu +43 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/sumrows.cuh +4 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_1-ncols2_16.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_1-ncols2_32.cu +6 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_1-ncols2_8.cu +11 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_16-ncols2_1.cu +10 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_16-ncols2_2.cu +10 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_16-ncols2_4.cu +12 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_2-ncols2_16.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_2-ncols2_32.cu +6 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_2-ncols2_4.cu +12 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_2-ncols2_8.cu +11 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_32-ncols2_1.cu +10 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_32-ncols2_2.cu +10 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_4-ncols2_16.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_4-ncols2_2.cu +10 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_4-ncols2_4.cu +12 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_4-ncols2_8.cu +11 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_64-ncols2_1.cu +10 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_8-ncols2_1.cu +10 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_8-ncols2_2.cu +10 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_8-ncols2_4.cu +12 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_8-ncols2_8.cu +11 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq112-dv112.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq128-dv128.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq256-dv256.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq320-dv256.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq40-dv40.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq512-dv512.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq576-dv512.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq64-dv64.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq72-dv72.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq80-dv80.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq96-dv96.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-bf16-bf16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-bf16-f16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-bf16-q4_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-bf16-q4_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-bf16-q5_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-bf16-q5_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-bf16-q8_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-f16-bf16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-f16-f16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-f16-q4_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-f16-q4_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-f16-q5_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-f16-q5_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-f16-q8_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_0-bf16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_0-f16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_0-q4_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_0-q4_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_0-q5_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_0-q5_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_0-q8_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_1-bf16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_1-f16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_1-q4_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_1-q4_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_1-q5_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_1-q5_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_1-q8_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_0-bf16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_0-f16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_0-q4_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_0-q4_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_0-q5_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_0-q5_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_0-q8_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_1-bf16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_1-f16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_1-q4_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_1-q4_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_1-q5_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_1-q5_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_1-q8_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q8_0-bf16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q8_0-f16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q8_0-q4_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q8_0-q4_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q8_0-q5_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q8_0-q5_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q8_0-q8_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_1.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_10.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_11.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_12.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_13.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_14.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_15.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_16.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_2.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_3.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_4.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_5.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_6.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_7.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_8.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_9.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-iq1_s.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-iq2_s.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-iq2_xs.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-iq2_xxs.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-iq3_s.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-iq3_xxs.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-iq4_nl.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-iq4_xs.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-mxfp4.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-nvfp4.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q1_0.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q2_k.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q3_k.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q4_0.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q4_1.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q4_k.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q5_0.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q5_1.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q5_k.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q6_k.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q8_0.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/top-k.cu +95 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/top-k.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/topk-moe.cu +415 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/topk-moe.cuh +27 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/tri.cu +136 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/tri.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/tsembd.cu +47 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/tsembd.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/unary.cu +644 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/unary.cuh +116 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/upscale.cu +293 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/upscale.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/vecdotq.cuh +1317 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/vendors/cuda.h +28 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/vendors/hip.h +306 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/vendors/musa.h +148 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/wkv.cu +199 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/wkv.cuh +7 -0
- data/vendor/crispasr/ggml/src/ggml-impl.h +783 -0
- data/vendor/crispasr/ggml/src/ggml-metal/CMakeLists.txt +124 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-common.cpp +457 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-common.h +52 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-context.h +41 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-context.m +778 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-device.cpp +2117 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-device.h +299 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-device.m +2093 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-impl.h +1267 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-ops.cpp +5023 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-ops.h +111 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal.cpp +954 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal.metal +11756 -0
- data/vendor/crispasr/ggml/src/ggml-opt.cpp +1094 -0
- data/vendor/crispasr/ggml/src/ggml-quants.c +5491 -0
- data/vendor/crispasr/ggml/src/ggml-quants.h +112 -0
- data/vendor/crispasr/ggml/src/ggml-threading.cpp +12 -0
- data/vendor/crispasr/ggml/src/ggml-threading.h +14 -0
- data/vendor/crispasr/ggml/src/ggml.c +7925 -0
- data/vendor/crispasr/ggml/src/ggml.cpp +26 -0
- data/vendor/crispasr/ggml/src/gguf.cpp +1556 -0
- data/vendor/crispasr/src/cohere-arch.h +137 -0
- data/vendor/crispasr/src/cohere.cpp +5642 -0
- data/vendor/crispasr/src/cohere.h +327 -0
- data/vendor/crispasr/src/cohere_batch_planner.h +82 -0
- data/vendor/crispasr/src/cohere_chunking.h +64 -0
- data/vendor/crispasr/src/cohere_decoder_batch_layout.h +60 -0
- data/vendor/crispasr/src/cohere_encoder_padded_layout.h +27 -0
- data/vendor/crispasr/src/cohere_frontend.cpp +189 -0
- data/vendor/crispasr/src/cohere_frontend.h +31 -0
- data/vendor/crispasr/src/cohere_ragged_controller.h +149 -0
- data/vendor/crispasr/src/cohere_token_renderer.h +181 -0
- data/vendor/crispasr/src/core/attention.h +924 -0
- data/vendor/crispasr/src/core/audio_chunking.h +97 -0
- data/vendor/crispasr/src/core/beam_decode.h +486 -0
- data/vendor/crispasr/src/core/cpu_ops.h +135 -0
- data/vendor/crispasr/src/core/gguf_loader.cpp +1021 -0
- data/vendor/crispasr/src/core/gguf_loader.h +216 -0
- data/vendor/crispasr/src/core/gpu_backend_pref.h +119 -0
- data/vendor/crispasr/src/core/mel.cpp +519 -0
- data/vendor/crispasr/src/core/mel.h +265 -0
- data/vendor/crispasr/src/core/ngram_loop_fix.h +173 -0
- data/vendor/crispasr/src/core/repetition_loop_guard.h +54 -0
- data/vendor/crispasr/src/crispasr_imatrix.cpp +255 -0
- data/vendor/crispasr/src/crispasr_imatrix.h +38 -0
- metadata +596 -0
|
@@ -0,0 +1,924 @@
|
|
|
1
|
+
// src/core/attention.h — shared multi-head attention helpers (header-only).
|
|
2
|
+
//
|
|
3
|
+
// Replaces the Q/K/V-projection + reshape + RoPE + GQA-expand + flash-attn +
|
|
4
|
+
// output-projection block that every LLM-based model in src/ has 1–2 copies
|
|
5
|
+
// of. The helper is header-only so the compiler inlines it straight into
|
|
6
|
+
// each caller, producing the exact same ggml op sequence as the original
|
|
7
|
+
// inline code and preserving bit-identical graph execution.
|
|
8
|
+
//
|
|
9
|
+
// Scope of the initial version (this commit):
|
|
10
|
+
//
|
|
11
|
+
// core_attn::llama_self_attn_kv() — the classic Llama / Mistral LLM
|
|
12
|
+
// attention block: RMSNorm weights applied by caller, no biases on
|
|
13
|
+
// Q/K/V/O, NEOX RoPE, optional GQA expansion, ggml_flash_attn_ext with
|
|
14
|
+
// a caller-supplied causal-or-sliding-window mask, reshape + output
|
|
15
|
+
// projection. Used by voxtral, voxtral4b, qwen3 (without Q/K norm),
|
|
16
|
+
// and granite LLM decoders.
|
|
17
|
+
//
|
|
18
|
+
// Follow-up variants (to be added when their first consumer migrates):
|
|
19
|
+
//
|
|
20
|
+
// * post-projection Q/K RMSNorm (qwen3)
|
|
21
|
+
// * separate audio-encoder variant with biases + no RoPE (voxtral audio)
|
|
22
|
+
// * adaptive scale / residual_multiplier (granite µP)
|
|
23
|
+
// * KV-cache lookup that returns a (K, V) pair instead of taking
|
|
24
|
+
// pre-permuted inputs (needed when KV cache is stored in a different
|
|
25
|
+
// layout than (head_dim, T, n_heads))
|
|
26
|
+
//
|
|
27
|
+
// This staged approach keeps the first commit narrow and verifiable. Every
|
|
28
|
+
// new caller either fits the existing helper or adds a new sibling helper
|
|
29
|
+
// with its own regression test.
|
|
30
|
+
|
|
31
|
+
#pragma once
|
|
32
|
+
|
|
33
|
+
#include "ggml-backend.h"
|
|
34
|
+
#include "ggml.h"
|
|
35
|
+
|
|
36
|
+
#include <cstddef>
|
|
37
|
+
#include <cstdint>
|
|
38
|
+
#include <cstdio>
|
|
39
|
+
#include <cstdlib>
|
|
40
|
+
#include <cstring>
|
|
41
|
+
#include <vector>
|
|
42
|
+
|
|
43
|
+
// Declared in ggml-backend-impl.h, which is not on the public include path,
|
|
44
|
+
// but the symbol is GGML_API-exported by the ggml backend library. Returns
|
|
45
|
+
// true iff the backend performed a direct device-to-device tensor copy
|
|
46
|
+
// (GH #161 — used to pick the KV-snapshot storage mode below).
|
|
47
|
+
extern "C" bool ggml_backend_buffer_copy_tensor(const struct ggml_tensor* src, struct ggml_tensor* dst);
|
|
48
|
+
|
|
49
|
+
namespace core_attn {
|
|
50
|
+
|
|
51
|
+
// PLAN #60e: KV cache dtype selection from `CRISPASR_KV_QUANT`.
|
|
52
|
+
//
|
|
53
|
+
// Default returns `GGML_TYPE_F16` so any backend that calls this in
|
|
54
|
+
// its `*_kv_init` is bit-identical to legacy behaviour until the user
|
|
55
|
+
// opts in. Recognised values: `f16` (default), `q8_0`, `q4_0`. Anything
|
|
56
|
+
// else logs a warning to stderr and falls back to F16.
|
|
57
|
+
//
|
|
58
|
+
// Pairs with the `core_attn::kv_self_attn` write- and read-path
|
|
59
|
+
// quant-safety: when the cache type is quantised, the helper switches
|
|
60
|
+
// to `ggml_set_rows` for the write (vs `ggml_cpy` for F16, which
|
|
61
|
+
// requires contig dst that quant slices never satisfy) and uses
|
|
62
|
+
// `ggml_cast(...,F32)` to dequantise on read (CPU-backend safe; F16
|
|
63
|
+
// would be metal-only).
|
|
64
|
+
//
|
|
65
|
+
// `backend_tag` is the prefix on the warning line so a misconfigured
|
|
66
|
+
// env var points at a specific backend rather than a generic message.
|
|
67
|
+
// Parse a single KV-quant string. Internal helper.
|
|
68
|
+
inline ggml_type kv_dtype_parse(const char* s, const char* backend_tag, const char* env_name, ggml_type fallback) {
|
|
69
|
+
if (!s || !*s)
|
|
70
|
+
return fallback;
|
|
71
|
+
if (std::strcmp(s, "f16") == 0 || std::strcmp(s, "F16") == 0)
|
|
72
|
+
return GGML_TYPE_F16;
|
|
73
|
+
if (std::strcmp(s, "f32") == 0 || std::strcmp(s, "F32") == 0)
|
|
74
|
+
return GGML_TYPE_F32;
|
|
75
|
+
if (std::strcmp(s, "q8_0") == 0 || std::strcmp(s, "Q8_0") == 0)
|
|
76
|
+
return GGML_TYPE_Q8_0;
|
|
77
|
+
if (std::strcmp(s, "q4_0") == 0 || std::strcmp(s, "Q4_0") == 0)
|
|
78
|
+
return GGML_TYPE_Q4_0;
|
|
79
|
+
std::fprintf(stderr, "%s: %s='%s' unrecognised, defaulting to f16\n", backend_tag, env_name, s);
|
|
80
|
+
return GGML_TYPE_F16;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
inline ggml_type kv_dtype_from_env(const char* backend_tag) {
|
|
84
|
+
return kv_dtype_parse(std::getenv("CRISPASR_KV_QUANT"), backend_tag, "CRISPASR_KV_QUANT", GGML_TYPE_F16);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Asymmetric K/V cache types. PLAN #69e — llama.cpp-style independent
|
|
88
|
+
// `--cache-type-k` / `--cache-type-v`. The two halves of the KV cache
|
|
89
|
+
// have very different sensitivity profiles:
|
|
90
|
+
//
|
|
91
|
+
// * V quantises down well: it gets used as `softmax(QK^T) · V`, where
|
|
92
|
+
// softmax already concentrates probability mass and per-element
|
|
93
|
+
// errors get averaged across attended positions. q4_0 V is usually
|
|
94
|
+
// indistinguishable from F16.
|
|
95
|
+
// * K is the fragile half: errors in `QK^T / sqrt(d)` distort *which*
|
|
96
|
+
// positions get attended to (the softmax exponentiates errors).
|
|
97
|
+
// K typically wants q8_0 or higher for the same PPL floor.
|
|
98
|
+
//
|
|
99
|
+
// Common llama.cpp recipe is `-ctk q8_0 -ctv q4_0`, ~40 % KV memory
|
|
100
|
+
// savings vs symmetric Q8_0 with PPL barely moved on Llama-class
|
|
101
|
+
// models. The legacy CRISPASR_KV_QUANT remains the default for both
|
|
102
|
+
// halves; the per-half overrides take precedence.
|
|
103
|
+
struct kv_dtype_pair {
|
|
104
|
+
ggml_type k;
|
|
105
|
+
ggml_type v;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
inline kv_dtype_pair kv_dtype_pair_from_env(const char* backend_tag) {
|
|
109
|
+
const ggml_type both = kv_dtype_from_env(backend_tag);
|
|
110
|
+
const ggml_type k = kv_dtype_parse(std::getenv("CRISPASR_KV_QUANT_K"), backend_tag, "CRISPASR_KV_QUANT_K", both);
|
|
111
|
+
const ggml_type v = kv_dtype_parse(std::getenv("CRISPASR_KV_QUANT_V"), backend_tag, "CRISPASR_KV_QUANT_V", both);
|
|
112
|
+
return {k, v};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// PLAN #69b — pick the backend on which to allocate the KV cache.
|
|
116
|
+
// Default: same backend as the model weights (`gpu_backend`). When
|
|
117
|
+
// `CRISPASR_KV_ON_CPU=1` is set, allocate on `cpu_backend` instead so
|
|
118
|
+
// users with very long context + tight VRAM can spill the cache to
|
|
119
|
+
// system RAM. The cost is per-step GPU↔CPU copy of the KV slice, which
|
|
120
|
+
// is typically slower than just running with `CRISPASR_KV_QUANT=q4_0`
|
|
121
|
+
// to fit KV in VRAM — try KV_QUANT first.
|
|
122
|
+
//
|
|
123
|
+
// `backend_tag` is the prefix on the warning line. Returns gpu_backend
|
|
124
|
+
// when neither offload is requested, cpu_backend when it is.
|
|
125
|
+
inline ggml_backend_t kv_backend_from_env(ggml_backend_t gpu_backend, ggml_backend_t cpu_backend,
|
|
126
|
+
const char* backend_tag) {
|
|
127
|
+
const char* s = std::getenv("CRISPASR_KV_ON_CPU");
|
|
128
|
+
if (!s || !*s || std::strcmp(s, "0") == 0)
|
|
129
|
+
return gpu_backend;
|
|
130
|
+
if (!cpu_backend) {
|
|
131
|
+
std::fprintf(stderr, "%s: CRISPASR_KV_ON_CPU=%s requested but no CPU backend available, falling back to GPU\n",
|
|
132
|
+
backend_tag, s);
|
|
133
|
+
return gpu_backend;
|
|
134
|
+
}
|
|
135
|
+
return cpu_backend;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// GH #161 — on-device KV-cache snapshot for branched beam search.
|
|
139
|
+
//
|
|
140
|
+
// `core_beam_decode::run_with_probs_branched` snapshots and restores the
|
|
141
|
+
// decoder's KV cache once per surviving beam per step. The original
|
|
142
|
+
// per-backend lambdas did this through host memory
|
|
143
|
+
// (`ggml_backend_tensor_get` → std::vector → `ggml_backend_tensor_set`),
|
|
144
|
+
// which on a GPU backend means a full KV round-trip over PCIe *plus* a
|
|
145
|
+
// blocking device synchronize on every copy. With the default beam_size=5
|
|
146
|
+
// that is ~B×(K+V) bytes of GPU↔CPU traffic per decode step — the bulk of
|
|
147
|
+
// the #161 cohere regression (one core pegged in a sync-spin, time spent
|
|
148
|
+
// entirely outside the profiled compute).
|
|
149
|
+
//
|
|
150
|
+
// `kv_snapshot_pool` instead keeps the snapshot resident on the *same*
|
|
151
|
+
// buffer type as the cache, so save/restore are device-to-device blits with
|
|
152
|
+
// no host transfer and no sync-to-host. It snapshots an arbitrary list of
|
|
153
|
+
// live tensors, so it serves both the single `kv_k`/`kv_v` layout (cohere,
|
|
154
|
+
// canary, kyutai_stt, omniasr) and the per-layer `kv.k[il]`/`kv.v[il]`
|
|
155
|
+
// layout (moonshine).
|
|
156
|
+
//
|
|
157
|
+
// Allocating a fresh backend buffer per snapshot is itself expensive on a
|
|
158
|
+
// GPU backend (MTLBuffer creation / cudaMalloc can synchronize the device),
|
|
159
|
+
// and beam search saves O(B) snapshots *per step*. The pool therefore
|
|
160
|
+
// recycles slots: at most ~beam_size+1 snapshots are ever live at once, so
|
|
161
|
+
// after the first few steps every `save` reuses an idle slot.
|
|
162
|
+
//
|
|
163
|
+
// Two storage modes, chosen once from whether the cache backend supports a
|
|
164
|
+
// direct device-to-device tensor copy:
|
|
165
|
+
// * DEVICE — discrete-VRAM backends (CUDA, Vulkan, ROCm). The snapshot
|
|
166
|
+
// lives in VRAM and save/restore are on-device blits: no PCIe transfer,
|
|
167
|
+
// no sync-to-host. This is the path that fixes #161.
|
|
168
|
+
// * HOST — unified-memory / CPU backends (Metal, CPU), where the cache
|
|
169
|
+
// is already host-addressable and an on-device blit isn't implemented
|
|
170
|
+
// (and `ggml_backend_tensor_copy` would silently round-trip through a
|
|
171
|
+
// freshly malloc'd staging buffer). Here we snapshot into a recycled
|
|
172
|
+
// host buffer, identical cost to the original code minus the per-step
|
|
173
|
+
// allocation churn.
|
|
174
|
+
struct kv_snapshot {
|
|
175
|
+
ggml_backend_buffer_t buf = nullptr; // DEVICE mode (all tensors packed here)
|
|
176
|
+
ggml_context* meta = nullptr; // DEVICE mode
|
|
177
|
+
std::vector<ggml_tensor*> dev; // DEVICE mode: per-source snapshot tensor
|
|
178
|
+
std::vector<std::vector<uint8_t>> host; // HOST mode: per-source snapshot bytes
|
|
179
|
+
bool in_use = false;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
struct kv_snapshot_pool {
|
|
183
|
+
std::vector<ggml_tensor*> live; // tensors to snapshot, in order
|
|
184
|
+
enum { UNKNOWN, DEVICE, HOST } mode = UNKNOWN;
|
|
185
|
+
std::vector<kv_snapshot*> slots;
|
|
186
|
+
|
|
187
|
+
explicit kv_snapshot_pool(std::vector<ggml_tensor*> tensors) : live(std::move(tensors)) {}
|
|
188
|
+
kv_snapshot_pool(ggml_tensor* k, ggml_tensor* v) : live{k, v} {}
|
|
189
|
+
kv_snapshot_pool(const kv_snapshot_pool&) = delete;
|
|
190
|
+
kv_snapshot_pool& operator=(const kv_snapshot_pool&) = delete;
|
|
191
|
+
|
|
192
|
+
~kv_snapshot_pool() {
|
|
193
|
+
for (kv_snapshot* s : slots) {
|
|
194
|
+
if (s->buf)
|
|
195
|
+
ggml_backend_buffer_free(s->buf);
|
|
196
|
+
if (s->meta)
|
|
197
|
+
ggml_free(s->meta);
|
|
198
|
+
delete s;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
void alloc_device(kv_snapshot* s) {
|
|
203
|
+
const ggml_init_params ip = {ggml_tensor_overhead() * (live.size() + 1) + 256, nullptr, /*no_alloc=*/true};
|
|
204
|
+
s->meta = ggml_init(ip);
|
|
205
|
+
size_t total = 0;
|
|
206
|
+
for (ggml_tensor* t : live)
|
|
207
|
+
total += ggml_nbytes(t);
|
|
208
|
+
ggml_backend_buffer_type_t buft = ggml_backend_buffer_get_type(live[0]->buffer);
|
|
209
|
+
s->buf = ggml_backend_buft_alloc_buffer(buft, total);
|
|
210
|
+
char* base = (char*)ggml_backend_buffer_get_base(s->buf);
|
|
211
|
+
size_t off = 0;
|
|
212
|
+
s->dev.resize(live.size());
|
|
213
|
+
for (size_t i = 0; i < live.size(); i++) {
|
|
214
|
+
s->dev[i] = ggml_new_tensor(s->meta, live[i]->type, GGML_MAX_DIMS, live[i]->ne);
|
|
215
|
+
ggml_backend_tensor_alloc(s->buf, s->dev[i], base + off);
|
|
216
|
+
off += ggml_nbytes(live[i]);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
void free_device(kv_snapshot* s) {
|
|
221
|
+
if (s->buf)
|
|
222
|
+
ggml_backend_buffer_free(s->buf);
|
|
223
|
+
if (s->meta)
|
|
224
|
+
ggml_free(s->meta);
|
|
225
|
+
s->buf = nullptr;
|
|
226
|
+
s->meta = nullptr;
|
|
227
|
+
s->dev.clear();
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
kv_snapshot* save() {
|
|
231
|
+
kv_snapshot* s = nullptr;
|
|
232
|
+
for (kv_snapshot* slot : slots) {
|
|
233
|
+
if (!slot->in_use) {
|
|
234
|
+
s = slot;
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
const bool fresh = (s == nullptr);
|
|
239
|
+
if (fresh) {
|
|
240
|
+
s = new kv_snapshot();
|
|
241
|
+
slots.push_back(s);
|
|
242
|
+
}
|
|
243
|
+
s->in_use = true;
|
|
244
|
+
|
|
245
|
+
// Decide the storage mode the first time we see a real copy: try a
|
|
246
|
+
// device-to-device blit; if the backend can't do it, fall back to a
|
|
247
|
+
// host snapshot for this and every subsequent slot.
|
|
248
|
+
if (mode == UNKNOWN) {
|
|
249
|
+
alloc_device(s);
|
|
250
|
+
bool ok = true;
|
|
251
|
+
for (size_t i = 0; i < live.size(); i++)
|
|
252
|
+
ok = ok && ggml_backend_buffer_copy_tensor(live[i], s->dev[i]);
|
|
253
|
+
if (ok) {
|
|
254
|
+
mode = DEVICE;
|
|
255
|
+
return s;
|
|
256
|
+
}
|
|
257
|
+
mode = HOST;
|
|
258
|
+
free_device(s);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (mode == DEVICE) {
|
|
262
|
+
if (fresh)
|
|
263
|
+
alloc_device(s);
|
|
264
|
+
for (size_t i = 0; i < live.size(); i++)
|
|
265
|
+
ggml_backend_buffer_copy_tensor(live[i], s->dev[i]);
|
|
266
|
+
} else {
|
|
267
|
+
s->host.resize(live.size());
|
|
268
|
+
for (size_t i = 0; i < live.size(); i++) {
|
|
269
|
+
s->host[i].resize(ggml_nbytes(live[i]));
|
|
270
|
+
ggml_backend_tensor_get(live[i], s->host[i].data(), 0, s->host[i].size());
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return s;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
void restore(const kv_snapshot* s) {
|
|
277
|
+
if (mode == DEVICE) {
|
|
278
|
+
for (size_t i = 0; i < live.size(); i++)
|
|
279
|
+
ggml_backend_buffer_copy_tensor(s->dev[i], live[i]);
|
|
280
|
+
} else {
|
|
281
|
+
for (size_t i = 0; i < live.size(); i++)
|
|
282
|
+
ggml_backend_tensor_set(live[i], s->host[i].data(), 0, s->host[i].size());
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
void release(kv_snapshot* s) {
|
|
287
|
+
if (s)
|
|
288
|
+
s->in_use = false;
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
// PLAN #73 — quant-safe per-step KV cache write. Replaces the inline
|
|
293
|
+
// `ggml_cpy(K_perm, ggml_view_4d(kv_k, …))` pattern that several
|
|
294
|
+
// backends use (canary, cohere, kyutai_stt, …). Works for any cache
|
|
295
|
+
// dtype: F16 / F32 take the strided-view + ggml_cpy path (preserved
|
|
296
|
+
// for bit-exactness with the legacy code), Q8_0 / Q4_0 take a
|
|
297
|
+
// ggml_set_rows path keyed by a runtime indices tensor.
|
|
298
|
+
//
|
|
299
|
+
// Caller responsibilities:
|
|
300
|
+
// * `K_perm` / `V_perm` shape: [head_dim, T, n_kv_heads], i.e.
|
|
301
|
+
// already permuted from the QKV layout into cache layout.
|
|
302
|
+
// * `kv_k` / `kv_v` shape: [head_dim, max_ctx, n_kv_heads, n_layers].
|
|
303
|
+
// * `indices` is an I32 tensor of length T containing the cache
|
|
304
|
+
// positions to write to (typically `[n_past, n_past+T)` — the
|
|
305
|
+
// same tensor used as RoPE positions). Required for quant cache;
|
|
306
|
+
// may be nullptr for F16/F32 (the fast static-offset path will
|
|
307
|
+
// be used).
|
|
308
|
+
//
|
|
309
|
+
// Adds the K and V writes to `gf` via ggml_build_forward_expand. The
|
|
310
|
+
// returned bool is informational: true if the quant path was taken,
|
|
311
|
+
// false for the F16 fast path.
|
|
312
|
+
inline bool kv_cache_write(ggml_context* ctx, ggml_cgraph* gf, ggml_tensor* K_perm, ggml_tensor* V_perm,
|
|
313
|
+
ggml_tensor* kv_k, ggml_tensor* kv_v, int layer_idx, int n_past, int T,
|
|
314
|
+
ggml_tensor* indices) {
|
|
315
|
+
const bool quant_k = ggml_is_quantized(kv_k->type);
|
|
316
|
+
const bool quant_v = ggml_is_quantized(kv_v->type);
|
|
317
|
+
const bool quant_any = quant_k || quant_v;
|
|
318
|
+
|
|
319
|
+
if (!quant_any) {
|
|
320
|
+
// Legacy F16/F32 path: strided view + ggml_cpy. Bit-identical
|
|
321
|
+
// to the inline code that callers used to have.
|
|
322
|
+
const int hd = (int)kv_k->ne[0];
|
|
323
|
+
const int nh = (int)kv_k->ne[2];
|
|
324
|
+
ggml_tensor* k_dst = ggml_view_4d(ctx, kv_k, hd, T, nh, 1, kv_k->nb[1], kv_k->nb[2], kv_k->nb[3],
|
|
325
|
+
(size_t)layer_idx * kv_k->nb[3] + (size_t)n_past * kv_k->nb[1]);
|
|
326
|
+
ggml_build_forward_expand(gf, ggml_cpy(ctx, K_perm, k_dst));
|
|
327
|
+
ggml_tensor* v_dst = ggml_view_4d(ctx, kv_v, hd, T, nh, 1, kv_v->nb[1], kv_v->nb[2], kv_v->nb[3],
|
|
328
|
+
(size_t)layer_idx * kv_v->nb[3] + (size_t)n_past * kv_v->nb[1]);
|
|
329
|
+
ggml_build_forward_expand(gf, ggml_cpy(ctx, V_perm, v_dst));
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Quant path: ggml_set_rows expects rows along ne[0] of the dst.
|
|
334
|
+
// The cache layout is [hd, max_ctx, n_kv, n_layers]; rows are along
|
|
335
|
+
// max_ctx (dim 1). So we view the layer slice as [hd, max_ctx, nh],
|
|
336
|
+
// then ggml_set_rows writes T rows at positions given by `indices`.
|
|
337
|
+
GGML_ASSERT(indices && "kv_cache_write: quant cache requires indices tensor");
|
|
338
|
+
const int hd = (int)kv_k->ne[0];
|
|
339
|
+
const int nh = (int)kv_k->ne[2];
|
|
340
|
+
ggml_tensor* k_layer =
|
|
341
|
+
ggml_view_3d(ctx, kv_k, hd, (int)kv_k->ne[1], nh, kv_k->nb[1], kv_k->nb[2], (size_t)layer_idx * kv_k->nb[3]);
|
|
342
|
+
ggml_tensor* v_layer =
|
|
343
|
+
ggml_view_3d(ctx, kv_v, hd, (int)kv_v->ne[1], nh, kv_v->nb[1], kv_v->nb[2], (size_t)layer_idx * kv_v->nb[3]);
|
|
344
|
+
ggml_build_forward_expand(gf, ggml_set_rows(ctx, k_layer, K_perm, indices));
|
|
345
|
+
ggml_build_forward_expand(gf, ggml_set_rows(ctx, v_layer, V_perm, indices));
|
|
346
|
+
(void)n_past; // unused on quant path; indices carries position info
|
|
347
|
+
return true;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Parameters that differ from call to call. Everything here is a plain
|
|
351
|
+
// value type so the compiler can inline the caller's constants into the
|
|
352
|
+
// helper's ggml_* op chain.
|
|
353
|
+
struct LlamaSelfAttnParams {
|
|
354
|
+
int n_heads; // query heads (== n_kv_heads for MHA)
|
|
355
|
+
int n_kv_heads; // key/value heads; with GQA, n_heads / n_kv_heads > 1
|
|
356
|
+
int head_dim; // per-head dimension
|
|
357
|
+
int n_kv_grp; // == n_heads / n_kv_heads (caller precomputes)
|
|
358
|
+
int n_ctx_orig; // rope n_ctx_orig (usually llm_max_pos)
|
|
359
|
+
float rope_theta;
|
|
360
|
+
float attn_scale; // usually 1 / sqrt(head_dim); pass explicitly
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
// Llama / Mistral-style self-attention with optional GQA, NEOX RoPE, and
|
|
364
|
+
// ggml_flash_attn_ext.
|
|
365
|
+
//
|
|
366
|
+
// Inputs:
|
|
367
|
+
// x [d_model, T] — RMSNormed input for this layer (the
|
|
368
|
+
// caller does the norm + the learned
|
|
369
|
+
// scale multiplication)
|
|
370
|
+
// q_w,k_w,v_w Q/K/V weight tensors (no biases in the LLM case)
|
|
371
|
+
// o_w output projection weight
|
|
372
|
+
// positions [T] — RoPE position ids
|
|
373
|
+
// mask [ctx, T] F16 — causal / sliding-window mask or nullptr
|
|
374
|
+
// for no-mask (voxtral audio case)
|
|
375
|
+
//
|
|
376
|
+
// Output:
|
|
377
|
+
// attn [d_model, T] — post-output-projection tensor. The
|
|
378
|
+
// caller adds it to the residual.
|
|
379
|
+
// Fused QKV variant: if qkv_w is non-null, do a single matmul and split.
|
|
380
|
+
// qkv_w shape: [d_model, n_q*hd + 2*n_kv*hd] — concatenated Q, K, V weights.
|
|
381
|
+
// Falls back to 3 separate matmuls when qkv_w is null (backward compat).
|
|
382
|
+
static inline ggml_tensor* llama_self_attn(ggml_context* ctx, ggml_tensor* x, ggml_tensor* q_w, ggml_tensor* k_w,
|
|
383
|
+
ggml_tensor* v_w, ggml_tensor* o_w, ggml_tensor* positions,
|
|
384
|
+
ggml_tensor* mask, const LlamaSelfAttnParams& p,
|
|
385
|
+
ggml_tensor* qkv_w = nullptr) {
|
|
386
|
+
const int hd = p.head_dim;
|
|
387
|
+
const int n_q = p.n_heads;
|
|
388
|
+
const int n_kv = p.n_kv_heads;
|
|
389
|
+
const int n_ctx = p.n_ctx_orig;
|
|
390
|
+
const int grp = p.n_kv_grp;
|
|
391
|
+
|
|
392
|
+
ggml_tensor* Q;
|
|
393
|
+
ggml_tensor* K;
|
|
394
|
+
ggml_tensor* V;
|
|
395
|
+
|
|
396
|
+
if (qkv_w) {
|
|
397
|
+
// Single fused matmul: one mul_mat instead of three.
|
|
398
|
+
// qkv_w: [d_model, q_dim + k_dim + v_dim]
|
|
399
|
+
// Output: [q_dim + k_dim + v_dim, T]
|
|
400
|
+
ggml_tensor* qkv = ggml_mul_mat(ctx, qkv_w, x);
|
|
401
|
+
const int q_dim = n_q * hd;
|
|
402
|
+
const int kv_dim = n_kv * hd;
|
|
403
|
+
const int T = (int)x->ne[1];
|
|
404
|
+
// Split along ne[0]: Q=[0..q_dim), K=[q_dim..q_dim+kv_dim), V=[q_dim+kv_dim..)
|
|
405
|
+
Q = ggml_view_2d(ctx, qkv, q_dim, T, qkv->nb[1], 0);
|
|
406
|
+
K = ggml_view_2d(ctx, qkv, kv_dim, T, qkv->nb[1], q_dim * ggml_type_size(qkv->type));
|
|
407
|
+
V = ggml_view_2d(ctx, qkv, kv_dim, T, qkv->nb[1], (q_dim + kv_dim) * ggml_type_size(qkv->type));
|
|
408
|
+
} else {
|
|
409
|
+
// Standard 3 separate matmuls (backward compat).
|
|
410
|
+
Q = ggml_mul_mat(ctx, q_w, x);
|
|
411
|
+
K = ggml_mul_mat(ctx, k_w, x);
|
|
412
|
+
V = ggml_mul_mat(ctx, v_w, x);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// T is the time dim of x; ggml stores [d_model, T] as ne = [d_model, T].
|
|
416
|
+
const int T = (int)x->ne[1];
|
|
417
|
+
|
|
418
|
+
Q = ggml_reshape_3d(ctx, Q, hd, n_q, T);
|
|
419
|
+
K = ggml_reshape_3d(ctx, K, hd, n_kv, T);
|
|
420
|
+
V = ggml_reshape_3d(ctx, V, hd, n_kv, T);
|
|
421
|
+
|
|
422
|
+
// NEOX RoPE on Q and K. Same args as the original inline code in
|
|
423
|
+
// voxtral / voxtral4b / qwen3 / granite LLM blocks.
|
|
424
|
+
Q = ggml_rope_ext(ctx, Q, positions, /*freq_factors*/ nullptr, hd, GGML_ROPE_TYPE_NEOX, n_ctx, p.rope_theta,
|
|
425
|
+
/*freq_scale*/ 1.0f, /*ext_factor*/ 0.0f,
|
|
426
|
+
/*attn_factor*/ 1.0f, /*beta_fast*/ 32.0f, /*beta_slow*/ 1.0f);
|
|
427
|
+
K = ggml_rope_ext(ctx, K, positions, nullptr, hd, GGML_ROPE_TYPE_NEOX, n_ctx, p.rope_theta, 1.0f, 0.0f, 1.0f, 32.0f,
|
|
428
|
+
1.0f);
|
|
429
|
+
|
|
430
|
+
// GQA expansion: replicate each KV head `grp` times along a new dim so
|
|
431
|
+
// K/V have n_heads rows instead of n_kv_heads, then flatten back.
|
|
432
|
+
if (grp > 1) {
|
|
433
|
+
ggml_tensor* K4 = ggml_reshape_4d(ctx, K, hd, 1, n_kv, T);
|
|
434
|
+
ggml_tensor* V4 = ggml_reshape_4d(ctx, V, hd, 1, n_kv, T);
|
|
435
|
+
K4 = ggml_repeat_4d(ctx, K4, hd, grp, n_kv, T);
|
|
436
|
+
V4 = ggml_repeat_4d(ctx, V4, hd, grp, n_kv, T);
|
|
437
|
+
K = ggml_cont(ctx, ggml_reshape_3d(ctx, K4, hd, n_q, T));
|
|
438
|
+
V = ggml_cont(ctx, ggml_reshape_3d(ctx, V4, hd, n_q, T));
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Permute to flash-attention layout: (head_dim, T, n_heads).
|
|
442
|
+
Q = ggml_cont(ctx, ggml_permute(ctx, Q, 0, 2, 1, 3));
|
|
443
|
+
K = ggml_cont(ctx, ggml_permute(ctx, K, 0, 2, 1, 3));
|
|
444
|
+
V = ggml_cont(ctx, ggml_permute(ctx, V, 0, 2, 1, 3));
|
|
445
|
+
|
|
446
|
+
// Flash attention. Output shape = (head_dim, n_heads, T, 1).
|
|
447
|
+
ggml_tensor* attn =
|
|
448
|
+
ggml_flash_attn_ext(ctx, Q, K, V, mask, p.attn_scale, /*max_bias*/ 0.0f, /*logit_softcap*/ 0.0f);
|
|
449
|
+
|
|
450
|
+
// Back to (d_model, T).
|
|
451
|
+
attn = ggml_reshape_2d(ctx, attn, hd * n_q, T);
|
|
452
|
+
|
|
453
|
+
// Output projection (no bias).
|
|
454
|
+
return ggml_mul_mat(ctx, o_w, attn);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// ---------------------------------------------------------------------------
|
|
458
|
+
// Encoder self-attention — biased Q/K/V/O projections, optional RoPE.
|
|
459
|
+
//
|
|
460
|
+
// Covers architectures like the Whisper audio encoder (voxtral 3B) and the
|
|
461
|
+
// causal RoPE+SwiGLU audio encoder (voxtral4b). Key differences from the
|
|
462
|
+
// LLM llama_self_attn():
|
|
463
|
+
// - Q, K, V, O projections can each have an optional bias (nullptr = skip)
|
|
464
|
+
// - RoPE is optional: pass positions == nullptr to skip
|
|
465
|
+
// - GQA expansion is included for architectures that use it
|
|
466
|
+
//
|
|
467
|
+
// The caller still handles the pre-attention norm and post-attention
|
|
468
|
+
// residual add.
|
|
469
|
+
// ---------------------------------------------------------------------------
|
|
470
|
+
|
|
471
|
+
struct EncoderSelfAttnParams {
|
|
472
|
+
int n_heads; // query heads
|
|
473
|
+
int n_kv_heads; // key/value heads (usually == n_heads for encoders)
|
|
474
|
+
int head_dim;
|
|
475
|
+
int n_kv_grp; // n_heads / n_kv_heads (1 for MHA)
|
|
476
|
+
float attn_scale; // usually 1/sqrt(head_dim)
|
|
477
|
+
// RoPE params (only used when positions != nullptr)
|
|
478
|
+
int n_ctx_orig;
|
|
479
|
+
float rope_theta;
|
|
480
|
+
// When true (default), wrap ggml_permute() in ggml_cont() before
|
|
481
|
+
// flash_attn_ext. voxtral 3B needs this; voxtral4b does not (its
|
|
482
|
+
// encoder was written without cont and changing it would alter the
|
|
483
|
+
// ggml graph structure). Set to false for voxtral4b compatibility.
|
|
484
|
+
bool permute_cont = true;
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
static inline ggml_tensor* encoder_self_attn(ggml_context* ctx, ggml_tensor* x, ggml_tensor* q_w, ggml_tensor* q_b,
|
|
488
|
+
ggml_tensor* k_w, ggml_tensor* k_b, ggml_tensor* v_w, ggml_tensor* v_b,
|
|
489
|
+
ggml_tensor* o_w, ggml_tensor* o_b, ggml_tensor* positions,
|
|
490
|
+
ggml_tensor* mask, const EncoderSelfAttnParams& p) {
|
|
491
|
+
const int hd = p.head_dim;
|
|
492
|
+
const int n_q = p.n_heads;
|
|
493
|
+
const int n_kv = p.n_kv_heads;
|
|
494
|
+
const int grp = p.n_kv_grp;
|
|
495
|
+
const int T = (int)x->ne[1];
|
|
496
|
+
|
|
497
|
+
// Q/K/V projections with optional biases.
|
|
498
|
+
ggml_tensor* Q = ggml_mul_mat(ctx, q_w, x);
|
|
499
|
+
if (q_b)
|
|
500
|
+
Q = ggml_add(ctx, Q, q_b);
|
|
501
|
+
ggml_tensor* K = ggml_mul_mat(ctx, k_w, x);
|
|
502
|
+
if (k_b)
|
|
503
|
+
K = ggml_add(ctx, K, k_b);
|
|
504
|
+
ggml_tensor* V = ggml_mul_mat(ctx, v_w, x);
|
|
505
|
+
if (v_b)
|
|
506
|
+
V = ggml_add(ctx, V, v_b);
|
|
507
|
+
|
|
508
|
+
Q = ggml_reshape_3d(ctx, Q, hd, n_q, T);
|
|
509
|
+
K = ggml_reshape_3d(ctx, K, hd, n_kv, T);
|
|
510
|
+
V = ggml_reshape_3d(ctx, V, hd, n_kv, T);
|
|
511
|
+
|
|
512
|
+
// Optional RoPE (skip for encoders with learned positional embeddings).
|
|
513
|
+
if (positions) {
|
|
514
|
+
Q = ggml_rope_ext(ctx, Q, positions, nullptr, hd, GGML_ROPE_TYPE_NEOX, p.n_ctx_orig, p.rope_theta, 1.0f, 0.0f,
|
|
515
|
+
1.0f, 0.0f, 0.0f);
|
|
516
|
+
K = ggml_rope_ext(ctx, K, positions, nullptr, hd, GGML_ROPE_TYPE_NEOX, p.n_ctx_orig, p.rope_theta, 1.0f, 0.0f,
|
|
517
|
+
1.0f, 0.0f, 0.0f);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// GQA expansion (when n_kv_heads < n_heads).
|
|
521
|
+
if (grp > 1) {
|
|
522
|
+
ggml_tensor* K4 = ggml_reshape_4d(ctx, K, hd, 1, n_kv, T);
|
|
523
|
+
ggml_tensor* V4 = ggml_reshape_4d(ctx, V, hd, 1, n_kv, T);
|
|
524
|
+
K4 = ggml_repeat_4d(ctx, K4, hd, grp, n_kv, T);
|
|
525
|
+
V4 = ggml_repeat_4d(ctx, V4, hd, grp, n_kv, T);
|
|
526
|
+
K = ggml_cont(ctx, ggml_reshape_3d(ctx, K4, hd, n_q, T));
|
|
527
|
+
V = ggml_cont(ctx, ggml_reshape_3d(ctx, V4, hd, n_q, T));
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Permute to flash-attention layout: (head_dim, T, n_heads).
|
|
531
|
+
Q = ggml_permute(ctx, Q, 0, 2, 1, 3);
|
|
532
|
+
K = ggml_permute(ctx, K, 0, 2, 1, 3);
|
|
533
|
+
V = ggml_permute(ctx, V, 0, 2, 1, 3);
|
|
534
|
+
if (p.permute_cont) {
|
|
535
|
+
Q = ggml_cont(ctx, Q);
|
|
536
|
+
K = ggml_cont(ctx, K);
|
|
537
|
+
V = ggml_cont(ctx, V);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// Flash attention (bidirectional if mask==nullptr, causal/SWA otherwise).
|
|
541
|
+
ggml_tensor* attn = ggml_flash_attn_ext(ctx, Q, K, V, mask, p.attn_scale, 0.0f, 0.0f);
|
|
542
|
+
attn = ggml_reshape_2d(ctx, attn, hd * n_q, T);
|
|
543
|
+
|
|
544
|
+
// Output projection with optional bias.
|
|
545
|
+
attn = ggml_mul_mat(ctx, o_w, attn);
|
|
546
|
+
if (o_b)
|
|
547
|
+
attn = ggml_add(ctx, attn, o_b);
|
|
548
|
+
return attn;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// ---------------------------------------------------------------------------
|
|
552
|
+
// KV-cached self-attention for the LLM decoders (qwen3-asr, voxtral,
|
|
553
|
+
// voxtral4b, granite-speech).
|
|
554
|
+
//
|
|
555
|
+
// Replaces the Q/K/V-proj + [optional Q/K norm] + RoPE + persistent-KV-cache
|
|
556
|
+
// write + cache read + [manual GQA expansion] + flash-attn-ext + output-proj
|
|
557
|
+
// block that each of the four models has its own copy of. The helper does
|
|
558
|
+
// NOT do the pre-attention RMSNorm or the post-attention residual add —
|
|
559
|
+
// callers do those inline so the helper stays focused on the attention
|
|
560
|
+
// block proper (which is where the per-model knobs live).
|
|
561
|
+
//
|
|
562
|
+
// KV cache layout convention: ne = (head_dim, max_ctx, n_kv_heads, n_layers).
|
|
563
|
+
// Every consumer already stores its cache this way, which is why this helper
|
|
564
|
+
// is shareable in the first place.
|
|
565
|
+
// ---------------------------------------------------------------------------
|
|
566
|
+
|
|
567
|
+
// GQA expansion strategy.
|
|
568
|
+
//
|
|
569
|
+
// qwen3 and voxtral (3b) manually expand each KV head into `n_kv_grp` query
|
|
570
|
+
// heads via reshape_4d -> repeat_4d -> reshape_3d, and then wrap the final
|
|
571
|
+
// reshape in ggml_cont. voxtral4b also manually expands, but skips the final
|
|
572
|
+
// ggml_cont. granite skips the manual expansion entirely and relies on
|
|
573
|
+
// ggml_flash_attn_ext's native GQA support (pass Kfull/Vfull with n_kv heads
|
|
574
|
+
// directly, flash-attn handles the repeat internally).
|
|
575
|
+
//
|
|
576
|
+
// Each mode produces slightly different graph ops. Picking the wrong one
|
|
577
|
+
// breaks bit-identity on the regression sweep, so this is an explicit knob.
|
|
578
|
+
enum GqaMode {
|
|
579
|
+
GQA_MANUAL_CONT = 0, // reshape_4d / repeat_4d / reshape_3d + ggml_cont
|
|
580
|
+
GQA_MANUAL_NOCONT = 1, // reshape_4d / repeat_4d / reshape_3d, no final cont
|
|
581
|
+
GQA_NATIVE = 2, // no expansion; flash_attn_ext handles GQA itself
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
struct KvSelfAttnParams {
|
|
585
|
+
int n_heads; // query heads
|
|
586
|
+
int n_kv_heads; // key/value heads (== n_heads for MHA)
|
|
587
|
+
int head_dim; // per-head dimension
|
|
588
|
+
int n_kv_grp; // n_heads / n_kv_heads (caller precomputes)
|
|
589
|
+
int n_ctx_orig; // RoPE n_ctx_orig (some models 0, some llm_max_pos)
|
|
590
|
+
float rope_theta;
|
|
591
|
+
float rope_beta_fast; // RoPE extrapolation beta_fast (qwen3/voxtral: 32, others: 0)
|
|
592
|
+
float rope_beta_slow; // RoPE extrapolation beta_slow (qwen3/voxtral: 1, others: 0)
|
|
593
|
+
float attn_scale; // usually 1/sqrt(head_dim); granite uses µP scale
|
|
594
|
+
float qk_norm_eps; // RMSNorm epsilon for optional Q/K norm (qwen3); unused otherwise
|
|
595
|
+
GqaMode gqa_mode;
|
|
596
|
+
int rope_type = GGML_ROPE_TYPE_NEOX; // NEOX for most models, NORMAL for fairseq2/omniasr
|
|
597
|
+
// Partial-rotary RoPE: number of head-dim entries to rotate. The
|
|
598
|
+
// remaining `head_dim - n_rot` entries pass through unchanged. Used
|
|
599
|
+
// by Gemma4 full-attention layers (`partial_rotary_factor=0.25`,
|
|
600
|
+
// i.e. n_rot = head_dim/4) and Phi-3-style models. Default 0 means
|
|
601
|
+
// rotate the entire head_dim — matches every existing caller.
|
|
602
|
+
int n_rot = 0;
|
|
603
|
+
// Apply RMSNorm-without-learned-weight to V before the cache write.
|
|
604
|
+
// Gemma4's `v_norm` is constructed with `with_scale=False`, i.e.
|
|
605
|
+
// RMSNorm with no learned scale tensor — there is no weight to load,
|
|
606
|
+
// we just need to run the normalisation op on V. Default false → no
|
|
607
|
+
// op, matches every other consumer.
|
|
608
|
+
bool v_rms_norm = false;
|
|
609
|
+
// Optional per-dimension RoPE frequency factors (e.g. Llama 3 scaling).
|
|
610
|
+
ggml_tensor* rope_freq_factors = nullptr;
|
|
611
|
+
// Force the cached K/V to be cast to F32 before the GQA repeat/expansion,
|
|
612
|
+
// exactly like the global CRISPASR_KV_READ_F32 knob but per-call. Needed on
|
|
613
|
+
// Vulkan, where REPEAT has no f16→f16 pipeline (the GQA head-expansion
|
|
614
|
+
// `ggml_repeat_4d` on an F16 cache aborts with "Missing op: REPEAT for f16
|
|
615
|
+
// to f16"; #192). Casting to F32 first lowers it to a supported F32 REPEAT.
|
|
616
|
+
// Default false → legacy F16 fast path on Metal/CPU. Caller sets it true only
|
|
617
|
+
// for the Vulkan-native graph.
|
|
618
|
+
bool force_kv_read_f32 = false;
|
|
619
|
+
};
|
|
620
|
+
|
|
621
|
+
// KV-cached self-attention. Writes the new K/V into the persistent cache
|
|
622
|
+
// slice at [n_past, n_past + T) for layer `il`, then reads the full history
|
|
623
|
+
// [0, n_past + T) back out and runs flash-attention against Q.
|
|
624
|
+
//
|
|
625
|
+
// Inputs:
|
|
626
|
+
// x [d_model, T] — pre-attention normalized activations
|
|
627
|
+
// q_w,k_w,v_w projection weights (no biases for the Llama case)
|
|
628
|
+
// o_w output projection weight (no bias)
|
|
629
|
+
// q_norm_w [head_dim] Q-norm weight, or nullptr to skip (non-qwen3)
|
|
630
|
+
// k_norm_w [head_dim] K-norm weight, or nullptr to skip
|
|
631
|
+
// positions [T] I32 — absolute positions n_past, n_past+1, ...
|
|
632
|
+
// causal_mask [Lk, T] F16 or nullptr (decode path uses nullptr)
|
|
633
|
+
// kv_k, kv_v persistent cache, ne = (hd, max_ctx, n_kv, n_layers)
|
|
634
|
+
// il layer index into the cache's trailing dim
|
|
635
|
+
// n_past number of tokens already in the cache
|
|
636
|
+
//
|
|
637
|
+
// Output:
|
|
638
|
+
// attn [d_model, T] — post-output-projection tensor. Caller adds
|
|
639
|
+
// it to the residual.
|
|
640
|
+
// fixed_kv_len > 0: override the KV-read length (Lk) to a constant, keeping
|
|
641
|
+
// topology identical across calls with different n_past. Unwritten slots are
|
|
642
|
+
// masked to -inf by causal_mask so they never affect output.
|
|
643
|
+
//
|
|
644
|
+
// kv_indices != nullptr: scatter the new K/V into the cache via ggml_set_rows
|
|
645
|
+
// keyed by the runtime indices tensor instead of the default static-offset
|
|
646
|
+
// ggml_cpy. Required for graph-cache reuse across calls at different n_past:
|
|
647
|
+
// the static-offset path bakes n_past into the graph as a literal byte offset,
|
|
648
|
+
// so a cached graph built at n_past=A would write to slot A even when reused at
|
|
649
|
+
// n_past=B; the dynamic-index path makes the destination a runtime input. Pass
|
|
650
|
+
// the same `positions` tensor that's already populated with [n_past, n_past+T)
|
|
651
|
+
// for RoPE — the indices required for set_rows are bit-equivalent.
|
|
652
|
+
//
|
|
653
|
+
// q_b/k_b/v_b/o_b: optional projection biases. Qwen2 (mimo-asr LM) sets
|
|
654
|
+
// `attention_bias=true` and ships per-layer Q/K/V biases; Qwen3 / Llama /
|
|
655
|
+
// granite / voxtral / gemma4 do not. Default nullptr keeps the graph
|
|
656
|
+
// bit-identical for those callers.
|
|
657
|
+
//
|
|
658
|
+
// qkv_b: optional fused-bias for the Qwen2 fused-QKV path. When qkv_w is
|
|
659
|
+
// non-null and the GGUF stores a fused `attn.qkv.bias` (length q_dim +
|
|
660
|
+
// 2*kv_dim), pass it here — it's added to the fused matmul output before
|
|
661
|
+
// the Q/K/V split. q_b/k_b/v_b should be nullptr in that case (the
|
|
662
|
+
// caller emits one fused tensor instead of three). Algebraically
|
|
663
|
+
// identical to per-projection bias adds; one ggml_add op instead of
|
|
664
|
+
// three.
|
|
665
|
+
static inline ggml_tensor* kv_self_attn(ggml_context* ctx0, ggml_cgraph* gf, ggml_tensor* x, ggml_tensor* q_w,
|
|
666
|
+
ggml_tensor* k_w, ggml_tensor* v_w, ggml_tensor* o_w, ggml_tensor* q_norm_w,
|
|
667
|
+
ggml_tensor* k_norm_w, ggml_tensor* positions, ggml_tensor* causal_mask,
|
|
668
|
+
ggml_tensor* kv_k, ggml_tensor* kv_v, int il, int n_past,
|
|
669
|
+
const KvSelfAttnParams& p, ggml_tensor* qkv_w = nullptr, int fixed_kv_len = 0,
|
|
670
|
+
ggml_tensor* kv_indices = nullptr, ggml_tensor* q_b = nullptr,
|
|
671
|
+
ggml_tensor* k_b = nullptr, ggml_tensor* v_b = nullptr,
|
|
672
|
+
ggml_tensor* o_b = nullptr, ggml_tensor* qkv_b = nullptr) {
|
|
673
|
+
const int hd = p.head_dim;
|
|
674
|
+
const int n_q = p.n_heads;
|
|
675
|
+
const int n_kv = p.n_kv_heads;
|
|
676
|
+
const int grp = p.n_kv_grp;
|
|
677
|
+
const int T = (int)x->ne[1];
|
|
678
|
+
const int Lk = fixed_kv_len > 0 ? fixed_kv_len : (n_past + T);
|
|
679
|
+
|
|
680
|
+
// ---- Q/K/V projections ----
|
|
681
|
+
ggml_tensor* Q;
|
|
682
|
+
ggml_tensor* K;
|
|
683
|
+
ggml_tensor* V;
|
|
684
|
+
|
|
685
|
+
if (qkv_w) {
|
|
686
|
+
// Fused: one matmul, then split output. The 2D views below are
|
|
687
|
+
// strided (each T-row leaves gaps for the other Q/K/V), so for T>1
|
|
688
|
+
// the downstream ggml_reshape_3d would fail its contiguity assert.
|
|
689
|
+
// ggml_cont materialises each into its own contiguous buffer; for
|
|
690
|
+
// T=1 the cont is a no-op (single row is already contiguous).
|
|
691
|
+
ggml_tensor* qkv = ggml_mul_mat(ctx0, qkv_w, x);
|
|
692
|
+
if (qkv_b) {
|
|
693
|
+
// Fused bias (1D, length q_dim + 2*kv_dim) added before the
|
|
694
|
+
// split so each Q/K/V chunk picks up its own slice. One add
|
|
695
|
+
// instead of three; algebraically identical to per-proj adds.
|
|
696
|
+
qkv = ggml_add(ctx0, qkv, qkv_b);
|
|
697
|
+
}
|
|
698
|
+
const int q_dim = n_q * hd;
|
|
699
|
+
const int kv_dim = n_kv * hd;
|
|
700
|
+
const size_t ts = ggml_type_size(qkv->type);
|
|
701
|
+
Q = ggml_view_2d(ctx0, qkv, q_dim, T, qkv->nb[1], 0);
|
|
702
|
+
K = ggml_view_2d(ctx0, qkv, kv_dim, T, qkv->nb[1], q_dim * ts);
|
|
703
|
+
V = ggml_view_2d(ctx0, qkv, kv_dim, T, qkv->nb[1], (q_dim + kv_dim) * ts);
|
|
704
|
+
if (T > 1) {
|
|
705
|
+
Q = ggml_cont(ctx0, Q);
|
|
706
|
+
K = ggml_cont(ctx0, K);
|
|
707
|
+
V = ggml_cont(ctx0, V);
|
|
708
|
+
}
|
|
709
|
+
} else {
|
|
710
|
+
Q = ggml_mul_mat(ctx0, q_w, x);
|
|
711
|
+
K = ggml_mul_mat(ctx0, k_w, x);
|
|
712
|
+
V = ggml_mul_mat(ctx0, v_w, x);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// Optional Q/K/V projection biases (Qwen2). Applied before reshape so
|
|
716
|
+
// the bias broadcasts along the time dim; q_b/k_b/v_b are 1D.
|
|
717
|
+
if (q_b)
|
|
718
|
+
Q = ggml_add(ctx0, Q, q_b);
|
|
719
|
+
if (k_b)
|
|
720
|
+
K = ggml_add(ctx0, K, k_b);
|
|
721
|
+
if (v_b)
|
|
722
|
+
V = ggml_add(ctx0, V, v_b);
|
|
723
|
+
|
|
724
|
+
Q = ggml_reshape_3d(ctx0, Q, hd, n_q, T);
|
|
725
|
+
K = ggml_reshape_3d(ctx0, K, hd, n_kv, T);
|
|
726
|
+
V = ggml_reshape_3d(ctx0, V, hd, n_kv, T);
|
|
727
|
+
|
|
728
|
+
// ---- Optional Q/K RMSNorm (qwen3) ----
|
|
729
|
+
if (q_norm_w) {
|
|
730
|
+
Q = ggml_rms_norm(ctx0, Q, p.qk_norm_eps);
|
|
731
|
+
Q = ggml_mul(ctx0, Q, q_norm_w);
|
|
732
|
+
}
|
|
733
|
+
if (k_norm_w) {
|
|
734
|
+
K = ggml_rms_norm(ctx0, K, p.qk_norm_eps);
|
|
735
|
+
K = ggml_mul(ctx0, K, k_norm_w);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// ---- Optional V RMSNorm without learned weight (gemma4) ----
|
|
739
|
+
// gemma4's v_norm is `Gemma4RMSNorm(head_dim, with_scale=False)`,
|
|
740
|
+
// so there is no weight tensor — we just normalise V along its
|
|
741
|
+
// last (head_dim) axis, exactly as ggml_rms_norm does.
|
|
742
|
+
if (p.v_rms_norm) {
|
|
743
|
+
V = ggml_rms_norm(ctx0, V, p.qk_norm_eps);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
// ---- RoPE (NEOX for most models, NORMAL for fairseq2/omniasr) ----
|
|
747
|
+
// p.n_rot > 0 selects partial-rotary mode (only the first n_rot
|
|
748
|
+
// entries of each head are rotated; the rest pass through). 0
|
|
749
|
+
// means rotate the entire head_dim, which matches every existing
|
|
750
|
+
// caller's prior behaviour.
|
|
751
|
+
// Skip RoPE when rope_theta <= 0 (e.g. VoxCPM2 RALM has no positional
|
|
752
|
+
// encoding). powf(0, -2/d) = inf → NaN (#164).
|
|
753
|
+
if (p.rope_theta > 0.0f) {
|
|
754
|
+
const int n_rot = p.n_rot > 0 ? p.n_rot : hd;
|
|
755
|
+
Q = ggml_rope_ext(ctx0, Q, positions, p.rope_freq_factors, n_rot, p.rope_type, p.n_ctx_orig, p.rope_theta,
|
|
756
|
+
/*freq_scale*/ 1.0f, /*ext_factor*/ 0.0f,
|
|
757
|
+
/*attn_factor*/ 1.0f, p.rope_beta_fast, p.rope_beta_slow);
|
|
758
|
+
K = ggml_rope_ext(ctx0, K, positions, p.rope_freq_factors, n_rot, p.rope_type, p.n_ctx_orig, p.rope_theta, 1.0f,
|
|
759
|
+
0.0f, 1.0f, p.rope_beta_fast, p.rope_beta_slow);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// ---- Permute new K/V to (hd, T, n_kv) for cache write ----
|
|
763
|
+
ggml_tensor* K_new_perm = ggml_permute(ctx0, K, 0, 2, 1, 3);
|
|
764
|
+
ggml_tensor* V_new_perm = ggml_permute(ctx0, V, 0, 2, 1, 3);
|
|
765
|
+
|
|
766
|
+
// ---- Write into the persistent KV cache at [n_past, n_past+T) ----
|
|
767
|
+
// The default ggml_cpy(F32, slice-of-cache) path requires the
|
|
768
|
+
// destination to be contiguous when the source/dst types differ
|
|
769
|
+
// (CPU backend's `dup_to_q` aborts otherwise, and Metal's CPY also
|
|
770
|
+
// skips non-contiguous quantised dst). For a quantised cache —
|
|
771
|
+
// PLAN #60e CRISPASR_KV_QUANT={q8_0,q4_0} — we instead always use
|
|
772
|
+
// `ggml_set_rows` with a per-token row-index tensor, which both
|
|
773
|
+
// backends accept for F32→Q* directly. When the caller already
|
|
774
|
+
// supplies `kv_indices` (cached-graph reuse path) we honour that;
|
|
775
|
+
// otherwise we synthesise the indices from `positions` (which is
|
|
776
|
+
// [n_past..n_past+T) by construction for RoPE — exactly the row
|
|
777
|
+
// ids set_rows needs).
|
|
778
|
+
const bool quant_kv = ggml_is_quantized(kv_k->type);
|
|
779
|
+
// When the write goes through ggml_set_rows we keep the result tensors so
|
|
780
|
+
// the read view below can be based on them (see the read path) — that gives
|
|
781
|
+
// the scheduler an explicit write→read dependency edge. Without it the read
|
|
782
|
+
// views the bare cache and the set_rows nodes become graph dead-ends, so on
|
|
783
|
+
// Metal the KV read races the in-place set_rows write and reads stale/garbage
|
|
784
|
+
// (the Lk-bucket single-step decode in orpheus/parler hits this). Mirrors
|
|
785
|
+
// parler_tts's bucket read path.
|
|
786
|
+
ggml_tensor* sr_k = nullptr;
|
|
787
|
+
ggml_tensor* sr_v = nullptr;
|
|
788
|
+
if (kv_indices || quant_kv) {
|
|
789
|
+
ggml_tensor* eff_idx = kv_indices ? kv_indices : positions;
|
|
790
|
+
ggml_tensor* k_layer =
|
|
791
|
+
ggml_view_3d(ctx0, kv_k, hd, kv_k->ne[1], n_kv, kv_k->nb[1], kv_k->nb[2], (size_t)il * kv_k->nb[3]);
|
|
792
|
+
ggml_tensor* v_layer =
|
|
793
|
+
ggml_view_3d(ctx0, kv_v, hd, kv_v->ne[1], n_kv, kv_v->nb[1], kv_v->nb[2], (size_t)il * kv_v->nb[3]);
|
|
794
|
+
sr_k = ggml_set_rows(ctx0, k_layer, K_new_perm, eff_idx);
|
|
795
|
+
sr_v = ggml_set_rows(ctx0, v_layer, V_new_perm, eff_idx);
|
|
796
|
+
ggml_build_forward_expand(gf, sr_k);
|
|
797
|
+
ggml_build_forward_expand(gf, sr_v);
|
|
798
|
+
} else {
|
|
799
|
+
ggml_tensor* k_view = ggml_view_4d(ctx0, kv_k, hd, T, n_kv, 1, kv_k->nb[1], kv_k->nb[2], kv_k->nb[3],
|
|
800
|
+
(size_t)il * kv_k->nb[3] + (size_t)n_past * kv_k->nb[1]);
|
|
801
|
+
ggml_tensor* v_view = ggml_view_4d(ctx0, kv_v, hd, T, n_kv, 1, kv_v->nb[1], kv_v->nb[2], kv_v->nb[3],
|
|
802
|
+
(size_t)il * kv_v->nb[3] + (size_t)n_past * kv_v->nb[1]);
|
|
803
|
+
ggml_build_forward_expand(gf, ggml_cpy(ctx0, K_new_perm, k_view));
|
|
804
|
+
ggml_build_forward_expand(gf, ggml_cpy(ctx0, V_new_perm, v_view));
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
// ---- Read full K/V history from cache ----
|
|
808
|
+
// Cache may be allocated as F16 (default) or as a quantized type
|
|
809
|
+
// (Q8_0 / Q4_0 / etc., per CRISPASR_KV_QUANT — PLAN #60e). For the
|
|
810
|
+
// default F16 path the strided per-layer view becomes a contiguous
|
|
811
|
+
// F16 tensor via ggml_cont (a CPY F16→F16 op). For a quantized
|
|
812
|
+
// cache the equivalent CPY (Q8_0→Q8_0 etc.) isn't supported by
|
|
813
|
+
// Metal, so we use ggml_cast(...,F32) which lowers to CPY Q*→F32
|
|
814
|
+
// — supported on both Metal and the CPU backend (the CPU `dup`
|
|
815
|
+
// dispatch only implements `Q*→F32` for the dequant-on-read path,
|
|
816
|
+
// not `Q*→F16`; so F32 is the only safe target if the scheduler
|
|
817
|
+
// splits the op). The cache *storage* still uses ~half the bytes
|
|
818
|
+
// (for Q8_0); reads pay one dequant pass per layer per step.
|
|
819
|
+
// Flash-attn-ext on Metal accepts F32 K/V natively (and F16 / quant
|
|
820
|
+
// too) but mixing types across K and V isn't supported, so both
|
|
821
|
+
// sides cast to the same dtype.
|
|
822
|
+
// Read from the set_rows RESULT when we wrote via set_rows (sr_k/sr_v are
|
|
823
|
+
// in-place views of the layer slice, so offset 0 == this layer's data);
|
|
824
|
+
// otherwise read the bare cache at the per-layer offset (ggml_cpy path).
|
|
825
|
+
ggml_tensor* k_read_src = sr_k ? sr_k : kv_k;
|
|
826
|
+
ggml_tensor* v_read_src = sr_v ? sr_v : kv_v;
|
|
827
|
+
const size_t k_read_off = sr_k ? 0 : (size_t)il * kv_k->nb[3];
|
|
828
|
+
const size_t v_read_off = sr_v ? 0 : (size_t)il * kv_v->nb[3];
|
|
829
|
+
ggml_tensor* k_layer_view = ggml_view_3d(ctx0, k_read_src, hd, Lk, n_kv, kv_k->nb[1], kv_k->nb[2], k_read_off);
|
|
830
|
+
ggml_tensor* v_layer_view = ggml_view_3d(ctx0, v_read_src, hd, Lk, n_kv, kv_v->nb[1], kv_v->nb[2], v_read_off);
|
|
831
|
+
// CRISPASR_KV_READ_F32=1 forces the cache read to dequantise (or
|
|
832
|
+
// upcast F16) to F32 before flash_attn. Useful when F16 attention
|
|
833
|
+
// accumulator drift on Metal sends the sampler off the rails for
|
|
834
|
+
// sensitive models (chatterbox T3 — see LEARNINGS §82). Default
|
|
835
|
+
// off to preserve legacy bit-exactness with the F16 fast path.
|
|
836
|
+
static const bool s_kv_read_f32 = []() {
|
|
837
|
+
const char* s = std::getenv("CRISPASR_KV_READ_F32");
|
|
838
|
+
return s && *s && std::strcmp(s, "0") != 0;
|
|
839
|
+
}();
|
|
840
|
+
// Vulkan has no f16→f16 REPEAT pipeline, so the GQA head-expansion
|
|
841
|
+
// (ggml_repeat_4d below) on an F16 cache aborts with "Missing op: REPEAT
|
|
842
|
+
// for f16 to f16" (issue #200/#192). When the cache lives on a Vulkan
|
|
843
|
+
// buffer AND we're about to take the manual-repeat path on an F16 cache,
|
|
844
|
+
// force the F32 read so the repeat lowers to a supported F32 REPEAT. This
|
|
845
|
+
// central detection covers every kv_self_attn caller automatically (no
|
|
846
|
+
// per-backend Vulkan plumbing needed). Scoped to exactly the crash
|
|
847
|
+
// condition so Metal/CPU and the GQA_NATIVE / MHA / quantized / F32-cache
|
|
848
|
+
// paths stay bit-identical even on Vulkan.
|
|
849
|
+
const bool gqa_manual_repeat = (p.gqa_mode != GQA_NATIVE) && (grp > 1);
|
|
850
|
+
const bool kv_f16_repeat_on_vulkan = gqa_manual_repeat && (kv_k->type == GGML_TYPE_F16) && kv_k->buffer && [&]() {
|
|
851
|
+
const char* bn = ggml_backend_buft_name(ggml_backend_buffer_get_type(kv_k->buffer));
|
|
852
|
+
return bn && std::strstr(bn, "Vulkan") != nullptr;
|
|
853
|
+
}();
|
|
854
|
+
const bool want_f32_read = s_kv_read_f32 || p.force_kv_read_f32 || kv_f16_repeat_on_vulkan;
|
|
855
|
+
const bool need_dequant_k = ggml_is_quantized(kv_k->type) || (want_f32_read && kv_k->type != GGML_TYPE_F32);
|
|
856
|
+
const bool need_dequant_v = ggml_is_quantized(kv_v->type) || (want_f32_read && kv_v->type != GGML_TYPE_F32);
|
|
857
|
+
ggml_tensor* Kfull = need_dequant_k ? ggml_cast(ctx0, k_layer_view, GGML_TYPE_F32) : ggml_cont(ctx0, k_layer_view);
|
|
858
|
+
ggml_tensor* Vfull = need_dequant_v ? ggml_cast(ctx0, v_layer_view, GGML_TYPE_F32) : ggml_cont(ctx0, v_layer_view);
|
|
859
|
+
|
|
860
|
+
// ---- GQA expansion ----
|
|
861
|
+
if (p.gqa_mode != GQA_NATIVE && grp > 1) {
|
|
862
|
+
ggml_tensor* K4 = ggml_reshape_4d(ctx0, Kfull, hd, Lk, 1, n_kv);
|
|
863
|
+
ggml_tensor* V4 = ggml_reshape_4d(ctx0, Vfull, hd, Lk, 1, n_kv);
|
|
864
|
+
K4 = ggml_repeat_4d(ctx0, K4, hd, Lk, grp, n_kv);
|
|
865
|
+
V4 = ggml_repeat_4d(ctx0, V4, hd, Lk, grp, n_kv);
|
|
866
|
+
if (p.gqa_mode == GQA_MANUAL_CONT) {
|
|
867
|
+
Kfull = ggml_cont(ctx0, ggml_reshape_3d(ctx0, K4, hd, Lk, n_q));
|
|
868
|
+
Vfull = ggml_cont(ctx0, ggml_reshape_3d(ctx0, V4, hd, Lk, n_q));
|
|
869
|
+
} else {
|
|
870
|
+
Kfull = ggml_reshape_3d(ctx0, K4, hd, Lk, n_q);
|
|
871
|
+
Vfull = ggml_reshape_3d(ctx0, V4, hd, Lk, n_q);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// CrispASR debug hook (#83 bisect): when CRISPASR_CORE_ATTN_DUMP_FA_LAYER
|
|
876
|
+
// matches the current layer index, name + add the FA inputs and output as
|
|
877
|
+
// graph outputs so chatterbox.cpp's run_t3_kv post-compute dumper can
|
|
878
|
+
// fetch them. Negligible perf cost when the env knob is unset.
|
|
879
|
+
auto dbg_dump_il_env = std::getenv("CRISPASR_CORE_ATTN_DUMP_FA_LAYER");
|
|
880
|
+
const int dbg_dump_il = dbg_dump_il_env ? (int)std::strtol(dbg_dump_il_env, nullptr, 10) : -1;
|
|
881
|
+
const bool dbg_dump = ((int)il == dbg_dump_il);
|
|
882
|
+
if (dbg_dump) {
|
|
883
|
+
ggml_tensor* Q_pre = ggml_cont(ctx0, Q);
|
|
884
|
+
ggml_set_name(Q_pre, "DBG_Q_post_rope");
|
|
885
|
+
ggml_set_output(Q_pre);
|
|
886
|
+
ggml_build_forward_expand(gf, Q_pre);
|
|
887
|
+
|
|
888
|
+
ggml_tensor* Kfull_dbg = ggml_cast(ctx0, Kfull, GGML_TYPE_F32);
|
|
889
|
+
ggml_set_name(Kfull_dbg, "DBG_Kfull");
|
|
890
|
+
ggml_set_output(Kfull_dbg);
|
|
891
|
+
ggml_build_forward_expand(gf, Kfull_dbg);
|
|
892
|
+
|
|
893
|
+
ggml_tensor* Vfull_dbg = ggml_cast(ctx0, Vfull, GGML_TYPE_F32);
|
|
894
|
+
ggml_set_name(Vfull_dbg, "DBG_Vfull");
|
|
895
|
+
ggml_set_output(Vfull_dbg);
|
|
896
|
+
ggml_build_forward_expand(gf, Vfull_dbg);
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
// ---- Permute Q to (hd, T, n_q) for flash-attn ----
|
|
900
|
+
Q = ggml_cont(ctx0, ggml_permute(ctx0, Q, 0, 2, 1, 3));
|
|
901
|
+
|
|
902
|
+
// ---- Flash attention + reshape + output projection ----
|
|
903
|
+
ggml_tensor* attn = ggml_flash_attn_ext(ctx0, Q, Kfull, Vfull, causal_mask, p.attn_scale, /*max_bias*/ 0.0f,
|
|
904
|
+
/*logit_softcap*/ 0.0f);
|
|
905
|
+
if (dbg_dump) {
|
|
906
|
+
ggml_set_name(attn, "DBG_fa_out");
|
|
907
|
+
ggml_set_output(attn);
|
|
908
|
+
ggml_build_forward_expand(gf, attn);
|
|
909
|
+
}
|
|
910
|
+
attn = ggml_reshape_2d(ctx0, attn, hd * n_q, T);
|
|
911
|
+
|
|
912
|
+
if (dbg_dump) {
|
|
913
|
+
ggml_set_name(attn, "DBG_fa_reshaped");
|
|
914
|
+
ggml_set_output(attn);
|
|
915
|
+
ggml_build_forward_expand(gf, attn);
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
ggml_tensor* out = ggml_mul_mat(ctx0, o_w, attn);
|
|
919
|
+
if (o_b)
|
|
920
|
+
out = ggml_add(ctx0, out, o_b);
|
|
921
|
+
return out;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
} // namespace core_attn
|