← Back to C-Kernel-Engine Docs Doxygen Source Documentation
vision_kernels.c
Go to the documentation of this file.
1 /**
2  * @file vision_kernels.c
3  * @brief Vision kernels (im2patch, patch embedding, etc.)
4  *
5  * CK-ENGINE KERNEL RULES:
6  * =======================
7  * 1. NO malloc/free - memory via bump allocator, pointers passed in
8  * 2. NO OpenMP - parallelization at orchestrator/codegen layer
9  * 3. API must define: inputs, outputs, workspace, and memory layouts
10  * 4. Pure computation - deterministic, no side effects
11  *
12  * After changes: make test && make llamacpp-parity-full
13  */
14 
15 #include <string.h>
16 #include <stddef.h>
17 #include <stdint.h>
18 
19 /**
20  * im2patch: Transforms an image into a sequence of flattened patches.
21  *
22  * Image Layout: [C, H, W] (Row-major: W is fastest moving)
23  * Output Layout: [num_patches, C * P * P]
24  *
25  * num_patches = (H/P) * (W/P)
26  * P = patch_size
27  */
28 void im2patch(const float *image,
29  float *patches,
30  int C, int H, int W, int P)
31 {
32  int num_patches_h = H / P;
33  int num_patches_w = W / P;
34  int patch_dim = C * P * P;
35 
36  // ph, pw: patch grid coordinates
37  for (int ph = 0; ph < num_patches_h; ++ph) {
38  for (int pw = 0; pw < num_patches_w; ++pw) {
39 
40  int patch_idx = ph * num_patches_w + pw;
41  float *dst_patch = patches + (size_t)patch_idx * patch_dim;
42 
43  // For each patch, grab pixels from all channels
44  for (int c = 0; c < C; ++c) {
45  for (int py = 0; py < P; ++py) {
46  int y = ph * P + py;
47  int x = pw * P;
48 
49  // Input row start in the image
50  const float *src_row = image + (size_t)c * H * W + (size_t)y * W + x;
51 
52  // Destination row in the flattened patch sequence
53  float *dst_row = dst_patch + (size_t)c * P * P + (size_t)py * P;
54 
55  // Copy P pixels (one row of the patch)
56  memcpy(dst_row, src_row, P * sizeof(float));
57  }
58  }
59  }
60  }
61 }
62 
63 /**
64  * patch2im: Accumulates gradients from patches back into the image. (Backward pass)
65  *
66  * d_patches: [num_patches, C * P * P]
67  * d_image: [C, H, W] (Accumulated)
68  */
69 void patch2im(const float *d_patches,
70  float *d_image,
71  int C, int H, int W, int P)
72 {
73  int num_patches_h = H / P;
74  int num_patches_w = W / P;
75  int patch_dim = C * P * P;
76 
77  // Zero out the image first as we are accumulating gradients
78  memset(d_image, 0, (size_t)C * H * W * sizeof(float));
79 
80  for (int ph = 0; ph < num_patches_h; ++ph) {
81  for (int pw = 0; pw < num_patches_w; ++pw) {
82 
83  int patch_idx = ph * num_patches_w + pw;
84  const float *src_patch = d_patches + (size_t)patch_idx * patch_dim;
85 
86  for (int c = 0; c < C; ++c) {
87  for (int py = 0; py < P; ++py) {
88  int y = ph * P + py;
89  int x = pw * P;
90 
91  float *dst_row = d_image + (size_t)c * H * W + (size_t)y * W + x;
92  const float *src_row = src_patch + (size_t)c * P * P + (size_t)py * P;
93 
94  // Add the patch gradient to the image gradient
95  for (int px = 0; px < P; ++px) {
96  dst_row[px] += src_row[px];
97  }
98  }
99  }
100  }
101  }
102 }
#define C(color)
Definition: show_config.c:39
void patch2im(const float *d_patches, float *d_image, int C, int H, int W, int P)
void im2patch(const float *image, float *patches, int C, int H, int W, int P)