{"record":{"id":"e3333e0452c7ecd5","repo":"huggingface/candle","slug":"backward-not-supported-for-upsample-bilinear2d","errorCode":null,"errorMessage":"backward not supported for upsample_bilinear2d","messagePattern":"backward not supported for upsample_bilinear2d","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"candle-core/src/backprop.rs","lineNumber":412,"sourceCode":"                    } => {\n                        let (_n, c, h, w) = arg.dims4()?;\n                        if target_h % h != 0 || target_w % w != 0 {\n                            crate::bail!(\"backward not supported for non integer upscaling factors\")\n                        }\n                        let scale_h = target_h / h;\n                        let scale_w = target_w / w;\n\n                        if scale_h != scale_w {\n                            crate::bail!(\"backward not supported for non uniform upscaling factors\")\n                        };\n                        let kernel =\n                            Tensor::ones((c, 1, scale_h, scale_w), arg.dtype(), arg.device())?;\n                        let conv_sum = grad.conv2d(&kernel, 0, scale_h, 1, c)?;\n                        let sum_grad = grads.or_insert(arg)?;\n                        *sum_grad = conv_sum;\n                    }\n                    Op::UpsampleBilinear2D { .. } => {\n                        crate::bail!(\"backward not supported for upsample_bilinear2d\")\n                    }\n                    Op::SliceScatter0(lhs, rhs, start_rhs) => {\n                        let rhs_sum_grad = grads.or_insert(rhs)?;\n                        let rhs_grad = grad.narrow(0, *start_rhs, rhs.dim(0)?)?;\n                        *rhs_sum_grad = rhs_sum_grad.add(&rhs_grad)?;\n\n                        let lhs_sum_grad = grads.or_insert(lhs)?;\n                        let lhs_grad = grad.slice_scatter0(&rhs.zeros_like()?, *start_rhs)?;\n                        *lhs_sum_grad = lhs_sum_grad.add(&lhs_grad)?\n                    }\n                    Op::Gather(arg, indexes, dim) => {\n                        let sum_grad = grads.or_insert(arg)?;\n                        *sum_grad = sum_grad.scatter_add(indexes, &grad, *dim)?;\n                    }\n                    Op::Scatter(init, indexes, src, dim) => {\n                        let init_sum_grad = grads.or_insert(init)?;\n                        *init_sum_grad = init_sum_grad.add(&grad)?;\n","sourceCodeStart":394,"sourceCodeEnd":430,"githubUrl":"https://github.com/huggingface/candle/blob/d5fee525bfde3273eb7c9b75fd2bc4937be867ca/candle-core/src/backprop.rs#L394-L430","documentation":"candle has no backward implementation for the UpsampleBilinear2D op at all; when backward_step walks the op graph and reaches it, it unconditionally bails. Unlike nearest-neighbor upsampling (whose gradient is a strided sum), bilinear interpolation gradients were simply not implemented.","triggerScenarios":"Any call to Tensor::upsample_bilinear2d(...) (directly or inside a model forward) followed by backward() on a loss that depends on it.","commonSituations":"Porting PyTorch models using F.interpolate(mode='bilinear') or nn.Upsample(mode='bilinear'); training U-Net-style architectures with bilinear upsampling in candle.","solutions":["Replace upsample_bilinear2d with upsample_nearest2d (backward supported for integer uniform scales).","Replace the bilinear upsample with a ConvTranspose2d layer (learned upsampling), which is differentiable in candle.","Stop the gradient at the upsample by calling detach() on the tensor before the op (training downstream layers only).","Implement the op with primitive ops (e.g. gather + weighted combinations) so autograd can differentiate through it."],"exampleFix":"// before\nlet up = x.upsample_bilinear2d(64, 64)?;\n// after\nlet up = x.upsample_nearest2d(64, 64)?; // integer, uniform -> backward works","handlingStrategy":"fallback","validationCode":"// detect bilinear upsample in graph inputs before building the VarMap training loop\nlet uses_bilinear = layers.iter().any(|l| l.kind == LayerKind::UpsampleBilinear2D);\nif uses_bilinear { eprintln!(\"warning: bilinear upsample has no backward in candle; swapping to nearest\"); }","typeGuard":null,"tryCatchPattern":"match loss.backward() { Err(e) if e.to_string().contains(\"upsample_bilinear2d\") => { // rebuild model with upsample_nearest2d or ConvTranspose2d\n}, other => other?, }","preventionTips":["Never call upsample_bilinear2d inside trainable forward passes; keep it inference-only.","Prefer upsample_nearest2d or ConvTranspose2d when gradients are needed.","Search imported model code (PyTorch ports) for interpolate(mode='bilinear') and replace before training."],"tags":["autograd","unsupported-op","tensor","rust"],"backgroundTag":"backward-not-implemented","analyzedSha":"d5fee525bfde3273eb7c9b75fd2bc4937be867ca","analyzedAt":"2026-09-02T00:15:47.023Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}