Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ggml/src/ggml-openvino/ggml-decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ int GgmlOvDecoder::compute_op_case(const ggml_tensor * node) const {
if (src->ne[2] * src->ne[3] == node->ne[1]) {
op_case = 5;
}
} else if (src->ne[0] * src->ne[1] * src->ne[2] == node->ne[1]) {
} else if (src->ne[0] * src->ne[1] * src->ne[2] == node->ne[1] && is_kvcache(src, node)) {
op_case = 3;
} else if (name.find("linear_attn_qkv_mixed") == 0 || name.find("alpha") == 0) {
op_case = 6;
Expand Down
24 changes: 18 additions & 6 deletions ggml/src/ggml-openvino/ggml-openvino.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -909,20 +909,32 @@ static bool has_non_contiguous_view_input(const ggml_tensor * op) {

static bool is_supported_flash_attn_pattern(const ggml_tensor * op) {
// Each Q/K/V input must follow one of:
// PERMUTE -> VIEW -> base (view_src==nullptr) (llama KV-cache path)
// PERMUTE -> RESHAPE -> base (view_src==nullptr) (whisper Q)
// VIEW -> base (view_src==nullptr) (whisper K/V from kv_pad)
// (CPY ->) PERMUTE -> VIEW / RESHAPE / CONCAT / RMS_NORM (llama, whisper, gemma4v)
// (CPY ->) VIEW -> base (whisper K/V from kv_pad)
for (int i = 0; i < 3; i++) {
const ggml_tensor * src = op->src[i];
if (src == nullptr) {
return false;
}
if (src->op == GGML_OP_CPY) {
src = src->src[0];
if (src == nullptr) {
return false;
}
}
if (src->op == GGML_OP_PERMUTE) {
if (src->src[0] == nullptr) {
return false;
}
if (src->src[0]->op != GGML_OP_VIEW && src->src[0]->op != GGML_OP_RESHAPE) {
const enum ggml_op inner_op = src->src[0]->op;
if (inner_op != GGML_OP_VIEW && inner_op != GGML_OP_RESHAPE && inner_op != GGML_OP_CONCAT &&
inner_op != GGML_OP_RMS_NORM) {
return false;
}
if (src->src[0]->src[0] == nullptr || src->src[0]->src[0]->view_src != nullptr) {
return false;
if (inner_op == GGML_OP_VIEW || inner_op == GGML_OP_RESHAPE) {
if (src->src[0]->src[0] == nullptr || src->src[0]->src[0]->view_src != nullptr) {
return false;
}
}
} else if (src->op == GGML_OP_VIEW) {
if (src->src[0] == nullptr || src->src[0]->view_src != nullptr) {
Expand Down
10 changes: 10 additions & 0 deletions ggml/src/ggml-openvino/openvino/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <openvino/op/squeeze.hpp>
#include <openvino/op/subtract.hpp>
#include <openvino/op/transpose.hpp>
#include <openvino/op/unsqueeze.hpp>
#include <string>

namespace ov {
Expand Down Expand Up @@ -336,6 +337,15 @@ ov::Output<ov::Node> process_view_input_new(const NodeContext & context, int inp
}
}

// some weight tensors have 2D/3D shapes which would be incompatible with the
// 4D slices in this utility. unsqueeze to 4D in order to avoid this issue.
ov::Rank rank = input.get_partial_shape().rank();
if (rank.is_static() && rank.get_length() == 2){
input = std::make_shared<ov::op::v0::Unsqueeze>(input, ov::op::v0::Constant::create(ov::element::i64, {2}, {0, 1}));
} else if (rank.is_static() && rank.get_length() == 3){
input = std::make_shared<ov::op::v0::Unsqueeze>(input, ov::op::v0::Constant::create(ov::element::i64, {1}, {0}));
}

// In static mode, use Split instead of Slice for single-dimension reductions.
// This ensures NPUW's FOLD doesn't parametrize per-layer slice indices (which
// would introduce dynamic shapes). A shared Split node sits outside the repeated
Expand Down