#include "../node_context.h" #include "../op_table.h" #include "../utils.h" #include #include #include #include #include #include #include #include #include #include namespace ov { namespace frontend { namespace ggml { namespace op { static std::pair, ov::Output> get_glu_inputs(const NodeContext & context) { num_inputs_check(context, 1, 2); ov::Output src0; ov::Output src1; if (context.get_input_size() == 2) { // Inputs may be VIEW slices of a combined gate_up tensor (MoE experts): // resolve them so each half has its real sliced shape, not the base tensor. src0 = process_view_input_new(context, 0); src1 = process_view_input_new(context, 1); } else { // GGML splits along ne[0] (OV last axis) using floor division: nc = ne[0] / 2. // Both halves are nc elements; if the dimension is odd, the last element is dropped. // Use Slice instead of Split to handle odd dimensions correctly. // Resolve a VIEW input (e.g. non-contiguous slice) to its real shape first. auto combined = process_view_input_new(context, 0); auto combined_shape = combined.get_partial_shape(); int64_t last_dim_val = combined_shape[combined_shape.rank().get_length() - 1].get_length(); int64_t nc = last_dim_val / 2; auto axis = ov::op::v0::Constant::create(ov::element::i64, {1}, {-1}); auto step = ov::op::v0::Constant::create(ov::element::i64, {1}, {1}); auto start0 = ov::op::v0::Constant::create(ov::element::i64, {1}, {0}); auto stop0 = ov::op::v0::Constant::create(ov::element::i64, {1}, {nc}); auto start1 = ov::op::v0::Constant::create(ov::element::i64, {1}, {nc}); auto stop1 = ov::op::v0::Constant::create(ov::element::i64, {1}, {2 * nc}); src0 = std::make_shared(combined, start0, stop0, step, axis); src1 = std::make_shared(combined, start1, stop1, step, axis); } int32_t * params = context.get_output_op_params(); const int32_t swapped = params[1]; if (swapped) { std::swap(src0, src1); } return {src0, src1}; } OutputVector translate_glu_swiglu(const NodeContext & context) { auto [src0, src1] = get_glu_inputs(context); auto sigmoid = std::make_shared(src0); auto silu = std::make_shared(src0, sigmoid); auto res = std::make_shared(silu, src1); return rename_outputs_with_suffix({res}, context.get_name()); } OutputVector translate_glu_swiglu_oai(const NodeContext & context) { auto [src0, src1] = get_glu_inputs(context); const int32_t * params = context.get_output_op_params(); const float alpha = reinterpret_cast(params)[2]; const float limit = reinterpret_cast(params)[3]; auto gate = std::make_shared(src0, -std::numeric_limits::infinity(), limit); auto alpha_const = ov::op::v0::Constant::create(ov::element::f32, {}, {alpha}); auto scaled_gate = std::make_shared(gate, alpha_const); auto sigmoid = std::make_shared(scaled_gate); auto out_glu = std::make_shared(gate, sigmoid); auto up = std::make_shared(src1, -limit, limit); auto one = ov::op::v0::Constant::create(ov::element::f32, {}, {1.0f}); auto up_plus_one = std::make_shared(up, one); auto res = std::make_shared(out_glu, up_plus_one); return rename_outputs_with_suffix({res}, context.get_name()); } OutputVector translate_glu_swiglu_clamp(const NodeContext & context) { auto [src0, src1] = get_glu_inputs(context); const int32_t * params = context.get_output_op_params(); const float limit = reinterpret_cast(params)[3]; auto gate = std::make_shared(src0, -std::numeric_limits::infinity(), limit); auto sigmoid = std::make_shared(gate); auto silu = std::make_shared(gate, sigmoid); auto up = std::make_shared(src1, -limit, limit); auto res = std::make_shared(silu, up); return rename_outputs_with_suffix({res}, context.get_name()); } } // namespace op } // namespace ggml } // namespace frontend } // namespace ov