← Back to list

Implementing a Custom Backward Pass for 3D Gaussian Splatting

In a previous blog post, we implemented the forward pass for 3D Gaussian Splatting (3DGS) from scratch. We covered how to project millions…

Papers in 100 Lines of Code · 2026-02-06 16:00 · 5 claps · 3.5 min read paywalled
#computer-vision #3dgaussiansplatting #3dgs #neural-radiance-fields #graphics
Open on Medium ↗

Implementing a Custom Backward Pass for 3D Gaussian Splatting

Building 3D Gaussian Splatting in PyTorch (From Scratch)

Building 3D Gaussian Splatting in PyTorch (From Scratch)

In a previous blog post, we implemented the forward pass for 3D Gaussian Splatting (3DGS) from scratch. We covered how to project millions of 3D Gaussians into 2D, apply tile-based sorting, and perform compositing using explicit alpha blending. One of the defining characteristics of 3DGS — and a major reason for its training performance — is its custom backward pass, where we manually implement the gradient computations instead of relying on PyTorch’s automatic differentiation.

In this article, we add that custom backward pass. We’ll briefly explain why it’s useful, show how to implement it using PyTorch’s autograd.Function interface, and walk through a working example that computes the gradient with respect to color only. This is a simplified tutorial; full gradients (including position, opacity, rotation, and scale) are implemented in my full 3DGS course.

Why Implement a Custom Backward Pass in 3DGS?

While PyTorch’s autograd can differentiate through most operations, it’s not always optimal for performance-heavy rendering pipelines. In our forward pass, we loop over millions of Gaussians, tiles, and pixels, computing values like Gaussian weights g, per-pixel opacities α, and transmittance T. Letting PyTorch trace and store all these operations would be slow and memory-intensive.

By implementing our own backward pass, we:

  • Store only essential data from the forward pass (e.g. coordinates, covariances, masks)
  • Recompute cheap intermediate variables on-the-fly (like g, α, and T)
  • Trade memory for computation

Note: This approach is widely used in custom operators. For example, in fused layer normalization, a manually defined backward pass avoids materializing large intermediate tensors, leading to substantial memory savings.

Creating a Custom Autograd Function in PyTorch

To define a custom backward, we subclass torch.autograd.Function and implement two static methods: forward(ctx, ...) and backward(ctx, grad_output). PyTorch automatically calls backward during the gradient step.

Inside the forward pass, we store any data we’ll need later using ctx.save_for_backward(...), and optionally stash metadata (like image size or tile size) directly on ctx.

Minimal Structure

[embed]Custom Backward Pass | 3D Gaussian Splatting from Scratch

Computing Gradients: The Backward Pass

Let’s now build the backward method. PyTorch gives us grad_output, the gradient of the loss w.r.t. the output image. Our task is to compute the gradient w.r.t. the input color tensor.

The math

In the forward pass, each pixel’s final RGB value is a weighted sum of the colors of contributing Gaussians:

C_pixel = Σ w · color

where w is the weight of Gaussian i on that pixel.

Applying the chain rule:

∂L/∂color = ∂L/∂C_pixel · Σ w

This expression shows that the color gradient depends on the same per-pixel weights used during the forward pass. Although these weights w are not stored explicitly-doing so would be prohibitively expensive-we retain (ctx) all necessary information to reconstruct them, such as tile assignments, screen-space coordinates, opacities, and inverse covariances. During the backward pass, the weights are therefore recomputed tile-by-tile using the same logic as in the forward pass.

Backward Implementation Skeleton

[embed]Custom Backward Pass | 3D Gaussian Splatting Tutorial

At the end of the backward pass, we return a tuple of gradients, one per input. For inputs that don’t require gradients (e.g. camera intrinsics), we return None. In this example, only color gets a gradient (grad_color).

Important: The order of returned gradients must match the order of forward inputs.

Summary of the Algorithm

  • Use saved data (from ctx) to identify which Gaussians influence which pixels
  • Recompute the weight w per pixel using Gaussian opacity, visibility, and spatial kernel
  • For each Gaussian, accumulate: Σ w · grad_pixel
  • Return gradients (here: only for color)

Advantages of our implementation

As discussed above, implementing our own backward pass has major benefits:

  • Memory Efficiency: We avoid storing huge per-pixel tensors like alpha maps or intermediate weights. This reduces peak memory and allows scaling to more Gaussians.
  • Speed: Our backward skips unnecessary gradients and could fuse computations. With custom kernels (as in the original 3DGS), this yields real-time performance.
  • Numerical Stability: We can clip opacities, filter degenerate covariances, and enforce symmetry or positive semidefinite constraints in ways autograd would not.

If you ever write a custom backward pass, it’s good practice to verify gradients using torch.autograd.gradcheck or numerical finite-differences. We trust the math here, but in more complex cases, testing is key.

What’s Next

We now have a custom differentiable rasterizer with a working backward pass. In my next blog, I’ll compare this custom backward to using PyTorch autograd end-to-end, focusing on:

  • Speed (batch size vs. runtime)
  • Memory usage (CUDA memory during training)
  • Numerical accuracy (does our backward match autograd?)

Want to be notified when that article goes live? Subscribe to my newsletter for future posts, updates, and practical guides on PyTorch, 3DGS, and differentiable rendering.

📘 Learn 3DGS Step-by-Step (PyTorch Only)

Want to truly understand 3D Gaussian Splatting-not just run a repo? My 3D Gaussian Splatting Course teaches the full pipeline from first principles in PyTorch only (no C++, no CUDA). You’ll learn initialization, rasterization, backward passes, training loops, and how to experiment with recent papers.

Explore the Course →

💼 Research & Engineering Consulting

We help teams integrate 3D Gaussian Splatting techniques, build custom pipelines, and prototype new splatting research. If you need expertise, we can help.

Contact: contact@qubitanalytics.be

Originally published at https://www.3dgaussiansplattingcourse.com.


메타데이터
post_id
3d8d352bdd94
slug
implementing-a-custom-backward-pass-for-3d-gaussian-splatting-3d8d352bdd94
url
https://medium.com/@papers-100-lines/implementing-a-custom-backward-pass-for-3d-gaussian-splatting-3d8d352bdd94
canonical_url
https://medium.com/@papers-100-lines/implementing-a-custom-backward-pass-for-3d-gaussian-splatting-3d8d352bdd94
author_url
https://medium.com/@papers-100-lines
status
ok
fetched_at
2026-06-14 11:28:49