A classifier that reports 95% accuracy no matter what it predicts is not a metrics bug — it’s a lie the code was telling on every training run.
Today we released TenfloweRS 0.1.2 — a release that ships real new capability (PyTorch-style implicit autograd for Python, real ONNX protobuf import/export, a from-scratch pure-Rust Blosc codec) alongside something you don’t see in most changelogs: a deliberate sweep through the framework looking for exactly that kind of lie, and replacing every one it found with either a real computation or an honest error.
TenfloweRS is the pure-Rust answer to TensorFlow. The tensor engine, the autodiff tape, the neural layers, the dataset pipeline, and the GPU backend are all Rust — no C runtime, no CUDA-C kernels, and no Python interpreter required at inference time (Python is opt-in, through a PyO3 FFI crate that isn’t published to crates.io). It compiles to a single static binary and runs everywhere the SciRS2/NumRS2 stack beneath it already runs.
Why TenfloweRS 0.1.2 is a game changer
Every ML framework asks you to trust it. The usual reasons not to are familiar:
- A CUDA/C++ toolchain you have to keep in lockstep with driver and Python versions before a single kernel builds
- A Python runtime and GIL riding along into production even when all you need is a trained model doing inference
- Framework internals you can’t read, patch, or independently verify when a result looks suspicious
0.1.2 goes after a fourth, less-discussed failure mode: a research-scale codebase — 150+ domains, 11,596 tests in the neural crate alone — inevitably accumulates code paths nobody finished, and it’s far too easy for those paths to return a plausible-looking Ok(()) instead of failing loudly.
TenfloweRS 0.1.2 ends all of that.
- PyTorch-style implicit autograd, for real, from Python.
tensor.backward()/tensor.grad()now work eagerly againstPyTensor, layered on the existing explicitGradientTapeengine via a thread-local auto-activating tape and an address-keyed side-table design — deliberately built to avoid touching ~190 existing struct-literal call sites, and closing an address-reuse hazard (a freed tensor’s stale gradient being attributed to a new tensor at the same allocation address) that was caught during development and pinned down with a dedicated regression test. - Real ONNX protobuf import/export, not a stub. The new
onnx_interop::converthand-rolls aModelProtoschema and rejects unrecognized attribute/dtype codes with a descriptive error instead of silently coercing them toFloat(0.0)/Float32. - A from-scratch, pure-Rust Blosc decoder for Zarr arrays — the full C-Blosc container format plus all five inner codecs (a hand-written, bounds-checked
BloscLzport, plus LZ4/Snappy/Zlib/Zstd via OxiARC) and both shuffle prefilters, validated against real chunks produced by the reference C-Blosc library. - Graph optimization is wired into real execution for the first time. Constant folding, algebraic simplification, CSE, strength reduction, scheduling, and dead-code elimination now run inside
Sessionitself, not as unused passes sitting beside it. - The honesty sweep touched every layer. Distributed backends (NCCL, Gloo, MPI, thread) that used to silently clone or scale a local tensor and call it a “collective” now return honest
NotImplementederrors; acompute_accuracythat was hardcoded to0.95regardless of predictions now does real argmax/threshold accuracy; aMishactivation computed as atanhapproximation (numerically wrong —mish(2.0)≈ 1.944 vs.tanh(2.0)≈ 0.964) now calls the real op. Each one was caught, fixed for real, and pinned down with a regression test.
That work sits on top of a large test suite: 14,289+ tests passing (39 skipped) across 6 crates, zero clippy warnings, zero rustdoc warnings.
Technical Deep Dive: what actually changed under the hood
tenflowers-core— real ONNX protobuf interop, graph optimization wired intoSessionvia a newprotected_output_rootsaccumulator (so a previously-fetched node always survives later optimization passes), realwgpu::Adaptercapability probing to replace vendor-guessing GPU detection, real LAPACK-backed f64 linear algebra (inverse_f64,determinant_f64,svd_f64,solve_f64) viascirs2-linalg, and N-D support for segment reductions.tenflowers-autogradandtenflowers-neural— the honesty sweep’s home base: a newGradientExecutortrait bridges the two crates (dependency-inversion, no circular dependency) sotenflowers-core’s gradient-validation framework can call into a realGradientTape-backed implementation instead of fabricatingpassed: true; Conv2D/Conv3D backward gradients went from zero-tensor placeholders to real transposed-cross-correlation implementations; and acrosstenflowers-neural, distributed backends, the pruning engine, mixture-of-experts routing, and weight serialization all moved from simulated or fabricated output to genuine computation or honest errors.tenflowers-dataset— HDF5 chunked/attribute/tree/slice readers, Parquet row-group readers with filter predicates and schema inspection, the new Blosc decoder, real masked-CRC TFRecord integrity checks (TensorFlow’s actual algorithm, not an approximation), GPU image transforms (affine, perspective, elastic distortion, histogram equalization, each backed by its own WGSL shader), and auto-vectorized SIMD preprocessing functions.tenflowers-ffi— theimplicit_autogradmodule described above, a standalone pure-RustGradientParityChecker(finite-difference gradient verification usable outside PyO3), a session-basedPyProfilerrecording op name/duration/memory/device, and 46 fixed#[pyo3(signature = ...)]annotations closing a class of silent breakage where calling e.g.tf.sum(x)withoutdim/keepdimraisedTypeError: missing required argumentdespite the Rust side already having a default.
Getting Started
Add the meta-crate:
cargo add tenflowers
A small taste of 0.1.2’s new structured logging and platform introspection, wrapped around ordinary eager tensor math:
use tenflowers::prelude::*;
use tenflowers::logging::{init_from_env, set_log_level, LogLevel};
use tenflowers::platform::{current_platform, detect_simd_capabilities};
use tenflowers::{log_info, log_warn};
fn main() -> Result<()> {
// New in 0.1.2: structured logging, configurable via TENFLOWERS_LOG
init_from_env();
set_log_level(LogLevel::Info);
let simd = detect_simd_capabilities();
log_info!("running on {} (AVX2: {})", current_platform(), simd.has_avx2);
// Ordinary eager tensor math, unchanged
let a = Tensor::<f32>::from_vec(vec![1.0, 2.0, 3.0, 4.0], &[2, 2])?;
let b = Tensor::<f32>::from_vec(vec![10.0, 20.0, 30.0, 40.0], &[2, 2])?;
let c = ops::matmul(&a, &b)?;
log_info!("matmul result: {:?}", c.to_vec()?);
if c.size() == 0 {
log_warn!("empty result -- check your inputs");
}
Ok(())
}
What’s New in 0.1.2
- Meta-crate (
tenflowers): a unifiedFrameworkError/Result<T>error type, structured logging (TENFLOWERS_LOGenv var, fivelog_*!macros, zero overhead when disabled),platform/detect_simd_capabilitiesruntime introspection, andversion_checkhelpers to keep subcrate versions aligned. - FFI (
tenflowers-ffi): implicit.backward()/.grad()autograd, a session-based profiler, a pure-Rust gradient-parity checker, astable_apimodule, and a real fix to attention masking —key_padding_maskpreviously reached the validator but was silently dropped before softmax, so a “masked” key still received real attention weight. - Dataset (
tenflowers-dataset): HDF5 and Parquet advanced readers, the pure-Rust Blosc decoder, real masked-CRC TFRecord parsing, GPU image transforms, SIMD preprocessing, and a reusableTransformArenafor intermediate buffers. - Core (
tenflowers-core): real ONNX import/export, theGradientExecutorbridge, graph optimization wired intoSession, real LAPACK f64 ops, real GPU device-capability probing, and N-D segment reductions. - Dependencies:
numrs2→ 0.4.0, thescirs2-*stack → 0.6.0,wgpu→ 30.0,pyo3→ 0.29,arrow/parquet→ 59.0, plus new directoxiarc-lz4/oxiarc-deflate/oxiarc-snappydependencies for Blosc’s inner codecs. - Security: the
pyo30.29 upgrade resolves RUSTSEC-2026-0176 and RUSTSEC-2026-0177; three remaining advisories are transitive, tracked, and — per the project’s own accounting — none directly exploitable. - The honesty sweep: dozens of functions across
tenflowers-autogradandtenflowers-neuralthat used to fabricate, simulate, or hardcode results — distributed collectives, pruning statistics, MoE routing, weight (de)serialization, SavedModel loading, WASM bundle-size reporting — now compute for real or fail with a specific, honest error.
Tips
- Turn on structured logging before you debug anything else.
TENFLOWERS_LOG=trace cargo run --example your_exampleor calllogging::set_log_level(LogLevel::Info)directly — the level is checked before formatting, so disabled log sites cost a single atomic load. - Try the new implicit autograd from Python. Call
tensor.set_requires_grad(True)and then.backward()/.grad()— no explicitGradientTapeneeded on the Python side. The Rust-levelGradientParityCheckeris there if you want to verify a gradient by finite differences before you trust it. - Re-check any code that touched
compute_accuracy, the distributed backends, orMishbefore this release. These specific functions previously returned fabricated results; see the CHANGELOG’s Fixed section for the full list before you upgrade a training pipeline that depends on them. - Reach for the new format readers instead of hand-rolling one.
Hdf5ChunkedReader,ParquetRowGroupReader(withread_filteredfor predicate pushdown), and the Blosc-aware Zarr path are all real implementations now, not stubs. - If you build a
Sessionmanually,enable_graph_optimizationis on by default. Constant folding, CSE, and dead-code elimination now genuinely run — turn it off only if you need to inspect an unoptimized graph. - Pin
pyo3 = "0.29"if you embedtenflowers-ffidirectly. It must trackscirs2-numpy’s own pyo3 requirement, since both link against the same native Python library — mismatch it and you’ll get link errors, not a clean version conflict.
This is the foundation
TenfloweRS leans directly on the rest of the COOLJAPAN ecosystem: NumRS2 (bumped to 0.4.0 this release) for n-dimensional arrays, the SciRS2 stack (now 0.6.0) for the scientific core and the new LAPACK-backed linear algebra, Oxicode for serialization, OxiARC (oxiarc-archive plus new direct oxiarc-lz4/oxiarc-deflate/oxiarc-snappy dependencies) for every compression codec the Blosc decoder needs, OxiBLAS (oxiblas-ndarray, wired in behind the blas-oxiblas feature per COOLJAPAN’s pure-Rust BLAS policy) for linear algebra, and OxiFFT for the FFT ops that landed real implementations this release. It stands alongside ToRSh, TrustformeRS, and sklears in the COOLJAPAN machine-learning stack.
Repository: https://github.com/cool-japan/tenflowers
Star the repo if a framework that fixes its own fabricated results instead of quietly shipping around them is something you want to see more of. The era of trusting a black box because it printed a confident number is over. Pure Rust ML is here — fast, safe, and sovereign.
— KitaSan at COOLJAPAN OÜ July 8, 2026