DeepRelaxo

August 6, 2026 · View on GitHub

Fast Mono-Exponential Magnitude Brain R2* Mapping With Reduced Echoes Using Self-Supervised Deep Learning

MRM 2025  |  HuggingFace  |  deepMRI collection

This repository contains a PyTorch inference pipeline for the DeepRelaxo cascade: an estimator stage based on Transformer-MLP followed by a denoiser stage based on 3D-UNet.

Jump to: Highlights · Layout · Quick Start · Docker · DICOM → NIfTI conversion · Web App · Command-Line Interface · Run Demo Examples

Highlights

  • NIfTI / MAT input — multiple 3D echoes or a single 4D volume (.nii, .nii.gz, .mat v5/v7.3 all supported).
  • DICOM folder input, no separate conversion step — the web app's DICOM Folder tab (and the CLI's --dicom_dir) walks a folder (sub-folders OK, mixed modalities OK) straight from the browser/command line, groups by the EchoTime tag, and auto-fills TEs. The standalone dicom_to_nifti.py (byte-identical with the copies in iQSM and iQSM+) is also still available for converting once and reusing the NIfTIs across multiple runs, or batch-scripting many subjects; see DICOM → NIfTI conversion.
  • Browser-based UI — collapsible sections, live progress, slice slider, shape verification (echo-to-echo and mask-vs-magnitudes), brain-mask preview alongside the R2* maps, per-run "equivalent CLI command" log entry, port auto-fallback (7860 → 7861 → …), and SSH-aware launch (the auto-open browser step is skipped on remote hosts and a port-forward hint is printed instead).
  • Two outputs — Step 1 (R2s_transformer_mlp.nii) is downloadable as soon as it's ready; Step 2 (R2s_deeprelaxo.nii) finalises afterwards.

Layout

  • app.py — Gradio web app for browser-based inference.
  • run_deeprelaxo_pipeline.py — runs the estimator stage followed by the denoiser stage.
  • run_estimator_stage.py — estimator-stage inference utilities.
  • run_denoiser_stage.py — single-map denoiser inference utilities.
  • dicom_to_nifti.py — standalone, self-contained DICOM → NIfTI converter. Byte-identical with the copies in iQSM and iQSM+; writes a single magnitude NIfTI (3D / 4D) plus a params.json ready for --from_converted.
  • data_utils.py — NIfTI / MAT / DICOM loaders and shape utilities (the in-repo magnitude-only DICOM loader is what run_deeprelaxo_pipeline.py --dicom_dir uses; for new workflows prefer the standalone dicom_to_nifti.py).
  • transformer_mlp_model.py and unet3d_model.py — model architectures.
  • bet2_utils.py — automatic brain-mask generation via vendor/bet2/, used by run_deeprelaxo_pipeline.py / app.py when no mask is supplied.
  • vendor/bet2/ — FSL's bet2 binary + its runtime shared libraries, vendored directly (not a full FSL install). Same copy as iQSM_Plus and iQSM.
  • Dockerfile — self-contained image (Python env, checkpoints, bet2 all baked in) -- see Docker.

Quick Start

1. Get the code

Option A — Git

git clone https://github.com/sunhongfu/DeepRelaxo.git
cd DeepRelaxo

Option B — Download ZIP

  1. Open the GitHub repository page.
  2. Click CodeDownload ZIP.
  3. Unzip and open a terminal in the folder.

2. Install dependencies

A fresh virtual environment is the recommended way — it isolates DeepRelaxo's dependencies from anything else on your system and avoids version conflicts.

You need Python 3.10 or 3.11. Check your version:

python --version

If Python is not installed, download it from python.org. On Windows, tick Add Python to PATH during installation.

Create and activate a virtual environment:

macOS / Linux:

python -m venv venv
source venv/bin/activate

Windows:

python -m venv venv
venv\Scripts\activate

You should see (venv) in your prompt. Run this activation command each time you open a new terminal.

Install PyTorch. Go to pytorch.org/get-started/locally, select your OS and CUDA version, and copy the install command. For example:

CUDA 12.4 (recommended if you have an NVIDIA GPU):

pip install torch --index-url https://download.pytorch.org/whl/cu124

CPU only (slower, but works without a GPU):

pip install torch --index-url https://download.pytorch.org/whl/cpu

