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.
Files changed (308) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -4
  3. data/ext/options.rb +1 -1
  4. data/ext/ruby_whisper.c +0 -1
  5. data/ext/ruby_whisper.h +7 -1
  6. data/ext/ruby_whisper_context.c +50 -1
  7. data/ext/ruby_whisper_log_settable.h +1 -2
  8. data/ext/ruby_whisper_params.c +9 -8
  9. data/ext/ruby_whisper_transcribe.cpp +0 -19
  10. data/ext/ruby_whisper_vad_context.c +30 -10
  11. data/ext/ruby_whisper_vad_context_detect.cpp +8 -9
  12. data/ext/ruby_whisper_vad_params.c +4 -4
  13. data/ext/ruby_whisper_vad_segment.c +2 -2
  14. data/ext/sources/CMakeLists.txt +2 -1
  15. data/ext/sources/cmake/parakeet.pc.in +2 -2
  16. data/ext/sources/cmake/whisper.pc.in +2 -2
  17. data/ext/sources/examples/cli/cli.cpp +9 -1
  18. data/ext/sources/examples/common-ggml.cpp +2 -0
  19. data/ext/sources/examples/vad-speech-segments/speech.cpp +3 -2
  20. data/ext/sources/ggml/CMakeLists.txt +3 -4
  21. data/ext/sources/ggml/include/ggml-cuda.h +0 -3
  22. data/ext/sources/ggml/include/ggml-sycl.h +8 -0
  23. data/ext/sources/ggml/include/ggml.h +3 -1
  24. data/ext/sources/ggml/src/CMakeLists.txt +8 -1
  25. data/ext/sources/ggml/src/ggml-backend-meta.cpp +7 -4
  26. data/ext/sources/ggml/src/ggml-common.h +13 -2
  27. data/ext/sources/ggml/src/ggml-cpu/CMakeLists.txt +1 -1
  28. data/ext/sources/ggml/src/ggml-cpu/amx/mmq.cpp +5 -6
  29. data/ext/sources/ggml/src/ggml-cpu/arch/arm/quants.c +78 -4
  30. data/ext/sources/ggml/src/ggml-cpu/arch/x86/quants.c +142 -4
  31. data/ext/sources/ggml/src/ggml-cpu/arch-fallback.h +7 -2
  32. data/ext/sources/ggml/src/ggml-cpu/ggml-cpu.c +14 -0
  33. data/ext/sources/ggml/src/ggml-cpu/llamafile/sgemm.cpp +26 -19
  34. data/ext/sources/ggml/src/ggml-cpu/ops.cpp +129 -46
  35. data/ext/sources/ggml/src/ggml-cpu/quants.c +51 -0
  36. data/ext/sources/ggml/src/ggml-cpu/quants.h +3 -0
  37. data/ext/sources/ggml/src/ggml-cpu/simd-gemm.h +1 -1
  38. data/ext/sources/ggml/src/ggml-cpu/simd-mappings.h +11 -0
  39. data/ext/sources/ggml/src/ggml-cpu/vec.cpp +2 -2
  40. data/ext/sources/ggml/src/ggml-cuda/binbcast.cu +90 -46
  41. data/ext/sources/ggml/src/ggml-cuda/col2im-1d.cu +81 -0
  42. data/ext/sources/ggml/src/ggml-cuda/col2im-1d.cuh +3 -0
  43. data/ext/sources/ggml/src/ggml-cuda/common.cuh +4 -0
  44. data/ext/sources/ggml/src/ggml-cuda/concat.cu +33 -21
  45. data/ext/sources/ggml/src/ggml-cuda/conv-transpose-1d.cu +14 -12
  46. data/ext/sources/ggml/src/ggml-cuda/convert.cu +86 -34
  47. data/ext/sources/ggml/src/ggml-cuda/cpy.cu +80 -29
  48. data/ext/sources/ggml/src/ggml-cuda/fattn-common.cuh +9 -5
  49. data/ext/sources/ggml/src/ggml-cuda/fattn-mma-f16.cuh +4 -0
  50. data/ext/sources/ggml/src/ggml-cuda/fattn-tile.cuh +9 -5
  51. data/ext/sources/ggml/src/ggml-cuda/fattn.cu +27 -21
  52. data/ext/sources/ggml/src/ggml-cuda/gated_delta_net.cu +40 -25
  53. data/ext/sources/ggml/src/ggml-cuda/gated_delta_net.cuh +10 -0
  54. data/ext/sources/ggml/src/ggml-cuda/getrows.cu +15 -12
  55. data/ext/sources/ggml/src/ggml-cuda/ggml-cuda.cu +718 -1248
  56. data/ext/sources/ggml/src/ggml-cuda/mmq.cu +7 -0
  57. data/ext/sources/ggml/src/ggml-cuda/mmvq.cu +77 -40
  58. data/ext/sources/ggml/src/ggml-cuda/out-prod.cu +55 -12
  59. data/ext/sources/ggml/src/ggml-cuda/set-rows.cu +64 -4
  60. data/ext/sources/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_16-ncols2_2.cu +1 -0
  61. data/ext/sources/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_32-ncols2_2.cu +1 -0
  62. data/ext/sources/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_4-ncols2_2.cu +1 -0
  63. data/ext/sources/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_8-ncols2_2.cu +1 -0
  64. data/ext/sources/ggml/src/ggml-cuda/topk-moe.cu +7 -1
  65. data/ext/sources/ggml/src/ggml-cuda/vendors/hip.h +1 -0
  66. data/ext/sources/ggml/src/ggml-cuda/vendors/musa.h +1 -0
  67. data/ext/sources/ggml/src/ggml-hexagon/CMakeLists.txt +0 -5
  68. data/ext/sources/ggml/src/ggml-hexagon/ggml-hexagon.cpp +1634 -1293
  69. data/ext/sources/ggml/src/ggml-hexagon/htp/CMakeLists.txt +11 -40
  70. data/ext/sources/ggml/src/ggml-hexagon/htp/cmake-toolchain.cmake +13 -15
  71. data/ext/sources/ggml/src/ggml-hexagon/htp/concat-ops.c +1 -1
  72. data/ext/sources/ggml/src/ggml-hexagon/htp/flash-attn-ops.c +1749 -399
  73. data/ext/sources/ggml/src/ggml-hexagon/htp/flash-attn-ops.h +303 -0
  74. data/ext/sources/ggml/src/ggml-hexagon/htp/hex-common.h +80 -0
  75. data/ext/sources/ggml/src/ggml-hexagon/htp/hex-dma.h +26 -23
  76. data/ext/sources/ggml/src/ggml-hexagon/htp/hex-profile.h +64 -0
  77. data/ext/sources/ggml/src/ggml-hexagon/htp/hex-utils.h +1 -83
  78. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-fa-kernels.h +555 -0
  79. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-mm-kernels-tiled.h +1303 -0
  80. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-queue.c +9 -0
  81. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-queue.h +27 -4
  82. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-utils.h +59 -37
  83. data/ext/sources/ggml/src/ggml-hexagon/htp/htp-ctx.h +11 -3
  84. data/ext/sources/ggml/src/ggml-hexagon/htp/htp-ops.h +52 -12
  85. data/ext/sources/ggml/src/ggml-hexagon/htp/htp-vtcm.h +19 -0
  86. data/ext/sources/ggml/src/ggml-hexagon/htp/htp_iface.idl +2 -1
  87. data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-base.h +14 -30
  88. data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-exp.h +39 -0
  89. data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-fa-kernels.h +232 -0
  90. data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-mm-kernels-flat.h +1511 -0
  91. data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-mm-kernels-tiled.h +1200 -0
  92. data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-sigmoid.h +39 -0
  93. data/ext/sources/ggml/src/ggml-hexagon/htp/main.c +127 -32
  94. data/ext/sources/ggml/src/ggml-hexagon/htp/matmul-ops.c +3023 -4425
  95. data/ext/sources/ggml/src/ggml-hexagon/htp/matmul-ops.h +650 -0
  96. data/ext/sources/ggml/src/ggml-hexagon/htp/rope-ops.c +48 -13
  97. data/ext/sources/ggml/src/ggml-hexagon/htp/ssm-conv.c +10 -9
  98. data/ext/sources/ggml/src/ggml-hexagon/htp/worker-pool.c +15 -3
  99. data/ext/sources/ggml/src/ggml-hexagon/htp/worker-pool.h +8 -0
  100. data/ext/sources/ggml/src/ggml-hexagon/htp-opnode.h +168 -50
  101. data/ext/sources/ggml/src/ggml-hexagon/libggml-htp.inf +0 -4
  102. data/ext/sources/ggml/src/ggml-hip/CMakeLists.txt +5 -0
  103. data/ext/sources/ggml/src/ggml-metal/ggml-metal-device.cpp +69 -5
  104. data/ext/sources/ggml/src/ggml-metal/ggml-metal-device.h +4 -1
  105. data/ext/sources/ggml/src/ggml-metal/ggml-metal-device.m +27 -6
  106. data/ext/sources/ggml/src/ggml-metal/ggml-metal-impl.h +38 -0
  107. data/ext/sources/ggml/src/ggml-metal/ggml-metal-ops.cpp +132 -2
  108. data/ext/sources/ggml/src/ggml-metal/ggml-metal-ops.h +2 -0
  109. data/ext/sources/ggml/src/ggml-metal/ggml-metal.metal +345 -87
  110. data/ext/sources/ggml/src/ggml-opencl/CMakeLists.txt +13 -0
  111. data/ext/sources/ggml/src/ggml-opencl/fa_tune.h +92 -0
  112. data/ext/sources/ggml/src/ggml-opencl/ggml-opencl.cpp +4060 -357
  113. data/ext/sources/ggml/src/ggml-opencl/kernels/cvt.cl +198 -0
  114. data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f16.cl +81 -41
  115. data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f32.cl +88 -39
  116. data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f32_f16.cl +1995 -96
  117. data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f32_q4_0.cl +1615 -0
  118. data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f32_q8_0.cl +1486 -0
  119. data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_pre_f16.cl +156 -0
  120. data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_mxfp4_f32_ns.cl +74 -6
  121. data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q4_0_f32_ns.cl +74 -6
  122. data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q4_1_f32_ns.cl +74 -6
  123. data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q4_k_f32_ns.cl +71 -6
  124. data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q5_0_f32_ns.cl +74 -6
  125. data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q5_1_f32_ns.cl +74 -6
  126. data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q5_k_f32_ns.cl +74 -6
  127. data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q6_k_f32_ns.cl +74 -6
  128. data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q1_0_f32.cl +94 -0
  129. data/ext/sources/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q1_0_f32.cl +121 -0
  130. data/ext/sources/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q8_0_f32.cl +1 -1
  131. data/ext/sources/ggml/src/ggml-opencl/kernels/mul_mm_q1_0_f32_l4_lm.cl +156 -0
  132. data/ext/sources/ggml/src/ggml-opencl/kernels/mul_mv_f16_f32_l4.cl +1149 -0
  133. data/ext/sources/ggml/src/ggml-opencl/kernels/mul_mv_q1_0_f32.cl +141 -0
  134. data/ext/sources/ggml/src/ggml-opencl/kernels/mul_mv_q1_0_f32_flat.cl +190 -0
  135. data/ext/sources/ggml/src/ggml-opencl/kernels/norm.cl +5 -2
  136. data/ext/sources/ggml/src/ggml-opencl/kernels/set_rows.cl +500 -0
  137. data/ext/sources/ggml/src/ggml-opencl/libdl.h +79 -0
  138. data/ext/sources/ggml/src/ggml-openvino/.clang-format +0 -5
  139. data/ext/sources/ggml/src/ggml-openvino/CMakeLists.txt +2 -4
  140. data/ext/sources/ggml/src/ggml-openvino/ggml-decoder.cpp +733 -130
  141. data/ext/sources/ggml/src/ggml-openvino/ggml-decoder.h +76 -23
  142. data/ext/sources/ggml/src/ggml-openvino/ggml-openvino-extra.cpp +57 -3
  143. data/ext/sources/ggml/src/ggml-openvino/ggml-openvino-extra.h +29 -8
  144. data/ext/sources/ggml/src/ggml-openvino/ggml-openvino.cpp +307 -59
  145. data/ext/sources/ggml/src/ggml-openvino/ggml-quants.cpp +66 -0
  146. data/ext/sources/ggml/src/ggml-openvino/ggml-quants.h +10 -4
  147. data/ext/sources/ggml/src/ggml-openvino/openvino/decoder.h +56 -16
  148. data/ext/sources/ggml/src/ggml-openvino/openvino/frontend.h +1 -1
  149. data/ext/sources/ggml/src/ggml-openvino/openvino/input_model.h +4 -4
  150. data/ext/sources/ggml/src/ggml-openvino/openvino/node_context.h +94 -37
  151. data/ext/sources/ggml/src/ggml-openvino/openvino/op/add_id.cpp +76 -0
  152. data/ext/sources/ggml/src/ggml-openvino/openvino/op/argsort.cpp +47 -0
  153. data/ext/sources/ggml/src/ggml-openvino/openvino/op/clamp.cpp +33 -0
  154. data/ext/sources/ggml/src/ggml-openvino/openvino/op/concat.cpp +48 -0
  155. data/ext/sources/ggml/src/ggml-openvino/openvino/op/cont.cpp +8 -16
  156. data/ext/sources/ggml/src/ggml-openvino/openvino/op/cpy.cpp +14 -1
  157. data/ext/sources/ggml/src/ggml-openvino/openvino/op/div.cpp +146 -0
  158. data/ext/sources/ggml/src/ggml-openvino/openvino/op/flash_attn_ext.cpp +108 -21
  159. data/ext/sources/ggml/src/ggml-openvino/openvino/op/gated_delta_net.cpp +282 -0
  160. data/ext/sources/ggml/src/ggml-openvino/openvino/op/gated_delta_net.hpp +65 -0
  161. data/ext/sources/ggml/src/ggml-openvino/openvino/op/get_rows.cpp +2 -9
  162. data/ext/sources/ggml/src/ggml-openvino/openvino/op/glu_geglu.cpp +21 -7
  163. data/ext/sources/ggml/src/ggml-openvino/openvino/op/glu_swiglu.cpp +41 -8
  164. data/ext/sources/ggml/src/ggml-openvino/openvino/op/im2col.cpp +120 -0
  165. data/ext/sources/ggml/src/ggml-openvino/openvino/op/l2_norm.cpp +44 -0
  166. data/ext/sources/ggml/src/ggml-openvino/openvino/op/mul_mat_id.cpp +226 -0
  167. data/ext/sources/ggml/src/ggml-openvino/openvino/op/mulmat.cpp +19 -9
  168. data/ext/sources/ggml/src/ggml-openvino/openvino/op/norm.cpp +58 -0
  169. data/ext/sources/ggml/src/ggml-openvino/openvino/op/pad.cpp +95 -0
  170. data/ext/sources/ggml/src/ggml-openvino/openvino/op/permute.cpp +58 -13
  171. data/ext/sources/ggml/src/ggml-openvino/openvino/op/repeat.cpp +74 -0
  172. data/ext/sources/ggml/src/ggml-openvino/openvino/op/reshape.cpp +13 -6
  173. data/ext/sources/ggml/src/ggml-openvino/openvino/op/rms_norm.cpp +1 -1
  174. data/ext/sources/ggml/src/ggml-openvino/openvino/op/rope.cpp +134 -38
  175. data/ext/sources/ggml/src/ggml-openvino/openvino/op/set_rows.cpp +3 -3
  176. data/ext/sources/ggml/src/ggml-openvino/openvino/op/softmax.cpp +126 -49
  177. data/ext/sources/ggml/src/ggml-openvino/openvino/op/ssm_conv.cpp +59 -0
  178. data/ext/sources/ggml/src/ggml-openvino/openvino/op/sum_rows.cpp +27 -0
  179. data/ext/sources/ggml/src/ggml-openvino/openvino/op/transpose.cpp +32 -1
  180. data/ext/sources/ggml/src/ggml-openvino/openvino/op/unary_silu.cpp +1 -1
  181. data/ext/sources/ggml/src/ggml-openvino/openvino/op/unary_softplus.cpp +38 -0
  182. data/ext/sources/ggml/src/ggml-openvino/openvino/op/view.cpp +90 -25
  183. data/ext/sources/ggml/src/ggml-openvino/openvino/op_table.cpp +41 -23
  184. data/ext/sources/ggml/src/ggml-openvino/openvino/op_table.h +18 -5
  185. data/ext/sources/ggml/src/ggml-openvino/openvino/pass/mark_decompression_convert_constant_folding.h +1 -1
  186. data/ext/sources/ggml/src/ggml-openvino/openvino/translate_session.cpp +43 -40
  187. data/ext/sources/ggml/src/ggml-openvino/openvino/translate_session.h +5 -4
  188. data/ext/sources/ggml/src/ggml-openvino/openvino/utils.cpp +548 -3
  189. data/ext/sources/ggml/src/ggml-openvino/openvino/utils.h +28 -26
  190. data/ext/sources/ggml/src/ggml-openvino/utils.cpp +383 -94
  191. data/ext/sources/ggml/src/ggml-openvino/utils.h +11 -8
  192. data/ext/sources/ggml/src/ggml-quants.c +76 -0
  193. data/ext/sources/ggml/src/ggml-quants.h +3 -0
  194. data/ext/sources/ggml/src/ggml-sycl/CMakeLists.txt +5 -5
  195. data/ext/sources/ggml/src/ggml-sycl/backend.hpp +2 -0
  196. data/ext/sources/ggml/src/ggml-sycl/binbcast.cpp +12 -0
  197. data/ext/sources/ggml/src/ggml-sycl/col2im-1d.cpp +102 -0
  198. data/ext/sources/ggml/src/ggml-sycl/col2im-1d.hpp +8 -0
  199. data/ext/sources/ggml/src/ggml-sycl/common.cpp +6 -8
  200. data/ext/sources/ggml/src/ggml-sycl/common.hpp +19 -2
  201. data/ext/sources/ggml/src/ggml-sycl/concat.cpp +21 -1
  202. data/ext/sources/ggml/src/ggml-sycl/conv2d-dw.cpp +158 -0
  203. data/ext/sources/ggml/src/ggml-sycl/conv2d-dw.hpp +10 -0
  204. data/ext/sources/ggml/src/ggml-sycl/conv2d-transpose.cpp +125 -0
  205. data/ext/sources/ggml/src/ggml-sycl/conv2d-transpose.hpp +10 -0
  206. data/ext/sources/ggml/src/ggml-sycl/conv2d.cpp +150 -0
  207. data/ext/sources/ggml/src/ggml-sycl/conv2d.hpp +10 -0
  208. data/ext/sources/ggml/src/ggml-sycl/conv3d.cpp +224 -0
  209. data/ext/sources/ggml/src/ggml-sycl/conv3d.hpp +8 -0
  210. data/ext/sources/ggml/src/ggml-sycl/convert.cpp +6 -0
  211. data/ext/sources/ggml/src/ggml-sycl/cpy.cpp +706 -0
  212. data/ext/sources/ggml/src/ggml-sycl/cpy.hpp +281 -0
  213. data/ext/sources/ggml/src/ggml-sycl/cross_entropy_loss.cpp +255 -0
  214. data/ext/sources/ggml/src/ggml-sycl/cross_entropy_loss.hpp +7 -0
  215. data/ext/sources/ggml/src/ggml-sycl/dequantize.hpp +15 -0
  216. data/ext/sources/ggml/src/ggml-sycl/dmmv.cpp +492 -319
  217. data/ext/sources/ggml/src/ggml-sycl/dpct/helper.hpp +15 -7
  218. data/ext/sources/ggml/src/ggml-sycl/element_wise.cpp +215 -115
  219. data/ext/sources/ggml/src/ggml-sycl/element_wise.hpp +2 -0
  220. data/ext/sources/ggml/src/ggml-sycl/ggml-sycl.cpp +1006 -336
  221. data/ext/sources/ggml/src/ggml-sycl/mmvq.cpp +252 -67
  222. data/ext/sources/ggml/src/ggml-sycl/mmvq.hpp +17 -0
  223. data/ext/sources/ggml/src/ggml-sycl/norm.cpp +103 -49
  224. data/ext/sources/ggml/src/ggml-sycl/outprod.cpp +45 -9
  225. data/ext/sources/ggml/src/ggml-sycl/pool.cpp +185 -0
  226. data/ext/sources/ggml/src/ggml-sycl/pool.hpp +22 -0
  227. data/ext/sources/ggml/src/ggml-sycl/presets.hpp +3 -1
  228. data/ext/sources/ggml/src/ggml-sycl/set_rows.cpp +10 -2
  229. data/ext/sources/ggml/src/ggml-sycl/softmax.cpp +9 -10
  230. data/ext/sources/ggml/src/ggml-sycl/vecdotq.hpp +35 -0
  231. data/ext/sources/ggml/src/ggml-vulkan/CMakeLists.txt +5 -0
  232. data/ext/sources/ggml/src/ggml-vulkan/ggml-vulkan.cpp +833 -215
  233. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/col2im_1d.comp +61 -0
  234. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/conv2d_mm.comp +1 -1
  235. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/conv3d_mm.comp +431 -0
  236. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/diag.comp +3 -3
  237. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/flash_attn.comp +1 -0
  238. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/flash_attn_cm1.comp +1 -0
  239. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/generic_unary_head.glsl +21 -19
  240. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/get_rows_back.comp +25 -0
  241. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/glu_head.glsl +23 -4
  242. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/glu_main.glsl +14 -18
  243. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/l2_norm.comp +4 -7
  244. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/mul_mat_vecq.comp +21 -24
  245. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/mul_mm.comp +31 -23
  246. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/mul_mm_cm2.comp +6 -5
  247. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/mul_mm_funcs.glsl +84 -67
  248. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/norm.comp +10 -10
  249. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/repeat_back.comp +3 -3
  250. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/roll.comp +3 -3
  251. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/tri.comp +3 -3
  252. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/unary.comp +168 -0
  253. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/vulkan-shaders-gen.cpp +121 -74
  254. data/ext/sources/ggml/src/ggml-webgpu/ggml-webgpu-shader-lib.hpp +26 -19
  255. data/ext/sources/ggml/src/ggml-webgpu/ggml-webgpu.cpp +31 -36
  256. data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/common_decls.tmpl +16 -2
  257. data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/flash_attn_vec_split.wgsl +7 -7
  258. data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/get_rows.wgsl +21 -0
  259. data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_decls.tmpl +439 -320
  260. data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_id_vec.wgsl +2 -2
  261. data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_vec.wgsl +45 -39
  262. data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_vec_acc.tmpl +586 -465
  263. data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_vec_q_acc.tmpl +63 -69
  264. data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/quantize_q8.wgsl +14 -9
  265. data/ext/sources/ggml/src/ggml.c +36 -14
  266. data/ext/sources/include/whisper.h +21 -0
  267. data/ext/sources/src/whisper.cpp +164 -14
  268. data/lib/whisper/log_settable.rb +5 -8
  269. data/lib/whisper/model/uri.rb +0 -7
  270. data/sig/whisper.rbs +6 -0
  271. data/test/test_vad.rb +9 -0
  272. data/test/test_vad_context.rb +2 -2
  273. data/whispercpp.gemspec +1 -1
  274. metadata +62 -37
  275. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-flash-attn-ops.c +0 -1878
  276. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-matmul-ops.c +0 -2066
  277. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-ops.c +0 -6
  278. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-ops.h +0 -88
  279. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-profile.h +0 -34
  280. data/ext/sources/ggml/src/ggml-hexagon/htp/vtcm-utils.h +0 -16
  281. data/ext/sources/ggml/src/ggml-openvino/openvino/op/unary_gelu.cpp +0 -25
  282. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/abs.comp +0 -21
  283. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/ceil.comp +0 -22
  284. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/clamp.comp +0 -17
  285. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/cos.comp +0 -17
  286. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/elu.comp +0 -27
  287. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/exp.comp +0 -20
  288. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/floor.comp +0 -22
  289. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/gelu.comp +0 -25
  290. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/gelu_erf.comp +0 -39
  291. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/gelu_quick.comp +0 -23
  292. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/hardsigmoid.comp +0 -22
  293. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/hardswish.comp +0 -22
  294. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/leaky_relu.comp +0 -22
  295. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/neg.comp +0 -20
  296. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/relu.comp +0 -21
  297. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/round.comp +0 -29
  298. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/sgn.comp +0 -21
  299. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/sigmoid.comp +0 -20
  300. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/silu.comp +0 -22
  301. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/sin.comp +0 -17
  302. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/softplus.comp +0 -23
  303. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/sqrt.comp +0 -17
  304. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/square.comp +0 -17
  305. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/step.comp +0 -22
  306. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/tanh.comp +0 -20
  307. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/trunc.comp +0 -22
  308. 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> mask_sliced, res;
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
- mask_sliced = context.get_input(mask_name);
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 (mask_sliced.get_element_type() != ov::element::f16) {
53
- mask_sliced = std::make_shared<ov::op::v0::Convert>(mask_sliced, ov::element::f16);
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
- int64_t factor = num_heads / num_heads_kv;
58
- if (factor > 1 && num_heads_kv > 1) {
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
- ov::element::i64, {5}, {(int64_t) 1, (int64_t) 1, factor, (int64_t) 1, (int64_t) 1});
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, num_heads, (int64_t) -1, head_size});
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, mask_sliced, scale_node, false);
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