whispercpp 1.3.7 → 1.3.8
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 +4 -4
- data/README.md +5 -4
- data/ext/options.rb +1 -1
- data/ext/ruby_whisper.c +0 -1
- data/ext/ruby_whisper.h +7 -1
- data/ext/ruby_whisper_context.c +50 -1
- data/ext/ruby_whisper_log_settable.h +1 -2
- data/ext/ruby_whisper_params.c +9 -8
- data/ext/ruby_whisper_transcribe.cpp +0 -19
- data/ext/ruby_whisper_vad_context.c +30 -10
- data/ext/ruby_whisper_vad_context_detect.cpp +8 -9
- data/ext/ruby_whisper_vad_params.c +4 -4
- data/ext/ruby_whisper_vad_segment.c +2 -2
- data/ext/sources/CMakeLists.txt +2 -1
- data/ext/sources/cmake/parakeet.pc.in +2 -2
- data/ext/sources/cmake/whisper.pc.in +2 -2
- data/ext/sources/examples/cli/cli.cpp +9 -1
- data/ext/sources/examples/common-ggml.cpp +2 -0
- data/ext/sources/examples/vad-speech-segments/speech.cpp +3 -2
- data/ext/sources/ggml/CMakeLists.txt +3 -4
- data/ext/sources/ggml/include/ggml-cuda.h +0 -3
- data/ext/sources/ggml/include/ggml-sycl.h +8 -0
- data/ext/sources/ggml/include/ggml.h +3 -1
- data/ext/sources/ggml/src/CMakeLists.txt +8 -1
- data/ext/sources/ggml/src/ggml-backend-meta.cpp +7 -4
- data/ext/sources/ggml/src/ggml-common.h +13 -2
- data/ext/sources/ggml/src/ggml-cpu/CMakeLists.txt +1 -1
- data/ext/sources/ggml/src/ggml-cpu/amx/mmq.cpp +5 -6
- data/ext/sources/ggml/src/ggml-cpu/arch/arm/quants.c +78 -4
- data/ext/sources/ggml/src/ggml-cpu/arch/x86/quants.c +142 -4
- data/ext/sources/ggml/src/ggml-cpu/arch-fallback.h +7 -2
- data/ext/sources/ggml/src/ggml-cpu/ggml-cpu.c +14 -0
- data/ext/sources/ggml/src/ggml-cpu/llamafile/sgemm.cpp +26 -19
- data/ext/sources/ggml/src/ggml-cpu/ops.cpp +129 -46
- data/ext/sources/ggml/src/ggml-cpu/quants.c +51 -0
- data/ext/sources/ggml/src/ggml-cpu/quants.h +3 -0
- data/ext/sources/ggml/src/ggml-cpu/simd-gemm.h +1 -1
- data/ext/sources/ggml/src/ggml-cpu/simd-mappings.h +11 -0
- data/ext/sources/ggml/src/ggml-cpu/vec.cpp +2 -2
- data/ext/sources/ggml/src/ggml-cuda/binbcast.cu +90 -46
- data/ext/sources/ggml/src/ggml-cuda/col2im-1d.cu +81 -0
- data/ext/sources/ggml/src/ggml-cuda/col2im-1d.cuh +3 -0
- data/ext/sources/ggml/src/ggml-cuda/common.cuh +4 -0
- data/ext/sources/ggml/src/ggml-cuda/concat.cu +33 -21
- data/ext/sources/ggml/src/ggml-cuda/conv-transpose-1d.cu +14 -12
- data/ext/sources/ggml/src/ggml-cuda/convert.cu +86 -34
- data/ext/sources/ggml/src/ggml-cuda/cpy.cu +80 -29
- data/ext/sources/ggml/src/ggml-cuda/fattn-common.cuh +9 -5
- data/ext/sources/ggml/src/ggml-cuda/fattn-mma-f16.cuh +4 -0
- data/ext/sources/ggml/src/ggml-cuda/fattn-tile.cuh +9 -5
- data/ext/sources/ggml/src/ggml-cuda/fattn.cu +27 -21
- data/ext/sources/ggml/src/ggml-cuda/gated_delta_net.cu +40 -25
- data/ext/sources/ggml/src/ggml-cuda/gated_delta_net.cuh +10 -0
- data/ext/sources/ggml/src/ggml-cuda/getrows.cu +15 -12
- data/ext/sources/ggml/src/ggml-cuda/ggml-cuda.cu +718 -1248
- data/ext/sources/ggml/src/ggml-cuda/mmq.cu +7 -0
- data/ext/sources/ggml/src/ggml-cuda/mmvq.cu +77 -40
- data/ext/sources/ggml/src/ggml-cuda/out-prod.cu +55 -12
- data/ext/sources/ggml/src/ggml-cuda/set-rows.cu +64 -4
- data/ext/sources/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_16-ncols2_2.cu +1 -0
- data/ext/sources/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_32-ncols2_2.cu +1 -0
- data/ext/sources/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_4-ncols2_2.cu +1 -0
- data/ext/sources/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_8-ncols2_2.cu +1 -0
- data/ext/sources/ggml/src/ggml-cuda/topk-moe.cu +7 -1
- data/ext/sources/ggml/src/ggml-cuda/vendors/hip.h +1 -0
- data/ext/sources/ggml/src/ggml-cuda/vendors/musa.h +1 -0
- data/ext/sources/ggml/src/ggml-hexagon/CMakeLists.txt +0 -5
- data/ext/sources/ggml/src/ggml-hexagon/ggml-hexagon.cpp +1634 -1293
- data/ext/sources/ggml/src/ggml-hexagon/htp/CMakeLists.txt +11 -40
- data/ext/sources/ggml/src/ggml-hexagon/htp/cmake-toolchain.cmake +13 -15
- data/ext/sources/ggml/src/ggml-hexagon/htp/concat-ops.c +1 -1
- data/ext/sources/ggml/src/ggml-hexagon/htp/flash-attn-ops.c +1749 -399
- data/ext/sources/ggml/src/ggml-hexagon/htp/flash-attn-ops.h +303 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hex-common.h +80 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hex-dma.h +26 -23
- data/ext/sources/ggml/src/ggml-hexagon/htp/hex-profile.h +64 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hex-utils.h +1 -83
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-fa-kernels.h +555 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-mm-kernels-tiled.h +1303 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-queue.c +9 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-queue.h +27 -4
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-utils.h +59 -37
- data/ext/sources/ggml/src/ggml-hexagon/htp/htp-ctx.h +11 -3
- data/ext/sources/ggml/src/ggml-hexagon/htp/htp-ops.h +52 -12
- data/ext/sources/ggml/src/ggml-hexagon/htp/htp-vtcm.h +19 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/htp_iface.idl +2 -1
- data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-base.h +14 -30
- data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-exp.h +39 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-fa-kernels.h +232 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-mm-kernels-flat.h +1511 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-mm-kernels-tiled.h +1200 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-sigmoid.h +39 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/main.c +127 -32
- data/ext/sources/ggml/src/ggml-hexagon/htp/matmul-ops.c +3023 -4425
- data/ext/sources/ggml/src/ggml-hexagon/htp/matmul-ops.h +650 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/rope-ops.c +48 -13
- data/ext/sources/ggml/src/ggml-hexagon/htp/ssm-conv.c +10 -9
- data/ext/sources/ggml/src/ggml-hexagon/htp/worker-pool.c +15 -3
- data/ext/sources/ggml/src/ggml-hexagon/htp/worker-pool.h +8 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp-opnode.h +168 -50
- data/ext/sources/ggml/src/ggml-hexagon/libggml-htp.inf +0 -4
- data/ext/sources/ggml/src/ggml-hip/CMakeLists.txt +5 -0
- data/ext/sources/ggml/src/ggml-metal/ggml-metal-device.cpp +69 -5
- data/ext/sources/ggml/src/ggml-metal/ggml-metal-device.h +4 -1
- data/ext/sources/ggml/src/ggml-metal/ggml-metal-device.m +27 -6
- data/ext/sources/ggml/src/ggml-metal/ggml-metal-impl.h +38 -0
- data/ext/sources/ggml/src/ggml-metal/ggml-metal-ops.cpp +132 -2
- data/ext/sources/ggml/src/ggml-metal/ggml-metal-ops.h +2 -0
- data/ext/sources/ggml/src/ggml-metal/ggml-metal.metal +345 -87
- data/ext/sources/ggml/src/ggml-opencl/CMakeLists.txt +13 -0
- data/ext/sources/ggml/src/ggml-opencl/fa_tune.h +92 -0
- data/ext/sources/ggml/src/ggml-opencl/ggml-opencl.cpp +4060 -357
- data/ext/sources/ggml/src/ggml-opencl/kernels/cvt.cl +198 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f16.cl +81 -41
- data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f32.cl +88 -39
- data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f32_f16.cl +1995 -96
- data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f32_q4_0.cl +1615 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f32_q8_0.cl +1486 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_pre_f16.cl +156 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_mxfp4_f32_ns.cl +74 -6
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q4_0_f32_ns.cl +74 -6
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q4_1_f32_ns.cl +74 -6
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q4_k_f32_ns.cl +71 -6
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q5_0_f32_ns.cl +74 -6
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q5_1_f32_ns.cl +74 -6
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q5_k_f32_ns.cl +74 -6
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q6_k_f32_ns.cl +74 -6
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q1_0_f32.cl +94 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q1_0_f32.cl +121 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q8_0_f32.cl +1 -1
- data/ext/sources/ggml/src/ggml-opencl/kernels/mul_mm_q1_0_f32_l4_lm.cl +156 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/mul_mv_f16_f32_l4.cl +1149 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/mul_mv_q1_0_f32.cl +141 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/mul_mv_q1_0_f32_flat.cl +190 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/norm.cl +5 -2
- data/ext/sources/ggml/src/ggml-opencl/kernels/set_rows.cl +500 -0
- data/ext/sources/ggml/src/ggml-opencl/libdl.h +79 -0
- data/ext/sources/ggml/src/ggml-openvino/.clang-format +0 -5
- data/ext/sources/ggml/src/ggml-openvino/CMakeLists.txt +2 -4
- data/ext/sources/ggml/src/ggml-openvino/ggml-decoder.cpp +733 -130
- data/ext/sources/ggml/src/ggml-openvino/ggml-decoder.h +76 -23
- data/ext/sources/ggml/src/ggml-openvino/ggml-openvino-extra.cpp +57 -3
- data/ext/sources/ggml/src/ggml-openvino/ggml-openvino-extra.h +29 -8
- data/ext/sources/ggml/src/ggml-openvino/ggml-openvino.cpp +307 -59
- data/ext/sources/ggml/src/ggml-openvino/ggml-quants.cpp +66 -0
- data/ext/sources/ggml/src/ggml-openvino/ggml-quants.h +10 -4
- data/ext/sources/ggml/src/ggml-openvino/openvino/decoder.h +56 -16
- data/ext/sources/ggml/src/ggml-openvino/openvino/frontend.h +1 -1
- data/ext/sources/ggml/src/ggml-openvino/openvino/input_model.h +4 -4
- data/ext/sources/ggml/src/ggml-openvino/openvino/node_context.h +94 -37
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/add_id.cpp +76 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/argsort.cpp +47 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/clamp.cpp +33 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/concat.cpp +48 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/cont.cpp +8 -16
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/cpy.cpp +14 -1
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/div.cpp +146 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/flash_attn_ext.cpp +108 -21
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/gated_delta_net.cpp +282 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/gated_delta_net.hpp +65 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/get_rows.cpp +2 -9
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/glu_geglu.cpp +21 -7
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/glu_swiglu.cpp +41 -8
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/im2col.cpp +120 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/l2_norm.cpp +44 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/mul_mat_id.cpp +226 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/mulmat.cpp +19 -9
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/norm.cpp +58 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/pad.cpp +95 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/permute.cpp +58 -13
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/repeat.cpp +74 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/reshape.cpp +13 -6
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/rms_norm.cpp +1 -1
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/rope.cpp +134 -38
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/set_rows.cpp +3 -3
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/softmax.cpp +126 -49
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/ssm_conv.cpp +59 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/sum_rows.cpp +27 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/transpose.cpp +32 -1
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/unary_silu.cpp +1 -1
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/unary_softplus.cpp +38 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/view.cpp +90 -25
- data/ext/sources/ggml/src/ggml-openvino/openvino/op_table.cpp +41 -23
- data/ext/sources/ggml/src/ggml-openvino/openvino/op_table.h +18 -5
- data/ext/sources/ggml/src/ggml-openvino/openvino/pass/mark_decompression_convert_constant_folding.h +1 -1
- data/ext/sources/ggml/src/ggml-openvino/openvino/translate_session.cpp +43 -40
- data/ext/sources/ggml/src/ggml-openvino/openvino/translate_session.h +5 -4
- data/ext/sources/ggml/src/ggml-openvino/openvino/utils.cpp +548 -3
- data/ext/sources/ggml/src/ggml-openvino/openvino/utils.h +28 -26
- data/ext/sources/ggml/src/ggml-openvino/utils.cpp +383 -94
- data/ext/sources/ggml/src/ggml-openvino/utils.h +11 -8
- data/ext/sources/ggml/src/ggml-quants.c +76 -0
- data/ext/sources/ggml/src/ggml-quants.h +3 -0
- data/ext/sources/ggml/src/ggml-sycl/CMakeLists.txt +5 -5
- data/ext/sources/ggml/src/ggml-sycl/backend.hpp +2 -0
- data/ext/sources/ggml/src/ggml-sycl/binbcast.cpp +12 -0
- data/ext/sources/ggml/src/ggml-sycl/col2im-1d.cpp +102 -0
- data/ext/sources/ggml/src/ggml-sycl/col2im-1d.hpp +8 -0
- data/ext/sources/ggml/src/ggml-sycl/common.cpp +6 -8
- data/ext/sources/ggml/src/ggml-sycl/common.hpp +19 -2
- data/ext/sources/ggml/src/ggml-sycl/concat.cpp +21 -1
- data/ext/sources/ggml/src/ggml-sycl/conv2d-dw.cpp +158 -0
- data/ext/sources/ggml/src/ggml-sycl/conv2d-dw.hpp +10 -0
- data/ext/sources/ggml/src/ggml-sycl/conv2d-transpose.cpp +125 -0
- data/ext/sources/ggml/src/ggml-sycl/conv2d-transpose.hpp +10 -0
- data/ext/sources/ggml/src/ggml-sycl/conv2d.cpp +150 -0
- data/ext/sources/ggml/src/ggml-sycl/conv2d.hpp +10 -0
- data/ext/sources/ggml/src/ggml-sycl/conv3d.cpp +224 -0
- data/ext/sources/ggml/src/ggml-sycl/conv3d.hpp +8 -0
- data/ext/sources/ggml/src/ggml-sycl/convert.cpp +6 -0
- data/ext/sources/ggml/src/ggml-sycl/cpy.cpp +706 -0
- data/ext/sources/ggml/src/ggml-sycl/cpy.hpp +281 -0
- data/ext/sources/ggml/src/ggml-sycl/cross_entropy_loss.cpp +255 -0
- data/ext/sources/ggml/src/ggml-sycl/cross_entropy_loss.hpp +7 -0
- data/ext/sources/ggml/src/ggml-sycl/dequantize.hpp +15 -0
- data/ext/sources/ggml/src/ggml-sycl/dmmv.cpp +492 -319
- data/ext/sources/ggml/src/ggml-sycl/dpct/helper.hpp +15 -7
- data/ext/sources/ggml/src/ggml-sycl/element_wise.cpp +215 -115
- data/ext/sources/ggml/src/ggml-sycl/element_wise.hpp +2 -0
- data/ext/sources/ggml/src/ggml-sycl/ggml-sycl.cpp +1006 -336
- data/ext/sources/ggml/src/ggml-sycl/mmvq.cpp +252 -67
- data/ext/sources/ggml/src/ggml-sycl/mmvq.hpp +17 -0
- data/ext/sources/ggml/src/ggml-sycl/norm.cpp +103 -49
- data/ext/sources/ggml/src/ggml-sycl/outprod.cpp +45 -9
- data/ext/sources/ggml/src/ggml-sycl/pool.cpp +185 -0
- data/ext/sources/ggml/src/ggml-sycl/pool.hpp +22 -0
- data/ext/sources/ggml/src/ggml-sycl/presets.hpp +3 -1
- data/ext/sources/ggml/src/ggml-sycl/set_rows.cpp +10 -2
- data/ext/sources/ggml/src/ggml-sycl/softmax.cpp +9 -10
- data/ext/sources/ggml/src/ggml-sycl/vecdotq.hpp +35 -0
- data/ext/sources/ggml/src/ggml-vulkan/CMakeLists.txt +5 -0
- data/ext/sources/ggml/src/ggml-vulkan/ggml-vulkan.cpp +833 -215
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/col2im_1d.comp +61 -0
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/conv2d_mm.comp +1 -1
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/conv3d_mm.comp +431 -0
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/diag.comp +3 -3
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/flash_attn.comp +1 -0
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/flash_attn_cm1.comp +1 -0
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/generic_unary_head.glsl +21 -19
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/get_rows_back.comp +25 -0
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/glu_head.glsl +23 -4
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/glu_main.glsl +14 -18
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/l2_norm.comp +4 -7
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/mul_mat_vecq.comp +21 -24
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/mul_mm.comp +31 -23
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/mul_mm_cm2.comp +6 -5
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/mul_mm_funcs.glsl +84 -67
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/norm.comp +10 -10
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/repeat_back.comp +3 -3
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/roll.comp +3 -3
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/tri.comp +3 -3
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/unary.comp +168 -0
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/vulkan-shaders-gen.cpp +121 -74
- data/ext/sources/ggml/src/ggml-webgpu/ggml-webgpu-shader-lib.hpp +26 -19
- data/ext/sources/ggml/src/ggml-webgpu/ggml-webgpu.cpp +31 -36
- data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/common_decls.tmpl +16 -2
- data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/flash_attn_vec_split.wgsl +7 -7
- data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/get_rows.wgsl +21 -0
- data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_decls.tmpl +439 -320
- data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_id_vec.wgsl +2 -2
- data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_vec.wgsl +45 -39
- data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_vec_acc.tmpl +586 -465
- data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_vec_q_acc.tmpl +63 -69
- data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/quantize_q8.wgsl +14 -9
- data/ext/sources/ggml/src/ggml.c +36 -14
- data/ext/sources/include/whisper.h +21 -0
- data/ext/sources/src/whisper.cpp +164 -14
- data/lib/whisper/log_settable.rb +5 -8
- data/lib/whisper/model/uri.rb +0 -7
- data/sig/whisper.rbs +6 -0
- data/test/test_vad.rb +9 -0
- data/test/test_vad_context.rb +2 -2
- data/whispercpp.gemspec +1 -1
- metadata +62 -37
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-flash-attn-ops.c +0 -1878
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-matmul-ops.c +0 -2066
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-ops.c +0 -6
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-ops.h +0 -88
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-profile.h +0 -34
- data/ext/sources/ggml/src/ggml-hexagon/htp/vtcm-utils.h +0 -16
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/unary_gelu.cpp +0 -25
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/abs.comp +0 -21
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/ceil.comp +0 -22
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/clamp.comp +0 -17
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/cos.comp +0 -17
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/elu.comp +0 -27
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/exp.comp +0 -20
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/floor.comp +0 -22
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/gelu.comp +0 -25
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/gelu_erf.comp +0 -39
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/gelu_quick.comp +0 -23
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/hardsigmoid.comp +0 -22
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/hardswish.comp +0 -22
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/leaky_relu.comp +0 -22
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/neg.comp +0 -20
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/relu.comp +0 -21
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/round.comp +0 -29
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/sgn.comp +0 -21
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/sigmoid.comp +0 -20
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/silu.comp +0 -22
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/sin.comp +0 -17
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/softplus.comp +0 -23
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/sqrt.comp +0 -17
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/square.comp +0 -17
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/step.comp +0 -22
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/tanh.comp +0 -20
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/trunc.comp +0 -22
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/xielu.comp +0 -35
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#include "../node_context.h"
|
|
2
|
+
#include "../op_table.h"
|
|
3
|
+
#include "../utils.h"
|
|
4
|
+
#include "ggml.h"
|
|
5
|
+
|
|
6
|
+
#include <memory>
|
|
7
|
+
#include <openvino/op/constant.hpp>
|
|
8
|
+
#include <openvino/op/convert.hpp>
|
|
9
|
+
#include <openvino/op/divide.hpp>
|
|
10
|
+
#include <openvino/op/multiply.hpp>
|
|
11
|
+
#include <openvino/op/shape_of.hpp>
|
|
12
|
+
#include <openvino/op/sigmoid.hpp>
|
|
13
|
+
#include <openvino/op/tile.hpp>
|
|
14
|
+
#include <openvino/op/util/precision_sensitive_attribute.hpp>
|
|
15
|
+
#include <vector>
|
|
16
|
+
|
|
17
|
+
namespace ov {
|
|
18
|
+
namespace frontend {
|
|
19
|
+
namespace ggml {
|
|
20
|
+
namespace op {
|
|
21
|
+
|
|
22
|
+
namespace {
|
|
23
|
+
|
|
24
|
+
bool is_silu_div_pattern(const ov::Output<ov::Node> & numerator,
|
|
25
|
+
const ov::Output<ov::Node> & denominator,
|
|
26
|
+
const NodeContext & context) {
|
|
27
|
+
if (context.get_input_size() != 2) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const auto * unary_op = reinterpret_cast<const ggml_unary_op *>(context.get_input_op_params(0));
|
|
32
|
+
if (unary_op == nullptr || *unary_op != GGML_UNARY_OP_SILU) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
auto mul = std::dynamic_pointer_cast<ov::op::v1::Multiply>(numerator.get_node_shared_ptr());
|
|
37
|
+
if (!mul) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const auto denom_node = denominator.get_node_shared_ptr();
|
|
42
|
+
const auto mul_input_0 = mul->input_value(0).get_node_shared_ptr();
|
|
43
|
+
const auto mul_input_1 = mul->input_value(1).get_node_shared_ptr();
|
|
44
|
+
|
|
45
|
+
auto sigmoid = std::dynamic_pointer_cast<ov::op::v0::Sigmoid>(mul_input_1);
|
|
46
|
+
if (mul_input_0 == denom_node && sigmoid && sigmoid->input_value(0).get_node_shared_ptr() == denom_node) {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
sigmoid = std::dynamic_pointer_cast<ov::op::v0::Sigmoid>(mul_input_0);
|
|
51
|
+
return mul_input_1 == denom_node && sigmoid && sigmoid->input_value(0).get_node_shared_ptr() == denom_node;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
ov::Output<ov::Node> repeat_input_to_match(const NodeContext & context,
|
|
55
|
+
const ov::Output<ov::Node> & input,
|
|
56
|
+
const ov::Output<ov::Node> & target,
|
|
57
|
+
size_t input_index) {
|
|
58
|
+
const auto input_shape = context.get_input_shape(input_index);
|
|
59
|
+
const auto target_shape = context.get_input_shape(0);
|
|
60
|
+
|
|
61
|
+
if (input_shape == target_shape) {
|
|
62
|
+
return input;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (input_shape.rank().is_static() && target_shape.rank().is_static()) {
|
|
66
|
+
const auto rank = static_cast<size_t>(input_shape.rank().get_length());
|
|
67
|
+
std::vector<int64_t> repeats(rank, 1);
|
|
68
|
+
bool needs_repeat = false;
|
|
69
|
+
|
|
70
|
+
for (size_t axis = 0; axis < rank; ++axis) {
|
|
71
|
+
FRONT_END_OP_CONVERSION_CHECK(input_shape[axis].is_static() && target_shape[axis].is_static(),
|
|
72
|
+
"DIV repeat requires static dimensions on both inputs");
|
|
73
|
+
|
|
74
|
+
const int64_t input_dim = input_shape[axis].get_length();
|
|
75
|
+
const int64_t target_dim = target_shape[axis].get_length();
|
|
76
|
+
|
|
77
|
+
FRONT_END_OP_CONVERSION_CHECK(input_dim > 0 && target_dim > 0 && target_dim % input_dim == 0,
|
|
78
|
+
"DIV input shape ", input_shape, " cannot repeat to match ", target_shape);
|
|
79
|
+
|
|
80
|
+
repeats[axis] = target_dim / input_dim;
|
|
81
|
+
needs_repeat = needs_repeat || repeats[axis] != 1;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (!needs_repeat) {
|
|
85
|
+
return input;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
auto repeats_node = ov::op::v0::Constant::create(ov::element::i64, {repeats.size()}, repeats);
|
|
89
|
+
return std::make_shared<ov::op::v0::Tile>(input, repeats_node);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
auto input_shape_node = std::make_shared<ov::op::v3::ShapeOf>(input, ov::element::i64);
|
|
93
|
+
auto target_shape_node = std::make_shared<ov::op::v3::ShapeOf>(target, ov::element::i64);
|
|
94
|
+
auto repeats_node = std::make_shared<ov::op::v1::Divide>(target_shape_node, input_shape_node);
|
|
95
|
+
return std::make_shared<ov::op::v0::Tile>(input, repeats_node);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
} // namespace
|
|
99
|
+
|
|
100
|
+
OutputVector translate_div(const NodeContext & context) {
|
|
101
|
+
num_inputs_check(context, 2, 2);
|
|
102
|
+
|
|
103
|
+
auto input_0 = process_view_input_new(context, 0);
|
|
104
|
+
auto input_1 = process_view_input_new(context, 1);
|
|
105
|
+
|
|
106
|
+
if (is_silu_div_pattern(input_0, input_1, context)) {
|
|
107
|
+
ov::Output<ov::Node> res = std::make_shared<ov::op::v0::Sigmoid>(input_1);
|
|
108
|
+
if (res.get_element_type() != context.get_output_type()) {
|
|
109
|
+
res = std::make_shared<ov::op::v0::Convert>(res, context.get_output_type());
|
|
110
|
+
}
|
|
111
|
+
return rename_outputs_with_suffix({res}, context.get_name());
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
input_1 = repeat_input_to_match(context, input_1, input_0, 1);
|
|
115
|
+
|
|
116
|
+
const auto output_type = context.get_output_type();
|
|
117
|
+
const bool use_f32_compute = input_0.get_element_type() != ov::element::f32 ||
|
|
118
|
+
input_1.get_element_type() != ov::element::f32 || output_type != ov::element::f32;
|
|
119
|
+
|
|
120
|
+
if (use_f32_compute) {
|
|
121
|
+
input_0 = std::make_shared<ov::op::v0::Convert>(input_0, ov::element::f32);
|
|
122
|
+
input_1 = std::make_shared<ov::op::v0::Convert>(input_1, ov::element::f32);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
ov::Output<ov::Node> res = std::make_shared<ov::op::v1::Divide>(input_0, input_1);
|
|
126
|
+
if (use_f32_compute) {
|
|
127
|
+
// Keep the reciprocal/divide path in FP32. Without this hint, the GPU
|
|
128
|
+
// plugin can still compress the subgraph back to FP16 and overflow on
|
|
129
|
+
// small shexp gate values (e.g. silu(x) / x in qwen2moe).
|
|
130
|
+
ov::mark_as_precision_sensitive(res.get_node_shared_ptr()->input(0));
|
|
131
|
+
ov::mark_as_precision_sensitive(res.get_node_shared_ptr()->input(1));
|
|
132
|
+
}
|
|
133
|
+
if (res.get_element_type() != output_type) {
|
|
134
|
+
auto output_convert = std::make_shared<ov::op::v0::Convert>(res, output_type);
|
|
135
|
+
if (use_f32_compute) {
|
|
136
|
+
ov::mark_as_precision_sensitive(output_convert->input(0));
|
|
137
|
+
}
|
|
138
|
+
res = output_convert;
|
|
139
|
+
}
|
|
140
|
+
return rename_outputs_with_suffix({res}, context.get_name());
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
} // namespace op
|
|
144
|
+
} // namespace ggml
|
|
145
|
+
} // namespace frontend
|
|
146
|
+
} // namespace ov
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
#include "../node_context.h"
|
|
2
2
|
#include "../op_table.h"
|
|
3
3
|
#include "../utils.h"
|
|
4
|
+
#include "ggml-openvino/ggml-openvino-extra.h"
|
|
4
5
|
|
|
5
6
|
#include <cstdint>
|
|
7
|
+
#include <cstdlib>
|
|
6
8
|
#include <memory>
|
|
9
|
+
#include <openvino/op/add.hpp>
|
|
7
10
|
#include <openvino/op/broadcast.hpp>
|
|
8
11
|
#include <openvino/op/concat.hpp>
|
|
9
12
|
#include <openvino/op/constant.hpp>
|
|
10
13
|
#include <openvino/op/convert.hpp>
|
|
14
|
+
#include <openvino/op/matmul.hpp>
|
|
15
|
+
#include <openvino/op/multiply.hpp>
|
|
11
16
|
#include <openvino/op/reshape.hpp>
|
|
12
17
|
#include <openvino/op/scaled_dot_product_attention.hpp>
|
|
18
|
+
#include <openvino/op/softmax.hpp>
|
|
13
19
|
#include <openvino/op/transpose.hpp>
|
|
14
20
|
#include <openvino/op/unsqueeze.hpp>
|
|
15
21
|
#include <string>
|
|
@@ -34,36 +40,115 @@ OutputVector translate_flash_attn_ext(const NodeContext & context) {
|
|
|
34
40
|
auto q = std::make_shared<ov::op::v0::Convert>(q_f32, ov::element::f16);
|
|
35
41
|
auto scale_node = std::make_shared<ov::op::v0::Constant>(ov::element::f16, ov::Shape{}, std::vector<float>{scale});
|
|
36
42
|
|
|
37
|
-
ov::Output<ov::Node>
|
|
43
|
+
ov::Output<ov::Node> res;
|
|
44
|
+
|
|
45
|
+
// For stateful
|
|
38
46
|
std::string mask_name = "KQ_mask_sliced";
|
|
39
47
|
if (context.get_input_names()[3].find("swa") != std::string::npos) {
|
|
40
48
|
mask_name = "KQ_mask_swa_sliced";
|
|
41
49
|
}
|
|
42
50
|
if (context.has_input(mask_name)) {
|
|
43
|
-
|
|
44
|
-
} else {
|
|
45
|
-
auto zero = ov::op::v0::Constant::create(ov::element::i64, {1}, {0});
|
|
46
|
-
auto one = ov::op::v0::Constant::create(ov::element::i64, {1}, {1});
|
|
47
|
-
auto two = ov::op::v0::Constant::create(ov::element::i64, {1}, {2});
|
|
48
|
-
auto token_len = get_dimensions(q, {2});
|
|
49
|
-
mask_sliced = std::make_shared<ov::op::v8::Slice>(mask, zero, token_len, one, two);
|
|
51
|
+
mask = context.get_input(mask_name);
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
+
if (mask.get_element_type() != ov::element::f16) {
|
|
55
|
+
mask = std::make_shared<ov::op::v0::Convert>(mask, ov::element::f16);
|
|
54
56
|
}
|
|
55
57
|
|
|
56
|
-
auto tile_kv = [&](int64_t num_heads, int64_t num_heads_kv, int64_t head_size, ov::Output<Node> kv) {
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
//auto tile_kv = [&](int64_t num_heads, int64_t num_heads_kv, int64_t head_size, ov::Output<Node> kv) {
|
|
59
|
+
// int64_t factor = num_heads / num_heads_kv;
|
|
60
|
+
// if (factor > 1 && num_heads_kv > 1) {
|
|
61
|
+
auto q_shape = context.get_input_shape(0).to_shape();
|
|
62
|
+
auto k_shape = context.get_input_shape(1).to_shape();
|
|
63
|
+
const int64_t num_heads = q_shape[1];
|
|
64
|
+
const int64_t num_heads_kv = k_shape[1];
|
|
65
|
+
const int64_t head_size = q_shape[3];
|
|
66
|
+
const int64_t factor = num_heads / num_heads_kv;
|
|
67
|
+
|
|
68
|
+
// Manual GQA attention: enabled by default on GPU in stateless mode.
|
|
69
|
+
// Set GGML_OPENVINO_MANUAL_GQA_ATTN to a positive value (e.g. 1) to force-enable,
|
|
70
|
+
// or to 0 to force-disable. Unset falls back to the device-based default.
|
|
71
|
+
static const bool manual_gqa_enabled = []() {
|
|
72
|
+
const char * env = ggml_openvino_getenv_str("GGML_OPENVINO_MANUAL_GQA_ATTN");
|
|
73
|
+
if (env != nullptr) {
|
|
74
|
+
return ggml_openvino_getenv_int("GGML_OPENVINO_MANUAL_GQA_ATTN") > 0;
|
|
75
|
+
}
|
|
76
|
+
const char * dev = ggml_openvino_getenv_str("GGML_OPENVINO_DEVICE");
|
|
77
|
+
return dev != nullptr && std::string(dev) == "GPU";
|
|
78
|
+
}();
|
|
79
|
+
const bool use_manual_gqa_attention =
|
|
80
|
+
manual_gqa_enabled && factor > 1 && num_heads_kv > 1 && !context.is_stateful();
|
|
81
|
+
|
|
82
|
+
if (use_manual_gqa_attention) {
|
|
83
|
+
// Q, K, V arrive as [B, n_heads(_kv), S, head_size], where B is the active
|
|
84
|
+
// batch (n_seq_active) and may be > 1 (llama-perplexity, llama-server -np > 1)
|
|
85
|
+
// or dynamic. Reshape to
|
|
86
|
+
// K_r: [B, num_heads_kv, 1, S, head_size]
|
|
87
|
+
// Q_r: [B, num_heads_kv, factor, S_q, head_size]
|
|
88
|
+
// and let MatMul broadcast across the factor dim without materialising
|
|
89
|
+
// an expanded K/V. The leading 0 + special_zero=true copies B at runtime,
|
|
90
|
+
// so this is correct for B == 1, B > 1, and dynamic B alike. Only the head
|
|
91
|
+
// dims and head_size are baked in as literals; the sequence dim stays -1.
|
|
92
|
+
auto k_5d_shape = ov::op::v0::Constant::create(ov::element::i64, {5},
|
|
93
|
+
std::vector<int64_t>{0, num_heads_kv, 1, -1, head_size});
|
|
94
|
+
auto v_5d_shape = ov::op::v0::Constant::create(ov::element::i64, {5},
|
|
95
|
+
std::vector<int64_t>{0, num_heads_kv, 1, -1, head_size});
|
|
96
|
+
auto q_5d_shape = ov::op::v0::Constant::create(ov::element::i64, {5},
|
|
97
|
+
std::vector<int64_t>{0, num_heads_kv, factor, -1, head_size});
|
|
98
|
+
|
|
99
|
+
auto k_r = std::make_shared<ov::op::v1::Reshape>(k, k_5d_shape, true);
|
|
100
|
+
auto v_r = std::make_shared<ov::op::v1::Reshape>(v, v_5d_shape, true);
|
|
101
|
+
auto q_r = std::make_shared<ov::op::v1::Reshape>(q, q_5d_shape, true);
|
|
102
|
+
|
|
103
|
+
// QK^T → [B, num_heads_kv, factor, S_q, S_k]
|
|
104
|
+
auto qk = std::make_shared<ov::op::v0::MatMul>(q_r, k_r, /*tA=*/false, /*tB=*/true);
|
|
105
|
+
auto qk_scaled = std::make_shared<ov::op::v1::Multiply>(qk, scale_node);
|
|
106
|
+
|
|
107
|
+
// Mask arrives as [B, 1, S_q, S_k]. Unsqueeze a factor axis at position 2 to
|
|
108
|
+
// get [B, 1, 1, S_q, S_k], which NUMPY-broadcasts cleanly against the
|
|
109
|
+
// [B, num_heads_kv, factor, S_q, S_k] scores: B==B, then 1→num_heads_kv and
|
|
110
|
+
// 1→factor on the head dims.
|
|
111
|
+
auto mask_unsq1 =
|
|
112
|
+
std::make_shared<ov::op::v0::Unsqueeze>(mask, ov::op::v0::Constant::create(ov::element::i64, {1}, {2}));
|
|
113
|
+
// mask_unsq1: [B, 1, 1, S_q, S_k] (rank 5)
|
|
114
|
+
ov::Output<ov::Node> qk_masked = std::make_shared<ov::op::v1::Add>(qk_scaled, mask_unsq1);
|
|
115
|
+
|
|
116
|
+
auto softmax = std::make_shared<ov::op::v8::Softmax>(qk_masked, /*axis=*/-1);
|
|
117
|
+
|
|
118
|
+
// softmax @ V → [B, num_heads_kv, factor, S_q, head_size]
|
|
119
|
+
auto attn = std::make_shared<ov::op::v0::MatMul>(softmax, v_r);
|
|
120
|
+
|
|
121
|
+
// Reshape back to [B, num_heads, S_q, head_size] (combine num_heads_kv * factor).
|
|
122
|
+
// Leading 0 + special_zero=true copies B at runtime.
|
|
123
|
+
auto out_4d_shape =
|
|
124
|
+
ov::op::v0::Constant::create(ov::element::i64, {4}, std::vector<int64_t>{0, num_heads, -1, head_size});
|
|
125
|
+
auto out_4d = std::make_shared<ov::op::v1::Reshape>(attn, out_4d_shape, true);
|
|
126
|
+
|
|
127
|
+
// The standard SDPA path's downstream is Transpose(0,2,1,3) → Convert(f32).
|
|
128
|
+
// Replicate it here so callers see the same output layout/dtype.
|
|
129
|
+
res = std::make_shared<ov::op::v1::Transpose>(
|
|
130
|
+
out_4d, ov::op::v0::Constant::create(ov::element::i64, {4}, {0, 2, 1, 3}));
|
|
131
|
+
res = std::make_shared<ov::op::v0::Convert>(res, ov::element::f32);
|
|
132
|
+
return rename_outputs_with_suffix({res}, context.get_name());
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Default path: explicit Broadcast → SDPA. Kept as the fallback because
|
|
136
|
+
// (a) it goes through the GPU plugin's micro-SDPA fast path (FlashAttention
|
|
137
|
+
// tiles via DPAS), and (b) the manual path above is still being validated.
|
|
138
|
+
auto tile_kv = [&](int64_t n_heads, int64_t n_heads_kv, int64_t hs, ov::Output<Node> kv) {
|
|
139
|
+
int64_t f = n_heads / n_heads_kv;
|
|
140
|
+
if (f > 1 && n_heads_kv > 1) {
|
|
59
141
|
ov::Output<ov::Node> kv_broadcast_shape, kv_unsqueezed, new_kv_shape;
|
|
60
142
|
auto unsqueeze_axes = ov::op::v0::Constant::create(ov::element::i64, Shape{}, {2});
|
|
61
143
|
kv_unsqueezed = std::make_shared<ov::op::v0::Unsqueeze>(kv, unsqueeze_axes);
|
|
62
144
|
|
|
63
|
-
kv_broadcast_shape = ov::op::v0::Constant::create(
|
|
64
|
-
|
|
145
|
+
kv_broadcast_shape = ov::op::v0::Constant::create(ov::element::i64, {5},
|
|
146
|
+
{(int64_t) 1, (int64_t) 1, f, (int64_t) 1, (int64_t) 1});
|
|
65
147
|
new_kv_shape =
|
|
66
|
-
ov::op::v0::Constant::create(ov::element::i64, {4}, {(int64_t) 0,
|
|
148
|
+
ov::op::v0::Constant::create(ov::element::i64, {4}, {(int64_t) 0, n_heads, (int64_t) -1, hs});
|
|
149
|
+
// ov::element::i64, {5}, {(int64_t) 1, (int64_t) 1, factor, (int64_t) 1, (int64_t) 1});
|
|
150
|
+
//new_kv_shape =
|
|
151
|
+
// ov::op::v0::Constant::create(ov::element::i64, {4}, {(int64_t) 0, num_heads, (int64_t) -1, head_size});
|
|
67
152
|
|
|
68
153
|
kv = std::make_shared<ov::op::v3::Broadcast>(kv_unsqueezed, kv_broadcast_shape,
|
|
69
154
|
ov::op::BroadcastType::BIDIRECTIONAL);
|
|
@@ -72,12 +157,14 @@ OutputVector translate_flash_attn_ext(const NodeContext & context) {
|
|
|
72
157
|
return kv;
|
|
73
158
|
};
|
|
74
159
|
|
|
75
|
-
auto q_shape = context.get_input_shape(0).to_shape();
|
|
76
|
-
auto k_shape = context.get_input_shape(1).to_shape();
|
|
77
|
-
k = tile_kv(q_shape[1], k_shape[1], q_shape[3], k);
|
|
78
|
-
v = tile_kv(q_shape[1], k_shape[1], q_shape[3], v);
|
|
160
|
+
//auto q_shape = context.get_input_shape(0).to_shape();
|
|
161
|
+
//auto k_shape = context.get_input_shape(1).to_shape();
|
|
162
|
+
//k = tile_kv(q_shape[1], k_shape[1], q_shape[3], k);
|
|
163
|
+
//v = tile_kv(q_shape[1], k_shape[1], q_shape[3], v);
|
|
164
|
+
k = tile_kv(num_heads, num_heads_kv, head_size, k);
|
|
165
|
+
v = tile_kv(num_heads, num_heads_kv, head_size, v);
|
|
79
166
|
|
|
80
|
-
auto sdpa = std::make_shared<ov::op::v13::ScaledDotProductAttention>(q, k, v,
|
|
167
|
+
auto sdpa = std::make_shared<ov::op::v13::ScaledDotProductAttention>(q, k, v, mask, scale_node, false);
|
|
81
168
|
res = std::make_shared<ov::op::v1::Transpose>(sdpa,
|
|
82
169
|
ov::op::v0::Constant::create(ov::element::i64, {4}, {0, 2, 1, 3}));
|
|
83
170
|
res = std::make_shared<ov::op::v0::Convert>(res, ov::element::f32);
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
#include "gated_delta_net.hpp"
|
|
2
|
+
|
|
3
|
+
#include "../node_context.h"
|
|
4
|
+
#include "../op_table.h"
|
|
5
|
+
#include "../utils.h"
|
|
6
|
+
|
|
7
|
+
#include <cmath>
|
|
8
|
+
#include <cstdint>
|
|
9
|
+
#include <memory>
|
|
10
|
+
#include <openvino/op/add.hpp>
|
|
11
|
+
#include <openvino/op/broadcast.hpp>
|
|
12
|
+
#include <openvino/op/concat.hpp>
|
|
13
|
+
#include <openvino/op/constant.hpp>
|
|
14
|
+
#include <openvino/op/exp.hpp>
|
|
15
|
+
#include <openvino/op/gather.hpp>
|
|
16
|
+
#include <openvino/op/loop.hpp>
|
|
17
|
+
#include <openvino/op/matmul.hpp>
|
|
18
|
+
#include <openvino/op/multiply.hpp>
|
|
19
|
+
#include <openvino/op/reshape.hpp>
|
|
20
|
+
#include <openvino/op/squeeze.hpp>
|
|
21
|
+
#include <openvino/op/subtract.hpp>
|
|
22
|
+
#include <openvino/op/transpose.hpp>
|
|
23
|
+
#include <openvino/op/unsqueeze.hpp>
|
|
24
|
+
#include <vector>
|
|
25
|
+
|
|
26
|
+
namespace ov {
|
|
27
|
+
namespace frontend {
|
|
28
|
+
namespace ggml {
|
|
29
|
+
namespace op {
|
|
30
|
+
|
|
31
|
+
static OutputVector translate_gated_delta_net_ref(const NodeContext & context);
|
|
32
|
+
|
|
33
|
+
OutputVector translate_gated_delta_net(const NodeContext & context) {
|
|
34
|
+
// auto v_shape = context.get_input_shape(2).to_shape(); // [B, T, H_v, S_v]
|
|
35
|
+
// auto q_shape = context.get_input_shape(0).to_shape(); // [B, T, H_k, S_k]
|
|
36
|
+
|
|
37
|
+
// // Fused GatedDeltaNet op only supports scalar gate (kda=0).
|
|
38
|
+
// // Fall back to reference implementation for per-key-dimension gating.
|
|
39
|
+
// // if (kda) {
|
|
40
|
+
// // return translate_gated_delta_net_ref(context);
|
|
41
|
+
// // }
|
|
42
|
+
|
|
43
|
+
// auto q = context.get_input(0);
|
|
44
|
+
// auto k = context.get_input(1);
|
|
45
|
+
// auto v = context.get_input(2);
|
|
46
|
+
// auto g = context.get_input(3);
|
|
47
|
+
// auto beta = context.get_input(4);
|
|
48
|
+
// auto state = context.get_input(5);
|
|
49
|
+
|
|
50
|
+
// const int64_t B = v_shape[0];
|
|
51
|
+
// const int64_t T = v_shape[1];
|
|
52
|
+
// const int64_t H_v = v_shape[2];
|
|
53
|
+
// const int64_t S_v = v_shape[3];
|
|
54
|
+
// const int64_t S_k = q_shape[3];
|
|
55
|
+
|
|
56
|
+
// // ggml state layout (OV notation): [B, H_v, value_dim, key_dim]
|
|
57
|
+
// // GatedDeltaNet op expects: [B, H_v, key_dim, value_dim]
|
|
58
|
+
// auto state_reshape_shape =
|
|
59
|
+
// ov::op::v0::Constant::create(ov::element::i64, {4}, std::vector<int64_t>{B, H_v, S_v, S_k});
|
|
60
|
+
// state = std::make_shared<ov::op::v1::Reshape>(state, state_reshape_shape, false);
|
|
61
|
+
// auto state_perm = ov::op::v0::Constant::create(ov::element::i64, {4}, std::vector<int64_t>{0, 1, 3, 2});
|
|
62
|
+
// state = std::make_shared<ov::op::v1::Transpose>(state, state_perm);
|
|
63
|
+
|
|
64
|
+
// g = std::make_shared<ov::op::v0::Squeeze>(g, ov::op::v0::Constant::create(ov::element::i64, {1}, {3}));
|
|
65
|
+
// beta = std::make_shared<ov::op::v0::Squeeze>(beta, ov::op::v0::Constant::create(ov::element::i64, {1}, {3}));
|
|
66
|
+
|
|
67
|
+
// auto gdn = std::make_shared<ov::op::internal::GatedDeltaNet>(q, k, v, state, g, beta);
|
|
68
|
+
|
|
69
|
+
// auto attn_4d = gdn->output(0);
|
|
70
|
+
// auto state_4d = gdn->output(1); // [B, H_v, key_dim, value_dim]
|
|
71
|
+
// // Transpose output state back to ggml layout [B, H_v, value_dim, key_dim]
|
|
72
|
+
// auto state_transposed = std::make_shared<ov::op::v1::Transpose>(state_4d, state_perm);
|
|
73
|
+
// auto flat_shape_1d = ov::op::v0::Constant::create(ov::element::i64, {1}, {-1});
|
|
74
|
+
// auto attn = std::make_shared<ov::op::v1::Reshape>(attn_4d, flat_shape_1d, false);
|
|
75
|
+
// auto new_state = std::make_shared<ov::op::v1::Reshape>(state_transposed, flat_shape_1d, false);
|
|
76
|
+
// auto packed = std::make_shared<ov::op::v0::Concat>(ov::OutputVector{attn, new_state}, 0);
|
|
77
|
+
// auto out_shape =
|
|
78
|
+
// ov::op::v0::Constant::create(ov::element::i64, {4}, std::vector<int64_t>{1, 1, T * B + S_v * B, S_v * H_v});
|
|
79
|
+
// auto res = std::make_shared<ov::op::v1::Reshape>(packed, out_shape, false);
|
|
80
|
+
|
|
81
|
+
// return rename_outputs_with_suffix({res}, context.get_name());
|
|
82
|
+
|
|
83
|
+
// The OV version in CI does not have the GatedDeltaNet op, so use reference implementation for now.
|
|
84
|
+
return translate_gated_delta_net_ref(context);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
static OutputVector translate_gated_delta_net_ref(const NodeContext & context) {
|
|
88
|
+
num_inputs_check(context, 6, 6);
|
|
89
|
+
|
|
90
|
+
// Inputs (OV shapes are reversed from ggml):
|
|
91
|
+
// ggml: q[S_k, H_k, T, B], k[S_k, H_k, T, B], v[S_v, H_v, T, B]
|
|
92
|
+
// OV: q[B, T, H_k, S_k], k[B, T, H_k, S_k], v[B, T, H_v, S_v]
|
|
93
|
+
// ggml: g[1 or S_v, H_v, T, B], beta[1, H_v, T, B]
|
|
94
|
+
// OV: g[B, T, H_v, 1 or S_v], beta[B, T, H_v, 1]
|
|
95
|
+
// ggml: state[S_v, S_v, H_v, B]
|
|
96
|
+
// OV: state[B, H_v, S_v, S_v]
|
|
97
|
+
auto q = process_view_input_new(context, 0);
|
|
98
|
+
auto k = process_view_input_new(context, 1);
|
|
99
|
+
auto v = process_view_input_new(context, 2);
|
|
100
|
+
auto g = process_view_input_new(context, 3);
|
|
101
|
+
auto beta = process_view_input_new(context, 4);
|
|
102
|
+
auto state = process_view_input_new(context, 5);
|
|
103
|
+
|
|
104
|
+
auto v_shape = context.get_input_shape(2).to_shape(); // [B, T, H_v, S_v]
|
|
105
|
+
auto q_shape = context.get_input_shape(0).to_shape(); // [B, T, H_k, S_k]
|
|
106
|
+
auto g_shape = context.get_input_shape(3).to_shape(); // [B, T, H_v, 1 or S_v]
|
|
107
|
+
|
|
108
|
+
const int64_t B = v_shape[0];
|
|
109
|
+
const int64_t T = v_shape[1];
|
|
110
|
+
const int64_t H_v = v_shape[2];
|
|
111
|
+
const int64_t S_v = v_shape[3];
|
|
112
|
+
const int64_t H_k = q_shape[2];
|
|
113
|
+
const bool kda = (g_shape[3] == (size_t) S_v);
|
|
114
|
+
|
|
115
|
+
const int64_t rq1 = H_v / H_k; // head repeat factor
|
|
116
|
+
const float scale = 1.0f / std::sqrt((float) S_v);
|
|
117
|
+
|
|
118
|
+
auto axis_1 = ov::op::v0::Constant::create(ov::element::i64, {1}, {1});
|
|
119
|
+
auto axis_2 = ov::op::v0::Constant::create(ov::element::i64, {1}, {2});
|
|
120
|
+
|
|
121
|
+
// Transpose inputs from [B, T, H, S] to [B, H, T, S] for easier per-head processing
|
|
122
|
+
auto perm_0213 = ov::op::v0::Constant::create(ov::element::i64, {4}, std::vector<int64_t>{0, 2, 1, 3});
|
|
123
|
+
auto q_t = std::make_shared<ov::op::v1::Transpose>(q, perm_0213); // [B, H_k, T, S_k]
|
|
124
|
+
auto k_t = std::make_shared<ov::op::v1::Transpose>(k, perm_0213); // [B, H_k, T, S_k]
|
|
125
|
+
auto v_t = std::make_shared<ov::op::v1::Transpose>(v, perm_0213); // [B, H_v, T, S_v]
|
|
126
|
+
auto g_t = std::make_shared<ov::op::v1::Transpose>(g, perm_0213); // [B, H_v, T, 1 or S_v]
|
|
127
|
+
auto beta_t = std::make_shared<ov::op::v1::Transpose>(beta, perm_0213); // [B, H_v, T, 1]
|
|
128
|
+
|
|
129
|
+
// Broadcast Q, K heads to match V heads if GQA is used (H_v > H_k)
|
|
130
|
+
ov::Output<ov::Node> q_bh = q_t;
|
|
131
|
+
ov::Output<ov::Node> k_bh = k_t;
|
|
132
|
+
if (rq1 > 1) {
|
|
133
|
+
auto q_unsq = std::make_shared<ov::op::v0::Unsqueeze>(q_t, axis_2); // [B, H_k, 1, T, S]
|
|
134
|
+
auto k_unsq = std::make_shared<ov::op::v0::Unsqueeze>(k_t, axis_2); // [B, H_k, 1, T, S]
|
|
135
|
+
|
|
136
|
+
auto bcast_shape = ov::op::v0::Constant::create(ov::element::i64, {5}, std::vector<int64_t>{1, 1, rq1, 1, 1});
|
|
137
|
+
auto q_bcast =
|
|
138
|
+
std::make_shared<ov::op::v3::Broadcast>(q_unsq, bcast_shape, ov::op::BroadcastType::BIDIRECTIONAL);
|
|
139
|
+
auto k_bcast =
|
|
140
|
+
std::make_shared<ov::op::v3::Broadcast>(k_unsq, bcast_shape, ov::op::BroadcastType::BIDIRECTIONAL);
|
|
141
|
+
|
|
142
|
+
// Transpose [B, H_k, rq1, T, S] -> [B, rq1, H_k, T, S] so that reshape merges
|
|
143
|
+
// as [rq1, H_k] giving repeat-blocks pattern matching CPU: iq1 = iv1 % H_k
|
|
144
|
+
auto perm_5d = ov::op::v0::Constant::create(ov::element::i64, {5}, std::vector<int64_t>{0, 2, 1, 3, 4});
|
|
145
|
+
auto q_transposed = std::make_shared<ov::op::v1::Transpose>(q_bcast, perm_5d);
|
|
146
|
+
auto k_transposed = std::make_shared<ov::op::v1::Transpose>(k_bcast, perm_5d);
|
|
147
|
+
|
|
148
|
+
auto new_shape = ov::op::v0::Constant::create(ov::element::i64, {4}, std::vector<int64_t>{B, H_v, T, S_v});
|
|
149
|
+
q_bh = std::make_shared<ov::op::v1::Reshape>(q_transposed, new_shape, false);
|
|
150
|
+
k_bh = std::make_shared<ov::op::v1::Reshape>(k_transposed, new_shape, false);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Merge batch and head dims: [B*H_v, T, S_v]
|
|
154
|
+
auto merge_bh = [&](ov::Output<ov::Node> x, int64_t last_dim) {
|
|
155
|
+
auto shape = ov::op::v0::Constant::create(ov::element::i64, {3}, std::vector<int64_t>{B * H_v, T, last_dim});
|
|
156
|
+
return std::make_shared<ov::op::v1::Reshape>(x, shape, false);
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
auto q_m = merge_bh(q_bh, S_v); // [B*H_v, T, S_v]
|
|
160
|
+
auto k_m = merge_bh(k_bh, S_v); // [B*H_v, T, S_v]
|
|
161
|
+
auto v_m = merge_bh(v_t, S_v); // [B*H_v, T, S_v]
|
|
162
|
+
auto g_m = merge_bh(g_t, kda ? S_v : 1); // [B*H_v, T, 1 or S_v]
|
|
163
|
+
auto beta_m = merge_bh(beta_t, 1); // [B*H_v, T, 1]
|
|
164
|
+
|
|
165
|
+
// State: [B, H_v, S_v, S_v] -> [B*H_v, S_v, S_v]
|
|
166
|
+
auto state_shape = ov::op::v0::Constant::create(ov::element::i64, {3}, std::vector<int64_t>{B * H_v, S_v, S_v});
|
|
167
|
+
auto state_m = std::make_shared<ov::op::v1::Reshape>(state, state_shape, false);
|
|
168
|
+
|
|
169
|
+
auto scale_const = ov::op::v0::Constant::create(ov::element::f32, {}, std::vector<float>{scale});
|
|
170
|
+
|
|
171
|
+
// --- Build Loop body ---
|
|
172
|
+
// Body parameters (no iteration counter needed, use -1 in special ports)
|
|
173
|
+
auto body_state = std::make_shared<ov::op::v0::Parameter>(ov::element::f32, ov::PartialShape::dynamic());
|
|
174
|
+
auto body_q = std::make_shared<ov::op::v0::Parameter>(ov::element::f32, ov::PartialShape::dynamic());
|
|
175
|
+
auto body_k = std::make_shared<ov::op::v0::Parameter>(ov::element::f32, ov::PartialShape::dynamic());
|
|
176
|
+
auto body_v = std::make_shared<ov::op::v0::Parameter>(ov::element::f32, ov::PartialShape::dynamic());
|
|
177
|
+
auto body_g = std::make_shared<ov::op::v0::Parameter>(ov::element::f32, ov::PartialShape::dynamic());
|
|
178
|
+
auto body_beta = std::make_shared<ov::op::v0::Parameter>(ov::element::f32, ov::PartialShape::dynamic());
|
|
179
|
+
auto body_iter = std::make_shared<ov::op::v0::Parameter>(ov::element::i64, ov::Shape{1});
|
|
180
|
+
|
|
181
|
+
// Condition output (always true - we rely on trip_count for termination)
|
|
182
|
+
auto body_cond_out = ov::op::v0::Constant::create(ov::element::boolean, ov::Shape{1}, std::vector<bool>{true});
|
|
183
|
+
|
|
184
|
+
// Gather current token from invariant inputs using iteration counter
|
|
185
|
+
auto q_t_cur = std::make_shared<ov::op::v8::Gather>(body_q, body_iter, axis_1); // [B*H_v, 1, S_v]
|
|
186
|
+
auto k_t_cur = std::make_shared<ov::op::v8::Gather>(body_k, body_iter, axis_1); // [B*H_v, 1, S_v]
|
|
187
|
+
auto v_t_cur = std::make_shared<ov::op::v8::Gather>(body_v, body_iter, axis_1); // [B*H_v, 1, S_v]
|
|
188
|
+
auto g_t_cur = std::make_shared<ov::op::v8::Gather>(body_g, body_iter, axis_1); // [B*H_v, 1, 1 or S_v]
|
|
189
|
+
auto b_t_cur = std::make_shared<ov::op::v8::Gather>(body_beta, body_iter, axis_1); // [B*H_v, 1, 1]
|
|
190
|
+
|
|
191
|
+
// Squeeze token dim
|
|
192
|
+
auto q_cur = std::make_shared<ov::op::v0::Squeeze>(q_t_cur, axis_1); // [B*H_v, S_v]
|
|
193
|
+
auto k_cur = std::make_shared<ov::op::v0::Squeeze>(k_t_cur, axis_1); // [B*H_v, S_v]
|
|
194
|
+
auto v_cur = std::make_shared<ov::op::v0::Squeeze>(v_t_cur, axis_1); // [B*H_v, S_v]
|
|
195
|
+
auto g_cur = std::make_shared<ov::op::v0::Squeeze>(g_t_cur, axis_1); // [B*H_v, 1 or S_v]
|
|
196
|
+
auto b_cur = std::make_shared<ov::op::v0::Squeeze>(b_t_cur, axis_1); // [B*H_v, 1]
|
|
197
|
+
|
|
198
|
+
// Step 1: Apply decay gate to state
|
|
199
|
+
auto exp_g = std::make_shared<ov::op::v0::Exp>(g_cur); // [B*H_v, 1 or S_v]
|
|
200
|
+
auto exp_g_unsq = std::make_shared<ov::op::v0::Unsqueeze>(exp_g, axis_1); // [B*H_v, 1, 1 or S_v]
|
|
201
|
+
auto state_decayed = std::make_shared<ov::op::v1::Multiply>(body_state, exp_g_unsq); // [B*H_v, S_v, S_v]
|
|
202
|
+
|
|
203
|
+
// Step 2: delta = (v - S @ k) * beta
|
|
204
|
+
auto k_col = std::make_shared<ov::op::v0::Unsqueeze>(k_cur, axis_2); // [B*H_v, S_v, 1]
|
|
205
|
+
auto sk = std::make_shared<ov::op::v0::MatMul>(state_decayed, k_col, false, false); // [B*H_v, S_v, 1]
|
|
206
|
+
auto sk_sq = std::make_shared<ov::op::v0::Squeeze>(sk, axis_2); // [B*H_v, S_v]
|
|
207
|
+
auto v_minus_sk = std::make_shared<ov::op::v1::Subtract>(v_cur, sk_sq); // [B*H_v, S_v]
|
|
208
|
+
auto delta = std::make_shared<ov::op::v1::Multiply>(v_minus_sk, b_cur); // [B*H_v, S_v]
|
|
209
|
+
|
|
210
|
+
// Step 3: state += outer(delta, k)
|
|
211
|
+
auto delta_col = std::make_shared<ov::op::v0::Unsqueeze>(delta, axis_2); // [B*H_v, S_v, 1]
|
|
212
|
+
auto k_row = std::make_shared<ov::op::v0::Unsqueeze>(k_cur, axis_1); // [B*H_v, 1, S_v]
|
|
213
|
+
auto outer_prod = std::make_shared<ov::op::v0::MatMul>(delta_col, k_row, false, false); // [B*H_v, S_v, S_v]
|
|
214
|
+
auto state_updated = std::make_shared<ov::op::v1::Add>(state_decayed, outer_prod); // [B*H_v, S_v, S_v]
|
|
215
|
+
|
|
216
|
+
// Step 4: attn_out = S @ q * scale
|
|
217
|
+
auto q_col = std::make_shared<ov::op::v0::Unsqueeze>(q_cur, axis_2); // [B*H_v, S_v, 1]
|
|
218
|
+
auto sq = std::make_shared<ov::op::v0::MatMul>(state_updated, q_col, false, false); // [B*H_v, S_v, 1]
|
|
219
|
+
auto sq_squeezed = std::make_shared<ov::op::v0::Squeeze>(sq, axis_2); // [B*H_v, S_v]
|
|
220
|
+
auto attn_out = std::make_shared<ov::op::v1::Multiply>(sq_squeezed, scale_const); // [B*H_v, S_v]
|
|
221
|
+
|
|
222
|
+
// Unsqueeze attn_out to [B*H_v, 1, S_v] for scan output concatenation
|
|
223
|
+
auto attn_out_unsq = std::make_shared<ov::op::v0::Unsqueeze>(attn_out, axis_1); // [B*H_v, 1, S_v]
|
|
224
|
+
|
|
225
|
+
// --- Assemble Loop ---
|
|
226
|
+
// Body: results = [condition, state_updated, attn_out_unsq]
|
|
227
|
+
auto body = std::make_shared<ov::Model>(
|
|
228
|
+
ov::OutputVector{body_cond_out, state_updated, attn_out_unsq},
|
|
229
|
+
ov::ParameterVector{body_iter, body_state, body_q, body_k, body_v, body_g, body_beta});
|
|
230
|
+
|
|
231
|
+
auto trip_count = ov::op::v0::Constant::create(ov::element::i64, ov::Shape{1}, std::vector<int64_t>{T});
|
|
232
|
+
auto exec_cond = ov::op::v0::Constant::create(ov::element::boolean, ov::Shape{1}, std::vector<bool>{true});
|
|
233
|
+
|
|
234
|
+
auto loop = std::make_shared<ov::op::v5::Loop>(trip_count, exec_cond);
|
|
235
|
+
loop->set_function(body);
|
|
236
|
+
loop->set_special_body_ports(ov::op::v5::Loop::SpecialBodyPorts{0, 0});
|
|
237
|
+
|
|
238
|
+
// Carried state: feeds back from body output 1 to body_state param
|
|
239
|
+
loop->set_merged_input(body_state, state_m, state_updated);
|
|
240
|
+
// Invariant inputs: passed through unchanged each iteration
|
|
241
|
+
loop->set_invariant_input(body_q, q_m);
|
|
242
|
+
loop->set_invariant_input(body_k, k_m);
|
|
243
|
+
loop->set_invariant_input(body_v, v_m);
|
|
244
|
+
loop->set_invariant_input(body_g, g_m);
|
|
245
|
+
loop->set_invariant_input(body_beta, beta_m);
|
|
246
|
+
|
|
247
|
+
// Loop outputs:
|
|
248
|
+
// 1) Final state (last iteration value of state_updated)
|
|
249
|
+
auto final_state_out = loop->get_iter_value(state_updated, -1); // [B*H_v, S_v, S_v]
|
|
250
|
+
// 2) Concatenated attention outputs across all iterations along axis 1
|
|
251
|
+
auto attn_concat_out = loop->get_concatenated_slices(attn_out_unsq, 0, 1, 1, -1, 1); // [B*H_v, T, S_v]
|
|
252
|
+
|
|
253
|
+
// --- Pack outputs to match ggml layout ---
|
|
254
|
+
// ggml output ne = {S_v*H, T*B + S_v*B, 1, 1} -> OV [1, 1, T*B+S_v*B, S_v*H_v]
|
|
255
|
+
// attn: [B, T, H_v, S_v] row-major, state: [B, H_v, S_v, S_v] row-major
|
|
256
|
+
|
|
257
|
+
// attn: [B*H_v, T, S_v] -> [B, H_v, T, S_v] -> transpose to [B, T, H_v, S_v] -> flatten
|
|
258
|
+
auto attn_4d_shape = ov::op::v0::Constant::create(ov::element::i64, {4}, std::vector<int64_t>{B, H_v, T, S_v});
|
|
259
|
+
auto attn_4d = std::make_shared<ov::op::v1::Reshape>(attn_concat_out, attn_4d_shape, false);
|
|
260
|
+
auto attn_perm = std::make_shared<ov::op::v1::Transpose>(attn_4d, perm_0213); // [B, T, H_v, S_v]
|
|
261
|
+
|
|
262
|
+
auto flat_shape_1d = ov::op::v0::Constant::create(ov::element::i64, {1}, std::vector<int64_t>{-1});
|
|
263
|
+
auto attn_1d = std::make_shared<ov::op::v1::Reshape>(attn_perm, flat_shape_1d, false);
|
|
264
|
+
|
|
265
|
+
// state: [B*H_v, S_v, S_v] -> [B, H_v, S_v, S_v] -> flatten
|
|
266
|
+
auto state_4d_shape = ov::op::v0::Constant::create(ov::element::i64, {4}, std::vector<int64_t>{B, H_v, S_v, S_v});
|
|
267
|
+
auto state_4d = std::make_shared<ov::op::v1::Reshape>(final_state_out, state_4d_shape, false);
|
|
268
|
+
auto state_1d = std::make_shared<ov::op::v1::Reshape>(state_4d, flat_shape_1d, false);
|
|
269
|
+
|
|
270
|
+
// Concat [attn | state] and reshape to final output
|
|
271
|
+
auto packed = std::make_shared<ov::op::v0::Concat>(ov::OutputVector{attn_1d, state_1d}, 0);
|
|
272
|
+
auto out_shape =
|
|
273
|
+
ov::op::v0::Constant::create(ov::element::i64, {4}, std::vector<int64_t>{1, 1, T * B + S_v * B, S_v * H_v});
|
|
274
|
+
auto res = std::make_shared<ov::op::v1::Reshape>(packed, out_shape, false);
|
|
275
|
+
|
|
276
|
+
return rename_outputs_with_suffix({res}, context.get_name());
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
} // namespace op
|
|
280
|
+
} // namespace ggml
|
|
281
|
+
} // namespace frontend
|
|
282
|
+
} // namespace ov
|