Install remaining dependencies. Pick one of the two options below depending on whether you want the browser-based web app:

  • Web app + Command-Line (recommended for most users):

    pip install -r requirements-webapp.txt
    

    Adds Gradio and Matplotlib for the browser UI and slice previews.

  • Command-Line only (lighter install, fewer dependencies, no web stack):

    pip install -r requirements.txt
    

    Skips Gradio and its ~18 transitive packages (FastAPI, Pydantic, Uvicorn, etc.). Recommended for headless servers, HPC clusters, or environments where Gradio's deps conflict with other tools.

Already have PyTorch installed? Click here to skip the venv setup.

If you have a working Python environment with PyTorch and prefer to reuse it, install one of the two requirements files above into that environment directly.

Note: this may upgrade or downgrade other packages in the environment (e.g. pydantic, typing-extensions) and can conflict with unrelated tools like TensorFlow. A clean venv avoids this. The Command-Line only install is much less likely to cause conflicts since it doesn't pull in Gradio's dependency chain.


3. Download checkpoints (and optionally demo data)

Large files (checkpoints and demo data) are excluded from git and hosted on Hugging Face: sunhongfu/DeepRelaxo.

Download checkpoints (~350 MB, required, one-time):

python run_deeprelaxo_pipeline.py --download-checkpoints

Optional — download demo data. If you'd like to try DeepRelaxo on a provided 5-echo GRE NIfTI dataset (TE = 4.9, 9.9, 14.8, 19.8, 24.7 ms) before adapting it to your own data, also run:

python run_deeprelaxo_pipeline.py --download-demo

This places sample magnitude echoes and a BET mask in demo/. See Run Demo Examples below for how to run it.

Manual download (optional). If the auto-download fails (e.g. behind a firewall), grab the files from the Hugging Face page above and place them as follows:

DeepRelaxo/
├── checkpoints/
│   ├── transformer_mlp_epoch_80.pth
│   └── unet3d_epoch_140.pth
├── demo/
│   ├── BET_mask.nii
│   ├── mag1.nii
│   ├── mag2.nii
│   ├── mag3.nii
│   ├── mag4.nii
│   ├── mag5.nii
│   └── params.json
└── ...

4. Run

Choose the web app (recommended) or the command-line interface -- natively, or via Docker if you'd rather not set up a Python environment (also the only way to get automatic bet2 brain extraction on Windows or macOS, since vendor/bet2/ is a Linux/x86_64 binary that can't execute natively there).


Docker

Builds a self-contained image (Python env, checkpoints, and bet2 all baked in) that runs the same way on Windows, macOS, or Linux -- Docker Desktop runs a real Linux VM on all three, which is what lets vendor/bet2/'s Linux/x86_64 binary actually execute regardless of host OS.

# Build (from this repo's root; needs network access -- checkpoints are downloaded
# during the build). --platform linux/amd64 is required explicitly on Apple Silicon
# hosts (see the Dockerfile's header comment for why).
docker build --platform linux/amd64 -t deeprelaxo .

# Run the web app (default) -- open http://localhost:7860 in your browser
docker run --rm -p 7860:7860 deeprelaxo

# With GPU acceleration (needs the NVIDIA Container Toolkit on the host)
docker run --rm --gpus all -p 7860:7860 deeprelaxo

# Run the CLI instead, e.g. against a folder of NIfTIs already on the host
docker run --rm -v /path/to/data:/data deeprelaxo \
    python3 run_deeprelaxo_pipeline.py --from_converted /data/converted \
    --transformer_out /data/transformer_out --deeprelaxo_out /data/deeprelaxo_out

CPU-only hosts work too (just slower) -- drop --gpus all entirely, no other changes needed. See the Dockerfile itself for the full annotated build. If bet2 isn't found (checked $BET2_DIR, /opt/bet2, ./vendor/bet2) or fails to run, estimation still completes without a mask (all voxels processed) rather than failing.


DICOM → NIfTI conversion

If your data is a folder of raw DICOMs from a multi-echo GRE acquisition, the web app's DICOM Folder tab handles conversion automatically -- no separate step needed for a normal single-run use case. This section covers the standalone script, useful when you want to convert once and reuse the NIfTIs across multiple runs (CLI or web app), or when scripting a batch of subjects. The script is byte-identical with the copies in iQSM and iQSM+ — independent of the downstream pipeline. Pick whichever repo's copy is closest at hand.

Two modes

Normal path — --dicom_dir DIR [DIR …]  ·  auto-classifies by DICOM ImageType, ComplexImageComponent, and the GE private tag (0043, 102f). Use this whenever your tags are reliable. DeepRelaxo only needs magnitude, so passing extra modalities is harmless — they're written to disk but not consumed:

