{"record":{"id":"b06c3020e390757e","repo":"tracel-ai/burn","slug":"can-t-differentiate-max-pool2d-with-indices-backwa","errorCode":null,"errorMessage":"Can't differentiate max pool2d with indices backward.","messagePattern":"Can't differentiate max pool2d with indices backward\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/burn-autodiff/src/ops/module.rs","lineNumber":1749,"sourceCode":"                );\n                let output_tensor = prep.finish(output.output);\n\n                MaxPool2dWithIndices::new(output_tensor, output.indices)\n            }\n        }\n    }\n\n    fn max_pool2d_with_indices_backward(\n        _x: AutodiffTensor<B>,\n        _kernel_size: [usize; 2],\n        _stride: [usize; 2],\n        _padding: [usize; 2],\n        _dilation: [usize; 2],\n        _ceil_mode: bool,\n        _output_grad: AutodiffTensor<B>,\n        _indices: IntTensor<B>,\n    ) -> MaxPool2dBackward<Self> {\n        panic!(\"Can't differentiate max pool2d with indices backward.\");\n    }\n    fn adaptive_avg_pool1d(x: AutodiffTensor<B>, output_size: usize) -> AutodiffTensor<B> {\n        #[derive(Debug)]\n        struct AdaptiveAvgPool1D;\n\n        impl<B: Backend> Backward<B, 1> for AdaptiveAvgPool1D {\n            type State = NodeId;\n\n            fn backward(\n                self,\n                ops: Ops<Self::State, 1>,\n                grads: &mut Gradients,\n                checkpointer: &mut Checkpointer,\n            ) {\n                let [node_parent] = ops.parents;\n                let grad = grads.consume::<B>(&ops.node);\n                let state = checkpointer.retrieve_node_output(ops.state);\n","sourceCodeStart":1731,"sourceCodeEnd":1767,"githubUrl":"https://github.com/tracel-ai/burn/blob/d16f7ba2ed0d41408189384044cc886fb4c8f957/crates/burn-autodiff/src/ops/module.rs#L1731-L1767","documentation":"max_pool2d_with_indices_backward in the autodiff backend is a stub that panics. The autodiff layer cannot differentiate max pooling with indices because the forward op's gradient rule relies on the inner backend's indices-based backward, which is unavailable here.","triggerScenarios":"Calling max_pool2d_with_indices_backward on an AutodiffTensor, or hitting a backward pass that routes through this stub (e.g. second-order differentiation of max_pool2d).","commonSituations":"Differentiating through a network containing MaxPool2d twice (double-backward); building custom autodiff ops that reuse the pooled indices; tests that call the backward API directly.","solutions":["Use max_pool2d (without indices) which has a working forward+backward in the autodiff backend","Call max_pool2d_with_indices_backward on the inner backend instead of the autodiff wrapper","Restructure the model to avoid differentiating through max pooling twice","Implement the backward by scattering the output grad into the input positions given by the indices tensor"],"exampleFix":"// before\nlet (out, idx) = max_pool2d_with_indices(&x, [2,2], [2,2], [0,0], [1,1], false);\n// after\nlet out = max_pool2d(&x, [2,2], [2,2], [0,0], [1,1], false);","handlingStrategy":"fallback","validationCode":"// Avoid indices-based pooling in differentiable graphs\nif config.pooling == Pooling::MaxWithIndices && config.training {\n    eprintln!(\"max_pool2d_with_indices_backward panics under autodiff; use max_pool2d\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use max_pool2d (no indices) inside trainable graphs","Only use *_with_indices for inference paths","Avoid double-backward through pooling ops"],"tags":["rust","autodiff","unimplemented","backward-pass"],"backgroundTag":"unimplemented-op-backward","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"}