#include "../node_context.h" #include "../op_table.h" #include "../utils.h" #include "ggml-impl.h" #include #include #include #include #include #include #include #include #include #include #include namespace ov { namespace frontend { namespace ggml { namespace op { OutputVector translate_im2col(const NodeContext & context) { num_inputs_check(context, 2, 2); const int32_t * params = context.get_output_op_params(); int32_t s0 = params[0]; int32_t s1 = params[1]; int32_t p0 = params[2]; int32_t p1 = params[3]; int32_t d0 = params[4]; int32_t d1 = params[5]; bool is_2D = params[6] == 1; ov::Output res; ov::Output image = context.get_input(1); const ov::Shape kernel_shape = context.get_input(0).get_shape(); const size_t IC = is_2D ? kernel_shape[1] : kernel_shape[2]; const size_t KH = is_2D ? kernel_shape[2] : 1; const size_t KW = kernel_shape[3]; int32_t stride_w = s0; int32_t stride_h = is_2D ? s1 : 1; int32_t pad_w = p0; int32_t pad_h = is_2D ? p1 : 0; int32_t dil_w = d0; int32_t dil_h = is_2D ? d1 : 1; if (!is_2D) { // GGML input shape: [IW, IC, N, 1] // OpenVINO input shape: [1, N, IC, IW] // Reshape image to: [N, IC, 1, IW] const ov::Shape image_shape = image.get_shape(); const size_t N = image_shape[1]; const size_t IW = image_shape[3]; auto image_reshape_shape = ov::op::v0::Constant::create( ov::element::i64, ov::Shape{4}, std::vector{static_cast(N), static_cast(IC), 1, static_cast(IW)}); image = std::make_shared(image, image_reshape_shape, false); } const ov::Shape patch_sizes = {KH, KW}; const ov::Strides strides = {static_cast(stride_h), static_cast(stride_w)}; const ov::Shape rates = {static_cast(dil_h), static_cast(dil_w)}; auto pads_begin = ov::op::v0::Constant::create(ov::element::i64, ov::Shape{4}, std::vector{0, 0, pad_h, pad_w}); auto pads_end = ov::op::v0::Constant::create(ov::element::i64, ov::Shape{4}, std::vector{0, 0, pad_h, pad_w}); auto pad = std::make_shared(image, pads_begin, pads_end, ov::op::PadMode::CONSTANT); auto patches = std::make_shared(pad, patch_sizes, strides, rates, ov::op::PadType::VALID); // [N, KH*KW*IC, OH, OW] → [N, OH, OW, KH*KW*IC] auto perm1 = ov::op::v0::Constant::create(ov::element::i64, ov::Shape{4}, std::vector{0, 2, 3, 1}); auto t1 = std::make_shared(patches, perm1); // [N, OH, OW, KH*KW*IC] → [N, OH, OW, KH*KW, IC] const ov::Shape out_shape = t1->get_output_shape(0); const size_t N = out_shape[0]; const size_t OH = out_shape[1]; const size_t OW = out_shape[2]; auto reshape1_shape = ov::op::v0::Constant::create( ov::element::i64, ov::Shape{5}, std::vector{static_cast(N), static_cast(OH), static_cast(OW), static_cast(KH * KW), static_cast(IC)}); auto r1 = std::make_shared(t1, reshape1_shape, false); // [N, OH, OW, KH*KW, IC] → [N, OH, OW, IC, KH*KW] auto perm2 = ov::op::v0::Constant::create(ov::element::i64, ov::Shape{5}, std::vector{0, 1, 2, 4, 3}); auto t2 = std::make_shared(r1, perm2); // flatten back to [N, OH, OW, IC*KH*KW] auto r2_shape = ov::op::v0::Constant::create( ov::element::i64, ov::Shape{4}, std::vector{static_cast(N), static_cast(OH), static_cast(OW), static_cast(IC * KH * KW)}); res = std::make_shared(t2, r2_shape, false); if (!is_2D) { // [N, 1, OW, IC * KW] -> [1, N, OW, IC * KW] auto final_reshape_shape = ov::op::v0::Constant::create( ov::element::i64, ov::Shape{4}, std::vector{1, static_cast(N), static_cast(OW), static_cast(IC * KW)}); res = std::make_shared(res, final_reshape_shape, false); } auto output_type = context.get_output_type(); if (res.get_element_type() != output_type) { res = std::make_shared(res, output_type); } return rename_outputs_with_suffix({res}, context.get_name()); } } // namespace op } // namespace ggml } // namespace frontend } // namespace ov