Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions ggml/src/ggml-cuda/col2im_1d.cu
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#include "col2im_1d.cuh"


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

template <typename T>
static __global__ void col2im_1d_kernel(
const T * src, T * dst,
int64_t T_out, int64_t T_in, int64_t K, int64_t OC, int64_t K_OC,
int s0, int p0) {

const int64_t i = (int64_t)threadIdx.x + blockIdx.x * blockDim.x;
if (i >= T_out * OC) {
return; // Guard out-of-bounds threads
}

// Decompose 1D thread ID into 2D output coordinates
// dst layout: [T_out, OC] -> flat index = oc * T_out + t_out
const int64_t oc = i / T_out;
const int64_t t_out = i % T_out;
Comment on lines +17 to +18

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure how performance critical this is but you can use fast_div

@Ssamdeman Ssamdeman Jul 4, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes I found it. I digged deeper inside the ggml/src/ggml-cuda/common.cuh. I can implement it new faster but it does not mean it is a good idea. here is my analysis. The fast_div_modulo(it calls fastdiv inside of it) speeds up the kernel by avoiding expensive hardware division, but it requires casting thread IDs to 32-bit, Given our 1D tensor use cases, is this 32-bit ceiling a safe tradeoff for the performance boost, or should I stick to standard 64-bit division?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay not required for this PR anyway


const int64_t t_abs = t_out + p0;

// Establish bounds using the solved equation
int64_t t_in_min = (t_abs - K + 1 + s0 - 1) / s0;
if (t_in_min < 0) t_in_min = 0;

float sum = 0.0f; // Accumulate in fp32


for (int64_t t_in = t_in_min; t_in * s0 <= t_abs && t_in < T_in; t_in++) {
int64_t k = t_abs - t_in * s0;
Comment thread
Ssamdeman marked this conversation as resolved.

// src layout: [K_OC, T_in] -> element (oc * K + k) at column t_in
// flat offset = t_in * K_OC + (oc * K + k)
sum += (float)src[t_in * K_OC + (oc * K + k)];
}

// Write directly to current thread's mapped location
dst[i] = (T)sum;
}


// 2. Host function wrapper
void ggml_cuda_op_col2im_1d(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
const ggml_tensor * src = dst->src[0];
cudaStream_t stream = ctx.stream();

// Strict type pairing and format enforcement
GGML_ASSERT(src->type == dst->type);
GGML_ASSERT(src->type == GGML_TYPE_F32 || src->type == GGML_TYPE_F16 || src->type == GGML_TYPE_BF16);

// Extract structural parameters
const int32_t s0 = ((const int32_t *)(dst->op_params))[0];
const int32_t OC = ((const int32_t *)(dst->op_params))[1];
const int32_t p0 = ((const int32_t *)(dst->op_params))[2];

const int64_t K_OC = src->ne[0];
const int64_t T_in = src->ne[1];
const int64_t K = K_OC / OC;
const int64_t T_out = dst->ne[0];

// Grid configuration
const int64_t total_elements = T_out * OC;
const int block_size = 256;
const int num_blocks = (total_elements + block_size - 1) / block_size;

// Type dispatching
if (src->type == GGML_TYPE_F32) {
col2im_1d_kernel<float><<<num_blocks, block_size, 0, stream>>>(
(const float *)src->data, (float *)dst->data, T_out, T_in, K, OC, K_OC, s0, p0);
} else if (src->type == GGML_TYPE_F16) {
col2im_1d_kernel<half><<<num_blocks, block_size, 0, stream >>>(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
col2im_1d_kernel<half><<<num_blocks, block_size, 0, stream >>>(
col2im_1d_kernel<half><<<num_blocks, block_size, 0, stream>>>(

(const half *)src->data, (half *)dst->data, T_out, T_in, K, OC, K_OC, s0, p0);
} else if (src->type == GGML_TYPE_BF16) {
col2im_1d_kernel<nv_bfloat16><<<num_blocks, block_size, 0, stream>>>(
(const nv_bfloat16 *)src->data, (nv_bfloat16 *)dst->data, T_out, T_in, K, OC, K_OC, s0, p0);
} else {
GGML_ABORT("col2im_1d: unsupported type %d", src->type);
}
}
3 changes: 3 additions & 0 deletions ggml/src/ggml-cuda/col2im_1d.cuh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include "common.cuh"

void ggml_cuda_op_col2im_1d(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
6 changes: 6 additions & 0 deletions ggml/src/ggml-cuda/ggml-cuda.cu
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "ggml-cuda/fwht.cuh"
#include "ggml-cuda/getrows.cuh"
#include "ggml-cuda/im2col.cuh"
#include "ggml-cuda/col2im_1d.cuh"
#include "ggml-cuda/mmf.cuh"
#include "ggml-cuda/mmq.cuh"
#include "ggml-cuda/mmvf.cuh"
Expand Down Expand Up @@ -3078,6 +3079,9 @@ static bool ggml_cuda_compute_forward(ggml_backend_cuda_context & ctx, struct gg
case GGML_OP_IM2COL_3D:
ggml_cuda_op_im2col_3d(ctx, dst);
break;
case GGML_OP_COL2IM_1D:
ggml_cuda_op_col2im_1d(ctx, dst);
break;
case GGML_OP_CONV_2D:
ggml_cuda_op_conv2d(ctx, dst);
break;
Expand Down Expand Up @@ -5439,6 +5443,8 @@ static bool ggml_backend_cuda_device_supports_op(ggml_backend_dev_t dev, const g
case GGML_OP_CONV_TRANSPOSE_2D:
case GGML_OP_POOL_2D:
return true;
case GGML_OP_COL2IM_1D:
return true;
case GGML_OP_ACC:
// TODO: extend support like so:
//return ggml_is_contiguous_rows(op->src[0]) && ggml_is_contiguous_rows(op->src[1]);
Expand Down
Loading