Note
Go to the end to download the full example code.
Data and experiments¶
An experiment fixes a problem: the geometry, the noise, the dataset and its splits. Every method trained or tested on the same experiment sees the same data, so methods can be compared. Experiments give datasets, torch datasets of (measurements, target) pairs, and a record of each: what the data are, written so that they can be made again.
Previous: Parameters and specs. Next: Models.
Needs a GPU and the processed LIDC-IDRI data in LION_DATA_PATH (see
LION/data_loaders/LIDC_IDRI/).
The experiments¶
LION.experiments.ct_experiments has LION’s simulated CT problems on
LIDC-IDRI: clinical, low and extremely low dose, each with full, sparse-view
and limited-angle sampling. Their doses are photons per detector pixel:
import matplotlib.pyplot as plt
import torch
from LION.experiments import ct_experiments
print(
ct_experiments.CLINICAL_I0,
ct_experiments.LOW_DOSE_I0,
ct_experiments.EXTREMELY_LOW_DOSE_I0,
)
experiment = ct_experiments.LowDoseCTRecon()
print(experiment.experiment_params) # name, geometry, noise, data loader
42000 11000 2100
name : Low dose full angular sampling experiment
operator_params : CT Geometry
CT type/mode = fan
-----
Distance from source to detector (DSD) = 1050 mm
Distance from source to origin (DSO)= 575 mm
-----
Detector
Detector shape = [ 1 1024]
Detector size = [ 1 1024] mm
-----
Image
Image shape = [ 1 512 512]
Image size = [ 0.9765625 500. 500. ] mm
Number of angles = (360,)
noise_params : noise_model : physical
I0 : 11000
sigma : 5
sigma_blur : 0.3015
detector : energy_integrating
mass_attenuation : 0.1837
min_counts : 1.0
seed : 0
data_loader_params : name : LIDC-IDRI Data Loader
training_proportion : 0.8
validation_proportion : 0.1
testing_proportion : 0.09999999999999995
max_num_slices_per_patient : 5
pcg_slices_nodule : 0.5
legacy_slice_selection : False
legacy_patient_list : False
task : reconstruction
folder : /store/cia-lion/datasets/processed/LIDC-IDRI
clevel : 0.5
annotation : consensus
annotation_seed : 0
operator_params : CT Geometry
CT type/mode = fan
-----
Distance from source to detector (DSD) = 1050 mm
Distance from source to origin (DSO)= 575 mm
-----
Detector
Detector shape = [ 1 1024]
Detector size = [ 1 1024] mm
-----
Image
Image shape = [ 1 512 512]
Image size = [ 0.9765625 500. 500. ] mm
Number of angles = (360,)
Its geometry is the operator’s parameters (Operators: CT geometry, projections and reconstructions), the one the sinograms are made with and that models take:
print(experiment.operator_params)
CT Geometry
CT type/mode = fan
-----
Distance from source to detector (DSD) = 1050 mm
Distance from source to origin (DSO)= 575 mm
-----
Detector
Detector shape = [ 1 1024]
Detector size = [ 1 1024] mm
-----
Image
Image shape = [ 1 512 512]
Image size = [ 0.9765625 500. 500. ] mm
Number of angles = (360,)
Datasets¶
get_dataset("train"), "validation" or "test": the splits are by
patient, so no patient is in two. A sample is (noisy sinogram, image), on
LION’s device.
training = experiment.get_dataset("train")
validation = experiment.get_dataset("validation")
test = experiment.get_dataset("test")
print(len(training), len(validation), len(test))
sinogram, image = training[0]
print(sinogram.shape, image.shape, image.device)
fig, axes = plt.subplots(1, 2, figsize=(9, 4))
axes[0].imshow(sinogram[0].cpu(), cmap="gray", aspect="auto")
axes[0].set_title("noisy sinogram")
axes[1].imshow(image[0].cpu(), cmap="gray")
axes[1].set_title("image (density, g/cm³)")
for ax in axes:
ax.axis("off")

