Welcome to mrai-net’s documentation!

MRAI-net is a set of neural networks designed to learn MRI-scanner acquisition-invariant representations. In other words, it extracts lower-dimensional feature vectors from two sets of images, such that there is minimal variance between them outside of tissue variation.

Installation

mrainet is registered on PyPI and can be installed through:

pip install mrainet

Environment

Pip takes care of all dependencies, but the addition of these dependencies can mess up your current python environment. To ensure a clean install, it is recommended to set up a virtual environment using conda or virtualenv. To ease this set up, an environment file is provided, which can be run through:

conda env create -f environment.yml
source activate mrainet

For more information on getting started, see the Examples section.

Classifiers

This page contains information on MRAI neural networks.

MRAI Convolutional Neural Network

class mrainet.mraicnn.MRAIConvolutionalNeuralNetwork(patch_size=(31, 31), classes=[1, 2, 3], num_draw=10, num_kernels=[8], kernel_size=[(3, 3)], dense_size=[16, 8], strides=(1, 1), dropout=0.1, l2=0.001, margin=1, optimizer='rmsprop', batch_size=32, num_epochs=1)

Network for MRI-scanner acquisition-invariant representation learning.

Class of convolutional neural networks that aim to map patches of two datasets from different MRI-scanners Methods include image processing operations, pair sampling and Siamese loss minimization.

Methods

compile_net(self) Compile network architecture.
contrastive_loss(self, label, distance) Contrastive Siamese loss.
extract_random_patches(self, X, Y) Extract a random set of patches from image.
feedforward(self, patches, scan_ID) Feed a set of patches forward through the network.
gen_index_combs(self, x) Generate combinations of two index arrays.
index2patch(self, X, index) Slice patches from an image at given indices.
l1_norm(self, x) l1-norm for loss layer.
l2_norm(self, x) l2-norm for loss layer.
load_model(self, model_fn, weights_fn) Load model from filename.
matrix2sparse(self, X[, edge, remove_nans]) Map matrix to a sparse array format.
sample_pairs(self, X, y, Z, u[, num_draw]) Sample a set of pairs of patches from two images.
save_model(self, model_fn, weights_fn) Save model to filename.
segment_image(self, X, model[, feed, …]) Segment a new image using the trained network.
subsample_rows(self, X[, num_draw]) Take a random subsample of rows from X.
train(self, X, Y, Z, U[, num_targets]) Train the network using pairs of patches from the images.
compile_net(self)

Compile network architecture.

contrastive_loss(self, label, distance)

Contrastive Siamese loss.

For similar pairs, it consists of the squared Lp-distance. For dissimilar pairs, it consists of a hinge loss with respect to a margin parameter.

Parameters:
label : int

Similarity label, 1=similar and 0=dissimilar

distance: float

Lp-norm between pairs of patches mapped through the network.

Returns:
float

Loss value for current pair of patches.

extract_random_patches(self, X, Y)

Extract a random set of patches from image.

Parameters:
X : array

Input image to sample patches from.

Y : array

Label image corresponding to X.

Returns:
patches : array

Patches array, num patches by patch height by patch width by 1.

labels : array

Tissue label array corresponding to patches array.

feedforward(self, patches, scan_ID)

Feed a set of patches forward through the network.

Parameters:
patches : array

Contains patches in form of number of patches by patch height by patch width by 1.

scan_ID : int

Scanner identification variable, indicating from which MRI-scanner these patches came from.

Returns:
array

Final layer representation of patches fed forward through the network.

gen_index_combs(self, x)

Generate combinations of two index arrays.

index2patch(self, X, index)

Slice patches from an image at given indices.

Parameters:
X : array

input image

index : array

Row and column indices for the provided image.

Returns:
patches : array

Number of patches by patch height by patch width by 1.

l1_norm(self, x)

l1-norm for loss layer.

l2_norm(self, x)

l2-norm for loss layer.

