{"record":{"id":"11e38209cb0c2402","repo":"tracel-ai/burn","slug":"can-t-differentiate-adaptive-avg-pool2d-backward","errorCode":null,"errorMessage":"Can't differentiate adaptive avg pool2d backward.","messagePattern":"Can't differentiate adaptive avg pool2d backward\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/burn-autodiff/src/ops/module.rs","lineNumber":1833,"sourceCode":"            .prepare::<C>([x.node.clone()])\n            .compute_bound()\n            .stateful()\n        {\n            OpsKind::Tracked(mut prep) => {\n                let x_state = prep.checkpoint(&x);\n                prep.finish(x_state, B::adaptive_avg_pool2d(x.primitive, output_size))\n            }\n            OpsKind::UnTracked(prep) => {\n                prep.finish(B::adaptive_avg_pool2d(x.primitive, output_size))\n            }\n        }\n    }\n\n    fn adaptive_avg_pool2d_backward(\n        _x: AutodiffTensor<B>,\n        _grad: AutodiffTensor<B>,\n    ) -> AutodiffTensor<B> {\n        panic!(\"Can't differentiate adaptive avg pool2d backward.\");\n    }\n\n    fn adaptive_avg_pool3d(x: AutodiffTensor<B>, output_size: [usize; 3]) -> AutodiffTensor<B> {\n        #[derive(Debug)]\n        struct AdaptiveAvgPool3D;\n\n        impl<B: Backend> Backward<B, 1> for AdaptiveAvgPool3D {\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);","sourceCodeStart":1815,"sourceCodeEnd":1851,"githubUrl":"https://github.com/tracel-ai/burn/blob/d16f7ba2ed0d41408189384044cc886fb4c8f957/crates/burn-autodiff/src/ops/module.rs#L1815-L1851","documentation":"adaptive_avg_pool2d_backward in the autodiff backend panics unconditionally: there is no gradient rule for adaptive average pooling 2d on this backend. Only the forward adaptive_avg_pool2d is implemented.","triggerScenarios":"Training a model whose backward pass needs gradients through adaptive_avg_pool2d (e.g. Spatial Pyramid Pooling heads, variable-size input pooling) on the autodiff backend.","commonSituations":"SPP/pooled-output heads in vision models; dynamic image-size pipelines that use AdaptiveAvgPool2d before a classifier; porting torchvision-style models to burn.","solutions":["Replace AdaptiveAvgPool2d with fixed-kernel avg_pool2d only if gradients are supported, or with a flatten+linear combination","Ensure the inner backend implements adaptive_avg_pool2d_backward and use it directly instead of autodiff","Compute the pooling as reshape/chunk/mean ops that autodiff can differentiate","Contribute/implement the backward via the existing backward-framework (Backward<B, D>)"],"exampleFix":"// before\nlet pooled = adaptive_avg_pool2d(&x, [7, 7]);\n// after\nlet pooled = avg_pool2d(&x, [7, 7], [7, 7], [0, 0], true, false); // only if backward exists","handlingStrategy":"fallback","validationCode":"// Guard adaptive pooling heads in trainable models\nif model_uses_adaptive_avg_pool2d && is_training {\n    eprintln!(\"adaptive_avg_pool2d backward panics in burn-autodiff; replace with fixed avg_pool2d or flatten+linear\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Resize inputs to a fixed size so fixed-kernel pooling can replace adaptive pooling","Replace SPP heads with flatten + linear layers","Keep adaptive pooling outside the autodiff graph (use detach)"],"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"}