char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
890f1a27e
char/aliceai-t5-moe
1#include "../node_context.h" 2#include "../op_table.h" 3#include "../utils.h" 4#include "ggml.h" 5 6#include <memory> 7#include <openvino/op/constant.hpp> 8#include <openvino/op/convert.hpp> 9#include <openvino/op/divide.hpp> 10#include <openvino/op/multiply.hpp> 11#include <openvino/op/shape_of.hpp> 12#include <openvino/op/sigmoid.hpp> 13#include <openvino/op/tile.hpp> 14#include <openvino/op/util/precision_sensitive_attribute.hpp> 15#include <vector> 16 17namespace ov { 18namespace frontend { 19namespace ggml { 20namespace op { 21 22namespace { 23 24bool is_silu_div_pattern (const ov::Output < ov::Node > & numerator , 25const ov::Output < ov::Node > & denominator , 26const NodeContext & context ) { 27if (context .get_input_size ()!= 2 ) { 28return false; 29 } 30 31const auto * unary_op = reinterpret_cast < const ggml_unary_op *> (context .get_input_op_params (0 )); 32if (unary_op == nullptr || * unary_op != GGML_UNARY_OP_SILU ) { 33return false; 34 } 35 36auto mul = std::dynamic_pointer_cast < ov::op::v1::Multiply > (numerator .get_node_shared_ptr ()); 37if (!mul ) { 38return false; 39 } 40 41const auto denom_node = denominator .get_node_shared_ptr (); 42const auto mul_input_0 = mul -> input_value (0 ).get_node_shared_ptr (); 43const auto mul_input_1 = mul -> input_value (1 ).get_node_shared_ptr (); 44 45auto sigmoid = std::dynamic_pointer_cast < ov::op::v0::Sigmoid > (mul_input_1 ); 46if (mul_input_0 == denom_node && sigmoid && sigmoid -> input_value (0 ).get_node_shared_ptr ()== denom_node ) { 47return true; 48 } 49 50sigmoid = std::dynamic_pointer_cast < ov::op::v0::Sigmoid > (mul_input_0 ); 51return mul_input_1 == denom_node && sigmoid && sigmoid -> input_value (0 ).get_node_shared_ptr ()== denom_node ; 52} 53 54ov::Output < ov::Node > repeat_input_to_match (const NodeContext & context , 55const ov::Output < ov::Node > & input , 56const ov::Output < ov::Node > & target , 57size_t input_index ) { 58const auto input_shape = context .get_input_shape (input_index ); 59const auto target_shape = context .get_input_shape (0 ); 60 61if (input_shape == target_shape ) { 62return input ; 63 } 64 65if (input_shape .rank ().is_static ()&& target_shape .rank ().is_static ()) { 66const auto rank = static_cast < size_t > (input_shape .rank ().get_length ()); 67 std::vector < int64_t > repeats (rank ,1 ); 68bool needs_repeat = false; 69 70for (size_t axis = 0 ;axis < rank ;++ axis ) { 71FRONT_END_OP_CONVERSION_CHECK (input_shape [axis ].is_static ()&& target_shape [axis ].is_static (), 72"DIV repeat requires static dimensions on both inputs" ); 73 74const int64_t input_dim = input_shape [axis ].get_length (); 75const int64_t target_dim = target_shape [axis ].get_length (); 76 77FRONT_END_OP_CONVERSION_CHECK (input_dim > 0 && target_dim > 0 && target_dim %input_dim == 0 , 78"DIV input shape " ,input_shape ," cannot repeat to match " ,target_shape ); 79 80repeats [axis ]= target_dim /input_dim ; 81needs_repeat = needs_repeat || repeats [axis ]!= 1 ; 82 } 83 84if (!needs_repeat ) { 85return input ; 86 } 87 88auto repeats_node = ov::op::v0::Constant ::create (ov::element::i64 , {repeats .size ()},repeats ); 89return std::make_shared < ov::op::v0::Tile > (input ,repeats_node ); 90 } 91 92auto input_shape_node = std::make_shared < ov::op::v3::ShapeOf > (input , ov::element::i64 ); 93auto target_shape_node = std::make_shared < ov::op::v3::ShapeOf > (target , ov::element::i64 ); 94auto repeats_node = std::make_shared < ov::op::v1::Divide > (target_shape_node ,input_shape_node ); 95return std::make_shared < ov::op::v0::Tile > (input ,repeats_node ); 96} 97 98}// namespace 99 100OutputVector translate_div (const NodeContext & context ) { 101num_inputs_check (context ,2 ,2 ); 102 103auto input_0 = process_view_input_new (context ,0 ); 104auto input_1 = process_view_input_new (context ,1 ); 105 106if (is_silu_div_pattern (input_0 ,input_1 ,context )) { 107 ov::Output < ov::Node > res = std::make_shared < ov::op::v0::Sigmoid > (input_1 ); 108if (res .get_element_type ()!= context .get_output_type ()) { 109res = std::make_shared < ov::op::v0::Convert > (res ,context .get_output_type ()); 110 } 111return rename_outputs_with_suffix ({res },context .get_name ()); 112 } 113 114input_1 = repeat_input_to_match (context ,input_1 ,input_0 ,1 ); 115 116const auto output_type = context .get_output_type (); 117const bool use_f32_compute = input_0 .get_element_type ()!= ov::element::f32 || 118input_1 .get_element_type ()!= ov::element::f32 || output_type != ov::element::f32 ; 119 120if (use_f32_compute ) { 121input_0 = std::make_shared < ov::op::v0::Convert > (input_0 , ov::element::f32 ); 122input_1 = std::make_shared < ov::op::v0::Convert > (input_1 , ov::element::f32 ); 123 } 124 125 ov::Output < ov::Node > res = std::make_shared < ov::op::v1::Divide > (input_0 ,input_1 ); 126if (use_f32_compute ) { 127// Keep the reciprocal/divide path in FP32. Without this hint, the GPU 128// plugin can still compress the subgraph back to FP16 and overflow on 129// small shexp gate values (e.g. silu(x) / x in qwen2moe). 130 ov::mark_as_precision_sensitive (res .get_node_shared_ptr ()-> input (0 )); 131 ov::mark_as_precision_sensitive (res .get_node_shared_ptr ()-> input (1 )); 132 } 133if (res .get_element_type ()!= output_type ) { 134auto output_convert = std::make_shared < ov::op::v0::Convert > (res ,output_type ); 135if (use_f32_compute ) { 136 ov::mark_as_precision_sensitive (output_convert -> input (0 )); 137 } 138res = output_convert ; 139 } 140return rename_outputs_with_suffix ({res },context .get_name ()); 141} 142 143}// namespace op 144}// namespace ggml 145}// namespace frontend 146}// namespace ov