# Single mixed folder of DICOMs (any extension or none — .dcm, .ima, .dicom):
python dicom_to_nifti.py --dicom_dir /path/to/dicoms

# Multiple folders walked together (e.g. magnitude + phase in separate dirs):
python dicom_to_nifti.py --dicom_dir /path/to/mag /path/to/phase

# Specify the output folder (default: ./dicom_converted):
python dicom_to_nifti.py --dicom_dir /path/to/dicoms --out_dir ./my_subject_converted

Rescue path — --mag_dir  ·  for when magnitude DICOMs are mis-tagged (e.g. ImageType = ORIGINAL/PRIMARY/OTHER and --dicom_dir would route them to the wrong bucket). The script trusts the caller and force-places every file into the magnitude bucket:

python dicom_to_nifti.py --mag_dir /path/to/magnitude_dicoms

The --phase_dir, --real_dir, --imag_dir rescue flags exist too but produce phase / real / imaginary NIfTIs that DeepRelaxo doesn't consume — if you don't have any magnitude DICOMs at all, you'll have to derive magnitude yourself before running DeepRelaxo. The two modes can't be mixed.

After conversion the script writes (names depend on echo count):

converted/
├── dcm_converted_magnitude[_4d].nii.gz   # 3D for single-echo, 4D for multi-echo
├── dcm_converted_phase[_4d].nii.gz       # written if phase was present (DeepRelaxo ignores it)
└── params.json

…and prints a copy-paste-friendly summary:

─── Acquisition values (paste these into the web app) ───
  Echo Times (ms)  : 4.9, 9.9, 14.8, 19.8, 24.7
  Voxel size (mm)  : 1 1 1
  B0 (Tesla)       : 3.0
─────────────────────────────────────────────────────────

params.json carries machine-readable values (te_ms, voxel_size_mm, b0_T, b0_direction) and copy-paste strings (te_ms_string, voxel_size_string, b0_direction_string) formatted exactly the way the web app's input field expects them. Open the JSON, copy the relevant string, paste into the form. Or skip the form and use --from_converted (auto-fills everything from the same JSON):

# CLI — auto-loads TEs and the magnitude NIfTI path from params.json:
python run_deeprelaxo_pipeline.py --from_converted ./dicom_converted \
                                  --mask BET_mask.nii

# Web app — upload dcm_converted_magnitude[_4d].nii.gz to "MRI Magnitudes"
# (4D files are accepted as multi-echo), paste te_ms_string from
# params.json into the Echo Times field:
python app.py

--out_dir is overwritten in place on each run. A single consolidated params.json is written. If params.json or any dcm_converted_*.nii(.gz) already exists, the script lists them and prints a clear warning before overwriting. Use a fresh --out_dir per subject / acquisition.

Why isn't this in the web app? Browsers don't handle thousand-file folder uploads well: tempfile creation per file hits the OS open-file limit (OSError: Too many open files), and the "Upload N files to this site?" prompt makes some users worry their data is being uploaded to a remote server. Running the converter locally avoids both — and DICOM → NIfTI is a one-time step, so re-running the pipeline after that is fast.


Web App

python app.py

The app picks port 7860 by default; if it's busy, it falls back automatically (7861, 7862, …). Your default browser opens automatically at the dark-themed URL once the server is ready (no flash of light theme).

Usage walk-through

The page is organised top-to-bottom; each section is a collapsible accordion.

1. GRE Magnitudes

Two tabs, either one populates the same magnitude list below:

DICOM Folder (recommended for raw scanner data) — click Select DICOM Folder and pick a folder of raw multi-echo GRE magnitude DICOMs in your OS's native folder picker; sub-folders are walked automatically, and any non-magnitude files (phase, localizers, etc.) mixed in are silently ignored. Echoes are grouped by the EchoTime DICOM tag, slices sorted by ImagePositionPatient, converted to per-echo NIfTIs, and the detected TEs auto-fill the Echo Times field below -- no separate script or manual TE entry needed. Large studies (hundreds to low thousands of files) take anywhere from several seconds to a couple of minutes to upload and parse; progress is shown during both phases. Selecting a new DICOM folder replaces the current magnitude list (rather than merging), since mixing DICOM-derived echoes with separately uploaded NIfTI echoes would give an ambiguous TE association.