load_model(self, model_fn, weights_fn)

Load model from filename.

Parameters:
model_fn : str

Filename of saved model.

weights_fn : str

Filename of saved weight matrix.

Returns:
None
matrix2sparse(self, X, edge=(0, 0), remove_nans=False)

Map matrix to a sparse array format.

Parameters:
X : array

Matrix that should be mapped to sparse array format, may contain NaN’s.

edge : tuple(int, int)

Dimensions of edge to ignore.

remove_nans : bool

Whether to remove NaN’s as tissue labels.

Returns:
sX : array

Original matrix mapped to (i,j,v) format where i corresponds to the i-th row of X, j to the j-column of X and v of the value at position (i,j) of X.

sample_pairs(self, X, y, Z, u, num_draw=(10, 1))

Sample a set of pairs of patches from two images.

Parameters:
X : array

slice from source MRI-scanner

y : array

source tissue index sparse array; where each row i,j,k consists of the pixel’s row index i, the pixel’s column index j and the pixel’s tissue k.

Z : array

slice from target MRI-scanner

u : array

target tissue index sparse array; where each row i,j,k consists of the pixel’s row index i, the pixel’s column index j and the pixel’s tissue k.

num_draw : tuple(int, int)

maximum number of patches to draw from (source, target)

Returns:
P : list[A, B, a, b]

contains pairs of patches and scanner identifications

S : array

contains similarity labels between pairs

save_model(self, model_fn, weights_fn)

Save model to filename.

Parameters:
model_fn : str

Filename to save model to.

weights_fn : str

Filename to save weight matrix to.

Returns:
None
segment_image(self, X, model, feed=True, mapost=False, scan_ID=1)

Segment a new image using the trained network.

Parameters:
X : array

new image that needs to be segmented.

model : sklearn-model

Trained classifier from scikit-learn, needs to have a predict method.

feed : bool

whether the extracted patches should be fed through the network, a value of False is for experimental purposes (def: True)

mapost : bool

whether to map the predictions to a maximum a posteriori form. (def: False)

scan_ID : int

scanner identification of new image.

Returns:
preds : array

Label image of same size as input image, containing predictions made by the provided trained classifier.

subsample_rows(self, X, num_draw=1)

Take a random subsample of rows from X.

Parameters:
X : array

Array to subsample from.

num_draw : int

Number of rows to subsample.

replace : bool

Whether to replace sampled rows.

Returns:
array

Smaller array.

train(self, X, Y, Z, U, num_targets=1)

Train the network using pairs of patches from the images.

Parameters:
X : array

source scans, slices by height by width

Y : array

source labels, slices by height by width

Z : array

target scans, slices by height by width

U : array

target labels, slices by height by width, contains NaN’s at unknown labels

num_targets : int

How many target labels to use.

Returns:
None

MRAI Dense Neural Network

class mrainet.mraidnn.MRAIDenseNeuralNetwork(patch_size=(31, 31), classes=[1, 2, 3], num_draw=10, dense_size=[16, 8], dropout=0.1, l2=0.001, margin=1, optimizer='rmsprop', batch_size=32, num_epochs=2)

Network for MRI-scanner acquisition-invariant representation learning.

Class of fully-connected neural networks that aim to map patches of two datasets from different MRI-scanners Methods include image processing operations, pair sampling and Siamese loss minimization.

Methods