/mhome/damtp/r/ab2860/AItomotools/LION/data_loaders/LIDC_IDRI.py:487: UserWarning: LIDC-IDRI: left out 2 damaged or unusable files (re-run the pre-processing for these patients): ['LIDC-IDRI-0238 (not resampled)', 'LIDC-IDRI-0585 (not resampled)']
warnings.warn(
4030 505 510
torch.Size([1, 360, 1024]) torch.Size([1, 512, 512]) cuda:0
The noise is drawn from a seed and the slice: a slice has one noisy measurement, the same each epoch and in every run, as a scan is measured once.
print(torch.equal(training[0][0], training[0][0]))
True
A dataset is a torch dataset: use it with a DataLoader.
from torch.utils.data import DataLoader
loader = DataLoader(training, batch_size=4, shuffle=True)
sinograms, images = next(iter(loader))
print(sinograms.shape, images.shape)
torch.Size([4, 1, 360, 1024]) torch.Size([4, 1, 512, 512])
Records¶
A dataset’s record says what it is: the dataset’s spec, the noise, the experiment and split, and which samples (by patient and slice), so that the same data can be made again and evaluations can check that no test patient was trained on.
record = experiment.data_record("train")
print(record.split, record.samples.count, record.samples.ids[:3])
print(record.samples.groups[:5]) # the patients
train 4030 ['LIDC-IDRI-0001/slice_0', 'LIDC-IDRI-0001/slice_41', 'LIDC-IDRI-0001/slice_82']
['LIDC-IDRI-0001', 'LIDC-IDRI-0002', 'LIDC-IDRI-0003', 'LIDC-IDRI-0004', 'LIDC-IDRI-0005']
A torch.utils.data.Subset of a LION dataset is recorded too, by its
indices: training on part of the data is still reproducible.
from torch.utils.data import Subset
from LION.data_loaders.data_record import data_record
few = Subset(training, range(10))
print(data_record(few).subset.indices)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Changing an experiment¶
An experiment’s parameters can be changed like any others, e.g. another dose:
5000
The other experiments are made the same way:
for name in ["clinicalCTRecon", "SparseAngleLowDoseCTRecon", "LimitedAngleCTRecon"]:
e = getattr(ct_experiments, name)()
print(name, len(e.operator_params.angles), "angles")
clinicalCTRecon 360 angles
SparseAngleLowDoseCTRecon 50 angles
LimitedAngleCTRecon 60 angles
Measured data: 2DeteCT¶
The same experiments run on 2DeteCT (dataset="2DeteCT"), real scans of
109 objects, where the measured sinograms take the place of simulated ones;
LION.experiments.deteCT_benchmark has the 2DeteCT paper’s own. They need
the 2DeteCT data:
measured = ct_experiments.LowDoseCTRecon(dataset="2DeteCT")
The loaders¶
Under the experiments are the datasets themselves (LION.data_loaders):
LIDC_IDRI and deteCT, with their own parameters, e.g. other tasks
than reconstruction (segmentation, diagnosis):
from LION.data_loaders.LIDC_IDRI import LIDC_IDRI
print(LIDC_IDRI.default_parameters())
print(LIDC_IDRI.cite("MLA"))
name : LIDC-IDRI Data Loader
training_proportion : 0.8
validation_proportion : 0.1
testing_proportion : 0.09999999999999995
max_num_slices_per_patient : 5
pcg_slices_nodule : 0.5
legacy_slice_selection : False
legacy_patient_list : False
task : reconstruction
folder : /store/cia-lion/datasets/processed/LIDC-IDRI
clevel : 0.5
annotation : consensus
annotation_seed : 0
operator_params : CT Geometry
CT type/mode = fan
-----
Distance from source to detector (DSD) = 1050 mm
Distance from source to origin (DSO)= 575 mm
-----
Detector
Detector shape = [ 1 1024]
Detector size = [ 1 1024] mm
-----
Image
Image shape = [ 1 512 512]
Image size = [ 0.9765625 500. 500. ] mm
Number of angles = (360,)
Armato III, Samuel G., et al. "The Lung Image Database Consortium (LIDC) and Image Database Resource Initiative (IDRI): a completed reference database of lung nodules on CT scans." Medical Physics 38.2 (2011): 915-931.
Data From LIDC-IDRI. The Cancer Imaging Archive. doi:10.7937/K9/TCIA.2015.LO9QL9SX
Total running time of the script: (1 minutes 44.294 seconds)