Skip to main content

CG-SENSE HOME

Step-by-step tutorial of Conjugate Gradient SENSE (CG-SENSE) reconstruction by Hung P. Do.

Citing this work

DOI

Do, H. P. (2026). CG-SENSE Tutorial version 1.0.0 (1.0.0). Zenodo. https://doi.org/10.5281/zenodo.18526383

Organization of the tutorial

This tutorial was written by Hung Do based on the RRSG_Challenge_01 github repository.

My modifications are:

  1. Most importantly, I organized the code into coherent modules and repackaged the code into a Python package named cgsense2023 for easy installation and use. You can install the package by running pip install cgsense2023 in your terminal.

  2. For teaching purposes, I created this tutorial for anyone who is interested in learning about CG-SENSE and the artifacts that can arise from it.

  3. The gridding part was untouched, but I retouched the I/O interface such that parameters are consolidated and grouped in one and only one central location.

  4. For my own learning purposes, I re-implemented the CG-SENSE algorithm from scratch without referring to the original code. There are several variations of the CG-SENSE algorithm, but the results are generally similar.

  5. Implemented gradient descent (GD) and steepest descent (SD) algorithms for comparison with CG-SENSE.

  6. Added code to create k-space trajectories and visualize them.

  7. Added quantitative metrics for evaluating the reconstructed images, such as RMSE and SSIM, etc.

  8. Added code to visualize the artifacts in the reconstructed images and assess convergence of the CG-SENSE algorithm.

W.I.P Tasks

Contributions to the below tasks are welcome!

  • Document the standardization of the raw h5-file, otherwise read_data() has to be modified every time a deviation in h5-file is encountered.

  • Refactor, simplify, modularize the gridding reconstructions. Currently, it is difficult to understand, especially for new learner.

  • Add dstore flag in gradient descent or conjugate gradient optimization functions to store intermediate reconstruction in each iteration.

  • Add theoretical descriptions on MRI, MRI recons, and gradient Descent, and gonjugate gradient algorithms.

  • etc.

How it works

pip install

The cgsense2023 package was uploaded to PyPI and can be easily installed using the below command.

pip install cgsense2023

Plot Module

from cgsense2023.plot import *
import numpy as np
# Sequential - full - spoke radial trajectory
traj_full = gen_radial_traj(golden=False, full_spoke=True)
show_trajectory(traj_full, golden=True, figsize=(10,8))

# golden - full - spoke radial trajectory
traj_full_golden = gen_radial_traj(golden=True, full_spoke=True)
show_trajectory(traj_full_golden, golden=True, figsize=(10,8))

Nim, Nx, Ny = 12, 128, 256
x1 = np.random.randn(Nim, Nx, Ny)
x2 = np.random.randn(1, Nx, Ny)
show_image_grid(x1)
Warning: number of images (12) is larger than number of panels (2x5)!

show_image_grid(x2)

Metrics Module

from cgsense2023.metrics import *
import numpy as np
# same dimensions
Nim, Nx, Ny = 11, 128, 256
x1 = np.random.randn(1, Nx, Ny)
x2 = np.random.randn(1, Nx, Ny)
print_metrics(x1, x2)
+---------+-----------+
| Metrics |   Values  |
+---------+-----------+
|   MSE   | 1.999e+00 |
|   NMSE  | 2.000e+00 |
|   RMSE  | 1.414e+00 |
|  NRMSE  | 1.414e+00 |
|   PSNR  |   14.981  |
|   SSIM  | 0.0092604 |
+---------+-----------+

Gridding Reconstruction

from cgsense2023.math import *
from cgsense2023.io import *
import cgsense2023 as cgs2003
from cgsense2023.mri import *
from cgsense2023.optimizer import *
import h5py
import numpy as np
import matplotlib.pyplot as plt

Data Paths

# path to the data file
fpath = '../testdata/rawdata_brain.h5'
# path to the reference results
rpath = '../testdata/CG_reco_inscale_True_denscor_True_reduction_1.h5'
with h5py.File(rpath, 'r') as rf:
    print(list(rf.keys()))
    ref_cg = np.squeeze(rf['CG_reco'][()][-1])
    ref_grid = np.squeeze(rf['Coil_images'][()])
['CG_reco', 'Coil_images']
ref_cg.shape, ref_grid.shape
((300, 300), (12, 300, 300))

Setup Parameters

# one stop shop for all Parameters and Data
params = setup_params(fpath, R=1)
['Coils', 'InScale', 'rawdata', 'trajectory']

Setup MRI Operator