compile_net(self) Compile network architecture.
contrastive_loss(self, label, distance) Contrastive Siamese loss.
extract_random_patches(self, X, Y) Extract a random set of patches from image.
feedforward(self, patches, scan_ID) Feed a set of patches forward through the network.
gen_index_combs(self, x) Generate combinations of two index arrays.
index2patch(self, X, index) Slice patches from an image at given indices.
l1_norm(self, x) l1-norm for loss layer.
l2_norm(self, x) l2-norm for loss layer.
load_model(self, model_fn, weights_fn) Load model from filename.
matrix2sparse(self, X[, edge, remove_nans]) Map matrix to a sparse array format.
sample_pairs(self, X, y, Z, u[, num_draw]) Sample a set of pairs of patches from two images.
save_model(self, model_fn, weights_fn) Save model to filename.
segment_image(self, X, model[, feed, …]) Segment a new image using the trained network.
subsample_rows(self, X[, num_draw]) Take a random subsample of rows from X.
train(self, X, Y, Z, U[, num_targets]) Train the network using pairs of patches from the images.
compile_net(self)

Compile network architecture.

contrastive_loss(self, label, distance)

Contrastive Siamese loss.

For similar pairs, it consists of the squared Lp-distance. For dissimilar pairs, it consists of a hinge loss with respect to a margin parameter.

Parameters:
label : int

Similarity label, 1=similar and 0=dissimilar

distance: float

Lp-norm between pairs of patches mapped through the network.

Returns:
float

Loss value for current pair of patches.

extract_random_patches(self, X, Y)

Extract a random set of patches from image.

Parameters:
X : array

Input image to sample patches from.

Y : array

Label image corresponding to X.

Returns:
patches : array

Patches array, num patches by patch height by patch width by 1.

labels : array

Tissue label array corresponding to patches array.

feedforward(self, patches, scan_ID)

Feed a set of patches forward through the network.

Parameters:
patches : array

Contains patches in form of number of patches by patch height by patch width by 1.

scan_ID : int

Scanner identification variable, indicating from which MRI-scanner these patches came from.

Returns:
array

Final layer representation of patches fed forward through the network.

gen_index_combs(self, x)

Generate combinations of two index arrays.

index2patch(self, X, index)

Slice patches from an image at given indices.

Parameters:
X : array

input image

index : array

Row and column indices for the provided image.

Returns:
patches : array

Number of patches by patch height by patch width by 1.

l1_norm(self, x)

l1-norm for loss layer.

l2_norm(self, x)

l2-norm for loss layer.

load_model(self, model_fn, weights_fn)

Load model from filename.

Parameters:
model_fn : str

Filename of saved model.

weights_fn : str

Filename of saved weight matrix.

Returns:
None
matrix2sparse(self, X, edge=(0, 0), remove_nans=False)

Map matrix to a sparse array format.

Parameters:
X : array

Matrix that should be mapped to sparse array format, may contain NaN’s.

edge : tuple(int, int)

Dimensions of edge to ignore.

remove_nans : bool

Whether to remove NaN’s as tissue labels.

Returns:
sX : array

Original matrix mapped to (i,j,v) format where i corresponds to the i-th row of X, j to the j-column of X and v of the value at position (i,j) of X.

sample_pairs(self, X, y, Z, u, num_draw=(10, 1))

Sample a set of pairs of patches from two images.

Parameters:
X : array

slice from source MRI-scanner

y : array

source tissue index sparse array; where each row i,j,k consists of the pixel’s row index i, the pixel’s column index j and the pixel’s tissue k.

Z : array

slice from target MRI-scanner

u : array

target tissue index sparse array; where each row i,j,k consists of the pixel’s row index i, the pixel’s column index j and the pixel’s tissue k.

num_draw : tuple(int, int)

maximum number of patches to draw from (source, target)

Returns:
P : list[A, B, a, b]

contains pairs of patches and scanner identifications

S : array

contains similarity labels between pairs

save_model(self, model_fn, weights_fn)

Save model to filename.

Parameters:
model_fn : str

Filename to save model to.

weights_fn : str

Filename to save weight matrix to.

Returns:
None
segment_image(self, X, model, feed=True, mapost=False, scan_ID=1)

Segment a new image using the trained network.

Parameters:
X : array

new image that needs to be segmented.

model : sklearn-model

Trained classifier from scikit-learn, needs to have a predict method.

feed : bool

