char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
511f9c137
char/aliceai-t5-moe
1#include "utils.h" 2 3#include "ggml-impl.h" 4 5#include <cmath> 6#include <cstddef> 7#include <ctime> 8#include <memory> 9#include <openvino/op/add.hpp> 10#include <openvino/op/clamp.hpp> 11#include <openvino/op/convert.hpp> 12#include <openvino/op/cos.hpp> 13#include <openvino/op/divide.hpp> 14#include <openvino/op/gather.hpp> 15#include <openvino/op/maximum.hpp> 16#include <openvino/op/multiply.hpp> 17#include <openvino/op/reshape.hpp> 18#include <openvino/op/shape_of.hpp> 19#include <openvino/op/sin.hpp> 20#include <openvino/op/slice.hpp> 21#include <openvino/op/split.hpp> 22#include <openvino/op/squeeze.hpp> 23#include <openvino/op/subtract.hpp> 24#include <openvino/op/transpose.hpp> 25#include <string> 26 27namespace ov { 28namespace frontend { 29namespace ggml { 30 31std::string getCurrentTime () { 32 std::time_t now = std::time (nullptr ); 33char buf [100 ]; 34 std::strftime (buf ,sizeof (buf ),"%Y-%m-%d %H:%M:%S" , std::localtime (& now )); 35return buf ; 36} 37 38void num_inputs_check (const NodeContext & context ,size_t min_inputs ,size_t max_inputs ) { 39auto input_size = context .get_input_size (); 40FRONT_END_OP_CONVERSION_CHECK (input_size >=min_inputs ,"Got less inputs than expected" ); 41FRONT_END_OP_CONVERSION_CHECK (input_size <=max_inputs ,"Got more inputs than expected" ); 42} 43 44int non_cont_dim (std::vector < size_t > ne , std::vector < size_t > nb ) { 45int dim = nb .size ()- 1 ; 46size_t bytes = nb [dim ]; 47for (int i = dim ;i > 0 ;i -- ) { 48bytes *=ne [i ]; 49if (bytes != nb [i - 1 ]) { 50return i ; 51 } 52 } 53return 0 ; 54} 55 56std::shared_ptr < ov::Node > get_dimensions (const std::shared_ptr < ov::op::v3::ShapeOf > & shape , 57const std::vector < int > & dims ) { 58using namespace ov::op ; 59const auto zero = v0::Constant ::create (ov::element::i32 , ov::Shape {}, {0 }); 60const auto dims_const = v0::Constant ::create (ov::element::i32 , ov::Shape {dims .size ()},dims ); 61return std::make_shared < v8::Gather > (shape ,dims_const ,zero ); 62} 63 64std::shared_ptr < ov::Node > get_dimensions (const std::shared_ptr < ov::Node > & node ,const std::vector < int > & dims ) { 65return get_dimensions (std::make_shared < ov::op::v3::ShapeOf > (node ),dims ); 66} 67 68OutputVector rename_outputs_with_suffix (const OutputVector & outputs ,const std::string & suffix ) { 69for (const auto & output :outputs ) { 70auto node = output .get_node_shared_ptr (); 71 std::string name = node -> get_friendly_name (); 72name += "_" ; 73name += suffix ; 74node -> set_friendly_name (name ); 75// Uncomment to dump every node's inferred shape (used to hunt down dynamic dims on NPU). 76// std::cout << name << " " << output.get_partial_shape() << std::endl; 77 } 78return outputs ; 79} 80 81namespace { 82ov::Output < ov::Node > rope_yarn_ramp_mix (int n_dims ,const float corr_dims [2 ],float ext_factor ) { 83int half_n_dims = n_dims /2 ; 84 std::vector < float > dim_ids_vec (half_n_dims ); 85 std::iota (dim_ids_vec .begin (),dim_ids_vec .end (),0 ); 86auto dim_ids = ov::op::v0::Constant ::create (ov::element::f32 ,Shape {1 ,1 ,1 , (size_t )half_n_dims },dim_ids_vec ); 87auto corr_low = ov::op::v0::Constant ::create (ov::element::f32 ,Shape {1 ,1 ,1 ,1 }, {corr_dims [0 ]}); 88auto corr_high = ov::op::v0::Constant ::create (ov::element::f32 ,Shape {1 ,1 ,1 ,1 }, {corr_dims [1 ]}); 89auto denom = std::make_shared < ov::op::v1::Maximum > ( 90 std::make_shared < ov::op::v1::Subtract > (corr_high ,corr_low ), 91 ov::op::v0::Constant ::create (ov::element::f32 ,Shape {1 ,1 ,1 ,1 }, {0.001f })); 92auto ramp_y = 93 std::make_shared < ov::op::v1::Divide > (std::make_shared < ov::op::v1::Subtract > (dim_ids ,corr_low ),denom ); 94auto ramp_clamped = std::make_shared < ov::op::v0::Clamp > (ramp_y ,0.0f ,1.0f ); 95// rope_yarn_ramp returns (1 - clamp(y)), so invert before scaling 96auto one = ov::op::v0::Constant ::create (ov::element::f32 ,Shape {1 ,1 ,1 ,1 }, {1.0f }); 97auto ramp_inverted = std::make_shared < ov::op::v1::Subtract > (one ,ramp_clamped ); 98auto ext_factor_node = ov::op::v0::Constant ::create (ov::element::f32 ,Shape {}, {ext_factor }); 99auto ramp_mix = std::make_shared < ov::op::v1::Multiply > (ramp_inverted ,ext_factor_node ); 100return ramp_mix ; 101} 102 103float ggml_rope_yarn_corr_dim (int n_dims ,int n_ctx_orig ,float n_rot ,float base ) { 104#ifndef M_PI 105# define M_PI 3.14159265358979323846 106#endif 107return n_dims * logf (n_ctx_orig / (n_rot * 2 * (float )M_PI )) / (2 * logf (base )); 108} 109 110void ggml_rope_yarn_corr_dims (int n_dims , 111int n_ctx_orig , 112float freq_base , 113float beta_fast , 114float beta_slow , 115float dims [2 ]) { 116float start = floorf (ggml_rope_yarn_corr_dim (n_dims ,n_ctx_orig ,beta_fast ,freq_base )); 117float end = ceilf (ggml_rope_yarn_corr_dim (n_dims ,n_ctx_orig ,beta_slow ,freq_base )); 118dims [0 ]= std::max (0.0f ,start ); 119dims [1 ]= std::min (static_cast < float > (n_dims - 1 ),end ); 120} 121}// namespace 122 123std::pair < ov::Output < Node > , ov::Output < Node >> make_sin_cos (int32_t * rope_params , 124 std::shared_ptr < ov::Node > inp_pos , 125 std::shared_ptr < ov::Node > rope_freqs_weight , 126bool imrope , 127bool stateful ) { 128if (stateful ) { 129inp_pos = 130 std::make_shared < ov::op::v0::Squeeze > (inp_pos , ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {0 })); 131inp_pos = std::make_shared < ov::op::v0::Convert > (inp_pos , ov::element::f32 ); 132auto pos_perm = 133 std::make_shared < ov::op::v0::Constant > (ov::element::i64 , ov::Shape {3 }, std::vector < int64_t > {2 ,1 ,0 }); 134inp_pos = std::make_shared < ov::op::v1::Transpose > (inp_pos ,pos_perm ); 135 }else if (imrope ) { 136inp_pos = std::make_shared < ov::op::v0::Convert > (inp_pos , ov::element::f32 ); 137auto pos_shape = ov::op::v0::Constant ::create (ov::element::i64 , ov::Shape {5 }, {0 ,0 ,0 ,4 ,-1 }); 138inp_pos = std::make_shared < ov::op::v1::Reshape > (inp_pos ,pos_shape , true); 139auto pos_transpose_shape = 140 std::make_shared < ov::op::v0::Constant > (ov::element::i64 , ov::Shape {5 }, std::vector < int64_t > {0 ,1 ,2 ,4 ,3 }); 141inp_pos = std::make_shared < ov::op::v1::Transpose > (inp_pos ,pos_transpose_shape ); 142 }else { 143inp_pos = std::make_shared < ov::op::v0::Convert > (inp_pos , ov::element::f32 ); 144auto pos_perm = 145 std::make_shared < ov::op::v0::Constant > (ov::element::i64 , ov::Shape {4 }, std::vector < int64_t > {0 ,3 ,1 ,2 }); 146inp_pos = std::make_shared < ov::op::v1::Transpose > (inp_pos ,pos_perm ); 147 } 148 149float freq_base ; 150float freq_scale ; 151float ext_factor ; 152float attn_factor ; 153float beta_fast ; 154float beta_slow ; 155const int n_dims = rope_params [1 ]; 156const size_t n_dims_half = n_dims >>1 ; 157const int n_ctx_orig = rope_params [4 ]; 158memcpy (& freq_base ,rope_params + 5 ,sizeof (float )); 159memcpy (& freq_scale ,rope_params + 6 ,sizeof (float )); 160memcpy (& ext_factor ,rope_params + 7 ,sizeof (float )); 161memcpy (& attn_factor ,rope_params + 8 ,sizeof (float )); 162memcpy (& beta_fast ,rope_params + 9 ,sizeof (float )); 163memcpy (& beta_slow ,rope_params + 10 ,sizeof (float )); 164 165const float theta_scale = powf (freq_base ,-2.0f /n_dims ); 166 167 std::vector < float > factor (n_dims_half ); 168 169Output < Node > freq_factors ; 170 171Output < Node > theta ; 172float mscale = attn_factor ; 173if (imrope ) { 174 std::vector < int64_t > gather_indices (n_dims_half ); 175for (size_t j = 0 ;j < n_dims_half ;j ++ ) { 176gather_indices [j ]= j %3 ; 177factor [j ]= std::pow (theta_scale ,j ); 178 } 179auto gather_indices_const = 180 std::make_shared < ov::op::v0::Constant > (ov::element::i64 , ov::Shape {n_dims_half },gather_indices ); 181auto gather_axis = ov::op::v0::Constant ::create (ov::element::i32 , ov::Shape {}, {4 }); 182inp_pos = std::make_shared < ov::op::v8::Gather > (inp_pos ,gather_indices_const ,gather_axis ); 183auto factor_const = std::make_shared < ov::op::v0::Constant > (ov::element::f32 , ov::Shape {n_dims_half },factor ); 184theta = std::make_shared < ov::op::v1::Multiply > (inp_pos ,factor_const ); 185 }else { 186float corr_dims [2 ]; 187ggml_rope_yarn_corr_dims (n_dims ,n_ctx_orig ,freq_base ,beta_fast ,beta_slow ,corr_dims ); 188factor [0 ]= 1.0f ; 189for (size_t i = 1 ;i < factor .size ();i ++ ) { 190factor [i ]= theta_scale * factor [i - 1 ]; 191 } 192if (stateful ) { 193freq_factors = 194 std::make_shared < ov::op::v0::Constant > (ov::element::f32 , ov::Shape {1 ,1 ,factor .size ()},factor ); 195 }else { 196freq_factors = 197 std::make_shared < ov::op::v0::Constant > (ov::element::f32 , ov::Shape {1 ,1 ,1 ,factor .size ()},factor ); 198 } 199if (rope_freqs_weight ) { 200Output < Node > rope_factors = std::make_shared < ov::op::v8::Slice > ( 201rope_freqs_weight , 202 ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {0 }), 203 ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {(int64_t )n_dims_half }), 204 ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {1 }), 205 ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {rope_freqs_weight -> get_output_partial_shape (0 ).rank ().get_length ()- 1 })); 206if (stateful ) { 207rope_factors = std::make_shared < ov::op::v1::Reshape > ( 208rope_factors , 209 ov::op::v0::Constant ::create (ov::element::i64 , {3 }, {(int64_t )1 , (int64_t )1 , (int64_t )n_dims_half }), 210 false); 211 }else { 212rope_factors = std::make_shared < ov::op::v1::Reshape > ( 213rope_factors , 214 ov::op::v0::Constant ::create (ov::element::i64 , {4 }, {(int64_t )1 , (int64_t )1 , (int64_t )1 , (int64_t )n_dims_half }), 215 false); 216 } 217freq_factors = std::make_shared < ov::op::v1::Divide > (freq_factors ,rope_factors ); 218 } 219 220auto theta_extrap = std::make_shared < ov::op::v1::Multiply > (freq_factors ,inp_pos ); 221auto theta_interp = std::make_shared < ov::op::v1::Multiply > ( 222theta_extrap , ov::op::v0::Constant ::create (ov::element::f32 , {1 }, {freq_scale })); 223 224if (ext_factor == 0.0f ) { 225theta = theta_interp ; 226 }else { 227auto ramp_mix = rope_yarn_ramp_mix (n_dims ,corr_dims ,ext_factor ); 228Output < Node > one ; 229if (stateful ) { 230one = ov::op::v0::Constant ::create (ov::element::f32 ,Shape {1 ,1 ,1 }, {1.0f }); 231 }else { 232one = ov::op::v0::Constant ::create (ov::element::f32 ,Shape {1 ,1 ,1 ,1 }, {1.0f }); 233 } 234auto one_minus_ramp = std::make_shared < ov::op::v1::Subtract > (one ,ramp_mix ); 235 236theta = 237 std::make_shared < ov::op::v1::Add > (std::make_shared < ov::op::v1::Multiply > (theta_interp ,one_minus_ramp ), 238 std::make_shared < ov::op::v1::Multiply > (theta_extrap ,ramp_mix )); 239mscale *= (1.0f + 0.1f * std::log (1.0f /freq_scale )); 240 } 241 } 242 243Output < Node > cos_theta = std::make_shared < ov::op::v0::Cos > (theta ); 244Output < Node > sin_theta = std::make_shared < ov::op::v0::Sin > (theta ); 245 246if (!imrope ) { 247auto mscale_node = ov::op::v0::Constant ::create (ov::element::f32 ,Shape {}, {mscale }); 248 249cos_theta = std::make_shared < ov::op::v1::Multiply > (cos_theta ,mscale_node ); 250sin_theta = std::make_shared < ov::op::v1::Multiply > (sin_theta ,mscale_node ); 251 } 252 253return std::make_pair (sin_theta ,cos_theta ); 254} 255 256ov::Output < ov::Node > process_view_input (const NodeContext & context ,int input_index ,int slice_len ,int axis ) { 257// Only works for VIEW operations that does a non-strided slice with optinal reshape on the slice result. 258// The function only does the slice part, the reshape (if any) should be handled by the caller. 259// Default axis is -1, which means slicing the last dimension. 260// If the VIEW reshapes the result, `slice_len` should be provided 261auto input = context .get_input (input_index ); 262auto * op_params = (size_t * )context .get_input_op_params (input_index ); 263auto src_stride = context .get_input_stride (input_index ); 264 265int64_t slice_start = op_params [0 ] /src_stride [3 ]; 266if (slice_len == 0 ) { 267slice_len = context .get_input_shape (input_index )[3 ].get_length (); 268 } 269int64_t slice_end = slice_start + slice_len ; 270 271auto begin = ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {slice_start }); 272auto end = ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {slice_end }); 273auto stride = ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {1 }); 274 ov::Output < ov::Node > axes ; 275if (axis == -1 ) { 276axes = ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {context .is_stateful () ?2 :3 }); 277 }else { 278axes = ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {axis }); 279 } 280auto sliced = std::make_shared < ov::op::v8::Slice > (input ,begin ,end ,stride ,axes ); 281return sliced ; 282} 283 284ov::Output < ov::Node > process_view_input_new (const NodeContext & context ,int input_index ) { 285auto input = context .get_input (input_index ); 286 287// Check if this input has view inputs 288size_t view_input_size = context .get_view_input_size (input_index ); 289if (view_input_size == 0 ) { 290// No view inputs, return the input as is 291return input ; 292 } 293 294// If translate_view already resolved this VIEW (produced a Slice), the input 295// will already have the expected shape — skip re-slicing. 296// 297// Two notions of "matches" are accepted per axis: 298// - both dims static and equal, OR 299// - both dims dynamic. 300// The dynamic case matters for the MoE expert-plane views: translate_view now emits a 301// DYNAMIC-token slice (so the token dim is not frozen). An all-static-only check would 302// see the dynamic token dim, decide the shapes "don't match", and fall through to 303// re-slice/flatten the already-resolved view (a Reshape to the full flattened 304// n_expert_used*n_embd tail, which then conflicts with the single-plane input). Treat a 305// dynamic-vs-dynamic axis as matching so the already-resolved view is reused as-is. 306// 307// A third case matters for split-model MoE fragments: translate_view resolves the 308// expert-plane view against the fragment's INPUT parameter. When the graph is split 309// the token axis of that parameter may already be concrete (static n_tokens) even 310// though get_view_input_ov_shape() still reports it as dynamic (-1). The resolved 311// view is then static [1,1,n_tokens,n_embd] while `expected` is [1,1,?,n_embd]. 312// An "expected dynamic, actual static" axis is a valid concretization of the SAME 313// resolved view, so treat it as matching too. Falling through to process_single_view 314// here would re-slice/re-flatten the already-resolved single-plane view against the 315// recorded (multi-plane) source strides and emit a constant-target Reshape whose baked 316// dims no longer divide the concretized input -> "dimensions do not evenly divide". 317auto expected_ov_shape = context .get_view_input_ov_shape (input_index ,0 ); 318auto actual_shape = input .get_partial_shape (); 319if (expected_ov_shape .rank ().is_static ()&& actual_shape .rank ().is_static ()&& 320expected_ov_shape .rank ()== actual_shape .rank ()) { 321bool shapes_match = true; 322for (int64_t i = 0 ;i < expected_ov_shape .rank ().get_length ();++ i ) { 323const bool both_dynamic = expected_ov_shape [i ].is_dynamic ()&& actual_shape [i ].is_dynamic (); 324const bool both_static_equal = expected_ov_shape [i ].is_static ()&& actual_shape [i ].is_static ()&& 325expected_ov_shape [i ]== actual_shape [i ]; 326// expected dynamic, actual static: the resolved view already carries the 327// concrete size for this fragment; reuse it rather than re-materializing. 328const bool expected_dyn_actual_static = expected_ov_shape [i ].is_dynamic ()&& actual_shape [i ].is_static (); 329if (!both_dynamic && !both_static_equal && !expected_dyn_actual_static ) { 330shapes_match = false; 331break ; 332 } 333 } 334if (shapes_match ) { 335return input ; 336 } 337 } 338 339// In static mode, use Split instead of Slice for single-dimension reductions. 340// This ensures NPUW's FOLD doesn't parametrize per-layer slice indices (which 341// would introduce dynamic shapes). A shared Split node sits outside the repeated 342// subgraph boundary; each layer receives one of its output ports. 343if (context .is_static ()&& view_input_size == 1 ) { 344auto view_stride_v = context .get_view_input_stride (input_index ,0 ); 345auto view_src_stride_v = context .get_view_input_src_stride (input_index ,0 ); 346auto view_ggml_shape = context .get_view_input_ggml_shape (input_index ,0 ); 347auto view_src_ggml_shape = context .get_view_input_src_ggml_shape (input_index ,0 ); 348auto view_offset = context .get_view_input_offset (input_index ,0 ); 349auto view_src_offset = context .get_view_input_src_offset (input_index ,0 ); 350 351size_t ndims = view_ggml_shape .size (); 352 std::vector < int > diff_dims ; 353if (view_src_ggml_shape .size ()== ndims ) { 354for (size_t i = 0 ;i < ndims ;++ i ) { 355if (view_ggml_shape [i ]!= view_src_ggml_shape [i ]) { 356diff_dims .push_back (static_cast < int > (i )); 357 } 358 } 359 } 360 361if (diff_dims .size ()== 1 ) { 362int split_dim = diff_dims [0 ]; 363int64_t num_splits = static_cast < int64_t > (view_src_ggml_shape [split_dim ]); 364int64_t chunk_size = static_cast < int64_t > (view_ggml_shape [split_dim ]); 365 366// Only apply when slicing exactly 1 element from a multi-element dimension 367if (chunk_size == 1 && num_splits > 1 ) { 368// Check suffix strides match (dimensions after split_dim) 369bool suffix_ok = view_stride_v .size ()== view_src_stride_v .size (); 370if (suffix_ok ) { 371for (size_t i = static_cast < size_t > (split_dim )+ 1 ;i < ndims ;++ i ) { 372if (view_stride_v [i ]!= view_src_stride_v [i ]) { 373suffix_ok = false; 374break ; 375 } 376 } 377 } 378 379if (suffix_ok && view_src_stride_v [split_dim ]> 0 ) { 380size_t relative_offset = view_offset >=view_src_offset ?view_offset - view_src_offset :0 ; 381int64_t split_index = static_cast < int64_t > (relative_offset /view_src_stride_v [split_dim ]); 382 383if (split_index >=0 && split_index < num_splits ) { 384auto src_node = input .get_node_shared_ptr (); 385 std::string rt_key = "split_dim_" + std::to_string (split_dim ); 386auto & rt_info = src_node -> get_rt_info (); 387 388if (rt_info .find (rt_key )== rt_info .end ()) { 389auto axis_const = 390 ov::op::v0::Constant ::create (ov::element::i64 , {}, {static_cast < int64_t > (split_dim )}); 391auto split_node = 392 std::make_shared < ov::op::v1::Split > (input ,axis_const ,static_cast < size_t > (num_splits )); 393split_node -> set_friendly_name (src_node -> get_friendly_name ()+ "_split" ); 394rt_info [rt_key ]= split_node ; 395 } 396 397auto split_node = rt_info [rt_key ].as < std::shared_ptr < ov::op::v1::Split >> (); 398return split_node -> output (static_cast < size_t > (split_index )); 399 } 400 } 401 } 402 } 403 } 404 405// Lambda function to process a single view operation 406auto process_single_view = 407 [](ov::Output < ov::Node > current ,size_t view_offset ,const std::vector < size_t > & view_stride , 408const ov::Shape & view_ggml_shape ,const ov::PartialShape & view_ov_shape ,const std::string & view_name , 409size_t view_src_offset ,const std::vector < size_t > & view_src_stride ,const ov::Shape & view_src_ggml_shape , 410const ov::PartialShape & view_src_ov_shape ,const std::string & view_src_name )-> ov::Output < ov::Node > { 411auto build_reshape_pattern = [](const ov::PartialShape & target_ov_shape , 412const ov::Shape & target_ggml_shape )-> std::vector < int64_t > { 413const size_t ndims = target_ggml_shape .size (); 414 std::vector < int64_t > reshape_pattern (ndims ); 415size_t dynamic_dims = 0 ; 416 417if (target_ov_shape .rank ().is_static ()&& 418target_ov_shape .rank ().get_length ()== static_cast < int64_t > (ndims )) { 419for (size_t i = 0 ;i < ndims ;++ i ) { 420if (target_ov_shape [i ].is_static ()) { 421reshape_pattern [i ]= target_ov_shape [i ].get_length (); 422 }else { 423reshape_pattern [i ]= -1 ; 424++ dynamic_dims ; 425 } 426 } 427 }else { 428dynamic_dims = 2 ; 429 } 430 431if (dynamic_dims > 1 ) { 432for (size_t i = 0 ;i < ndims ;++ i ) { 433reshape_pattern [i ]= static_cast < int64_t > (target_ggml_shape [i ]); 434 } 435 } 436 437return reshape_pattern ; 438 }; 439 440auto build_prefix_tail_reshape_pattern = [](const ov::PartialShape & target_ov_shape , 441const ov::Shape & target_ggml_shape ,size_t prefix_dims , 442int64_t tail_dim )-> std::vector < int64_t > { 443 std::vector < int64_t > reshape_pattern (prefix_dims + 1 ); 444size_t dynamic_dims = 0 ; 445 446if (target_ov_shape .rank ().is_static ()&& 447target_ov_shape .rank ().get_length ()== static_cast < int64_t > (target_ggml_shape .size ())) { 448for (size_t i = 0 ;i < prefix_dims ;++ i ) { 449if (target_ov_shape [i ].is_static ()) { 450reshape_pattern [i ]= target_ov_shape [i ].get_length (); 451 }else { 452reshape_pattern [i ]= -1 ; 453++ dynamic_dims ; 454 } 455 } 456 }else { 457dynamic_dims = 2 ; 458 } 459 460if (dynamic_dims > 1 ) { 461for (size_t i = 0 ;i < prefix_dims ;++ i ) { 462reshape_pattern [i ]= static_cast < int64_t > (target_ggml_shape [i ]); 463 } 464 } 465 466reshape_pattern [prefix_dims ]= tail_dim ; 467return reshape_pattern ; 468 }; 469 470bool same_stride = view_stride .size ()== view_src_stride .size (); 471if (same_stride ) { 472for (size_t i = 0 ;i < view_stride .size ();++ i ) { 473if (view_stride [i ]!= view_src_stride [i ]) { 474same_stride = false; 475break ; 476 } 477 } 478 } 479 480bool same_ggml_shape = view_ggml_shape .size ()== view_src_ggml_shape .size (); 481if (same_ggml_shape ) { 482for (size_t i = 0 ;i < view_ggml_shape .size ();++ i ) { 483if (view_ggml_shape [i ]!= view_src_ggml_shape [i ]) { 484same_ggml_shape = false; 485break ; 486 } 487 } 488 } 489 490if (same_stride && same_ggml_shape ) { 491return current ; 492 } 493 494if (same_stride ) { 495const size_t relative_offset = view_offset >=view_src_offset ?view_offset - view_src_offset :0 ; 496const size_t ndims = view_stride .size (); 497 498 std::vector < int > diff_dims ; 499if (view_ggml_shape .size ()== ndims && view_src_ggml_shape .size ()== ndims ) { 500for (size_t i = 0 ;i < ndims ;++ i ) { 501if (view_ggml_shape [i ]!= view_src_ggml_shape [i ]) { 502diff_dims .push_back (static_cast < int > (i )); 503 } 504 } 505 } 506 507if (diff_dims .size ()== 1 ) { 508const int slice_dim = diff_dims [0 ]; 509const int64_t dim_size = static_cast < int64_t > (view_src_ggml_shape [slice_dim ]); 510 511if (view_stride [slice_dim ]> 0 && relative_offset %view_stride [slice_dim ]== 0 ) { 512const int64_t begin_val = static_cast < int64_t > ((relative_offset /view_stride [slice_dim ]) % 513static_cast < size_t > (dim_size )); 514const int64_t end_val = begin_val + static_cast < int64_t > (view_ggml_shape [slice_dim ]); 515 516if (begin_val >=0 && end_val <=dim_size ) { 517auto sliced = std::make_shared < ov::op::v8::Slice > ( 518current , ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {begin_val }), 519 ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {end_val }), 520 ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {1 }), 521 ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {slice_dim })); 522 523if (view_ov_shape .is_static ()) { 524auto reshaped = std::make_shared < ov::op::v1::Reshape > ( 525sliced , 526 ov::op::v0::Constant ::create (ov::element::i64 , {ndims },view_ov_shape .to_shape ()), 527 false); 528reshaped -> set_friendly_name (view_name ); 529return reshaped ; 530 } 531 532sliced -> set_friendly_name (view_name ); 533return sliced ; 534 } 535 } 536 537int64_t tail_src_elems = 1 ; 538int64_t tail_dst_elems = 1 ; 539for (size_t i = slice_dim ;i < ndims ;++ i ) { 540tail_src_elems *=static_cast < int64_t > (view_src_ggml_shape [i ]); 541tail_dst_elems *=static_cast < int64_t > (view_ggml_shape [i ]); 542 } 543 544const size_t elem_stride = view_stride [ndims - 1 ]; 545int64_t tail_begin = 0 ; 546if (elem_stride > 0 ) { 547tail_begin = 548static_cast < int64_t > ((relative_offset /elem_stride ) %static_cast < size_t > (tail_src_elems )); 549 } 550const int64_t tail_end = tail_begin + tail_dst_elems ; 551 552if (tail_begin >=0 && tail_end <=tail_src_elems ) { 553 std::vector < int64_t > flat_shape ; 554for (int i = 0 ;i < slice_dim ;++ i ) { 555flat_shape .push_back (static_cast < int64_t > (view_src_ggml_shape [i ])); 556 } 557flat_shape .push_back (tail_src_elems ); 558const size_t flat_ndims = flat_shape .size (); 559 560auto flat = std::make_shared < ov::op::v1::Reshape > ( 561current , ov::op::v0::Constant ::create (ov::element::i64 , {flat_ndims },flat_shape ), false); 562 563auto sliced = std::make_shared < ov::op::v8::Slice > ( 564flat , ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {tail_begin }), 565 ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {tail_end }), 566 ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {1 }), 567 ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {slice_dim })); 568 569if (view_ov_shape .is_static ()) { 570auto reshaped = std::make_shared < ov::op::v1::Reshape > ( 571sliced , ov::op::v0::Constant ::create (ov::element::i64 , {ndims },view_ov_shape .to_shape ()), 572 false); 573reshaped -> set_friendly_name (view_name ); 574return reshaped ; 575 } 576 577sliced -> set_friendly_name (view_name ); 578return sliced ; 579 } 580 } 581 582 std::vector < int64_t > begin (ndims ,0 ); 583 std::vector < int64_t > end (ndims ,0 ); 584 std::vector < int64_t > step (ndims ,1 ); 585 std::vector < int64_t > axes (ndims ,0 ); 586 587size_t remaining_offset = relative_offset ; 588for (size_t i = 0 ;i < ndims ;++ i ) { 589axes [i ]= static_cast < int64_t > (i ); 590if (view_stride [i ]> 0 ) { 591begin [i ]= static_cast < int64_t > (remaining_offset /view_stride [i ]); 592remaining_offset %=view_stride [i ]; 593 } 594end [i ]= begin [i ]+ static_cast < int64_t > (view_ggml_shape [i ]); 595 } 596 597bool in_bounds = view_src_ggml_shape .size ()== ndims && view_ggml_shape .size ()== ndims ; 598if (in_bounds ) { 599for (size_t i = 0 ;i < ndims ;++ i ) { 600if (end [i ]> static_cast < int64_t > (view_src_ggml_shape [i ])) { 601in_bounds = false; 602break ; 603 } 604 } 605 } 606 607if (in_bounds && remaining_offset == 0 ) { 608auto sliced = std::make_shared < ov::op::v8::Slice > ( 609current , ov::op::v0::Constant ::create (ov::element::i64 , {ndims },begin ), 610 ov::op::v0::Constant ::create (ov::element::i64 , {ndims },end ), 611 ov::op::v0::Constant ::create (ov::element::i64 , {ndims },step ), 612 ov::op::v0::Constant ::create (ov::element::i64 , {ndims },axes )); 613 614sliced -> set_friendly_name (view_name ); 615return sliced ; 616 } 617 }else { 618bool same_rank = view_stride .size ()== view_src_stride .size ()&& 619view_ggml_shape .size ()== view_src_ggml_shape .size ()&& 620view_stride .size ()== view_ggml_shape .size (); 621const size_t relative_offset = view_offset >=view_src_offset ?view_offset - view_src_offset :0 ; 622 623if (same_rank ) { 624const size_t ndims = view_ggml_shape .size (); 625 std::vector < int > diff_dims ; 626for (size_t i = 0 ;i < ndims ;++ i ) { 627if (view_ggml_shape [i ]!= view_src_ggml_shape [i ]) { 628diff_dims .push_back (static_cast < int > (i )); 629 } 630 } 631 632if (diff_dims .size ()== 1 ) { 633const size_t slice_dim = static_cast < size_t > (diff_dims [0 ]); 634bool suffix_stride_match = true; 635for (size_t i = slice_dim + 1 ;i < ndims ;++ i ) { 636if (view_stride [i ]!= view_src_stride [i ]) { 637suffix_stride_match = false; 638break ; 639 } 640 } 641 642if (suffix_stride_match && view_src_stride [slice_dim ]> 0 && 643relative_offset %view_src_stride [slice_dim ]== 0 ) { 644const int64_t begin_val = static_cast < int64_t > (relative_offset /view_src_stride [slice_dim ]); 645const int64_t end_val = begin_val + static_cast < int64_t > (view_ggml_shape [slice_dim ]); 646const int64_t dim_size = static_cast < int64_t > (view_src_ggml_shape [slice_dim ]); 647 648if (begin_val >=0 && end_val <=dim_size ) { 649auto sliced = std::make_shared < ov::op::v8::Slice > ( 650current , ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {begin_val }), 651 ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {end_val }), 652 ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {1 }), 653 ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {static_cast < int64_t > (slice_dim )})); 654sliced -> set_friendly_name (view_name ); 655return sliced ; 656 } 657 } 658 } 659 } 660 661size_t view_elems = 1 ; 662size_t src_elems = 1 ; 663if (same_rank ) { 664for (size_t i = 0 ;i < view_ggml_shape .size ();++ i ) { 665view_elems *=view_ggml_shape [i ]; 666src_elems *=view_src_ggml_shape [i ]; 667 } 668 } 669 670bool same_num_elements = same_rank && view_elems == src_elems ; 671 672if (same_rank && relative_offset == 0 && same_num_elements ) { 673auto reshape_pattern = build_reshape_pattern (view_ov_shape ,view_ggml_shape ); 674 675auto reshaped = std::make_shared < ov::op::v1::Reshape > ( 676current , ov::op::v0::Constant ::create (ov::element::i64 , {reshape_pattern .size ()},reshape_pattern ), 677 false); 678reshaped -> set_friendly_name (view_name ); 679return reshaped ; 680 } 681 682if (same_rank ) { 683const size_t ndims = view_ggml_shape .size (); 684 685// Match views that can be expressed as a regular strided slice over the 686// already reconstructed source tensor, e.g. offset on one axis plus step > 1 687// on another axis. 688bool is_regular_slice = view_src_ggml_shape .size ()== ndims ; 689 std::vector < int64_t > begin (ndims ,0 ); 690 std::vector < int64_t > end (ndims ,0 ); 691 std::vector < int64_t > step (ndims ,1 ); 692 std::vector < int64_t > axes (ndims ,0 ); 693size_t remaining_offset = relative_offset ; 694 695if (is_regular_slice ) { 696for (size_t i = 0 ;i < ndims ;++ i ) { 697axes [i ]= static_cast < int64_t > (i ); 698 699if (view_src_stride [i ]== 0 || view_stride [i ]== 0 || 700view_stride [i ] %view_src_stride [i ]!= 0 ) { 701is_regular_slice = false; 702break ; 703 } 704 705step [i ]= static_cast < int64_t > (view_stride [i ] /view_src_stride [i ]); 706if (step [i ] <=0 ) { 707is_regular_slice = false; 708break ; 709 } 710 711begin [i ]= static_cast < int64_t > (remaining_offset /view_src_stride [i ]); 712remaining_offset %=view_src_stride [i ]; 713 714if (view_ggml_shape [i ]== 0 ) { 715end [i ]= begin [i ]; 716continue ; 717 } 718 719end [i ]= begin [i ]+ step [i ]* static_cast < int64_t > (view_ggml_shape [i ]- 1 )+ 1 ; 720 721if (begin [i ]< 0 || end [i ]> static_cast < int64_t > (view_src_ggml_shape [i ])) { 722is_regular_slice = false; 723break ; 724 } 725 } 726 } 727 728if (is_regular_slice && remaining_offset == 0 ) { 729auto sliced = std::make_shared < ov::op::v8::Slice > ( 730current , ov::op::v0::Constant ::create (ov::element::i64 , {ndims },begin ), 731 ov::op::v0::Constant ::create (ov::element::i64 , {ndims },end ), 732 ov::op::v0::Constant ::create (ov::element::i64 , {ndims },step ), 733 ov::op::v0::Constant ::create (ov::element::i64 , {ndims },axes )); 734 735sliced -> set_friendly_name (view_name ); 736return sliced ; 737 } 738 739const size_t elem_stride = view_src_stride .back (); 740const bool aligned_offset = elem_stride > 0 && relative_offset %elem_stride == 0 ; 741 742if (aligned_offset ) { 743size_t suffix_start = 0 ; 744size_t expected_stride = elem_stride ; 745for (int i = static_cast < int > (ndims )- 1 ;i >=0 ;-- i ) { 746if (view_stride [i ]!= expected_stride ) { 747suffix_start = static_cast < size_t > (i + 1 ); 748break ; 749 } 750expected_stride *=view_ggml_shape [i ]; 751 } 752 753size_t prefix_elems = 1 ; 754size_t suffix_elems = 1 ; 755for (size_t i = 0 ;i < suffix_start ;++ i ) { 756prefix_elems *=view_ggml_shape [i ]; 757 } 758for (size_t i = suffix_start ;i < ndims ;++ i ) { 759suffix_elems *=view_ggml_shape [i ]; 760 } 761 762if (prefix_elems > 0 && src_elems %prefix_elems == 0 ) { 763const size_t src_tail_elems = src_elems /prefix_elems ; 764const int64_t tail_begin = static_cast < int64_t > (relative_offset /elem_stride ); 765const int64_t tail_end = tail_begin + static_cast < int64_t > (suffix_elems ); 766 767if (tail_begin >=0 && tail_end <=static_cast < int64_t > (src_tail_elems )) { 768auto prefix_tail_pattern = build_prefix_tail_reshape_pattern ( 769view_ov_shape ,view_ggml_shape ,suffix_start ,static_cast < int64_t > (src_tail_elems )); 770 771auto prefix_tail = std::make_shared < ov::op::v1::Reshape > ( 772current , 773 ov::op::v0::Constant ::create (ov::element::i64 , {prefix_tail_pattern .size ()}, 774prefix_tail_pattern ), 775 false); 776 777 ov::Output < ov::Node > selected = prefix_tail ; 778if (tail_begin != 0 || tail_end != static_cast < int64_t > (src_tail_elems )) { 779selected = std::make_shared < ov::op::v8::Slice > ( 780prefix_tail , ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {tail_begin }), 781 ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {tail_end }), 782 ov::op::v0::Constant ::create (ov::element::i64 , {1 }, {1 }), 783 ov::op::v0::Constant ::create (ov::element::i64 , {1 }, 784 {static_cast < int64_t > (suffix_start )})); 785 } 786 787auto reshape_pattern = build_reshape_pattern (view_ov_shape ,view_ggml_shape ); 788auto reshaped = std::make_shared < ov::op::v1::Reshape > ( 789selected , 790 ov::op::v0::Constant ::create (ov::element::i64 , {reshape_pattern .size ()}, 791reshape_pattern ), 792 false); 793reshaped -> set_friendly_name (view_name ); 794return reshaped ; 795 } 796 } 797 } 798 } 799 800return current ; 801 } 802 803 (void )view_name ; 804 (void )view_src_ov_shape ; 805 (void )view_src_name ; 806 807return current ; 808 }; 809 810// Special case: ggml collapses VIEW-of-VIEW chains so that `view_offs` is always an 811// ABSOLUTE offset from the true root allocation, regardless of how many VIEW levels 812// are in between (see ggml_new_tensor_impl). `src[0]` is still the immediate op-graph 813// parent though, which can be a DIFFERENT (already narrowed) VIEW with the SAME ggml 814// shape as this one but a different absolute offset -- e.g. a per-layer deepstack 815// slice `view_2d(embd, n_embd, n_tokens, embd->nb[1], layer*n_embd*sizeof(float))` 816// whose src[0] ("embd") is itself already a zero-offset VIEW of the true root (the 817// padded embedding). Chaining through "embd" here would try to re-slice an already 818// 2-narrowed tensor using a root-relative offset, going out of bounds and silently 819// falling back to a no-op (returning the wrong, already-resolved sibling slice). 820// Detect this (same shape as the immediate src, but different absolute offset) and 821// re-slice directly from the untouched root using the innermost view's absolute 822// offset against the ROOT's own shape/stride instead of chaining through src[0]. 823 { 824auto innermost_offset = context .get_view_input_offset (input_index ,0 ); 825auto innermost_src_offset = context .get_view_input_src_offset (input_index ,0 ); 826auto innermost_shape = context .get_view_input_ggml_shape (input_index ,0 ); 827auto innermost_src_shape = context .get_view_input_src_ggml_shape (input_index ,0 ); 828if (innermost_offset != innermost_src_offset && innermost_shape == innermost_src_shape ) { 829size_t root_view_idx = view_input_size - 1 ; 830auto root_ggml_shape = context .get_view_input_src_ggml_shape (input_index ,root_view_idx ); 831auto root_stride = context .get_view_input_src_stride (input_index ,root_view_idx ); 832auto root_offset = context .get_view_input_src_offset (input_index ,root_view_idx ); 833auto root_ov_shape = context .get_view_input_src_ov_shape (input_index ,root_view_idx ); 834auto root_name = context .get_view_input_src_name (input_index ,root_view_idx ); 835auto innermost_stride = context .get_view_input_stride (input_index ,0 ); 836auto innermost_ov_shape = context .get_view_input_ov_shape (input_index ,0 ); 837auto innermost_name = context .get_view_input_name (input_index ,0 ); 838 839return process_single_view (input ,innermost_offset ,innermost_stride ,innermost_shape ,innermost_ov_shape , 840innermost_name ,root_offset ,root_stride ,root_ggml_shape ,root_ov_shape , 841root_name ); 842 } 843 } 844 845// Process views from the base tensor (last) to the current view (first) 846// Start with the base tensor 847 ov::Output < ov::Node > current = input ; 848 849// Process each view in reverse order (from base to current) 850for (int view_idx = view_input_size - 1 ;view_idx >=0 ;view_idx -- ) { 851auto view_offset = context .get_view_input_offset (input_index ,view_idx ); 852auto view_stride = context .get_view_input_stride (input_index ,view_idx ); 853auto view_ggml_shape = context .get_view_input_ggml_shape (input_index ,view_idx ); 854auto view_ov_shape = context .get_view_input_ov_shape (input_index ,view_idx ); 855auto view_name = context .get_view_input_name (input_index ,view_idx ); 856 857// print view info 858// std::cout << "View " << view_idx << ": name = " << view_name << ", offset = " << view_offset << ", stride = [" 859// << view_stride[0] << "," << view_stride[1] << "," << view_stride[2] << "," << view_stride[3] 860// << "], ggml shape = [" << view_ggml_shape[0] << "," << view_ggml_shape[1] << "," 861// << view_ggml_shape[2] << "," << view_ggml_shape[3] << "], ov shape = " << view_ov_shape << std::endl; 862 863auto view_src_offset = context .get_view_input_src_offset (input_index ,view_idx ); 864auto view_src_stride = context .get_view_input_src_stride (input_index ,view_idx ); 865auto view_src_ggml_shape = context .get_view_input_src_ggml_shape (input_index ,view_idx ); 866auto view_src_ov_shape = context .get_view_input_src_ov_shape (input_index ,view_idx ); 867auto view_src_name = context .get_view_input_src_name (input_index ,view_idx ); 868// print source view info 869// std::cout << "View " << view_idx << ": source name = " << view_src_name 870// << ", source offset = " << view_src_offset << ", source stride = [" << view_src_stride[0] << "," 871// << view_src_stride[1] << "," << view_src_stride[2] << "," << view_src_stride[3] 872// << "], source ggml shape = [" << view_src_ggml_shape[0] << "," << view_src_ggml_shape[1] << "," 873// << view_src_ggml_shape[2] << "," << view_src_ggml_shape[3] 874// << "], source ov shape = " << view_src_ov_shape << std::endl; 875 876current = process_single_view (current ,view_offset ,view_stride ,view_ggml_shape ,view_ov_shape ,view_name , 877view_src_offset ,view_src_stride ,view_src_ggml_shape ,view_src_ov_shape , 878view_src_name ); 879 } 880 881return current ; 882} 883 884}// namespace ggml 885}// namespace frontend 886}// namespace ov