# Set up MRI operator
mrimodel = MriImagingModel(params)
mriop = MriOperator(data_par=params["Data"],optimizer_par=params["Optimizer"])
mriop.set_operator(mrimodel)
# Single Coil images after FFT
my_grid = mriop.operator.NuFFT.adjoint(params['Data']['rawdata_density_cor'])
my_grid.shape, ref_grid.shape
((12, 300, 300), (12, 300, 300))
# test gridding recon results
np.allclose(ref_grid, my_grid)
True
# test gridding recon results
np.array_equal(ref_grid, my_grid)
False
print_metrics(np.abs(ref_grid[0]), np.abs(my_grid[0]))
+---------+-----------+
| Metrics |   Values  |
+---------+-----------+
|   MSE   | 1.472e-24 |
|   NMSE  | 5.905e-15 |
|   RMSE  | 1.213e-12 |
|  NRMSE  | 7.684e-08 |
|   PSNR  |   154.87  |
|   SSIM  |    1.0    |
+---------+-----------+
show_image_grid(my_grid, figsize=(10,10), rows=3, cols=4)

show_image_grid(rss_rec(my_grid), figsize=(10,10))

Gradient Descent

guess = np.zeros((params['Data']['image_dim'],params['Data']['image_dim']))
SD_result, SD_residuals, SD_ref_res = steepest_descent(mriop, guess, 
                                            params['Data']['rawdata_density_cor'], 
                                            iters=50,
                                            ref=ref_cg)
Residuum at iter 50 : 6.553379e-06
show_compared_images(np.abs(ref_cg), np.abs(SD_result), diff_fac=10, 
                     labels=['Reference', 'Steepest Descent', 'diff'])

np.allclose(ref_cg, SD_result)
False
print_metrics(np.abs(ref_cg), np.abs(SD_result))
+---------+-----------+
| Metrics |   Values  |
+---------+-----------+
|   MSE   | 5.633e-14 |
|   NMSE  | 7.888e-05 |
|   RMSE  | 2.373e-07 |
|  NRMSE  | 8.882e-03 |
|   PSNR  |   55.242  |
|   SSIM  |   0.9988  |
+---------+-----------+

CG’s Semi-Convergence Behavior

CG_result, CG_residuals, CG_ref_res = conjugate_gradient(mriop, guess, 
                                            params['Data']['rawdata_density_cor'], 
                                            iters=50,
                                            ref=ref_cg)
Residuum at iter 50 : 2.993229e-06
plt.plot(np.log10(SD_ref_res),'*--', label='SD reference_norms');
plt.plot(np.log10(SD_residuals),'*--', label='SD residual_norms');
plt.plot(np.log10(CG_ref_res),'*--', label='CG reference_norms');
plt.plot(np.log10(CG_residuals),'*--', label='CG residual_norms');
plt.grid();
plt.xlabel("# iteration")
plt.ylabel("residuals (log10)")
plt.legend();

Conjugate Gradient vs. REF

Based on the “semi-convergence” plot above, the optimal number of iterations for CG and SD are around 10 and 28, respectively.

CG_result_vs_REF, _, _ = conjugate_gradient(mriop, guess, 
                                            params['Data']['rawdata_density_cor'], 
                                            iters=10,
                                            ref=ref_cg)
Residuum at iter 10 : 1.826174e-05
show_compared_images(np.abs(ref_cg), np.abs(CG_result_vs_REF), diff_fac=200000, 
                     labels=['Reference', 'Conjugate Gradient', 'diff'])

np.allclose(ref_cg, CG_result_vs_REF)
True
print_metrics(np.abs(ref_cg), np.abs(CG_result_vs_REF))
+---------+-----------+
| Metrics |   Values  |
+---------+-----------+
|   MSE   | 1.196e-22 |
|   NMSE  | 1.675e-13 |
|   RMSE  | 1.094e-11 |
|  NRMSE  | 4.093e-07 |
|   PSNR  |   141.97  |
|   SSIM  |    1.0    |
+---------+-----------+

References

The list is not exhaustive so if you notice any missing references, please report an issue. I will promptly correct it.

Citing this work

DOI

Do, H. P. (2026). CG-SENSE Tutorial version 1.0.0 (1.0.0). Zenodo. https://doi.org/10.5281/zenodo.18526383

Metadata

Release files for cgsense2023 1.0.2

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

Source distribution (sdist)

Source distribution for cgsense2023 1.0.2
File Size Uploaded Provenance
cgsense2023-1.0.2.tar.gz 24.1 kB Without provenance Details

Built distribution (wheel)

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

Total release size: 45.4 kB

Release files / cgsense2023-1.0.2.tar.gz

Download URL cgsense2023-1.0.2.tar.gz
Size 24.1 kB
Tags Source
SHA-256 checksum
How to use checksums
568a07d8b6c6e1d5524dc2edc85ed3ab1474d8a9370318ad07ac6dfc255eb79a
BLAKE2b-256 checksum
How to use checksums
f6d8a51fcb19b0959c575fd6562194449aff6f2320e401933ece39568776fb6f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.8

Release files / cgsense2023-1.0.2-py3-none-any.whl

Download URL cgsense2023-1.0.2-py3-none-any.whl
Size 21.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
21560250fd4501cc52467d8a8509fa981455cbc53c6c9b0d928f9723b886bd47
BLAKE2b-256 checksum
How to use checksums
4189eb401e6167977701cde67e5a1dcc6565870f68d00fc0eea9cc746895dd5c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.8

Security for cgsense2023 1.0.2

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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