{"record":{"id":"6d26bb463ad5cf59","repo":"huggingface/candle","slug":"in-channel-mismatch-between-input-c-in-groups","errorCode":null,"errorMessage":"in_channel mismatch between input ({c_in}, groups {groups}) and kernel ({c_in_k})","messagePattern":"in_channel mismatch between input \\((.+?), groups (.+?)\\) and kernel \\((.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"candle-core/src/conv.rs","lineNumber":312,"sourceCode":"        dilation: usize,\n        groups: usize,\n    ) -> Result<Self> {\n        self.conv2d_with_algo(kernel, padding, stride, dilation, groups, None)\n    }\n\n    pub fn conv2d_with_algo(\n        &self,\n        kernel: &Self,\n        padding: usize,\n        stride: usize,\n        dilation: usize,\n        groups: usize,\n        cudnn_fwd_algo: Option<CudnnFwdAlgo>,\n    ) -> Result<Self> {\n        let (b_size, c_in, i_h, i_w) = self.dims4()?;\n        let (c_out, c_in_k, k_h, k_w) = kernel.dims4()?;\n        if c_in != c_in_k * groups {\n            crate::bail!(\n                \"in_channel mismatch between input ({c_in}, groups {groups}) and kernel ({c_in_k})\"\n            )\n        }\n        let params = ParamsConv2D {\n            b_size,\n            i_h,\n            i_w,\n            k_h,\n            k_w,\n            c_out: c_out / groups,\n            c_in: c_in / groups,\n            padding,\n            stride,\n            dilation,\n            cudnn_fwd_algo,\n        };\n        if groups == 1 {\n            self.conv2d_single_group(kernel, &params)","sourceCodeStart":294,"sourceCodeEnd":330,"githubUrl":"https://github.com/huggingface/candle/blob/d5fee525bfde3273eb7c9b75fd2bc4937be867ca/candle-core/src/conv.rs#L294-L330","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Set groups = c_in / c_in_k when using grouped kernels (e.g. depthwise: groups = c_in, c_in_k = 1).","For groups=1, make kernel.dims4().1 equal input channels exactly.","Fix layer config in_channels to match the incoming tensor and rebuild the weight with the right shape.","Check checkpoint compatibility: reload weights into a layer whose channel layout matches the original model."],"exampleFix":"// before: x (8,32,H,W), kernel (64,16,3,3), groups=1\nx.conv2d(&k, 1, 1, 1, 1)?;\n// after: 32 = 16 * 2, so set groups = 2\nx.conv2d(&k, 1, 1, 1, 2)?;","handlingStrategy":"validation","validationCode":"let (_b, c_in, _h, _w) = x.dims4()?;\nlet (_c_out, c_in_k, _kh, _kw) = kernel.dims4()?;\nif c_in != c_in_k * groups { return Err(anyhow::anyhow!(\"conv2d: {c_in} != {c_in_k} * {groups}\")); }","typeGuard":null,"tryCatchPattern":"match result { Err(e) if e.to_string().contains(\"in_channel mismatch\") => { // recompute groups = c_in / c_in_k or fix kernel\n}, other => other?, }","preventionTips":["For grouped conv2d, always set groups = input_channels / kernel_in_channels.","Depthwise convs: groups == c_in and kernel second dim == 1.","Validate (in_channels, out_channels, groups) consistency at layer construction."],"tags":["shape-mismatch","convolution","groups","rust"],"backgroundTag":"shape-mismatch","analyzedSha":"d5fee525bfde3273eb7c9b75fd2bc4937be867ca","analyzedAt":"2026-09-02T00:15:47.023Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}