whether the extracted patches should be fed through the network, a value of False is for experimental purposes (def: True)

mapost : bool

whether to map the predictions to a maximum a posteriori form. (def: False)

scan_ID : int

scanner identification of new image.

Returns:
preds : array

Label image of same size as input image, containing predictions made by the provided trained classifier.

subsample_rows(self, X, num_draw=1)

Take a random subsample of rows from X.

Parameters:
X : array

Array to subsample from.

num_draw : int

Number of rows to subsample.

replace : bool

Whether to replace sampled rows.

Returns:
array

Smaller array.

train(self, X, Y, Z, U, num_targets=1)

Train the network using pairs of patches from the images.

Parameters:
X : array

source scans, slices by height by width

Y : array

source labels, slices by height by width

Z : array

target scans, slices by height by width

U : array

target labels, slices by height by width, contains NaN’s at unknown labels

num_targets : int

How many target labels to use.

Returns:
None

Examples

In the /demos folder, there are a number of example scripts. These show potential use cases.

Here we walk through a simple version. First, make sure to import some necessary modules:

import numpy as np
import matplotlib.pyplot as plt

from mrainet.mraicnn import MRAIConvolutionalNeuralNetwork
from mrainet.util import extract_all_patches
from mrainet.viz import viz_embedding

Next, we should load some data. The folder mrainet/demos/data/ contains a source MRI-scan and its segmentation as well as a target MRI-scan with an imcomplete segmentation.

# Load source MRI-scan and corresponding segmentation
X = np.load('./demos/data/subject01_GE2D_1.5T.npy')
Y = np.load('./demos/data/subject01_segmentation.npy')

# Load target MRI-scan and corresponding segmentation
Z = np.load('./demos/data/subject02_GE2D_3.0T.npy')
U = np.load('./demos/data/subject02_segmentation.npy')

# Note that U is missing a lot of labels
print('Proportion missing labels = ' + str(np.mean(~np.isnan(U.ravel()))))

Now, it’s time to initialize and compile the network.

# Initialize and compile a small neural network
N = MRAIConvolutionalNeuralNetwork(patch_size=(31, 31),
                                   num_kernels=[8],
                                   kernel_size=[(3, 3)],
                                   dense_size=[16, 8],
                                   batch_size=128,
                                   num_epochs=4,
                                   num_draw=10,
                                   margin=10)

Note that these options will result in a training set of 220 000 samples, and training might be quite expensive on a CPU laptop.

Now we’ll call the training procedure, which automatically handles the pair sampling procedure.

# Call training procedure on source and target data
N.train(X, Y, Z, U, num_targets=1)

After training, we’ll map all source and target patches extracted from the images to MRAI’s learned representation.

# Extract all source patches and feed them through network.
PX = extract_all_patches(X[0], patch_size=(31, 31), edge=(15, 15), add_4d=True)
HX = N.feedforward(PX, scan_ID=0)

# Map label image to sparse array format
sY = N.matrix2sparse(Y[0], edge=(15, 15))

# Extract all target patches and feed them through network.
PZ = extract_all_patches(Z[0], patch_size=(31, 31), edge=(15, 15), add_4d=True)
HZ = N.feedforward(PZ, scan_ID=1)

# Map label image to sparse array format
sU = N.matrix2sparse(U[0], edge=(15, 15), remove_nans=False)

# Filter out missing target labels
HZ = HZ[~np.isnan(sU[:, 2]), :]
sU = sU[~np.isnan(sU[:, 2]), :]

Given 2-dimensional feature vectors for each patch, we can visualize them using a scatter plot:

# Create figure
fig, ax = plt.subplots(figsize=(15, 10))

# Call visualizer
viz_embedding(HX, sY[:, 2], marker='o', ax=ax)
viz_embedding(HZ, sU[:, 2], marker='x', ax=ax)

Contact

Any comments, questions, or general feedback can be submitted to the repository’s issues tracker.