NIfTI / MAT — click Add NIfTI / MAT Magnitudes and pick:

  • multiple 3D files (one per echo) — .nii, .nii.gz, or .mat; or
  • a single 4D volume of shape (X, Y, Z, n_echoes).

Files with unsupported extensions are dropped with a Gradio warning toast. You can add files in batches. .mat files are accepted in both v5 (default save) and v7.3 (save -v7.3) formats; each .mat file must contain exactly one numeric array. Enter Echo Times yourself in this mode (not auto-detected, unlike the DICOM tab). If you'd rather convert DICOMs to NIfTI ahead of time (e.g. to reuse the same converted files across multiple runs), dicom_to_nifti.py is still available standalone.

2. Processing Order

Lists every magnitude file that will be fed to the pipeline (sorted in natural numeric order: mag1, mag2, …, mag10). Below the list, a one-line shape summary tells you whether all files share the same volume dimensions — and if not, lists each per-file shape so you can spot the outlier.

  • Click ✕ next to any file to remove it (≥2 files only).
  • Click ✕ Remove all magnitudes to wipe the list.

3. Echo Times (ms)

A single textbox accepts two equivalent formats:

  • Comma-separated values — one per echo, irregular spacings allowed: 2.4, 3.6, 9.2, 20.8
  • Compact first_TE : spacing : count — uniform spacing only: 4.9 : 5 : 5 expands to 4.9, 9.9, 14.8, 19.8, 24.7

4. Brain Mask (optional)

Click Select Brain Mask to provide a BET (or any binary) mask yourself. Supported: .nii, .nii.gz, .mat (v5 or v7.3).

After upload, the field shows: Loaded: BET_mask.nii · Shape: 192 × 256 × 176 · dtype: uint8 · ✓ matches magnitudes. If the mask shape doesn't match the spatial dims of your magnitudes, you get a clear warning so you can fix it before running.

Click ✕ Remove Brain Mask to clear it. If you don't upload one, one is generated automatically via bet2 (FSL's Brain Extraction Tool, vendored at vendor/bet2/) when you click Run — uncheck "Auto brain-extract via bet2 if no mask is uploaded" to skip that. Without any mask at all, all voxels are processed — significantly slower than processing only the masked brain region.

5. Hyper-parameters (collapsed by default)

Voxel Batch Size — defaults to 50,000. Reduce if you run out of GPU memory.

6. Run Pipeline

Hit the green Run Pipeline button. Three sections appear in sequence:

  • Log — streaming console output, including a RUN CONFIGURATION block that prints the equivalent command-line invocation so you can reproduce the run from a terminal.
  • ResultsR2s_transformer_mlp.nii (Step 1) downloadable as soon as it's ready, then R2s_deeprelaxo.nii (Step 2) once the denoiser finishes.
  • Visualisation — middle-slice grayscale preview of both maps, with a Z-slice slider (Prev / Next buttons or drag) to scrub through the volume. Display window (R2* min / max in s⁻¹) is editable. If you supplied a brain mask, it's previewed below the R2* maps (sharing the same slice slider) so you can spot orientation mismatches at a glance.

GPU memory is released between runs, so you can upload a new dataset and re-run without restarting the page.


Command-Line Interface

The pipeline can also be driven from the terminal using a YAML config file or explicit arguments.

Config file

python run_deeprelaxo_pipeline.py --config config.yaml

Example config.yaml:

data_dir: Data/your_subject
echoes:
  - file: mag_echo_01.nii
    te_ms: 4.9
  - file: mag_echo_02.nii
    te_ms: 9.9
  - file: mag_echo_03.nii
    te_ms: 14.8
mask: BET_mask.nii
transformer_out: transformer_outputs
deeprelaxo_out: deeprelaxo_outputs
transformer_batch_size: 50000

For a single 4D NIfTI:

data_dir: Data/your_subject
echo_4d: magnitudes_4d.nii.gz
te_ms: [4.9, 9.9, 14.8]
mask: BET_mask.nii

Direct Command-Line

From a folder produced by the standalone dicom_to_nifti.py — TE values and the magnitude NIfTI path are read from params.json:

python run_deeprelaxo_pipeline.py \
  --from_converted Data/your_subject/dicom_converted \
  --mask BET_mask.nii

--from_converted reads dcm_converted_magnitude[_4d].nii.gz (3D for single-echo, 4D for multi-echo) and the TE list from params.json. This is the recommended path.

