Skip to content

Batching

jax.vmap over splax.render renders a batch in one go rather than looping in Python, for both the forward and the backward pass.

Batched inference

We first prepare a batch of view matrices:

from functools import partial

import jax
import jax.numpy as jnp
import splax

SCENE = "https://huggingface.co/datasets/amacati/splax-test-data/resolve/main/scenes/lego.ply"
splats = splax.io.load_ply(splax.io.fetch(SCENE))
means, log_scales, quats, sh_colors, logit_opacities = splats
H, W, fx, fy = 400, 400, 400.0, 400.0
viewmat = splax.utils.look_at(jnp.array((0.0, -3.0, 1.0)), jnp.zeros(3), up=(0.0, 0.0, 1.0))
eyes = jnp.array([(0.0, -3.0, 1.0), (3.0, 0.0, 1.0)])
viewmats = splax.utils.look_at(eyes, jnp.zeros(3), up=(0.0, 0.0, 1.0))

Wrap splax.render in jax.vmap over any batched argument. Mapping over a stack of view matrices renders one image per camera.

render_at = partial(
    splax.render,
    means,
    log_scales,
    quats,
    sh_colors,
    logit_opacities,
    background=jnp.ones(3),
    img_shape=(H, W),
    f=(fx, fy),
)
frames, _ = jax.vmap(render_at)(viewmat=viewmats)  # (B, H, W, 3)

Batched gradients

jax.vmap(jax.grad(render)) computes batched gradients for efficient training. The reduction depends on how an input is batched.

  • Broadcast inputs, shared across the batch, get their gradients summed over the batch axis.
  • Per-image inputs, for example a batch of camera poses differentiated with jax.grad(loss, argnums=viewmat), get per-image gradients.

Memory trade at large batch

Rendering all B cameras together scales the working memory with the batch size, so at large B the peak footprint is higher than looping one camera at a time. splax.clear_cache releases it when switching between very different batch sizes.