im2col: [N, IC, IH, IW] => [N, OH, OW, IC*KH*KW] a: [OC,IC, KH, KW] b: [N, IC, IH, IW] result: [N, OH, OW, IC*KH*KW]
| 5344 | // b: [N, IC, IH, IW] |
| 5345 | // result: [N, OH, OW, IC*KH*KW] |
| 5346 | struct ggml_tensor * ggml_im2col( |
| 5347 | struct ggml_context * ctx, |
| 5348 | struct ggml_tensor * a, |
| 5349 | struct ggml_tensor * b, |
| 5350 | int s0, |
| 5351 | int s1, |
| 5352 | int p0, |
| 5353 | int p1, |
| 5354 | int d0, |
| 5355 | int d1, |
| 5356 | bool is_2D) { |
| 5357 | |
| 5358 | if(is_2D) { |
| 5359 | GGML_ASSERT(a->ne[2] == b->ne[2]); |
| 5360 | } else { |
| 5361 | GGML_ASSERT(a->ne[1] == b->ne[1]); |
| 5362 | } |
| 5363 | bool is_node = false; |
| 5364 | |
| 5365 | if (a->grad || b->grad) { |
| 5366 | GGML_ASSERT(false); // TODO: implement backward |
| 5367 | is_node = true; |
| 5368 | } |
| 5369 | |
| 5370 | const int64_t OH = is_2D ? ggml_calc_conv_output_size(b->ne[1], a->ne[1], s1, p1, d1) : 0; |
| 5371 | const int64_t OW = ggml_calc_conv_output_size(b->ne[0], a->ne[0], s0, p0, d0); |
| 5372 | |
| 5373 | const int64_t ne[4] = { |
| 5374 | is_2D ? (a->ne[2] * a->ne[1] * a->ne[0]) : a->ne[1] * a->ne[0], |
| 5375 | OW, |
| 5376 | is_2D ? OH : b->ne[2], |
| 5377 | is_2D ? b->ne[3] : 1, |
| 5378 | }; |
| 5379 | |
| 5380 | struct ggml_tensor * result = ggml_new_tensor(ctx, GGML_TYPE_F16, 4, ne); |
| 5381 | int32_t params[] = { s0, s1, p0, p1, d0, d1, (is_2D ? 1 : 0) }; |
| 5382 | ggml_set_op_params(result, params, sizeof(params)); |
| 5383 | |
| 5384 | result->op = GGML_OP_IM2COL; |
| 5385 | result->grad = is_node ? ggml_dup_tensor(ctx, result) : NULL; |
| 5386 | result->src[0] = a; |
| 5387 | result->src[1] = b; |
| 5388 | |
| 5389 | return result; |
| 5390 | } |
| 5391 | |
| 5392 | // a: [OC,IC, KH, KW] |
| 5393 | // b: [N, IC, IH, IW] |
no test coverage detected