medtokenizers
medtokenizers compresses 2D and 3D medical images into latents or discrete
token grids. It provides one encoder-decoder backbone with interchangeable
quantization heads (VQ, LFQ, FSQ, Residual FSQ, VAE, AE), so the quantizer can
be treated as a controlled variable rather than a fixed preprocessing choice.
It also provides shared reconstruction metrics and dataset tokenization
utilities.
This library accompanies the paper Tokenizer-Generator Coupling in Medical Image Generation, which uses it for the tokenizer half of a factorial study. See Citation.
Install
pip install -e ".[test]"
Requires Python 3.10+ and PyTorch 2.0+. Tested on Linux and macOS. A CUDA GPU is needed for 3D training, but everything below runs on CPU.
For a CPU-only install, take PyTorch from its CPU index first so torch and
torchvision come from the same build:
pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu
pip install -e ".[test]"
Run it
Swap the quantizer, keep everything else fixed:
import torch
from medtokenizers import DiscreteTokenizer
x = torch.randn(1, 1, 64, 64)
for quantizer in ["VQ", "FSQ", "RESFSQ"]:
model = DiscreteTokenizer(
dim=2, quantizer=quantizer, resolution=64, spatial_compression=8
).eval()
with torch.no_grad():
tokens = model.tokenize(x) # (1, 8, 8) integer codes
recon = model.detokenize(tokens) # (1, 1, 64, 64)
LFQ is the one head that needs two further arguments, because its codebook is defined by its binary dimension rather than inferred:
model = DiscreteTokenizer(
dim=2,
quantizer="LFQ",
resolution=64,
spatial_compression=8,
codebook_size=1024,
codebook_dim=10,
)
The continuous heads live on a separate class, selected by formulation
instead of quantizer, and return a real-valued latent rather than indices:
from medtokenizers import ContinuousTokenizer
model = ContinuousTokenizer(
dim=2, formulation="VAE", resolution=64, spatial_compression=8
).eval()
with torch.no_grad():
latent = model.tokenize(x) # (1, 4, 8, 8)
recon = model.detokenize(latent)
At evaluation time ContinuousTokenizer.encode returns the posterior mean, so
latents extracted with model.eval() are deterministic.
Set dim=3 for volumes; the same calls take (B, C, H, W, D) tensors.
Volumetric inference
A simulated T1-weighted brain volume ships inside the package (from the BrainWeb
Simulated Brain Database, with provenance in
src/medtokenizers/assets/README.md), so the
example runs without a download and works from an installed wheel.
example_volume_path() resolves it. Random initialisation is enough for a smoke
test; load your own weights for real reconstructions.
python examples/inference_on_brain.py --model-type maisi
Large volumes are reconstructed with Gaussian-weighted sliding windows:
import medrs
import torch
from medtokenizers import MAISITokenizer, example_volume_path
img = medrs.load(str(example_volume_path()))
volume = img.to_torch_with_dtype_and_device(dtype=torch.float32)
volume = volume.unsqueeze(0).unsqueeze(0) # (H, W, D) -> (1, 1, H, W, D)
volume = (volume - volume.min()) / (volume.max() - volume.min() + 1e-8)
model = MAISITokenizer().eval()
with torch.no_grad():
recon = model.reconstruct(volume, roi_size=(96, 96, 64), overlap=0.5)
Sliding-window reconstruction over a full 1 mm volume is memory-hungry. Reduce
roi_size or overlap if you are not on a GPU.
Tokenizers
| Class | Selected by | Output |
|---|---|---|
DiscreteTokenizer |
quantizer="VQ" | "FSQ" | "LFQ" | "RESFSQ" |
integer token grid |
ContinuousTokenizer |
formulation="VAE" | "AE" |
real-valued latent |
MAISITokenizer |
fixed MAISI configuration | real-valued latent |
TiTokTokenizer |
1D transformer tokenizer | fixed-length sequence of K tokens |
RAETokenizer (experimental) |
frozen foundation-model encoder | real-valued latent |
Adding a quantizer means subclassing BaseQuantizer (two abstract methods,
forward and indices_to_codes) and wiring it into DiscreteTokenizer. The
encoder-decoder and the tokenization I/O are unchanged by the choice.
TiTok
TiTok encodes an image or volume into a fixed-length 1D sequence of K tokens.
The encoder concatenates patch tokens with K learnable latent tokens and keeps
only the latter; the decoder reconstructs from quantized latents plus mask
tokens. Input shape must equal resolution, and each spatial dimension must be
divisible by patch_size.
from medtokenizers import TiTokTokenizer
tokenizer = TiTokTokenizer(
dim=2,
in_channels=1,
out_channels=1,
resolution=64,
patch_size=16,
num_tokens=32,
num_embeddings=1024,
hidden_dim=256,
)
indices, codes, quant_loss = tokenizer.encode(torch.randn(2, 1, 64, 64))
recon = tokenizer.decode(codes)
TiTok's original two-stage proxy-code warmup and decoder fine-tuning are not wired into the training scripts; implement that externally if you want the published recipe.
Evaluation
from medtokenizers import compute_lpips, compute_psnr, compute_ssim
psnr = compute_psnr(reference, reconstruction)
ssim = compute_ssim(reference, reconstruction)
lpips = compute_lpips(reference, reconstruction)
TokenizerEvaluator runs these over a loader, together with perplexity and
codebook utilisation for discrete models:
from medtokenizers import TokenizerEvaluator, load_tokenizer
model = load_tokenizer("./path/to/checkpoint")
results = TokenizerEvaluator(model, device="cuda").evaluate(test_loader)
No pretrained checkpoints ship with this repository.
Ecosystem
medtokenizers is one of three packages:
- medrs: medical-image I/O (NIfTI/DICOM) and preprocessing primitives.
- medtokenizers: tokenizers that compress scans into latents or token grids (this package).
- medlatents: generative models (autoregressive, MaskGIT, diffusion, flow matching, Bayesian flow) that learn over those tokens.
images -> medrs (load) -> medtokenizers (tokenize) -> medlatents (generate)
-> medtokenizers (detokenize) -> images
scripts/tokenize_dataset.py writes a directory of per-split .npz files plus
metadata.json, with key codes (int16) for discrete models and latents
(float16) for continuous ones.
Contributing
See CONTRIBUTING.md for development setup and the pull-request workflow, and CODE_OF_CONDUCT.md for community standards.
Citation
@article{chalcroft2026coupling,
author = {Chalcroft, Liam},
title = {Tokenizer--Generator Coupling in Medical Image Generation},
year = {2026},
note = {arXiv preprint, to appear}
}
@software{chalcroft_medtokenizers,
author = {Chalcroft, Liam},
title = {{medtokenizers}: Continuous and discrete tokenizers for volumetric medical imaging},
url = {https://github.com/liamchalcroft/medtokenizers},
version = {0.1.0}
}
Machine-readable metadata is in CITATION.cff.
License
MIT, see LICENSE.
Some modules derive from third-party projects: CompVis (Stable Diffusion,
taming-transformers) and lucidrains vector-quantize-pytorch under MIT, and
NVIDIA Cosmos-Tokenizer and MONAI/MAISI under Apache-2.0. Their terms are
preserved in THIRD_PARTY_NOTICES.md and
NOTICE. Two things are outside the MIT licence: NVIDIA MAISI
pretrained weights, if you use them, remain under NSCLv1; and the bundled
bundled BrainWeb volume is data carrying its own citation requirement.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file medtokenizers-0.1.0.tar.gz.
File metadata
- Download URL: medtokenizers-0.1.0.tar.gz
- Upload date:
- Size: 5.9 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c14b02aae6ff31922ac0ab6685c31e3840fc8b04926e730a59a48b07dc613407
|
|
| MD5 |
f1831a8cd6b34cf154fa77fd68dcc5d5
|
|
| BLAKE2b-256 |
ac4c35717c02d804f714a25d962e271d7ac80c7010250ca12c733f543543c033
|
File details
Details for the file medtokenizers-0.1.0-py3-none-any.whl.
File metadata
- Download URL: medtokenizers-0.1.0-py3-none-any.whl
- Upload date:
- Size: 5.8 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
304ace399f3785ee1b5fa30c8b3f6105bfe0900c1f686118a944049e69043e80
|
|
| MD5 |
d397627a708a454ccb09e822ad9c6859
|
|
| BLAKE2b-256 |
bb495fd356133fcc4cda8a091f4ddf83eb0ceaba031e161e6e3f8f5a49ac6cbe
|