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
@@ -1,20 +1,17 @@
1
1
  #include "ggml-decoder.h"
2
2
 
3
- #include "ggml-backend-impl.h"
4
- #include "ggml-backend.h"
3
+ #include "ggml-impl.h"
5
4
  #include "ggml-openvino-extra.h"
6
5
  #include "ggml-openvino.h"
7
6
  #include "ggml-quants.h"
8
-
9
- #include <ggml-impl.h>
10
- #include <ggml.h>
7
+ #include "ggml.h"
8
+ #include "utils.h"
11
9
 
12
10
  #include <algorithm>
13
11
  #include <cassert>
14
12
  #include <cstddef>
15
13
  #include <cstdint>
16
14
  #include <cstdlib>
17
- #include <execution>
18
15
  #include <fstream>
19
16
  #include <iomanip>
20
17
  #include <map>
@@ -30,12 +27,10 @@
30
27
  #include <openvino/op/convert.hpp>
31
28
  #include <openvino/op/parameter.hpp>
32
29
  #include <openvino/runtime/tensor.hpp>
33
- #include <optional>
34
30
  #include <ostream>
35
31
  #include <set>
36
32
  #include <stdexcept>
37
33
  #include <string>
38
- #include <unordered_map>
39
34
  #include <vector>
40
35
 