DICOM folder, one-shot (skips the standalone-conversion step — convenient if you don't plan to re-run on the same data):

python run_deeprelaxo_pipeline.py \
  --dicom_dir Data/your_subject_dicoms \
  --mask BET_mask.nii

The folder is walked recursively, magnitude images are filtered, grouped by EchoTime, sorted by ImagePositionPatient, and saved as one NIfTI per echo (dcm_converted_to_nii_e1.nii, dcm_converted_to_nii_e2.nii, …) inside <transformer_out_parent>/dicom_converted_nii/. TE values come from headers — pass --te_ms only to override. This is the legacy in-repo magnitude-only loader; for repeat runs over the same dataset, prefer the standalone dicom_to_nifti.py + --from_converted (output schema is unified and params.json carries copy-paste-ready strings).

Multiple 3D NIfTI echoes:

python run_deeprelaxo_pipeline.py \
  --data_dir Data/your_subject \
  --echo_files mag1.nii mag2.nii mag3.nii \
  --te_ms 4.9 9.9 14.8 \
  --mask BET_mask.nii

Single 4D NIfTI:

python run_deeprelaxo_pipeline.py \
  --data_dir Data/your_subject \
  --echo_4d magnitudes_4d.nii.gz \
  --te_ms 4.9 9.9 14.8 19.8 24.7 \
  --mask BET_mask.nii

MATLAB inputs (one file per echo):

python run_deeprelaxo_pipeline.py \
  --data_dir Data/your_subject \
  --echo_files mag1.mat mag2.mat mag3.mat \
  --te_ms 4.9 9.9 14.8 \
  --mask BET_mask.nii

MATLAB 4D:

python run_deeprelaxo_pipeline.py \
  --data_dir Data/your_subject \
  --echo_4d magnitudes_4d.mat \
  --te_ms 4.9 9.9 14.8 19.8 24.7 \
  --mask BET_mask.nii

.mat inputs (magnitudes or mask) must contain a single numeric array per file. If a .mat file contains multiple arrays, re-save it with only the array you want. The same applies to .mat masks.

Config notes

  • data_dir, transformer_out, and deeprelaxo_out are resolved relative to the config file.
  • Echo file and mask paths are resolved relative to data_dir. Absolute paths are kept verbatim (so you can mix files from different folders).
  • --data_dir is optional in direct CLI mode — defaults to the current working directory if omitted.
  • If mask is omitted, one is generated automatically via bet2 (FSL's Brain Extraction Tool, vendored at vendor/bet2/) run on the first magnitude echo; --no_bet2 (or no_bet2: true in a YAML config) reconstructs whole-head (all-ones mask) instead.
  • Default transformer_batch_size is 50000; reduce if GPU memory is limited.
  • Checkpoints are loaded from checkpoints/transformer_mlp_epoch_80.pth and checkpoints/unet3d_epoch_140.pth.

Run Demo Examples

Once you've downloaded the demo data (see step 3 of the Quick Start), the easiest way to verify your install is to run the demo from the command line. The demo is a 5-echo GRE acquisition with TE = 4.9, 9.9, 14.8, 19.8, 24.7 ms.

Option 1 — Command-line with direct arguments

python run_deeprelaxo_pipeline.py \
  --data_dir demo \
  --echo_files mag1.nii mag2.nii mag3.nii mag4.nii mag5.nii \
  --te_ms 4.9 9.9 14.8 19.8 24.7 \
  --mask BET_mask.nii

Option 2 — Command-line with a YAML config

Save the following as demo_config.yaml:

data_dir: demo
echoes:
  - file: mag1.nii
    te_ms: 4.9
  - file: mag2.nii
    te_ms: 9.9
  - file: mag3.nii
    te_ms: 14.8
  - file: mag4.nii
    te_ms: 19.8
  - file: mag5.nii
    te_ms: 24.7
mask: BET_mask.nii

Then run:

python run_deeprelaxo_pipeline.py --config demo_config.yaml

Option 3 — Run the demo through the web app

Launch the web app:

python app.py

Under MRI Magnitudes, click Add NIfTI / MAT Magnitudes and pick all five demo/mag*.nii files. In Echo Times, paste 4.9, 9.9, 14.8, 19.8, 24.7 (or the compact form 4.9 : 5 : 5). In Brain Mask, click Select Brain Mask and pick demo/BET_mask.nii. Hit Run Pipeline.

All three options produce the same outputs: a Step 1 R2* map (R2s_transformer_mlp.nii) and a final denoised R2* map (R2s_deeprelaxo.nii).