COOLJAPAN
← All posts

OxiGAF 0.1.2 Released — Two Backward-Pass Bugs Were Silently Breaking Every 0.1.1 Training Run

OxiGAF 0.1.2 is a correctness release: a hardcoded L2 photometric loss and a missing SH-color position gradient affected every training run on 0.1.1. Both are fixed, alongside pure-Rust PyTorch/.pkl checkpoint ingest, spec-conformant glTF 2.0 export, and a real meta-learning avatar model. 15,289 tests passing, 100% Pure Rust.

release oxigaf gaussian-splatting avatar-reconstruction diffusion flame pure-rust

If you trained an OxiGAF avatar on 0.1.1, the optimizer was not doing what LossConfig told it to do — and if sh_degree >= 1, it was doing that wrong thing with half a gradient missing.

Today we released OxiGAF 0.1.2 — a correctness release built around two GPU backward-pass bugs that affected every 0.1.1 training run, unconditionally, plus pure-Rust PyTorch/.pkl checkpoint ingest, spec-conformant glTF 2.0 export, and the first real meta-learning avatar model.

No C. No C++. No Fortran. OxiGAF reconstructs an animatable 3D Gaussian avatar from a single casual video and compiles to a single static binary — the GPU paths run through wgpu on Metal, Vulkan, and DirectX alike. 0.1.2 tightens that sovereignty further: switching the candle dependency to the COOLJAPAN fork oxicandle-core/oxicandle-nn drops C Oniguruma (onig/onig_sys) out of the tokenizer path, and oxigaf-cli’s HTTP stack drops OpenSSL and then ring entirely — hf-hub is gone, replaced by a direct ureq + rustls client (RustCrypto via oxitls-rustcrypto-provider) with native, byte-accurate download progress instead of shelling out to curl.

Why 0.1.2 is a game changer

0.1.1 shipped a Gaussian-Splatting trainer that looked correct and wasn’t:

0.1.2 ends all of that:

All under the same discipline as every OxiGAF release: 15,289 / 15,289 tests passing (28 skipped, GPU/slow-only — separately confirmed passing on real Metal hardware), zero unwrap(), every file under 2,000 lines.

Technical Deep Dive: where the fixes landed

  1. oxigaf-render — the backward shaders got a correctness pass. Beyond the four gradient fixes above (including a cull guard against inf * 0 = NaN for Gaussians at/behind the near plane, and a rewritten NaN-proof skip test), the crate also gains a real (non-approximating) Lottes tone-mapping operator, upfront device-limit validation (rasterizer_device_limits) so an under-provisioned GPU fails fast instead of hitting an opaque pipeline-validation panic later, a GPU-side GpuTimestampProfiler, and a single spec-conformant gltf module consolidating what were three independently-written, mutually-incompatible glTF emitters in the workspace.

  2. oxigaf-trainer — the gradient path is real end to end. Beyond the fixes, LrScheduleConfig (6 variants: Fixed, WarmupCosine, Cosine, Step, Exponential, Cyclic) and GradientClipConfig make schedules and clipping declarative instead of hand-wired; pruning::GaussianPruner adds prune_by_min_scale/prune_to_sparsity; and meta_learning_avatar::GaussianAvatarModel is the first MetaModel implementation over an actual Gaussian avatar — the only prior implementation was a LinearModel toy never connected to what the crate trains.

  3. oxigaf-bridge — pure-Rust ingest replaces the Python fallback. A new pickle module implements a non-executing Python pickle reader (protocols 0–5: GLOBAL/REDUCE/NEWOBJ/BUILD all produce inert data records, nothing is resolved or called) backing convert_pytorch_checkpoint and convert_flame_model. The old scripts/convert_*.py remain as a documented reference/escape hatch, but nothing in the pipeline needs Python, PyTorch, NumPy, or SciPy for this step anymore. Separately, GafLayerMapper stopped relying on a hardcoded, enumerated U-Net/VAE/CLIP/Upsampler layer table that didn’t match DiffusionConfig::default(), in favor of direct /. path substitution.

  4. oxigaf-flame — the heat method is now the heat method. heat_geodesic implements the actual Crane/Weischedel/Wardetzky (2013) algorithm — solving (M + t·Lc)u = δ_source via Jacobi-preconditioned CG, normalizing ∇u, then a Poisson solve — replacing what its own 0.1.1 doc comment called “a simplified approximation, not the full heat method.” geodesic_center switches its default from an exhaustive search (minutes on a 5,023-vertex FLAME head) to farthest-point sampling over DEFAULT_CENTER_SAMPLES (64) candidates.

Getting Started

cargo add oxigaf

Convert a raw PyTorch checkpoint directly — no torch.load, no Python:

use oxigaf_bridge::convert_pytorch_checkpoint;
use std::path::Path;

fn main() -> anyhow::Result<()> {
    // Splits tensors into unet/vae/clip/other by prefix and writes each
    // non-empty group as <component>.safetensors
    let report = convert_pytorch_checkpoint(
        Path::new("checkpoint.pt"),
        Path::new("weights/"),
        None, // target_dtype: keep the source precision
    )?;

    println!(
        "wrote {} tensors across {} components",
        report.total_tensors(),
        report.components.len()
    );
    Ok(())
}

Or drive training and export from the CLI:

# Train with the now-correct photometric gradient
oxigaf train  --config experiment.toml

# Export to spec-conformant glTF 2.0
oxigaf export --format gltf --input checkpoint.safetensors --output avatar.gltf

What’s New in 0.1.2

Tips

This is the foundation

OxiGAF 0.1.2 leans further into the COOLJAPAN ecosystem it’s built on: oxicandle-core/oxicandle-nn for the diffusion backbone, oxitls-rustcrypto-provider and ureq/rustls for a pure-Rust HTTP stack, oxiarc-archive for archives, and the ToRSh tensor bridge (torsh-core/torsh-tensor/torsh-nn, bumped 0.1.2 → 0.2.0 this release) via oxigaf-bridge. It pairs naturally with oxihuman for a full body-plus-photoreal-face digital human, pipes reconstructed avatars through oximedia for real-time video, and stays Pure Rust on the same foundations as SciRS2, OxiBLAS, and OxiFFT.

Repository: https://github.com/cool-japan/oxigaf

Star the repo if you want digital-human training you can actually trust the gradients of.

The era of a loss function that logs one thing and optimizes another is over. Pure Rust Gaussian avatars are here — and now they train on the objective you actually configured.

KitaSan at COOLJAPAN OÜ August 28, 2026

↑ Back to all posts