huggingface/candle · error

in_channel mismatch between input ({c_in}, groups {groups})

Error message

in_channel mismatch between input ({c_in}, groups {groups}) and kernel ({c_in_k})

What it means

conv2d (and conv2d_with_algo) checks that the input channel count equals kernel input channels times the group count: c_in == c_in_k * groups. For grouped conv2d the kernel holds per-group input channels, so this product must match the tensor's actual channels.

Source

Thrown at candle-core/src/conv.rs:312

        dilation: usize,
        groups: usize,
    ) -> Result<Self> {
        self.conv2d_with_algo(kernel, padding, stride, dilation, groups, None)
    }

    pub fn conv2d_with_algo(
        &self,
        kernel: &Self,
        padding: usize,
        stride: usize,
        dilation: usize,
        groups: usize,
        cudnn_fwd_algo: Option<CudnnFwdAlgo>,
    ) -> Result<Self> {
        let (b_size, c_in, i_h, i_w) = self.dims4()?;
        let (c_out, c_in_k, k_h, k_w) = kernel.dims4()?;
        if c_in != c_in_k * groups {
            crate::bail!(
                "in_channel mismatch between input ({c_in}, groups {groups}) and kernel ({c_in_k})"
            )
        }
        let params = ParamsConv2D {
            b_size,
            i_h,
            i_w,
            k_h,
            k_w,
            c_out: c_out / groups,
            c_in: c_in / groups,
            padding,
            stride,
            dilation,
            cudnn_fwd_algo,
        };
        if groups == 1 {
            self.conv2d_single_group(kernel, &params)

View on GitHub (pinned to d5fee525bf)

Solutions

  1. Set groups = c_in / c_in_k when using grouped kernels (e.g. depthwise: groups = c_in, c_in_k = 1).
  2. For groups=1, make kernel.dims4().1 equal input channels exactly.
  3. Fix layer config in_channels to match the incoming tensor and rebuild the weight with the right shape.
  4. Check checkpoint compatibility: reload weights into a layer whose channel layout matches the original model.

Example fix

// before: x (8,32,H,W), kernel (64,16,3,3), groups=1
x.conv2d(&k, 1, 1, 1, 1)?;
// after: 32 = 16 * 2, so set groups = 2
x.conv2d(&k, 1, 1, 1, 2)?;
Defensive patterns

Strategy: validation

Validate before calling

let (_b, c_in, _h, _w) = x.dims4()?;
let (_c_out, c_in_k, _kh, _kw) = kernel.dims4()?;
if c_in != c_in_k * groups { return Err(anyhow::anyhow!("conv2d: {c_in} != {c_in_k} * {groups}")); }

Try / catch

match result { Err(e) if e.to_string().contains("in_channel mismatch") => { // recompute groups = c_in / c_in_k or fix kernel
}, other => other?, }

Prevention

When it happens

Trigger: Tensor::conv2d(&kernel, padding, stride, dilation, groups) or a candle_nn::conv::Conv2d::forward where input dims4().1 != kernel.dims4().1 * groups, e.g. c_in=32, c_in_k=16, groups=1 (needs groups=2), or c_in=16, c_in_k=32, groups=1.

Common situations: Forgetting groups=2 when using a grouped kernel from a checkpoint; confusing regular conv kernel layout (c_out, c_in/g, kh, kw) with transposed conv layout (c_in, c_out, kh, kw); changing model channel widths without updating conv layers.

Related errors


AI-assisted analysis of huggingface/candle@d5fee525bf (2026-09-02). Data as JSON: /api/errors/6d26bb463ad5cf59. Report an issue: GitHub.