Skip to main content

diffct

English · 简体中文

Differentiable CUDA projectors for CT: arbitrary trajectories, multi-GPU, multi-node, geometry gradients.

License DOI PyPI version Documentation CI/CD Ask DeepWiki

diffct intro: projection, sinogram, trajectories, multi-GPU split, reconstruction and geometry calibration

Intro video (MP4) · Technical report · DOI

Install · Quickstart · Features · Performance · Examples · Citation

Install with the CUDA extra, pip install "diffct[cu12]" or pip install "diffct[cu13]", after PyTorch. A plain pip install diffct needs a system CUDA Toolkit.

Version 2.0 replaces the circular-orbit API of 1.x with per-view trajectories. Code written for 1.x needs changes; see the migration notes. For Apple Silicon, use the MLX port by Linda-Sophie Schneider.

Why diffct

To our knowledge, diffct is the only open-source GPU CT library that combines arbitrary per-view trajectories, autograd through the volume, first-order gradients through the acquisition geometry, and built-in multi-GPU and multi-node execution. We compared it with LEAP, TIGRE, ASTRA/tomosipo, DiffDRR and others in October 2026.

  • Arbitrary trajectories. Each view has its own source, detector centre and detector axes. Circular, helical, saddle, sinusoidal, random and calibrated scans use the same code. Trajectory tensors with requires_grad=True receive geometry gradients for calibration.
  • Curved detectors. A detector_surface(u, v) callback defines each pixel's position for arc, cylindrical or other parameterized surfaces. Projection and matched backprojection support first-order surface gradients. See the surface API.
  • Matched operators. project() and backproject() form an exact adjoint pair for the cell-constant Siddon model. Both support PyTorch autograd, with volume/sinogram gradients and Hessian-vector products.
  • Large volumes. CPU volumes and sinograms automatically stream spatial tiles and view batches through CUDA. Full arrays and data gradients stay on CPU; tile sizes follow the available device memory and can be overridden. See chunked execution.
  • Multi-GPU and multi-node. Use devices=[0, 1, 2, 3] in one process, or one process per GPU with torchrun and NCCL. Views are partitioned. CPU-backed volumes stay in host RAM while GPUs compute tiles; distributed ranks retain replicated-volume semantics. Speedup depends on workload and communication costs.
  • Analytical helpers. diffct.analytical provides ramp filters (ram-lak, shepp-logan, cosine, hamming, hann), fan, cone and Parker weights, and FBP and FDK backprojection.

Capabilities, limits and isocenter rules: docs/REFERENCE.md.

Install

You need an NVIDIA GPU. Install PyTorch for your CUDA version first. Then install diffct with the extra for the same CUDA major version:

pip install "diffct[cu12]"    # PyTorch built for CUDA 12
pip install "diffct[cu13]"    # PyTorch built for CUDA 13

The extra installs the CUDA compiler libraries that Numba CUDA needs to compile the kernels. A plain pip install diffct does not install them. Use it only if a CUDA Toolkit is already installed on the system.

From source, with the examples:

git clone https://github.com/sypsyp97/diffct.git
cd diffct && pip install -e ".[cu12]"
python examples/quickstart.py               # smoke test: prints adjoint mismatch ~1e-8 for each beam
Notes on CUDA versions
  • Numba CUDA imports numpy.row_stack, which NumPy 2.5 removes. Keep numpy<2.5.
  • Keep NVVM and NVJitLink compatible with the CUDA libraries that PyTorch loads. A newer NVVM with an older NVJitLink fails when the kernels compile.
  • A tested CUDA 13 set: pip install "numpy<2.5" "numba-cuda[cu13]" "cuda-toolkit[cccl,cudart,nvrtc,nvvm]==13.0.2" "nvidia-nvjitlink<13.1".
  • A tested CUDA 12 set: PyTorch 2.10 (cu126) with numba-cuda[cu12] 0.30.4 on NVIDIA driver 535.

Quickstart

Create the acquisition once. Then call project() and backproject().

import torch
from diffct import Projector, spiral_trajectory_3d