41
36
  GgmlOvDecoder::GgmlOvDecoder(ggml_cgraph * cgraph,
@@ -44,6 +39,7 @@ GgmlOvDecoder::GgmlOvDecoder(ggml_cgraph * cgraph,
44
39
  std::map<std::string, std::shared_ptr<ov::Node>> & model_weights,
45
40
  bool is_static,
46
41
  bool is_stateful,
42
+ bool model_is_splitted,
47
43
  bool is_prefill,
48
44
  int prefill_chunk_size) :
49
45
  m_is_static(is_static),
@@ -51,22 +47,23 @@ GgmlOvDecoder::GgmlOvDecoder(ggml_cgraph * cgraph,
51
47
  m_is_prefill(is_prefill),
52
48
  m_naive(false),
53
49
  m_prefill_chunk_size(prefill_chunk_size),
50
+ m_model_is_splitted(model_is_splitted),
54
51
  m_cgraph(cgraph),
55
52
  m_model_weights(model_weights),
56
53
  m_model_params(model_params),
57
54
  m_compute_params(compute_params) {
58
- if (auto * env = getenv("GGML_OPENVINO_PRINT_CGRAPH_TENSOR_ADDRESS"); env && std::string(env) != "0") {
59
- #ifdef _WIN32
60
- _putenv_s("GGML_OPENVINO_PRINT_CGRAPH_TENSOR_ADDRESS", "");
61
- #else
62
- unsetenv("GGML_OPENVINO_PRINT_CGRAPH_TENSOR_ADDRESS");
63
- #endif
64
- print_tensor_address_map(cgraph);
55
+ static bool printed_address_map = false;
56
+ if (!printed_address_map) {
57
+ if (ggml_openvino_getenv_int("GGML_OPENVINO_PRINT_CGRAPH_TENSOR_ADDRESS")) {
58
+ printed_address_map = true;
59
+ print_tensor_address_map(cgraph);
60
+ }
65
61
  }
66
62
 
67
63
  validate_cgraph();
68
64
 
69
65
  set_input_output();
66
+ compute_node_dynamic_dims();
70
67
  compute_model_inputs();
71
68
  compute_model_outputs();
72
69
 
@@ -136,6 +133,29 @@ void GgmlOvDecoder::set_input_output() {
136
133
  }
137
134
  current_node_info.node_inputs[src_name] = src;
138
135
  current_node_info.node_inputs_names.push_back(src_name);
136
+
137
+ if (src->op == GGML_OP_VIEW) {
138
+ // Traverse upward through nested VIEW operations
139
+ std::remove_reference_t<decltype(current_node_info.node_inputs_views[src_name])> view_chain;
140
+ auto current = src;
141
+
142
+ while (current != nullptr) {
143
+ auto current_name = std::string(current->name);
144
+ if (current->flags & GGML_TENSOR_FLAG_INPUT) {
145
+ current_name = get_graph_input_ov_name(current, node);
146
+ }
147
+ view_chain.emplace_back(current_name, current);
148
+ // If current src is also a VIEW, continue traversing
149
+ if (current->src[0] != nullptr && current->src[0]->op == GGML_OP_VIEW) {
150
+ current = current->src[0];
151
+ } else {
152
+ break;
153
+ }
154
+ }
155
+
156
+ // Assign all collected view inputs to node_inputs_views
157
+ current_node_info.node_inputs_views[src_name] = view_chain;
158
+ }
139
159
  }
140
160
 
141
161
  m_node_info_list.push_back(current_node_info);
@@ -156,20 +176,13 @@ int GgmlOvDecoder::compute_op_case(const ggml_tensor * node) const {
156
176
  if (src->ne[2] * src->ne[3] == node->ne[1]) {
157
177
  op_case = 5;
158
178
  }
159
- } else if (src->ne[0] * src->ne[1] == node->ne[1]) {
179
+ } else if (src->ne[0] * src->ne[1] * src->ne[2] == node->ne[1]) {
160
180
  op_case = 3;
161
181
  } else if (src->ne[1] * src->ne[2] == node->ne[1]) {
162
182
  op_case = 6;
163
183
  }
164
- break;
165
- }
166
- case GGML_OP_CONT: {
167
- if (node->src[0]->op == GGML_OP_PERMUTE) {
168
- op_case = 1;
169
- } else if (node->src[0]->op == GGML_OP_TRANSPOSE) {
170
- op_case = 2;
171
- } else if (node->src[0]->op == GGML_OP_VIEW) {
172
- op_case = 3;
184
+ if (op_case == 0 && ggml_nelements(node) == ggml_nelements(src)) {
185
+ op_case = 6;
173
186
  }
174
187
  break;
175
188
  }
@@ -179,23 +192,41 @@ int GgmlOvDecoder::compute_op_case(const ggml_tensor * node) const {
179
192
  } else if (node->src[0]->src[0]->op == GGML_OP_NONE) {
180
193
  // kv cache tensor
181
194
  std::string src_name(node->view_src->name);
182
- int layer = extract_layer_from_name(src_name);
183
- if (!is_swa_layer(layer)) {
184
- op_case = 2;
195
+ int layer = extract_layer_from_name(src_name).value();
196
+ if (ggml_is_contiguous(node->src[0])) {
197
+ // - 19: [ 64, 8, 256, 1] VIEW cache_k_l0 (view) [ 2, 128, 1024, 1048576]
198
+ // [ 512, 1024, 1, 1] 0: NONE cache_k_l0 [ 2, 1024, 1048576, 1048576]
199
+ // - 20: [ 64, 256, 8, 1] PERMUTE cache_k_l0 (view) (permuted) [ 2, 1024, 128, 1048576]
200
+ // [ 64, 8, 256, 1] 0: VIEW cache_k_l0 (view) [ 2, 128, 1024, 1048576]
201
+ if (!is_swa_layer(layer)) {
202
+ op_case = 3;
203
+ } else {
204
+ op_case = 4;
205
+ }
185
206
  } else {
186
- op_case = 3;
207
+ // special case of cache v when `-fa off`
208
+ // - 17: [ 256, 8, 64, 1] VIEW cache_v_l0 (view) [ 2, 131072, 2048, 1048576]
209
+ // [ 512, 1024, 1, 1] 0: NONE cache_v_l0 [ 2, 1024, 1048576, 1048576]
210
+ // - 18: [ 256, 64, 8, 1] PERMUTE cache_v_l0 (view) (permuted) [ 2, 2048, 131072, 1048576]
211
+ // [ 256, 8, 64, 1] 0: VIEW cache_v_l0 (view) [ 2, 131072, 2048, 1048576]
212
+ if (!is_swa_layer(layer)) {
213
+ op_case = 5;
214
+ } else {
215
+ op_case = 6;
216
+ }
187
217
  }
188
218
  } else {
189
219
  // rope'ed query tensor
190
- op_case = 4;
220
+ op_case = 2;
191
221
  }
192
222
  break;
193
223
  }
194
224
  case GGML_OP_MUL_MAT: {
195
- if (node->src[0]->op == GGML_OP_CONT && node->src[0]->src[0]->op == GGML_OP_TRANSPOSE) {
196
- op_case = 2;
197
- } else if (node->src[0]->op == GGML_OP_VIEW && node->src[1]->op == GGML_OP_VIEW) {
225
+ if (node->src[0]->op == GGML_OP_VIEW && node->src[1]->op == GGML_OP_VIEW) {
198
226
  op_case = 3;
227
+ } else if (node->src[1]->op == GGML_OP_SOFT_MAX) {
228
+ // In the case of `-fa off`, softmax is used, v_trans=true, the dynamic dim is ne[0] for cache_v
229
+ op_case = 2;
199
230
  }
200
231
  break;
201
232
  }
@@ -208,43 +239,57 @@ int GgmlOvDecoder::compute_op_case(const ggml_tensor * node) const {
208
239
  case GGML_OP_ROPE: {
209
240
  const int mode = node->op_params[2];
210
241
  switch (mode) {
211
- case GGML_ROPE_TYPE_NEOX: {
212
- op_case = 0x00010000;
242
+ case GGML_ROPE_TYPE_NEOX: {
243
+ op_case = 1;
213
244
  break;
214
245
  }
215
- case GGML_ROPE_TYPE_IMROPE: {
216
- op_case = 0x00020000;
246
+ case GGML_ROPE_TYPE_IMROPE: {
247
+ op_case = 2;
217
248
  break;
218
249
  }
219
250
  default:
220
- op_case = 0x00000000;
251
+ op_case = 0;
221
252
  break;
222
253
  }
223
- if (node->src[0]->op == GGML_OP_VIEW) {
224
- op_case = (op_case | 0x00000002);
225
- }
226
254
  break;
227
255
  }
228
256
  case GGML_OP_VIEW: {
229
257
  if (node->src[0]->op == GGML_OP_VIEW) {
230
258
  auto * src = node->src[0];
231
259
  if (ggml_nelements(node) != ggml_nelements(src)) {
232
- throw std::runtime_error("Unsupported VIEW case");
260
+ // throw std::runtime_error("Unsupported VIEW case");
261
+ }
262
+ op_case = 0;
263
+ if (m_model_is_splitted && m_model_inputs.find(std::string(src->name)) != m_model_inputs.end()) {
264
+ op_case = 0;
233
265
  }
234
- op_case = 2;
235
266
  }
236
267
  {
237
268
  auto * src = node->src[0];
238
- if ((ggml_nelements(node) != ggml_nelements(src)) && m_naive) {
239
- // Compare each dimension of node and src, if only one dimension differs then op_case=3
269
+ if (ggml_nelements(node) != ggml_nelements(src)) {
270
+ // Case 4: select one slice on src dim1 (via view offset), keep src dim2 as output dim1.
271
+ // Typical pattern:
272
+ // src: ne=[N, M, K, 1], nb=[b0, b1, b2, b3]
273
+ // dst: ne=[N, K, 1, 1], nb=[b0, b2, b3, b3]
274
+ if (node->ne[0] == src->ne[0] && node->ne[1] == src->ne[2] && node->ne[2] == 1 &&
275
+ node->nb[0] == src->nb[0] && node->nb[1] == src->nb[2] && src->ne[1] > 1) {
276
+ op_case = 0;
277
+ break;
278
+ }
279
+
280
+ // General case 3: shape differs from source (one or more dims) and is handled as VIEW slicing.
240
281
  int diff_count = 0;
241
282
  for (int i = 0; i < GGML_MAX_DIMS; i++) {
242
283
  if (node->ne[i] != src->ne[i]) {
243
284
  diff_count++;
244
285
  }
286
+ // if node ne[i] > src ne[i], case = 0
287
+ if (node->ne[i] > src->ne[i]) {
288
+ return 0;
289
+ }
245
290
  }
246
- if (diff_count == 1) {
247
- op_case = 3;
291
+ if (diff_count >= 1) {
292
+ op_case = 0;
248
293
  }
249
294
  }
250
295
  }
@@ -256,9 +301,11 @@ int GgmlOvDecoder::compute_op_case(const ggml_tensor * node) const {
256
301
  return op_case;
257
302
  }
258
303
 
259
- int extract_layer_from_name(const std::string & name) {
304
+ std::optional<int> extract_layer_from_name(const std::string & name) {
260
305
  size_t pos1 = name.find("_l");
261
- assert(pos1 != std::string::npos);
306
+ if (pos1 == std::string::npos) {
307
+ return std::nullopt;
308
+ }
262
309
  pos1 += 2;
263
310
  size_t pos2 = name.find(' ', pos1);
264
311
  if (pos2 == std::string::npos) {
@@ -272,26 +319,101 @@ int extract_layer_from_name(const std::string & name) {
272
319
  std::pair<ModelParams, ComputeParams> GgmlOvDecoder::compute_llm_params(ggml_cgraph * cgraph, bool is_static) {
273
320
  ModelParams model_params;
274
321
  ComputeParams compute_params;
322
+ auto get_attention_pattern_case = [](const ggml_tensor * node) -> int {
323
+ if (node == nullptr) {
324
+ return -1;
325
+ }
326
+
327
+ switch (node->op) {
328
+ case GGML_OP_FLASH_ATTN_EXT:
329
+ if (node->src[0] == nullptr || node->src[1] == nullptr || node->src[3] == nullptr) {
330
+ return -1;
331
+ }
332
+ switch (node->src[1]->op) {
333
+ case GGML_OP_PERMUTE:
334
+ // case 0: node op is FLASH_ATTN_EXT, src 1 not null & op is PERMUTE & the permuted tensor src is the view of cache k
335
+ if (node->src[1]->src[0] != nullptr && node->src[1]->src[0]->op == GGML_OP_VIEW) {
336
+ return 0;
337
+ }
338
+ break;
339
+ case GGML_OP_CPY:
340
+ // case 1: node op is FLASH_ATTN_EXT, src 1 not null & op is CPY & the copied tensor src is PERMUTE & the permuted tensor src is the view of cache k
341
+ if (node->src[1]->src[0] != nullptr && node->src[1]->src[0]->op == GGML_OP_PERMUTE &&
342
+ node->src[1]->src[0]->src[0] != nullptr && node->src[1]->src[0]->src[0]->op == GGML_OP_VIEW) {
343
+ return 1;
344
+ }
345
+ break;
346
+ default:
347
+ break;
348
+ }
349
+ break;
350
+ case GGML_OP_SOFT_MAX:
351
+ // case 2: node op is SOFT_MAX, src 0 not null & op is MUL_MAT & the src 0 of MUL_MAT is PERMUTE & the permuted tensor src is the view of cache k
352
+ if (node->src[0] != nullptr && node->src[1] != nullptr && node->src[0]->op == GGML_OP_MUL_MAT &&
353
+ node->src[0]->src[0] != nullptr && node->src[0]->src[1] != nullptr &&
354
+ node->src[0]->src[0]->op == GGML_OP_PERMUTE && node->src[0]->src[0]->src[0] != nullptr &&
355
+ node->src[0]->src[0]->src[0]->op == GGML_OP_VIEW) {
356
+ return 2;
357
+ }
358
+ // case 3: node op is SOFT_MAX, src 0 not null & op is ADD & the src 0 of ADD is MUL_MAT & the src 0 of MUL_MAT is PERMUTE
359
+ if (node->src[0]->op == GGML_OP_ADD && node->src[0]->src[0] != nullptr &&
360
+ node->src[0]->src[0]->op == GGML_OP_MUL_MAT && node->src[0]->src[0]->src[0] != nullptr &&
361
+ node->src[0]->src[0]->src[0]->op == GGML_OP_PERMUTE) {
362
+ return 3;
363
+ }
364
+ break;
365
+ default:
366
+ break;
367
+ }
368
+
369
+ return -1;
370
+ };
371
+
372
+ bool rope_seen = false;
275
373
  for (int i = 0; i < cgraph->n_nodes; i++) {
276
374
  auto * node = cgraph->nodes[i];
277
375
  std::string name = std::string(node->name);
278
- if (node->op == GGML_OP_FLASH_ATTN_EXT) {
279
- model_params.n_heads = node->src[0]->ne[2];
280
- model_params.n_heads_kv = node->src[1]->ne[2];
281
- model_params.head_size = node->src[0]->ne[0];
376
+ const int attention_pattern_case = get_attention_pattern_case(node);
377
+ if (attention_pattern_case != -1) {
378
+ ggml_tensor * cache_k_permute = nullptr;
379
+ ggml_tensor * mask = nullptr;
380
+
381
+ switch (attention_pattern_case) {
382
+ case 0:
383
+ cache_k_permute = node->src[1];
384
+ mask = node->src[3];
385
+ break;
386
+ case 1:
387
+ cache_k_permute = node->src[1]->src[0];
388
+ mask = node->src[3];
389
+ break;
390
+ case 2:
391
+ cache_k_permute = node->src[0]->src[0];
392
+ mask = node->src[1];
393
+ break;
394
+ case 3:
395
+ cache_k_permute = node->src[0]->src[0]->src[0];
396
+ mask = node->src[1];
397
+ break;
398
+ default:
399
+ break;
400
+ }
401
+
402
+ assert(cache_k_permute != nullptr);
403
+
404
+ model_params.head_size = cache_k_permute->ne[0];
405
+ model_params.n_heads_kv = cache_k_permute->ne[2];
282
406
  compute_params.input_len = node->src[0]->ne[1];
407
+ compute_params.token_len_per_seq = node->src[0]->ne[1];
283
408
 
284
- auto * cache_k_perm = node->src[1];
285
- if (cache_k_perm->op == GGML_OP_CPY) {
286
- cache_k_perm = cache_k_perm->src[0];
409
+ auto * cache_k_view = cache_k_permute->src[0];
410
+ if (cache_k_view->op != GGML_OP_VIEW || mask == nullptr) {
411
+ continue;
287
412
  }
288
- assert(cache_k_perm->op == GGML_OP_PERMUTE);
289
- auto * cache_k_view = cache_k_perm->src[0];
290
- assert(cache_k_view->op == GGML_OP_VIEW);
291
413
 
292
- auto * cache_k = cache_k_view->src[0];
293
- int layer = extract_layer_from_name(cache_k->name);
294
- auto * mask = node->src[3];
414
+ ggml_tensor * cache_k = cache_k_view->src[0];
415
+ int layer = extract_layer_from_name(cache_k->name).value();
416
+
295
417
  std::string mask_name(mask->name);
296
418
 
297
419
  model_params.kv_buffer_ctx_id = ggml_backend_openvino_buffer_get_ctx_id(cache_k->buffer);
@@ -308,7 +430,6 @@ std::pair<ModelParams, ComputeParams> GgmlOvDecoder::compute_llm_params(ggml_cgr
308
430
  size_t offset;
309
431
  memcpy(&offset, cache_k_view->op_params, sizeof(size_t));
310
432
  compute_params.seq_active_start = offset / seq_size;
311
- compute_params.token_len_per_seq = node->ne[2];
312
433
 
313
434
  if (mask_name.find("swa") != std::string::npos) {
314
435
  compute_params.attention_size_swa = mask->ne[0];
@@ -320,10 +441,40 @@ std::pair<ModelParams, ComputeParams> GgmlOvDecoder::compute_llm_params(ggml_cgr
320
441
  compute_params.attention_size_swa = model_params.ctx_per_seq_swa;
321
442
  compute_params.token_len_per_seq = 1;
322
443
  }
323
- break;
444
+ }
445
+
446
+ if (node->op == GGML_OP_MUL_MAT && node->src[0]->op == GGML_OP_PERMUTE &&
447
+ node->src[0]->src[0]->op == GGML_OP_VIEW && is_kvcache(node->src[0]->view_src, node->view_src)) {
448
+ if (node->src[1]->op == GGML_OP_PERMUTE && node->src[1]->src[0]->op == GGML_OP_VIEW &&
449
+ node->src[1]->src[0]->src[0]->op == GGML_OP_ROPE) {
450
+ compute_params.attention_size = node->ne[0];
451
+ }
452
+ }
453
+
454
+ // if the node op is TRANSPOSE and its input is PERMUTE and the source of the PERMUTE is VIEW, then get the attention size with the TRANSPOSE node ne[0] (in case no GGML_OP_FLASH_ATTN_EXT)
455
+ if (node->op == GGML_OP_TRANSPOSE && node->src[0]->op == GGML_OP_PERMUTE &&
456
+ node->src[0]->src[0]->op == GGML_OP_VIEW) {
457
+ compute_params.attention_size = node->ne[0];
458
+ if (is_static) {
459
+ compute_params.attention_size = model_params.ctx_per_seq;
460
+ }
324
461
  }
325
462
  if (node->op == GGML_OP_ROPE) {
326
- memcpy(model_params.rope_params, node->op_params, sizeof(int32_t) * 15);
463
+ if (compute_params.token_len_per_seq == -1 && node->src[1] != nullptr) {
464
+ compute_params.token_len_per_seq = ggml_nelements(node->src[1]);
465
+ }
466
+
467
+ // When multiple ROPE ops in the graph disagree on op_params (e.g. gemma4's
468
+ // mixed SWA/non-SWA layers with different n_dims or freq_base), we cannot
469
+ // share a single precomputed rope_sin/rope_cos. Track divergence so the
470
+ // translator falls back to per-op make_sin_cos in that case.
471
+ static_assert(sizeof(model_params.rope_params) == sizeof(int32_t) * 15, "rope_params size");
472
+ if (!rope_seen) {
473
+ memcpy(model_params.rope_params, node->op_params, sizeof(int32_t) * 15);
474
+ rope_seen = true;
475
+ } else if (memcmp(model_params.rope_params, node->op_params, sizeof(int32_t) * 15) != 0) {
476
+ model_params.mixed_rope_params = true;
477
+ }
327
478
  }
328
479
  }
329
480
  auto * output_tensor = cgraph->nodes[cgraph->n_nodes - 1];
@@ -333,7 +484,6 @@ std::pair<ModelParams, ComputeParams> GgmlOvDecoder::compute_llm_params(ggml_cgr
333
484
  compute_params.output_len = 1;
334
485
  }
335
486
  model_params.ctx = model_params.ctx_per_seq * model_params.n_seq;
336
- model_params.ctx_swa = model_params.ctx_per_seq_swa * model_params.n_seq;
337
487
  return {model_params, compute_params};
338
488
  }
339
489
 
@@ -343,9 +493,11 @@ void GgmlOvDecoder::validate_cgraph() const {
343
493
  }
344
494
  }
345
495
 
346
- ov::PartialShape GgmlOvDecoder::get_graph_input_shape(const ggml_tensor * op, const ggml_tensor * input) const {
496
+ ov::PartialShape GgmlOvDecoder::get_graph_input_shape(const ggml_tensor * op,
497
+ const ggml_tensor * input,
498
+ int dynamic_dim_index) const {
347
499
  if (m_naive) {
348
- return input!= nullptr ? ov::PartialShape{get_shape(input)} : ov::PartialShape{get_shape(op)};
500
+ return input != nullptr ? ov::PartialShape{get_shape(input)} : ov::PartialShape{get_shape(op)};
349
501
  }
350
502
  auto name = std::string(input->name);
351
503
  ov::PartialShape input_shape;
@@ -394,6 +546,15 @@ ov::PartialShape GgmlOvDecoder::get_graph_input_shape(const ggml_tensor * op, co
394
546
  } else {
395
547
  input_shape = ov::PartialShape{get_shape(input)};
396
548
  }
549
+ if (dynamic_dim_index != -1 && m_model_is_splitted) {
550
+ input_shape[3 - dynamic_dim_index] = -1;
551
+ }
552
+ if (op->op == GGML_OP_SOFT_MAX && op->src[1] != nullptr && op->src[1]->op == GGML_OP_NONE &&
553
+ op->src[1]->flags & GGML_TENSOR_FLAG_INPUT && op->src[1] == input) {
554
+ // for softmax input mask, the shape is [1, 1, seq_active, seq_active], where seq_active is determined by the input active sequence length instead of the kv cache sequence length
555
+ input_shape[2] = -1;
556
+ input_shape[3] = -1;
557
+ }
397
558
  return input_shape;
398
559
  }
399
560
 
@@ -421,15 +582,19 @@ void GgmlOvDecoder::add_extra_inputs() {
421
582
  }
422
583
  };
423
584
 
424
- create_1d_input("attention_size", m_compute_params.attention_size);
585
+ if (m_compute_params.attention_size != -1) {
586
+ create_1d_input("attention_size", m_compute_params.attention_size);
587
+ }
425
588
  if (m_compute_params.attention_size_swa != -1) {
426
589
  create_1d_input("attention_size_swa", m_compute_params.attention_size_swa);
427
590
  }
428
591
  create_1d_input("n_seq_active", m_compute_params.n_seq_active);
429
592
  create_1d_input("seq_active_start", m_compute_params.seq_active_start);
430
593
  create_1d_input("seq_active_end", m_compute_params.seq_active_start + m_compute_params.n_seq_active);
431
- create_1d_input("token_len_per_seq", m_compute_params.token_len_per_seq);
432
- // create_1d_input("token_len", m_token_len_per_seq * m_n_seq_active);
594
+ if (m_compute_params.token_len_per_seq != -1) {
595
+ create_1d_input("token_len_per_seq", m_compute_params.token_len_per_seq);
596
+ }
597
+ // create_1d_input("token_len", m_compute_params.token_len_per_seq * m_compute_params.n_seq_active);
433
598
  }
434
599
 
435
600
  bool GgmlOvDecoder::node_is_used_as_src(const int node_idx) {
@@ -455,8 +620,8 @@ void GgmlOvDecoder::compute_model_inputs() {
455
620
  std::string node_name(node->name);
456
621
  if (m_model_weights.find(node_name) == m_model_weights.end()) {
457
622
  m_inputs[node_name] = node;
458
- auto param_node =
459
- std::make_shared<ov::op::v0::Parameter>(get_ov_type(node), get_graph_input_shape(node, nullptr));
623
+ auto param_node = std::make_shared<ov::op::v0::Parameter>(
624
+ get_ov_type(node), get_graph_input_shape(node, nullptr, m_node_dynamic_dims[node]));
460
625
  param_node->set_friendly_name(node_name);
461
626
  param_node->output(0).get_tensor().set_names({node_name});
462
627
  m_model_inputs[node_name] = param_node;
@@ -500,7 +665,13 @@ void GgmlOvDecoder::compute_model_inputs() {
500
665
  m_model_params.kv_names.push_back(src_name);
501
666
  }
502
667
  }
503
- ov::PartialShape param_shape = get_graph_input_shape(node, src);
668
+ // Resolve nested VIEW nodes by following src[0] until the first non-VIEW tensor.
669
+ while (src->op == GGML_OP_VIEW && src->src[0] != nullptr) {
670
+ src = src->src[0];
671
+ src_name = std::string(src->name);
672
+ }
673
+ m_inputs[src_name] = src;
674
+ ov::PartialShape param_shape = get_graph_input_shape(node, src, m_node_dynamic_dims[src]);
504
675
  auto param_node = std::make_shared<ov::op::v0::Parameter>(get_ov_type(src), param_shape);
505
676
  param_node->set_friendly_name(src_name);
506
677
  param_node->output(0).get_tensor().set_names({src_name});
@@ -515,7 +686,7 @@ void GgmlOvDecoder::compute_model_outputs() {
515
686
  for (int node_n = 0; node_n < m_cgraph->n_nodes; node_n++) {
516
687
  auto * cur_node = m_cgraph->nodes[node_n];
517
688
  // if the node op is NONE means this node is not used at all, we can skip it directly without adding to model outputs.
518
- if (cur_node->op == GGML_OP_NONE) {
689
+ if (cur_node->op == GGML_OP_NONE || cur_node->op == GGML_OP_VIEW || cur_node->op == GGML_OP_RESHAPE) {
519
690
  continue;
520
691
  }
521
692
  auto cur_node_use_count = m_cgraph->use_counts[ggml_hash_find(&m_cgraph->visited_hash_set, cur_node)];
@@ -644,15 +815,26 @@ std::shared_ptr<ov::Node> GgmlOvDecoder::create_weight_node(ggml_tensor * tensor
644
815
  }
645
816
  }
646
817
 
818
+ // MUL_MAT_ID expert weights are 3D GGML tensors [k, m, n_expert].
819
+ // Keep the full reversed 4D shape when materializing non-quantized constants,
820
+ // otherwise the expert dimension is collapsed and later Gather/MatMul logic
821
+ // only sees a single expert slice.
822
+ if (!ggml_is_quantized(tensor->type) && (tensor->ne[2] > 1 || tensor->ne[3] > 1)) {
823
+ auto weight_tensor = ov::Tensor(get_ov_type(tensor), get_shape(tensor), tensor->data);
824
+ auto weight_node = std::make_shared<ov::op::v0::Constant>(weight_tensor);
825
+ weight_node->set_friendly_name(tensor->name);
826
+ return weight_node;
827
+ }
828
+
647
829
  // There are three cases where we need to create a new weight node:
648
830
  // 1. weights are in openvino_host_buffer. Weight loading to host buffer will not trigger backend_buffer_set_tensor
649
831
  // 2. weights are in cpu/cpu_mapped buffer. On token_embd.weight goes to case 1 or 2, depending on whether mmap or direct_io is used
650
832
  // 3. test-backend-ops. buffers in test-backend-ops does not set USAGE_WEIGHT so backend_buffer_set_tensor will not create weight node
651
833
 
652
834
  // GGML_LOG_DEBUG("%s: creating new weight node for %s\n", __func__, tensor->name);
653
- static const std::set<ggml_type> weight_types = {GGML_TYPE_F32, GGML_TYPE_F16, GGML_TYPE_BF16,
654
- GGML_TYPE_Q8_0, GGML_TYPE_Q4_0, GGML_TYPE_Q4_1,
655
- GGML_TYPE_Q4_K, GGML_TYPE_Q5_K, GGML_TYPE_Q6_K};
835
+ static const std::set<ggml_type> weight_types = {GGML_TYPE_F32, GGML_TYPE_F16, GGML_TYPE_BF16, GGML_TYPE_Q8_0,
836
+ GGML_TYPE_Q4_0, GGML_TYPE_Q4_1, GGML_TYPE_Q5_1, GGML_TYPE_Q4_K,
837
+ GGML_TYPE_Q5_K, GGML_TYPE_Q6_K};
656
838
  if (weight_types.find(tensor->type) == weight_types.end()) {
657
839
  throw std::runtime_error("Unexpected weight tensor type: " + std::string(tensor->name) + " with type " +
658
840
  ggml_type_name(tensor->type));
@@ -860,6 +1042,161 @@ std::vector<size_t> GgmlOvDecoder::get_input_stride(int node_idx, const std::str
860
1042
  return get_stride(m_node_info_list[node_idx].node_inputs.at(name));
861
1043
  }
862
1044
 
1045
+ size_t GgmlOvDecoder::get_view_input_size(int node_idx, const std::string & name) const {
1046
+ auto it = m_node_info_list[node_idx].node_inputs_views.find(name);
1047
+ if (it != m_node_info_list[node_idx].node_inputs_views.end()) {
1048
+ return it->second.size();
1049
+ }
1050
+ return 0;
1051
+ }
1052
+
1053
+ size_t GgmlOvDecoder::get_view_input_offset(int node_idx, const std::string & name, size_t view_index) const {
1054
+ auto it = m_node_info_list[node_idx].node_inputs_views.find(name);
1055
+ if (it != m_node_info_list[node_idx].node_inputs_views.end()) {
1056
+ if (view_index < it->second.size()) {
1057
+ return it->second[view_index].second->view_offs;
1058
+ }
1059
+ }
1060
+ return 0;
1061
+ }
1062
+
1063
+ size_t GgmlOvDecoder::get_view_input_src_offset(int node_idx, const std::string & name, size_t view_index) const {
1064
+ auto it = m_node_info_list[node_idx].node_inputs_views.find(name);
1065
+ if (it != m_node_info_list[node_idx].node_inputs_views.end()) {
1066
+ if (view_index < it->second.size()) {
1067
+ auto * view_tensor = it->second[view_index].second;
1068
+ if (view_tensor && view_tensor->src[0]) {
1069
+ return view_tensor->src[0]->view_offs;
1070
+ }
1071
+ }
1072
+ }
1073
+ return 0;
1074
+ }
1075
+
1076
+ std::vector<size_t> GgmlOvDecoder::get_view_input_stride(int node_idx,
1077
+ const std::string & name,
1078
+ size_t view_index) const {
1079
+ auto it = m_node_info_list[node_idx].node_inputs_views.find(name);
1080
+ if (it != m_node_info_list[node_idx].node_inputs_views.end()) {
1081
+ if (view_index < it->second.size()) {
1082
+ return get_stride(it->second[view_index].second);
1083
+ }
1084
+ }
1085
+ return {};
1086
+ }
1087
+
1088
+ std::vector<size_t> GgmlOvDecoder::get_view_input_src_stride(int node_idx,
1089
+ const std::string & name,
1090
+ size_t view_index) const {
1091
+ auto it = m_node_info_list[node_idx].node_inputs_views.find(name);
1092
+ if (it != m_node_info_list[node_idx].node_inputs_views.end()) {
1093
+ if (view_index < it->second.size()) {
1094
+ auto * view_tensor = it->second[view_index].second;
1095
+ if (view_tensor && view_tensor->src[0]) {
1096
+ return get_stride(view_tensor->src[0]);
1097
+ }
1098
+ }
1099
+ }
1100
+ return {};
1101
+ }
1102
+
1103
+ ov::Shape GgmlOvDecoder::get_view_input_ggml_shape(int node_idx, const std::string & name, size_t view_index) const {
1104
+ auto it = m_node_info_list[node_idx].node_inputs_views.find(name);
1105
+ if (it != m_node_info_list[node_idx].node_inputs_views.end()) {
1106
+ if (view_index < it->second.size()) {
1107
+ return get_shape(it->second[view_index].second);
1108
+ }
1109
+ }
1110
+ return {};
1111
+ }
1112
+
1113
+ ov::Shape GgmlOvDecoder::get_view_input_src_ggml_shape(int node_idx,
1114
+ const std::string & name,
1115
+ size_t view_index) const {
1116
+ auto it = m_node_info_list[node_idx].node_inputs_views.find(name);
1117
+ if (it != m_node_info_list[node_idx].node_inputs_views.end()) {
1118
+ if (view_index < it->second.size()) {
1119
+ auto * view_tensor = it->second[view_index].second;
1120
+ if (view_tensor && view_tensor->src[0]) {
1121
+ return get_shape(view_tensor->src[0]);
1122
+ }
1123
+ }
1124
+ }
1125
+ return {};
1126
+ }
1127
+
1128
+ ov::PartialShape GgmlOvDecoder::get_view_input_ov_shape(int node_idx,
1129
+ const std::string & name,
1130
+ size_t view_index) const {
1131
+ auto it = m_node_info_list[node_idx].node_inputs_views.find(name);
1132
+ if (it != m_node_info_list[node_idx].node_inputs_views.end()) {
1133
+ if (view_index < it->second.size()) {
1134
+ auto * tensor = it->second[view_index].second;
1135
+ ov::PartialShape shape = ov::PartialShape{get_shape(tensor)};
1136
+
1137
+ // Check if this tensor has a dynamic dimension
1138
+ auto dynamic_it = m_node_dynamic_dims.find(tensor);
1139
+ if (dynamic_it != m_node_dynamic_dims.end() && dynamic_it->second != -1) {
1140
+ int dynamic_dim_index = dynamic_it->second;
1141
+ // GGML uses reverse indexing, so convert to OpenVINO indexing
1142
+ shape[3 - dynamic_dim_index] = m_is_static ? get_static_n_tokens() : -1;
1143
+ }
1144
+
1145
+ return shape;
1146
+ }
1147
+ }
1148
+ return {};
1149
+ }
1150
+
1151
+ ov::PartialShape GgmlOvDecoder::get_view_input_src_ov_shape(int node_idx,
1152
+ const std::string & name,
1153
+ size_t view_index) const {
1154
+ auto it = m_node_info_list[node_idx].node_inputs_views.find(name);
1155
+ if (it != m_node_info_list[node_idx].node_inputs_views.end()) {
1156
+ if (view_index < it->second.size()) {
1157
+ auto * view_tensor = it->second[view_index].second;
1158
+ if (view_tensor && view_tensor->src[0]) {
1159
+ auto * src_tensor = view_tensor->src[0];
1160
+ ov::PartialShape shape = ov::PartialShape{get_shape(src_tensor)};
1161
+
1162
+ // Check if this tensor has a dynamic dimension
1163
+ auto dynamic_it = m_node_dynamic_dims.find(src_tensor);
1164
+ if (dynamic_it != m_node_dynamic_dims.end() && dynamic_it->second != -1) {
1165
+ int dynamic_dim_index = dynamic_it->second;
1166
+ // GGML uses reverse indexing, so convert to OpenVINO indexing
1167
+ shape[3 - dynamic_dim_index] = m_is_static ? get_static_n_tokens() : -1;
1168
+ }
1169
+
1170
+ return shape;
1171
+ }
1172
+ }
1173
+ }
1174
+ return {};
1175
+ }
1176
+
1177
+ std::string GgmlOvDecoder::get_view_input_name(int node_idx, const std::string & name, size_t view_index) const {
1178
+ auto it = m_node_info_list[node_idx].node_inputs_views.find(name);
1179
+ if (it != m_node_info_list[node_idx].node_inputs_views.end()) {
1180
+ if (view_index < it->second.size()) {
1181
+ return it->second[view_index].second->name;
1182
+ }
1183
+ }
1184
+ return "";
1185
+ }
1186
+
1187
+ std::string GgmlOvDecoder::get_view_input_src_name(int node_idx, const std::string & name, size_t view_index) const {
1188
+ auto it = m_node_info_list[node_idx].node_inputs_views.find(name);
1189
+ if (it != m_node_info_list[node_idx].node_inputs_views.end()) {
1190
+ if (view_index < it->second.size()) {
1191
+ auto * view_tensor = it->second[view_index].second;
1192
+ if (view_tensor && view_tensor->src[0]) {
1193
+ return view_tensor->src[0]->name;
1194
+ }
1195
+ }
1196
+ }
1197
+ return "";
1198
+ }
1199
+
863
1200
  ov::element::Type GgmlOvDecoder::get_input_type(int node_idx, const std::string & name) const {
864
1201
  return get_ov_type(m_node_info_list[node_idx].node_inputs.at(name));
865
1202
  }
@@ -885,6 +1222,11 @@ ov::element::Type GgmlOvDecoder::get_output_type(const int node_idx) const {
885
1222
  return get_ov_type(m_node_info_list[node_idx].node);
886
1223
  }
887
1224
 
1225
+ std::vector<size_t> GgmlOvDecoder::get_output_stride(int node_idx) const {
1226
+ auto * ggml_tensor = m_node_info_list[node_idx].node;
1227
+ return get_stride(ggml_tensor);
1228
+ }
1229
+
888
1230
  std::vector<std::string> GgmlOvDecoder::get_output_names(int node_idx) const {
889
1231
  return {m_node_info_list[node_idx].node_output_name};
890
1232
  }
@@ -894,6 +1236,14 @@ const std::string & GgmlOvDecoder::get_op_name() const {
894
1236
  return unknown_name;
895
1237
  }
896
1238
 
1239
+ int32_t GgmlOvDecoder::get_op_dynamic_dim(int node_idx) const {
1240
+ auto it = m_node_dynamic_dims.find(m_node_info_list[node_idx].node);
1241
+ if (it == m_node_dynamic_dims.end()) {
1242
+ return -1;
1243
+ }
1244
+ return it->second;
1245
+ }
1246
+
897
1247
  const std::string & GgmlOvDecoder::get_op_name(int node_idx) const {
898
1248
  return m_node_info_list[node_idx].node_name;
899
1249
  }
@@ -906,6 +1256,10 @@ int32_t * GgmlOvDecoder::get_output_op_params(int node_idx) const {
906
1256
  return m_node_info_list[node_idx].node->op_params;
907
1257
  }
908
1258
 
1259
+ size_t GgmlOvDecoder::get_output_op_offset(int node_idx) const {
1260
+ return m_node_info_list[node_idx].node->view_offs;
1261
+ }
1262
+
909
1263
  void GgmlOvDecoder::visit_subgraph(std::function<void(std::shared_ptr<GgmlDecoder>, int node_idx)> node_visitor) const {
910
1264
  for (int node_idx = 0; node_idx < m_cgraph->n_nodes; node_idx++) {
911
1265
  if (m_cgraph->nodes[node_idx]->op == GGML_OP_NONE) {
@@ -916,63 +1270,14 @@ void GgmlOvDecoder::visit_subgraph(std::function<void(std::shared_ptr<GgmlDecode
916
1270
  }
917
1271
 
918
1272
  std::string GgmlOvDecoder::compute_op_type(const ggml_tensor * node) {
919
- static const std::map<ggml_op, std::string> ops = {
920
- {GGML_OP_NONE, "GGML_OP_NONE" },
921
- {GGML_OP_ACC, "GGML_OP_ACC" },
922
- {GGML_OP_ADD, "GGML_OP_ADD" },
923
- {GGML_OP_ADD1, "GGML_OP_ADD1" },
924
- {GGML_OP_CONT, "GGML_OP_CONT" },
925
- {GGML_OP_DIV, "GGML_OP_DIV" },
926
- {GGML_OP_DUP, "GGML_OP_DUP" },
927
- {GGML_OP_GET_ROWS, "GGML_OP_GET_ROWS" },
928
- {GGML_OP_MUL, "GGML_OP_MUL" },
929
- {GGML_OP_MUL_MAT, "GGML_OP_MUL_MAT" },
930
- {GGML_OP_PERMUTE, "GGML_OP_PERMUTE" },
931
- {GGML_OP_RESHAPE, "GGML_OP_RESHAPE" },
932
- {GGML_OP_RMS_NORM, "GGML_OP_RMS_NORM" },
933
- {GGML_OP_ROPE, "GGML_OP_ROPE" },
934
- {GGML_OP_SCALE, "GGML_OP_SCALE" },
935
- {GGML_OP_SOFT_MAX, "GGML_OP_SOFT_MAX" },
936
- {GGML_OP_SUB, "GGML_OP_SUB" },
937
- {GGML_OP_TRANSPOSE, "GGML_OP_TRANSPOSE" },
938
- {GGML_OP_VIEW, "GGML_OP_VIEW" },
939
- {GGML_OP_SET_ROWS, "GGML_OP_SET_ROWS" },
940
- {GGML_OP_CPY, "GGML_OP_CPY" },
941
- {GGML_OP_FLASH_ATTN_EXT, "GGML_OP_FLASH_ATTN_EXT"},
942
- };
943
- static const std::map<ggml_unary_op, std::string> unary_ops = {
944
- {GGML_UNARY_OP_ABS, "GGML_UNARY_OP_ABS" },
945
- {GGML_UNARY_OP_SGN, "GGML_UNARY_OP_SGN" },
946
- {GGML_UNARY_OP_NEG, "GGML_UNARY_OP_NEG" },
947
- {GGML_UNARY_OP_STEP, "GGML_UNARY_OP_STEP" },
948
- {GGML_UNARY_OP_TANH, "GGML_UNARY_OP_TANH" },
949
- {GGML_UNARY_OP_ELU, "GGML_UNARY_OP_ELU" },
950
- {GGML_UNARY_OP_RELU, "GGML_UNARY_OP_RELU" },
951
- {GGML_UNARY_OP_SIGMOID, "GGML_UNARY_OP_SIGMOID" },
952
- {GGML_UNARY_OP_GELU, "GGML_UNARY_OP_GELU" },
953
- {GGML_UNARY_OP_GELU_QUICK, "GGML_UNARY_OP_GELU_QUICK" },
954
- {GGML_UNARY_OP_SILU, "GGML_UNARY_OP_SILU" },
955
- {GGML_UNARY_OP_HARDSWISH, "GGML_UNARY_OP_HARDSWISH" },
956
- {GGML_UNARY_OP_HARDSIGMOID, "GGML_UNARY_OP_HARDSIGMOID"},
957
- {GGML_UNARY_OP_EXP, "GGML_UNARY_OP_EXP" },
958
- {GGML_UNARY_OP_COUNT, "GGML_UNARY_OP_COUNT" }
959
- };
960
- static const std::map<ggml_glu_op, std::string> glu_ops = {
961
- {GGML_GLU_OP_SWIGLU, "GGML_GLU_OP_SWIGLU"},
962
- {GGML_GLU_OP_GEGLU, "GGML_GLU_OP_GEGLU" },
963
- {GGML_GLU_OP_REGLU, "GGML_GLU_OP_REGLU" }
964
- };
965
-
966
1273
  switch (node->op) {
967
1274
  case GGML_OP_UNARY:
968
- return unary_ops.at(ggml_get_unary_op(node));
1275
+ return std::string("GGML_UNARY_OP_") + ggml_unary_op_name(ggml_get_unary_op(node));
969
1276
  case GGML_OP_GLU:
970
- return glu_ops.at(ggml_get_glu_op(node));
1277
+ return std::string("GGML_GLU_OP_") + ggml_glu_op_name(ggml_get_glu_op(node));
971
1278
  default:
972
- return ops.at(node->op);
1279
+ return std::string("GGML_OP_") + ggml_op_name(node->op);
973
1280
  }
974
- static const std::string unknown_op = "UNKNOWN_GGML_OP";
975
- return unknown_op;
976
1281
  }
977
1282
 
978
1283
  const std::string & GgmlOvDecoder::get_op_type(int node_idx) const {
@@ -983,3 +1288,301 @@ const std::string & GgmlOvDecoder::get_op_type() const {
983
1288
  static const std::string unknown_op = "UNKNOWN_GGML_OP";
984
1289
  return unknown_op;
985
1290
  }
1291
+
1292
+ void GgmlOvDecoder::compute_node_dynamic_dims() {
1293
+ auto visit_node = [&](auto && self, ggml_tensor * node) -> void {
1294
+ if (!node) {
1295
+ return;
1296
+ }
1297
+
1298
+ if (node->op == GGML_OP_CPY) {
1299
+ m_node_dynamic_dims[node] = -1;
1300
+ }
1301
+
1302
+ if (m_node_dynamic_dims.count(node)) {
1303
+ return;
1304
+ }
1305
+ for (int i = 0; i < GGML_MAX_SRC; i++) {
1306
+ ggml_tensor * src = node->src[i];
1307
+ if (src == nullptr) {
1308
+ continue;
1309
+ }
1310
+ struct ggml_tensor * root_src = nullptr;
1311
+ // if (src->org_src) {
1312
+ // root_src = src->org_src;
1313
+ // }
1314
+ if (root_src) {
1315
+ if (is_inp_tok(root_src, node) || is_inp_pos(root_src, node) || is_output_idx(root_src, node)) {
1316
+ m_node_dynamic_dims[root_src] = 0;
1317
+ m_node_dynamic_dims[src] = m_node_dynamic_dims[root_src];
1318
+ continue;
1319
+ }
1320
+ self(self, root_src);
1321
+ m_node_dynamic_dims[src] = m_node_dynamic_dims[root_src];
1322
+ } else {
1323
+ if (is_inp_tok(src, node) || is_inp_pos(src, node) || is_output_idx(src, node)) {
1324
+ m_node_dynamic_dims[src] = 0;
1325
+ continue;
1326
+ }
1327
+ if (node->op == GGML_OP_VIEW && src->op == GGML_OP_NONE && !is_stateful() && !m_model_is_splitted) {
1328
+ m_node_dynamic_dims[src] = 1;
1329
+ continue;
1330
+ }
1331
+ self(self, src);
1332
+ }
1333
+ }
1334
+ switch (node->op) {
1335
+ case GGML_OP_NONE:
1336
+ m_node_dynamic_dims[node] = -1;
1337
+ break;
1338
+ case GGML_OP_GET_ROWS:
1339
+ m_node_dynamic_dims[node] = -1;
1340
+ if (m_node_dynamic_dims[node->src[1]] != -1) {
1341
+ auto dynamic_dim_idx = m_node_dynamic_dims[node->src[1]];
1342
+ if (dynamic_dim_idx == 0) {
1343
+ m_node_dynamic_dims[node] = 1;
1344
+ } else {
1345
+ auto dynamic_dim_stride = node->src[1]->nb[dynamic_dim_idx] / ggml_type_size(node->src[1]->type) *
1346
+ ggml_type_size(node->src[0]->type);
1347
+ for (int i = 0; i < GGML_MAX_DIMS; i++) {
1348
+ if (dynamic_dim_stride == node->src[0]->nb[i]) {
1349
+ m_node_dynamic_dims[node] = i;
1350
+ break;
1351
+ }
1352
+ }
1353
+ }
1354
+ // OPENVINO_ASSERT(dynamic_dim_value == node->ne[m_node_dynamic_dims[node]],
1355
+ // "Dynamic dim value mismatch for node: " + std::string(node->name) +
1356
+ // " and its src[1]: " + std::string(node->src[1]->name));
1357
+ }
1358
+ break;
1359
+ case GGML_OP_MUL:
1360
+ case GGML_OP_MUL_MAT:
1361
+ m_node_dynamic_dims[node] = -1;
1362
+ if (m_node_dynamic_dims[node->src[0]] != -1) {
1363
+ m_node_dynamic_dims[node] = m_node_dynamic_dims[node->src[0]];
1364
+ }
1365
+ if (m_node_dynamic_dims[node->src[1]] != -1) {
1366
+ m_node_dynamic_dims[node] = m_node_dynamic_dims[node->src[1]];
1367
+ }
1368
+ break;
1369
+ case GGML_OP_PERMUTE:
1370
+ m_node_dynamic_dims[node] = -1;
1371
+ if (m_node_dynamic_dims[node->src[0]] != -1) {
1372
+ auto dynamic_dim_idx = m_node_dynamic_dims[node->src[0]];
1373
+ // auto dynamic_dim_value = node->src[0]->ne[dynamic_dim_idx];
1374
+ for (int i = 0; i < GGML_MAX_DIMS; i++) {
1375
+ if (node->op_params[i] == dynamic_dim_idx) {
1376
+ m_node_dynamic_dims[node] = i;
1377
+ break;
1378
+ }
1379
+ }
1380
+ // OPENVINO_ASSERT(dynamic_dim_value == node->ne[m_node_dynamic_dims[node]],
1381
+ // "Dynamic dim value mismatch for node: " + std::string(node->name) +
1382
+ // " and its src[0]: " + std::string(node->src[0]->name));
1383
+ }
1384
+ break;
1385
+ case GGML_OP_VIEW: {
1386
+ // Use stride-based matching: the stride of a VIEW dimension directly
1387
+ // encodes which source dimension it indexes into, so it uniquely
1388
+ // identifies the dynamic dim even when two dims share the same size.
1389
+ m_node_dynamic_dims[node] = -1;
1390
+ if (m_node_dynamic_dims[node->src[0]] != -1) {
1391
+ if (node->src[0]->op == GGML_OP_NONE) {
1392
+ m_node_dynamic_dims[node] = m_node_dynamic_dims[node->src[0]];
1393
+ break;
1394
+ }
1395
+ auto dynamic_dim_idx = m_node_dynamic_dims[node->src[0]];
1396
+ auto dynamic_dim_value = node->src[0]->ne[dynamic_dim_idx];
1397
+ auto dynamic_dim_stride =
1398
+ node->src[0]->nb[dynamic_dim_idx] / ggml_type_size(node->src[0]->type) * ggml_type_size(node->type);
1399
+ for (int i = 0; i < GGML_MAX_DIMS; i++) {
1400
+ if (node->nb[i] == dynamic_dim_stride) {
1401
+ m_node_dynamic_dims[node] = i;
1402
+ break;
1403
+ }
1404
+ }
1405
+ if (m_node_dynamic_dims[node] != -1 && dynamic_dim_value != node->ne[m_node_dynamic_dims[node]]) {
1406
+ m_node_dynamic_dims[node] = -1;
1407
+ // std::cout << "Warning: Dynamic dim value mismatch for node: " << node->name
1408
+ // << " and its src[0]: " << node->src[0]->name << std::endl;
1409
+ }
1410
+ }
1411
+ break;
1412
+ }
1413
+ case GGML_OP_TRANSPOSE:
1414
+ case GGML_OP_RESHAPE: {
1415
+ // RESHAPE requires src[0] to be contiguous, so both src and result
1416
+ // have standard compact strides: nb[i] = type_size * prod(ne[0..i-1]).
1417
+ // Match src->nb[dynamic_dim] against result->nb[i] to find the output
1418
+ // dimension whose flat-memory boundary aligns with the source dynamic
1419
+ // boundary. This is unambiguous (result strides are strictly monotone)
1420
+ // and handles merged-lower-dim cases that ne-value matching misses.
1421
+ m_node_dynamic_dims[node] = -1;
1422
+ if (m_node_dynamic_dims[node->src[0]] != -1) {
1423
+ auto dynamic_dim_idx = m_node_dynamic_dims[node->src[0]];
1424
+ auto dynamic_dim_stride = node->src[0]->nb[dynamic_dim_idx];
1425
+ for (int i = 0; i < GGML_MAX_DIMS; i++) {
1426
+ if (node->nb[i] == dynamic_dim_stride && node->ne[i] == node->src[0]->ne[dynamic_dim_idx]) {
1427
+ m_node_dynamic_dims[node] = i;
1428
+ break;
1429
+ }
1430
+ }
1431
+ if (m_node_dynamic_dims[node] == -1) {
1432
+ // std::cout << "Cannot determine dynamic dim for RESHAPE node: " << node->name << std::endl;
1433
+ }
1434
+ }
1435
+ break;
1436
+ }
1437
+ case GGML_OP_FLASH_ATTN_EXT: {
1438
+ // Output shape is hard-coded in ggml_flash_attn_ext as:
1439
+ // ne = { v->ne[0], q->ne[2], q->ne[1], q->ne[3] }
1440
+ // i.e. output dim 0 <- v dim 0 (head_size, static)
1441
+ // output dim 1 <- q dim 2 (n_heads, static)
1442
+ // output dim 2 <- q dim 1 (n_tokens, potentially dynamic)
1443
+ // output dim 3 <- q dim 3 (batch, static)
1444
+ // Using the fixed q-dim -> output-dim mapping table.
1445
+ // q is src[0]; the mapping from q's dynamic dim to the output dim is:
1446
+ // q dim 1 -> output dim 2
1447
+ // q dim 2 -> output dim 1
1448
+ // q dim 3 -> output dim 3
1449
+ // q dim 0 -> output dim 0 (head_size axis, unlikely to be dynamic)
1450
+ constexpr int q_to_out[GGML_MAX_DIMS] = {0, 2, 1, 3};
1451
+ m_node_dynamic_dims[node] = -1;
1452
+ if (m_node_dynamic_dims[node->src[0]] != -1) {
1453
+ auto q_dynamic_dim = m_node_dynamic_dims[node->src[0]];
1454
+ m_node_dynamic_dims[node] = q_to_out[q_dynamic_dim];
1455
+ }
1456
+ break;
1457
+ }
1458
+ case GGML_OP_CONT:
1459
+ m_node_dynamic_dims[node] = -1;
1460
+ if (m_node_dynamic_dims[node->src[0]] != -1) {
1461
+ auto dynamic_dim_idx = m_node_dynamic_dims[node->src[0]];
1462
+ if (ggml_are_same_shape(node, node->src[0])) {
1463
+ m_node_dynamic_dims[node] = dynamic_dim_idx;
1464
+ } else {
1465
+ size_t src_logical_nb[GGML_MAX_DIMS];
1466
+ src_logical_nb[0] = ggml_type_size(node->src[0]->type);
1467
+ src_logical_nb[1] = src_logical_nb[0] * (node->src[0]->ne[0] / ggml_blck_size(node->src[0]->type));
1468
+ for (int i = 2; i < GGML_MAX_DIMS; i++) {
1469
+ src_logical_nb[i] = src_logical_nb[i - 1] * node->src[0]->ne[i - 1];
1470
+ }
1471
+
1472
+ auto dynamic_dim_stride = src_logical_nb[dynamic_dim_idx] / ggml_type_size(node->src[0]->type) *
1473
+ ggml_type_size(node->type);
1474
+ int matched_dim_count = 0;
1475
+ for (int i = 0; i < GGML_MAX_DIMS; i++) {
1476
+ if (node->nb[i] == dynamic_dim_stride && node->ne[i] == node->src[0]->ne[dynamic_dim_idx]) {
1477
+ m_node_dynamic_dims[node] = i;
1478
+ matched_dim_count++;
1479
+ }
1480
+ }
1481
+ if (matched_dim_count != 1) {
1482
+ m_node_dynamic_dims[node] = -1;
1483
+ // std::cout << "Warning: Cannot determine dynamic dim for CONT node: " << node->name
1484
+ // << " and its src[0]: " << node->src[0]->name << std::endl;
1485
+ }
1486
+ }
1487
+ }
1488
+ break;
1489
+ case GGML_OP_RMS_NORM:
1490
+ case GGML_OP_NORM:
1491
+ case GGML_OP_ADD:
1492
+ case GGML_OP_GLU:
1493
+ case GGML_OP_ROPE:
1494
+ case GGML_OP_SCALE:
1495
+ case GGML_OP_SOFT_MAX:
1496
+ case GGML_OP_ARGSORT:
1497
+ case GGML_OP_ADD_ID:
1498
+ case GGML_OP_UNARY:
1499
+ m_node_dynamic_dims[node] = m_node_dynamic_dims[node->src[0]];
1500
+ break;
1501
+ case GGML_OP_MUL_MAT_ID:
1502
+ m_node_dynamic_dims[node] = m_node_dynamic_dims[node->src[1]];
1503
+ break;
1504
+ case GGML_OP_CPY:
1505
+ case GGML_OP_SET_ROWS:
1506
+ m_node_dynamic_dims[node] = -1;
1507
+ break;
1508
+ case GGML_OP_IM2COL: {
1509
+ m_node_dynamic_dims[node] = -1;
1510
+ if (m_node_dynamic_dims[node->src[1]] != -1) {
1511
+ const bool is_2D = node->op_params[6] == 1;
1512
+ const int src_dyn = m_node_dynamic_dims[node->src[1]];
1513
+ if (is_2D) {
1514
+ if (src_dyn == 0) {
1515
+ m_node_dynamic_dims[node] = 1; // IW -> OW
1516
+ } else if (src_dyn == 1) {
1517
+ m_node_dynamic_dims[node] = 2; // IH -> OH
1518
+ } else if (src_dyn == 3) {
1519
+ m_node_dynamic_dims[node] = 3; // N -> N
1520
+ }
1521
+ } else {
1522
+ if (src_dyn == 0) {
1523
+ m_node_dynamic_dims[node] = 1; // IW -> OW
1524
+ } else if (src_dyn == 2) {
1525
+ m_node_dynamic_dims[node] = 2; // N -> N (1D: b->ne[2] is the batch/channel dim)
1526
+ }
1527
+ }
1528
+ if (m_node_dynamic_dims[node] != -1) {
1529
+ OPENVINO_ASSERT(node->src[1]->ne[src_dyn] == node->ne[m_node_dynamic_dims[node]],
1530
+ "Dynamic dim value mismatch for IM2COL node: " + std::string(node->name) +
1531
+ " and its src[1]: " + std::string(node->src[1]->name));
1532
+ }
1533
+ }
1534
+ break;
1535
+ }
1536
+ default:
1537
+ // std::cout << "Doesn't handle node name: " << node->name << " op: " << ggml_op_name(node->op) << std::endl;
1538
+ break;
1539
+ }
1540
+ };
1541
+
1542
+ for (int i = 0; i < m_cgraph->n_nodes; i++) {
1543
+ ggml_tensor * node = m_cgraph->nodes[i];
1544
+ visit_node(visit_node, node);
1545
+ }
1546
+
1547
+ // print the nodes in m_cgraph name & shape with the dynamic dim (the dynamic dim is the dimension with -1 in m_node_dynamic_dims) for debugging
1548
+ if (0) {
1549
+ for (int i = 0; i < m_cgraph->n_nodes; i++) {
1550
+ ggml_tensor * node = m_cgraph->nodes[i];
1551
+ int dynamic_dim = m_node_dynamic_dims[node];
1552
+ std::cout << "[" << i << "] " << "node_name: " << node->name << " op: " << ggml_op_name(node->op)
1553
+ << " shape: [";
1554
+ for (int j = 0; j < 4; j++) {
1555
+ if (j == dynamic_dim) {
1556
+ std::cout << "*";
1557
+ } else {
1558
+ std::cout << node->ne[j];
1559
+ }
1560
+ if (j < 3) {
1561
+ std::cout << ", ";
1562
+ }
1563
+ }
1564
+ std::cout << "]" << std::endl;
1565
+ // print the src name & shape with the dynamic dim for debugging
1566
+ for (int j = 0; j < GGML_MAX_SRC; j++) {
1567
+ ggml_tensor * src = node->src[j];
1568
+ if (src == nullptr) {
1569
+ continue;
1570
+ }
1571
+ int src_dynamic_dim = m_node_dynamic_dims[src];
1572
+ std::cout << " [" << j << "] src_name: " << src->name << " [";
1573
+ for (int k = 0; k < 4; k++) {
1574
+ if (k == src_dynamic_dim) {
1575
+ std::cout << "*";
1576
+ } else {
1577
+ std::cout << src->ne[k];
1578
+ }
1579
+ if (k < 3) {
1580
+ std::cout << ", ";
1581
+ }
1582
+ }
1583
+ std::cout << "]" << std::endl;
1584
+ }
1585
+ std::cout << std::endl;
1586
+ }
1587
+ }
1588
+ }