char-fork/llama.cpp

git clone https://git.t4t.associates/char-fork/llama.cpp

Zijun Yuopenvino: OV 2026.2, context-shift, Q5_1 support, gemma4 dense/embedding, and -fa off (#24503)890f1a27e

char/aliceai-t5-moe
3.1 KiB75 linesraw
1#include "../node_context.h"
2#include "../op_table.h"
3#include "../utils.h"
4
5#include <memory>
6#include <openvino/core/node_output.hpp>
7#include <openvino/op/clamp.hpp>
8#include <openvino/op/constant.hpp>
9#include <openvino/op/gelu.hpp>
10#include <openvino/op/multiply.hpp>
11#include <openvino/op/sigmoid.hpp>
12#include <openvino/op/slice.hpp>
13
14namespace ov {
15namespace frontend {
16namespace ggml {
17namespace op {
18
19OutputVector translate_glu_geglu(const NodeContext & context) {
20    num_inputs_check(context, 1, 2);
21
22    ov::Output<ov::Node> src0;
23    ov::Output<ov::Node> src1;
24    if (context.get_input_size() == 2) {
25        // Inputs may be VIEW slices of a combined gate_up tensor (MoE experts):
26        // resolve them so each half has its real sliced shape, not the base tensor.
27        src0 = process_view_input_new(context, 0);
28        src1 = process_view_input_new(context, 1);
29    } else {
30        // GGML splits along ne[0] (OV last axis) using floor division: nc = ne[0] / 2.
31        // Both halves are nc elements; if the dimension is odd, the last element is dropped.
32        // Use Slice instead of Split to handle odd dimensions correctly.
33        // Resolve a VIEW input (e.g. non-contiguous slice) to its real shape first.
34        auto combined = process_view_input_new(context, 0);
35        auto combined_shape = combined.get_partial_shape();
36        int64_t last_dim_val = combined_shape[combined_shape.rank().get_length() - 1].get_length();
37        int64_t nc = last_dim_val / 2;
38
39        auto axis = ov::op::v0::Constant::create(ov::element::i64, {1}, {-1});
40        auto step = ov::op::v0::Constant::create(ov::element::i64, {1}, {1});
41        auto start0 = ov::op::v0::Constant::create(ov::element::i64, {1}, {0});
42        auto stop0 = ov::op::v0::Constant::create(ov::element::i64, {1}, {nc});
43        auto start1 = ov::op::v0::Constant::create(ov::element::i64, {1}, {nc});
44        auto stop1 = ov::op::v0::Constant::create(ov::element::i64, {1}, {2 * nc});
45
46        src0 = std::make_shared<ov::op::v8::Slice>(combined, start0, stop0, step, axis);
47        src1 = std::make_shared<ov::op::v8::Slice>(combined, start1, stop1, step, axis);
48    }
49
50    int32_t * params = context.get_output_op_params();
51    const int32_t swapped = params[1];
52    if (swapped) {
53        std::swap(src0, src1);
54    }
55
56    if (context.is_static()) {
57        // TODO: Temporary solution for NPU accuracy issue due to fp16 overflow
58        // To be removed once permanent solution is implemented
59        // Justification:
60        // For |x| > 5, GELU(x) ≈ max(x, 0)  (behaves like ReLU)
61        // So Clamp(-10, 10) only affects values where GELU would return ≈ x anyway.
62        // The only loss: values > 10 get mapped to 10 instead of x.
63        // In practice, FFN intermediates rarely exceed 10 after GEGLU gating.
64        src0 = std::make_shared<ov::op::v0::Clamp>(src0, -10.0, 10.0);
65    }
66    auto gelu = std::make_shared<ov::op::v7::Gelu>(src0);
67    auto res = std::make_shared<ov::op::v1::Multiply>(gelu, src1);
68
69    return rename_outputs_with_suffix({res}, context.get_name());
70}
71
72}  // namespace op
73}  // namespace ggml
74}  // namespace frontend
75}  // namespace ov