trajectory = spiral_trajectory_3d(360, sid=320.0, sdd=512.0, z_range=40.0, n_turns=1.0, device="cpu")
A = Projector(trajectory, volume_shape=(128, 128, 128), detector_shape=(384, 256), detector_spacing=0.8)

volume = torch.rand(A.volume_shape, device="cuda")
sinogram = A.project(volume)        # (360, 384, 256) line integrals
adjoint = A.backproject(sinogram)   # matched adjoint A^T

x = torch.zeros_like(volume, requires_grad=True)
loss = 0.5 * (A.project(x) - sinogram).square().sum()
loss.backward()                     # x.grad = A^T (A x - y)

Custom or calibrated trajectories. Pass calibrated tensors directly instead of a generator; no circular fit is needed. See REFERENCE.

Geometry gradients. Set requires_grad=True on trajectory tensors before you build Projector. See REFERENCE.

Several GPUs and nodes. Use devices=[0, 1, 2, 3] in one process, or one process per GPU with torchrun for one or more nodes. See REFERENCE and DISTRIBUTED.md.

A = Projector(trajectory, (128, 128, 128), (384, 256), detector_spacing=0.8, devices=[0, 1, 2, 3])

Volumes larger than GPU memory. Keep the arrays on CPU. The same calls use CUDA tiles automatically; CUDA inputs retain the full-volume path when its estimated working set fits. Explicit limits are optional:

A = Projector(trajectory, (128, 128, 128), (384, 256), detector_spacing=0.8)
volume = torch.ones(A.volume_shape, device="cpu", requires_grad=True)
sinogram = A.project(volume)                 # CPU output, CUDA computation
sinogram.square().mean().backward()          # CPU volume.grad
# Optional: volume_chunk_shape=(32, 64, 64), view_chunk_size=16

Run python examples/chunked_reconstruction.py for CPU-backed CGLS and measured CUDA allocation. Chunking preserves the Siddon model, with float32 summation differences; smaller blocks can increase transfer and launch overhead. Full arrays and iterative state still need enough host RAM.

Performance

Time per forward, adjoint and CGLS iteration on 1, 4 and 8 GPUs, 64^3 and 128^3

128³ volume 1 GPU 4 GPUs, 1 node 8 GPUs, 2 nodes
Forward projection 8.45 ms 2.66 ms (3.2×) 1.68 ms (5.0×)
Adjoint (backprojection) 20.66 ms 5.89 ms (3.5×) 4.62 ms (4.5×)
CGLS iteration 30.08 ms 8.08 ms (3.7×) 5.59 ms (5.4×)

Circular trajectory, 360 views, detector (2n, 1.5n) cells at pitch 1.25, A100 64 GB GPUs. Small volumes scale less: at 64³, one CGLS iteration takes 4.63 ms on 1 GPU, 1.57 ms on 4 and 1.56 ms on 8. Raw data: docs/assets/scaling.json.

To measure one against several GPUs on your machine (default scan of the script, not the table setup):

python examples/benchmark_projector.py --devices 0 1

TV denotes TV-regularized iterative reconstruction; Adam is the optimizer. Figure labels distinguish the method from its optimizer.

Measured walnut. 240 measured views, circular cone beam, 256³: FDK (Hann window), SIRT (200 iterations), CGLS (20), TV (300, weight 0.3); axial and coronal centre slices.

Measured walnut: FDK, SIRT, CGLS and TV reconstructions

python examples/walnut_reconstruction.py --figure out.png

Simulated helical scan of the walnut. The FDK walnut volume as ground truth, 720 views, 1% noise, 256³. PSNR: FDK 26.67 dB, CGLS (30 iterations) 34.13 dB, SIRT (200) 34.52 dB, TV (200, weight 1.0) 37.77 dB.

Simulated helical scan of the walnut: FDK, CGLS, SIRT and TV reconstructions

python examples/walnut_reconstruction.py --algorithms --save-volume walnut256.npy
python examples/iterative_reconstruction.py --size 256 --views 720 --trajectory helical --noise 0.01 --phantom walnut256.npy --figure out.png

