{"record":{"id":"b22e1491d83f944e","repo":"tracel-ai/burn","slug":"both-channels-must-be-divisible-by-the-number-of-g","errorCode":null,"errorMessage":"Both channels must be divisible by the number of groups. Got channels_in={channels_in}, channels_out={channels_out}, groups={groups}","messagePattern":"Both channels must be divisible by the number of groups\\. Got channels_in=(.+?), channels_out=(.+?), groups=(.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/burn-nn/src/modules/conv/checks.rs","lineNumber":6,"sourceCode":"pub(crate) fn checks_channels_div_groups(channels_in: usize, channels_out: usize, groups: usize) {\n    let channels_in_div_by_group = channels_in.is_multiple_of(groups);\n    let channels_out_div_by_group = channels_out.is_multiple_of(groups);\n\n    if !channels_in_div_by_group || !channels_out_div_by_group {\n        panic!(\n            \"Both channels must be divisible by the number of groups. Got \\\n             channels_in={channels_in}, channels_out={channels_out}, groups={groups}\"\n        );\n    }\n}\n\n// https://github.com/tracel-ai/burn/issues/2676\n/// Only symmetric padding is currently supported. As such, using `Same` padding with an even kernel\n/// size is not supported as it will not produce the same output size.\npub(crate) fn check_same_padding_support(kernel_size: &[usize]) {\n    for k in kernel_size.iter() {\n        if k % 2 == 0 {\n            unimplemented!(\"Same padding with an even kernel size is not supported\");\n        }\n    }\n}\n","sourceCodeStart":1,"sourceCodeEnd":23,"githubUrl":"https://github.com/tracel-ai/burn/blob/d16f7ba2ed0d41408189384044cc886fb4c8f957/crates/burn-nn/src/modules/conv/checks.rs#L1-L23","documentation":"Convolution layer configuration validation requires both input and output channel counts to be evenly divisible by the group count (grouped/depthwise convolution). If either `channels_in % groups != 0` or `channels_out % groups != 0`, the weight tensor cannot be shaped into groups, so `checks_channels_div_groups` panics at layer construction.","triggerScenarios":"Constructing any conv config (Conv1d/2d/3d, and deform conv's weight_groups) via `init(&device)` where `groups` does not evenly divide `channels[0]` (in) or `channels[1]` (out), e.g. Conv2dConfig { channels: [3, 16], groups: 2 }.","commonSituations":"Setting depthwise `groups = channels_in` but forgetting that channels_out must also be divisible (common with padding-out channels); hand-editing configs; switching a standard conv to grouped without adjusting channels.","solutions":["Make `groups` a divisor of both channels_in and channels_out (e.g. groups of 1, 2, 4, ... that divide both).","For depthwise convs, set channels_out = channels_in * multiplier with groups = channels_in.","Set groups = 1 (standard convolution) if grouping is not required.","Assert divisibility in your config-builder before constructing the layer."],"exampleFix":"// before\nlet config = Conv2dConfig { channels: [3, 16], groups: 2, ..Default::default() }; // 3 % 2 != 0\n// after\nlet config = Conv2dConfig { channels: [4, 16], groups: 2, ..Default::default() }; // or groups: 1","handlingStrategy":"validation","validationCode":"fn validate_grouped_conv(channels_in: usize, channels_out: usize, groups: usize) {\n    assert!(groups > 0, \"groups must be nonzero\");\n    assert!(channels_in % groups == 0, \"channels_in={channels_in} not divisible by groups={groups}\");\n    assert!(channels_out % groups == 0, \"channels_out={channels_out} not divisible by groups={groups}\");\n}\nvalidate_grouped_conv(config.channels[0], config.channels[1], config.groups);","typeGuard":"fn groups_are_valid(channels_in: usize, channels_out: usize, groups: usize) -> bool {\n    groups > 0 && channels_in.is_multiple_of(groups) && channels_out.is_multiple_of(groups)\n}","tryCatchPattern":"let result = std::panic::catch_unwind(|| config.init(&device));\nmatch result {\n    Ok(layer) => layer,\n    Err(_) => {\n        let mut c = config;\n        c.groups = 1; // safe fallback: standard convolution\n        c.init(&device)\n    }\n}","preventionTips":["For depthwise convs set groups = channels_in and channels_out = channels_in * multiplier.","Run divisibility asserts in your config builder before init().","Prefer groups = 1 unless grouping is explicitly required."],"tags":["rust","panic","convolution","config-validation","shape-mismatch"],"backgroundTag":"channels-not-divisible-by-groups","analyzedSha":"d16f7ba2ed0d41408189384044cc886fb4c8f957","analyzedAt":"2026-09-05T13:19:14.260Z","contentChangedAt":"2026-09-05T13:19:14.260Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}