char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
aee56b3ab
char/aliceai-t5-moe
1#include "../node_context.h" 2#include "../op_table.h" 3#include "../utils.h" 4 5#include <openvino/op/broadcast.hpp> 6#include <openvino/op/constant.hpp> 7#include <openvino/op/divide.hpp> 8#include <openvino/op/gather.hpp> 9#include <openvino/op/loop.hpp> 10#include <openvino/op/matmul.hpp> 11#include <openvino/op/scatter_update.hpp> 12#include <openvino/op/shape_of.hpp> 13#include <openvino/op/subtract.hpp> 14 15namespace ov { 16namespace frontend { 17namespace ggml { 18namespace op { 19 20// GGML SOLVE_TRI: solve Ax = B for lower-triangular A via forward substitution. 21// Currently only lower, right, non-unitriangular variant is implemented. 22// 23// ggml layout: A [n, n, B1, B2], B [k, n, B1, B2] → X [k, n, B1, B2] 24// OV layout: A [B2, B1, n, n], B [B2, B1, n, k] → X [B2, B1, n, k] 25// 26// Forward substitution row i: 27// x[i] = (b[i] - sum_{t<i} A[i,t]*x[t]) / A[i,i] 28// 29// Implemented as an OV Loop op iterating n times with a carried X accumulator. 30// Key insight: A is lower-triangular and X starts as zeros, so the full matmul 31// A_row_i @ X_partial = sum_{t<i} A[i,t]*x[t] exactly (upper triangle of A 32// is zero; unfilled rows of X are zero). 33OutputVector translate_solve_tri (const NodeContext & context ) { 34num_inputs_check (context ,2 ,2 ); 35 36auto A = context .get_input (0 );// [B2, B1, n, n] 37auto B = context .get_input (1 );// [B2, B1, n, k] 38 39auto A_shape = context .get_input_shape (0 ).to_shape (); 40int64_t n = static_cast < int64_t > (A_shape [2 ]); 41 42// Initial X: zeros with shape of B 43auto B_shape_node = std::make_shared < ov::op::v3::ShapeOf > (B , ov::element::i64 ); 44auto zero_f32 = ov::op::v0::Constant ::create (ov::element::f32 , {}, {0.0f }); 45auto X_init = std::make_shared < ov::op::v3::Broadcast > (zero_f32 ,B_shape_node ); 46 47// --- Loop body parameters --- 48// body_iter: iteration counter injected by the Loop op (i64, shape {1}) 49auto body_iter = std::make_shared < ov::op::v0::Parameter > (ov::element::i64 , ov::Shape {1 }); 50auto body_X = std::make_shared < ov::op::v0::Parameter > (ov::element::f32 , ov::PartialShape ::dynamic (4 )); 51auto body_A = std::make_shared < ov::op::v0::Parameter > (ov::element::f32 , ov::PartialShape ::dynamic (4 )); 52auto body_B_p = std::make_shared < ov::op::v0::Parameter > (ov::element::f32 , ov::PartialShape ::dynamic (4 )); 53 54auto c_axis2 = ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {int64_t (2 )}); 55auto c_axis3 = ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {int64_t (3 )}); 56auto c_axis2_scalar = ov::op::v0::Constant ::create (ov::element::i64 , {}, {int64_t (2 )}); 57 58// b_i = B[..., i, :] [B2, B1, 1, k] 59auto b_i = std::make_shared < ov::op::v8::Gather > (body_B_p ,body_iter ,c_axis2 ); 60 61// A_row_i = A[..., i, :] [B2, B1, 1, n] 62auto A_row_i = std::make_shared < ov::op::v8::Gather > (body_A ,body_iter ,c_axis2 ); 63 64// sum_i = A_row_i @ X [B2, B1, 1, k] 65// (lower-tri zeros + unfilled-X zeros make this equal to the partial sum) 66auto sum_i = std::make_shared < ov::op::v0::MatMul > (A_row_i ,body_X , false, false); 67 68// diag_i = A[..., i, i] [B2, B1, 1, 1] 69auto diag_i = std::make_shared < ov::op::v8::Gather > (A_row_i ,body_iter ,c_axis3 ); 70 71// x_i = (b_i - sum_i) / diag_i [B2, B1, 1, k] 72auto x_i = std::make_shared < ov::op::v1::Divide > ( 73 std::make_shared < ov::op::v1::Subtract > (b_i ,sum_i ),diag_i ); 74 75// X_updated: scatter x_i into body_X at row i along axis 2 76auto X_updated = std::make_shared < ov::op::v3::ScatterUpdate > (body_X ,body_iter ,x_i ,c_axis2_scalar ); 77 78auto body_cond = ov::op::v0::Constant ::create (ov::element::boolean , ov::Shape {1 }, {true}); 79 80auto body = std::make_shared < ov::Model > ( 81 ov::OutputVector {body_cond ,X_updated }, 82 ov::ParameterVector {body_iter ,body_X ,body_A ,body_B_p }); 83 84// --- Assemble Loop --- 85auto trip_count = ov::op::v0::Constant ::create (ov::element::i64 , ov::Shape {1 }, std::vector < int64_t > {n }); 86auto exec_cond = ov::op::v0::Constant ::create (ov::element::boolean , ov::Shape {1 }, {true}); 87 88auto loop = std::make_shared < ov::op::v5::Loop > (trip_count ,exec_cond ); 89loop -> set_function (body ); 90// iter_counter_body_param_idx=0 (body_iter), exec_condition_body_result_idx=0 (body_cond) 91loop -> set_special_body_ports (ov::op::v5::Loop ::SpecialBodyPorts {0 ,0 }); 92 93// Carried state: X feeds back from X_updated each iteration 94loop -> set_merged_input (body_X ,X_init ,X_updated ); 95// Invariant inputs passed through unchanged 96loop -> set_invariant_input (body_A ,A ); 97loop -> set_invariant_input (body_B_p ,B ); 98 99// Final output: value of X_updated after the last iteration 100auto X_final = loop -> get_iter_value (X_updated ,-1 ); 101 102return rename_outputs_with_suffix ({X_final },context .get_name ()); 103} 104 105}// namespace op 106}// namespace ggml 107}// namespace frontend 108}// namespace ov