Walnut data: Meaney 2022, Zenodo 6986012, CC BY 4.0; see examples/data/NOTICE.

Examples

quickstart.py, curved_detector.py, chunked_reconstruction.py, analytical_reconstruction.py, iterative_reconstruction.py, walnut_reconstruction.py, geometry_calibration.py, benchmark_projector.py, plot_trajectory.py, and the Slurm template slurm/multi_node.sbatch. Launch modes and distributed-loss rules are in examples/README.md.

Documentation

Document Contents
Trajectory guide Trajectory tuples and Projector usage
docs/REFERENCE.md Capabilities and limits, custom trajectories, geometry gradients, multi-GPU details, geometry and units
docs/DISTRIBUTED.md Execution/memory choices, distributed loss rules, Slurm and cross-node checks
docs/MIGRATION.md Moving from the circular-only API
docs/video/README.md How the intro video is rendered
CHANGELOG.md Release history

Run the test suite on a CUDA host with python -m pytest tests/ -q.

Citation

If you use this library in your research, please cite the software and the technical report:

@software{diffct2025,
  author    = {Yipeng Sun},
  title     = {diffct: Differentiable Computed Tomography Reconstruction with CUDA},
  year      = 2025,
  publisher = {Zenodo},
  doi       = {10.5281/zenodo.14999333},
  url       = {https://doi.org/10.5281/zenodo.14999333}
}

@article{202605.1446,
  doi       = {10.20944/preprints202605.1446.v1},
  url       = {https://doi.org/10.20944/preprints202605.1446.v1},
  year      = 2026,
  month     = {May},
  publisher = {Preprints},
  author    = {Yipeng Sun and Linda-Sophie Schneider and Chengze ye and Andreas Maier},
  title     = {diffct: Differentiable CT Operators from Circular Orbits to Arbitrary Trajectories},
  journal   = {Preprints}
}

License and acknowledgements

Apache 2.0, see LICENSE. The project draws on PYRO-NN and geometry_gradients_CT. Issues and pull requests are welcome. The walnut data are CC BY 4.0 (Meaney 2022); see NOTICE.

Metadata

Release files for diffct 2.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for diffct 2.1.0
File Size Uploaded
diffct-2.1.0.tar.gz 146.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for diffct 2.1.0
File Interpreter ABI Platform
diffct-2.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 215.4 kB

Release files / diffct-2.1.0.tar.gz

Download URL diffct-2.1.0.tar.gz
Size 146.9 kB
Tags Source
SHA-256 checksum
How to use checksums
9b85cf0f18090b6c3c1a81b2e58dc99d09190b293d897ed91508523db1997b0c
BLAKE2b-256 checksum
How to use checksums
7c70528d750afd65dd4161e8b5a4f8cd0dd47857586b5d2736aefa353fc4f9d6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release files / diffct-2.1.0-py3-none-any.whl

Download URL diffct-2.1.0-py3-none-any.whl
Size 68.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
610b60180308eb43ce361ab1c7099cc83de04cdee69b9d9c242cd0363ec13d04
BLAKE2b-256 checksum
How to use checksums
17c547439167bb21371437bd238c246a7883ac50e64593fbcbeb08719a3c1077
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release history Release notifications | RSS feed

2.3.0

2 release files

2.2.1

2 release files

2.2.0

2 release files

This release

2.1.0 This release

2 release files

2.0.2

2 release files

2.0.1

2 release files

2.0.0

2 release files

1.3.4

2 release files

1.3.3

2 release files

1.3.2

2 release files

1.3.1

2 release files

1.3.0

2 release files

1.2.11

2 release files

1.2.10

2 release files

1.2.9

2 release files

1.2.8

2 release files

1.2.7

2 release files

1.2.6

2 release files

1.2.5

2 release files

1.2.4

2 release files

1.2.3

2 release files

1.2.2

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.7

2 release files

1.1.6

2 release files

1.1.5

2 release files

1.1.4

2 release files

1.1.3

2 release files

1.1.2

2 release files

1.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page