Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
4b6378d
Add interface is_model_splitted() to check the c-graph is splited or not
zhaixuejun1993 Mar 6, 2026
1b39f34
Infer and propagate dynamic-dimension indices for all tensors in the …
zhaixuejun1993 Mar 17, 2026
3aad3f1
Only do this for fallback sub graph
zhaixuejun1993 Mar 19, 2026
3a10860
Move dynamic dims compute in graph missmatch
zhaixuejun1993 Mar 23, 2026
d6b80bc
ggml-openvino: fix tensor data handling for PERMUTE/VIEW ops in split…
zhaixuejun1993 Mar 19, 2026
64ee289
ggml-openvino:add comments
zhaixuejun1993 Mar 19, 2026
7ab30fc
ggml-openvino: override VIEW op_case to 0 for split model inputs
zhaixuejun1993 Mar 19, 2026
7887089
openvino backend: Handle unsupported VIEW shape-mismatch in OpenVINO …
zhaixuejun1993 Mar 19, 2026
cf6f541
Enable additional mul_mat tests and add tensor data saving function (…
zhaixuejun1993 Mar 23, 2026
3bca21b
ggml-openvino: fix CONT/TRANSPOSE mapping and improve dynamic-dimensi…
zhaixuejun1993 Mar 26, 2026
dafc05a
OpenVINO: add NORM/TANH support and rework SOFT_MAX translation
zhaixuejun1993 Mar 28, 2026
c947188
ggml-openvino: extend VIEW handling
zhaixuejun1993 Mar 30, 2026
e712a8e
Enable -fa off (#118)
wine99 Apr 2, 2026
02acad1
Enable --context-shift
wine99 Apr 10, 2026
3f0d4c7
Fix llm param compute error for normal softmax not the softmax in att…
zhaixuejun1993 Apr 13, 2026
c6e06ee
OpenVINO backend: fix error for attention size compute in llm param
zhaixuejun1993 Apr 13, 2026
cb9ca0a
use tensor->extra in infer_request i/o
wine99 Apr 27, 2026
900d7c9
OpenVINO backend: refacter the compute_llm_params() func add get_atte…
zhaixuejun1993 Apr 29, 2026
c72768b
OpenVINO backend: clean unused code
zhaixuejun1993 Apr 29, 2026
5cc2456
flash attn Q shape static conversion
cavusmustafa May 4, 2026
f730c74
Remove slice in permute translation when n_seq is 1
cavusmustafa May 4, 2026
05ed62f
1to1 match op update (#146)
cavusmustafa May 6, 2026
ccceb43
initial gemma4 support
May 5, 2026
057a719
removed hardcoded names for kv cache slicing
cavusmustafa May 5, 2026
f6250b4
OpenVINO backend: Add new attention pattern for llm parameters compute
zhaixuejun1993 May 6, 2026
9714941
Merge pull request #144 from cavusmustafa/stateless_perf_opt
cavusmustafa May 6, 2026
a452764
return optional in extract_layer_from_name
wine99 May 7, 2026
335cf5c
OpenVINO backend: refactor VIEW related operation (#148)
zhaixuejun1993 May 7, 2026
c2c4a20
OpenVINO backend: Add ops l2_norm & pad
zhaixuejun1993 May 6, 2026
e827d2e
OpenVINO backend does not support CPY with non-contiguous data or mis…
zhaixuejun1993 May 7, 2026
58c146c
add op SSM_CONV GATED_DELTA_NET
wine99 May 7, 2026
805b8d6
OpenVINO backend: fix error for bf16 in OV gpu plugin
zhaixuejun1993 May 7, 2026
388e69d
reverted static Q input shape for attention layer
cavusmustafa May 7, 2026
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
756 changes: 679 additions & 77 deletions ggml/src/ggml-openvino/ggml-decoder.cpp

Large diffs are not rendered by default.

69 changes: 54 additions & 15 deletions ggml/src/ggml-openvino/ggml-decoder.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "ggml-quants.h"
#include "ggml-backend-impl.h"
#include "ggml-backend.h"
#include "ggml.h"
#include "openvino/decoder.h"

Expand All @@ -14,21 +15,21 @@

struct ModelParams {
int ctx = -1;
int ctx_swa = -1;
int ctx_per_seq = -1;
int ctx_per_seq_swa = -1;
int n_seq = 1;
int n_heads = -1;
int n_heads_kv = -1;
int head_size = -1;
int32_t rope_params[15];
bool mixed_rope_params = false;
std::vector<int> swa_layers;

std::vector<std::string> kv_names;
size_t kv_buffer_ctx_id = 0;

bool same_rope_params(const ModelParams & other) const {
return memcmp(rope_params, other.rope_params, sizeof(int32_t) * 15) == 0;
return mixed_rope_params == other.mixed_rope_params &&
memcmp(rope_params, other.rope_params, sizeof(int32_t) * 15) == 0;
}

bool can_reuse_dynamically(const ModelParams & other) const { return same_rope_params(other); }
Expand Down Expand Up @@ -56,6 +57,7 @@ class GgmlOvDecoder : public ov::frontend::ggml::GgmlDecoder {
std::string node_name;
std::string node_op_type;
std::map<std::string, ggml_tensor *> node_inputs;
std::map<std::string, std::vector<std::pair<std::string, ggml_tensor *>>> node_inputs_views;
std::vector<std::string> node_inputs_names;
ggml_tensor * node_output;
std::string node_output_name;
Expand All @@ -69,6 +71,7 @@ class GgmlOvDecoder : public ov::frontend::ggml::GgmlDecoder {
std::map<std::string, std::shared_ptr<ov::Node>> & model_weights,
bool is_static,
bool is_stateful = false,
bool model_is_splitted = false,
bool is_prefill = false,
int prefill_chunk_size = 256);

Expand All @@ -84,6 +87,28 @@ class GgmlOvDecoder : public ov::frontend::ggml::GgmlDecoder {

virtual std::vector<size_t> get_input_stride(int node_idx, const std::string & name) const override;

virtual size_t get_view_input_size(int node_idx, const std::string & name) const override;

virtual size_t get_view_input_offset(int node_idx, const std::string & name, size_t view_index) const override;

virtual size_t get_view_input_src_offset(int node_idx, const std::string & name, size_t view_index) const override;

virtual std::vector<size_t> get_view_input_stride(int node_idx, const std::string & name, size_t view_index) const override;

virtual std::vector<size_t> get_view_input_src_stride(int node_idx, const std::string & name, size_t view_index) const override;

virtual ov::Shape get_view_input_ggml_shape(int node_idx, const std::string & name, size_t view_index) const override;

virtual ov::Shape get_view_input_src_ggml_shape(int node_idx, const std::string & name, size_t view_index) const override;

virtual ov::PartialShape get_view_input_ov_shape(int node_idx, const std::string & name, size_t view_index) const override;

virtual ov::PartialShape get_view_input_src_ov_shape(int node_idx, const std::string & name, size_t view_index) const override;

virtual std::string get_view_input_name(int node_idx, const std::string & name, size_t view_index) const override;

virtual std::string get_view_input_src_name(int node_idx, const std::string & name, size_t view_index) const override;

virtual ov::element::Type get_input_type(int node_idx, const std::string & name) const override;

virtual size_t get_input_size() const override;
Expand All @@ -106,10 +131,14 @@ class GgmlOvDecoder : public ov::frontend::ggml::GgmlDecoder {

virtual ov::element::Type get_output_type(int node_idx) const override;

virtual std::vector<size_t> get_output_stride(int node_idx) const override;

virtual int32_t * get_input_op_params(int node_idx, const std::string & name) const override;

virtual int32_t * get_output_op_params(int node_idx) const override;

virtual size_t get_output_op_offset(int node_idx) const override;

virtual std::vector<std::string> get_output_names(int node_idx) const override;

virtual const std::string & get_op_type() const override;
Expand All @@ -120,6 +149,8 @@ class GgmlOvDecoder : public ov::frontend::ggml::GgmlDecoder {

virtual const std::string & get_op_name(int node_idx) const override;

virtual int32_t get_op_dynamic_dim(int node_idx) const override;

virtual void visit_subgraph(std::function<void(std::shared_ptr<GgmlDecoder>, int node_idx)> node_visitor) const override;

ggml_tensor * get_input_ggml_tensor(const std::string & name) const { return m_inputs.at(name); }
Expand Down Expand Up @@ -150,8 +181,6 @@ class GgmlOvDecoder : public ov::frontend::ggml::GgmlDecoder {

virtual int get_ctx_size() const { return m_model_params.ctx; }

virtual int get_ctx_swa_size() const { return m_model_params.ctx_swa; }

virtual int get_ctx_per_seq() const { return m_model_params.ctx_per_seq; }

virtual int get_ctx_per_seq_swa() const { return m_model_params.ctx_per_seq_swa; }
Expand All @@ -169,13 +198,19 @@ class GgmlOvDecoder : public ov::frontend::ggml::GgmlDecoder {

virtual int32_t * get_rope_params() const override { return const_cast<int32_t *>(m_model_params.rope_params); }

virtual bool has_mixed_rope_params() const override { return m_model_params.mixed_rope_params; }

virtual std::map<std::string, std::string> get_kv_param_res_names() const override;

virtual bool is_static() const override { return m_is_static; }

virtual bool is_stateful() const override { return m_is_stateful; }

ov::PartialShape get_graph_input_shape(const ggml_tensor * op, const ggml_tensor * input) const;
virtual bool is_splited_model() const override {
return m_model_is_splitted;
}

ov::PartialShape get_graph_input_shape(const ggml_tensor * op, const ggml_tensor * input, int dynamic_dim_index=-1) const;

static void dump_cgraph(const ggml_cgraph * cgraph, std::string & filename);

Expand Down Expand Up @@ -205,6 +240,7 @@ class GgmlOvDecoder : public ov::frontend::ggml::GgmlDecoder {
bool m_is_prefill = false;
bool m_naive = false;
int m_prefill_chunk_size = 0;
bool m_model_is_splitted = false; // label the cgraph is splited or not

static ov::Shape get_shape(const ggml_tensor * tensor);
static std::vector<size_t> get_stride(const ggml_tensor * tensor);
Expand All @@ -227,15 +263,17 @@ class GgmlOvDecoder : public ov::frontend::ggml::GgmlDecoder {
}

inline static bool is_inp_mask(const ggml_tensor * tensor, const ggml_tensor * op) {
return op->op == GGML_OP_CPY || (op->op == GGML_OP_FLASH_ATTN_EXT && tensor == op->src[3]);
return op->op == GGML_OP_CPY || (op->op == GGML_OP_FLASH_ATTN_EXT && tensor == op->src[3]) ||
(op->op == GGML_OP_SOFT_MAX && tensor == op->src[1]);
}

inline static bool is_rope_freqs_weight(const ggml_tensor * tensor, const ggml_tensor * op) {
return op->op == GGML_OP_ROPE && tensor == op->src[2];
}

inline static bool is_kvcache(const ggml_tensor * tensor, const ggml_tensor * op) {
return op->op == GGML_OP_SET_ROWS && op->src[2] == tensor;
return tensor->buffer->usage == GGML_BACKEND_BUFFER_USAGE_ANY ||
(op != nullptr && op->op == GGML_OP_SET_ROWS && op->src[2] == tensor);
}

inline static bool is_kv_idx(const ggml_tensor * tensor, const ggml_tensor * op) {
Expand All @@ -246,7 +284,7 @@ class GgmlOvDecoder : public ov::frontend::ggml::GgmlDecoder {
return op->op == GGML_OP_GET_ROWS && tensor == op->src[1] && op->src[0]->op != GGML_OP_NONE;
}

static std::string get_graph_input_ov_name(const ggml_tensor * tensor, const ggml_tensor * op) {
std::string get_graph_input_ov_name(const ggml_tensor * tensor, const ggml_tensor * op) {
if (is_inp_tok(tensor, op)) {
return "inp_tokens";
}
Expand All @@ -256,10 +294,7 @@ class GgmlOvDecoder : public ov::frontend::ggml::GgmlDecoder {
if (is_inp_emb(tensor, op)) {
return "embd";
}
if (is_output_idx(tensor, op)) {
return "inp_out_ids";
}
if (is_inp_mask(tensor, op)) {
if (is_stateful() && is_inp_mask(tensor, op)) {
return std::string(tensor->name).find("swa") == std::string::npos ? "self_kq_mask" : "self_kq_mask_swa";
}
return tensor->name;
Expand All @@ -272,6 +307,9 @@ class GgmlOvDecoder : public ov::frontend::ggml::GgmlDecoder {
void compute_model_inputs();
void compute_model_outputs();

// Infer and propagate dynamic-dimension indices for all tensors in the GGML graph.
void compute_node_dynamic_dims();

void validate_cgraph() const;

ggml_cgraph * m_cgraph = nullptr;
Expand All @@ -284,11 +322,12 @@ class GgmlOvDecoder : public ov::frontend::ggml::GgmlDecoder {
std::map<std::string, ggml_tensor *> m_model_outputs;
std::vector<std::string> m_model_output_names;
std::vector<NodeInfo> m_node_info_list;
std::map<ggml_tensor *, int> m_node_dynamic_dims;

ModelParams m_model_params;
ComputeParams m_compute_params;
};

void print_tensor_address_map(const ggml_cgraph * cgraph);

int extract_layer_from_name(const std::string & name);
std::optional<int> extract_layer_from_name(const std::string & name);
72 changes: 46 additions & 26 deletions ggml/src/ggml-openvino/ggml-openvino.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,11 @@ static bool is_op_unsupported_case(const ggml_tensor * op) {
if (op->ne[3] != 1) {
return true;
}
if (op->ne[0] == 256 && (op->src[0]->type == GGML_TYPE_Q4_K || op->src[0]->type == GGML_TYPE_Q5_K)) {
// ERR = 0.000000306 > 0.000000100 GET_ROWS(type=q4_K,n=256,m=5,r=4,be1=1,be2=1,v=0)
// ERR = 0.000000197 > 0.000000100 GET_ROWS(type=q5_K,n=256,m=5,r=4,be1=1,be2=1,v=0)
return true;
}
break;
}
case GGML_OP_ADD:
Expand All @@ -823,15 +828,6 @@ static bool is_op_unsupported_case(const ggml_tensor * op) {
// GGML_LOG_WARN("OpenVINO backend does not support SOFT_MAX with sinks\n");
return true;
}
float scale = 1.0f;
float max_bias = 0.0f;
const auto * op_params = op->op_params;
memcpy(&scale, (const float *) op_params + 0, sizeof(float));
memcpy(&max_bias, (const float *) op_params + 1, sizeof(float));
if (max_bias > 0) {
// GGML_LOG_WARN("OpenVINO backend does not support SOFT_MAX with max_bias > 0\n");
return true;
}
break;
}
case GGML_OP_FLASH_ATTN_EXT: {
Expand Down Expand Up @@ -868,8 +864,8 @@ static bool is_op_unsupported_case(const ggml_tensor * op) {
break;
}
case GGML_OP_CPY: {
if (op->src[1] != op) {
// GGML_LOG_WARN("OpenVINO backend only supports CPY that is a cast\n");
if (!ggml_is_contiguous(op->src[0]) || !ggml_is_contiguous(op->src[1]) || op->src[0]->type == GGML_TYPE_BF16 || op->src[1]->type == GGML_TYPE_BF16) {
// GGML_LOG_WARN("OpenVINO backend does not support CPY with non-contiguous data or bf16 types\n");
return true;
}
break;
Expand All @@ -883,9 +879,6 @@ static bool is_op_unsupported_case(const ggml_tensor * op) {
if (op->src[0]->ne[3] != op->src[1]->ne[3] && op->src[0]->ne[3] != 1 && op->src[1]->ne[3] != 1) {
return true;
}
if (op->src[0]->op == GGML_OP_PERMUTE || op->src[1]->op == GGML_OP_PERMUTE) {
return true;
}
if (ggml_is_quantized(op->src[0]->type) && op->src[0]->ne[1] == 1) {
// MUL_MAT(type_a=q4_0,type_b=f32,m=1,n=2048,k=8192,bs=[1,1],nr=[1,1],per=[0,1,2,3],k_v=0,o=1)
// triggers a bug in ov matmul_shape_inference.hpp
Expand All @@ -909,7 +902,7 @@ static bool is_op_unsupported_case(const ggml_tensor * op) {
// op->src[0]->ne[0]);
return true;
}
if (op->type != GGML_TYPE_F32) {
if (op->type != GGML_TYPE_F32 && op->type != GGML_TYPE_F16) {
// GGML_LOG_WARN("OpenVINO backend does not support ROPE with type %s\n", ggml_type_name(op->type));
return true;
}
Expand All @@ -930,35 +923,60 @@ static bool is_op_unsupported_case(const ggml_tensor * op) {
}
break;
}
default:
case GGML_OP_TRANSPOSE: {
// if the type is bf16, will return true
if (op->type == GGML_TYPE_BF16) {
// GGML_LOG_WARN("OpenVINO backend does not support CONT with BF16 type\n");
return true;
}
break;
}
if (op->op == GGML_OP_GET_ROWS) {
if (op->ne[0] == 256 && (op->src[0]->type == GGML_TYPE_Q4_K || op->src[0]->type == GGML_TYPE_Q5_K)) {
// ERR = 0.000000306 > 0.000000100 GET_ROWS(type=q4_K,n=256,m=5,r=4,be1=1,be2=1,v=0)
// ERR = 0.000000197 > 0.000000100 GET_ROWS(type=q5_K,n=256,m=5,r=4,be1=1,be2=1,v=0)
case GGML_OP_GATED_DELTA_NET: {
if (op->src[0]->op == GGML_OP_PERMUTE) {
return true;
}
break;
}
default:
break;
}
return false;
}

static bool ggml_backend_openvino_device_supports_op(ggml_backend_dev_t dev, const ggml_tensor * op) {
// return true;
GGML_ASSERT(dev->reg != nullptr);

static std::set<ggml_type> supported_types{GGML_TYPE_F32, GGML_TYPE_F16, GGML_TYPE_BF16, GGML_TYPE_I64,
GGML_TYPE_I32, GGML_TYPE_Q4_0, GGML_TYPE_Q4_1, GGML_TYPE_Q4_K,
GGML_TYPE_Q5_K, GGML_TYPE_Q8_0, GGML_TYPE_Q6_K};

static const std::set<ggml_op> supported_ops{GGML_OP_NONE, GGML_OP_ADD, GGML_OP_MUL, GGML_OP_MUL_MAT, GGML_OP_VIEW,
/*GGML_OP_CONT,*/ GGML_OP_RESHAPE, GGML_OP_PERMUTE, GGML_OP_TRANSPOSE,
GGML_OP_GET_ROWS, GGML_OP_ROPE, GGML_OP_RMS_NORM, GGML_OP_SCALE,
// softmax is not updated due to replaced by flash_attn_ext
// GGML_OP_SOFT_MAX,
GGML_OP_SET_ROWS, GGML_OP_FLASH_ATTN_EXT, GGML_OP_CPY};
static const std::set<ggml_op> supported_ops{GGML_OP_NONE,
GGML_OP_ADD,
GGML_OP_MUL,
GGML_OP_MUL_MAT,
GGML_OP_VIEW,
GGML_OP_CONT,
GGML_OP_RESHAPE,
GGML_OP_PERMUTE,
GGML_OP_TRANSPOSE,
GGML_OP_GET_ROWS,
GGML_OP_ROPE,
GGML_OP_RMS_NORM,
GGML_OP_SCALE,
GGML_OP_NORM,
GGML_OP_SOFT_MAX,
GGML_OP_SET_ROWS,
GGML_OP_FLASH_ATTN_EXT,
GGML_OP_CPY,
GGML_OP_L2_NORM,
GGML_OP_PAD,
GGML_OP_SSM_CONV,
GGML_OP_GATED_DELTA_NET};
static const std::set<ggml_unary_op> supported_unary_ops{
GGML_UNARY_OP_GELU,
GGML_UNARY_OP_SILU,
GGML_UNARY_OP_TANH,
};
static const std::set<ggml_glu_op> supported_glu_ops{
GGML_GLU_OP_SWIGLU,
Expand Down Expand Up @@ -1005,6 +1023,8 @@ static bool ggml_backend_openvino_device_supports_op(ggml_backend_dev_t dev, con
static std::set<ggml_op> ops_not_support_view_input{
GGML_OP_GET_ROWS,
GGML_OP_RMS_NORM,
GGML_OP_NORM,
GGML_OP_L2_NORM,
};
if (ops_not_support_view_input.find(op->op) != ops_not_support_view_input.end() && has_view_op_input(op)) {
// GGML_LOG_WARN("OpenVINO backend does not support op %s with view input\n", ggml_op_name(op->op));
Expand Down
Loading
Loading