Skip to content

Commit

Permalink
Merge 23f178b into af78c44
Browse files Browse the repository at this point in the history
  • Loading branch information
lrouhier committed Aug 14, 2020
2 parents af78c44 + 23f178b commit 3e89082
Show file tree
Hide file tree
Showing 21 changed files with 575 additions and 60 deletions.
2 changes: 2 additions & 0 deletions .coveragerc
@@ -0,0 +1,2 @@
[run]
omit = setup.py
24 changes: 21 additions & 3 deletions .github/workflows/run_tests.yml
Expand Up @@ -6,7 +6,7 @@ name: Run tests
on: [push, pull_request]

jobs:
build:
test:

runs-on: ubuntu-latest
strategy:
Expand All @@ -22,7 +22,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest
pip install flake8 pytest coverage coveralls pytest-cov
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
pip install -e .
- name: Lint with flake8
Expand All @@ -32,5 +32,23 @@ jobs:
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_FLAG_NAME: ${{ matrix.test-name }}
COVERALLS_PARALLEL: true
run: |
pytest
ivadomed_download_data -d data_testing -o testing_data
pytest --cov=./ --cov-report term-missing
coveralls
coveralls:
needs: test
runs-on: ubuntu-latest
container: python:3-slim
steps:
- name: Finished
run: |
pip3 install --upgrade coveralls
coveralls --finish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -2,7 +2,7 @@

Integrated framework for medical image analysis with deep learning.

[![Coverage Status](https://coveralls.io/repos/github/neuropoly/ivadomed/badge.svg?branch=master)](https://coveralls.io/github/neuropoly/ivadomed?branch=master)
[![Coverage Status](https://coveralls.io/repos/github/ivadomed/ivadomed/badge.svg?branch=master)](https://coveralls.io/github/ivadomed/ivadomed?branch=master)
![](https://github.com/neuropoly/ivadomed/workflows/Python%20package/badge.svg)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE.md)

Expand Down
14 changes: 14 additions & 0 deletions testing/ivado_test.py
@@ -1,4 +1,18 @@
#Add custom tests here
# this test is run first so we will also do a little setup here

import ivadomed.models as imed_models
import torch
import os


def test_sample():
assert 1 == 1


def test_model_creation():
# creating basic model for test
model = imed_models.Unet()
torch.save(model, "testing_data/model_unet_test.pt")
assert os.path.isfile("testing_data/model_unet_test.pt")

2 changes: 1 addition & 1 deletion testing/test_HeMIS.py
Expand Up @@ -48,7 +48,7 @@ def test_HeMIS(p=0.0001):

roi_params = {"suffix": "_seg-manual", "slice_filter_roi": None}

train_lst = ['sub-test001']
train_lst = ['sub-unf01']
contrasts = ['T1w', 'T2w', 'T2star']

print('[INFO]: Creating dataset ...\n')
Expand Down
2 changes: 1 addition & 1 deletion testing/test_adaptative.py
Expand Up @@ -20,7 +20,7 @@

def test_hdf5():
print('[INFO]: Starting test ... \n')
train_lst = ['sub-test001']
train_lst = ['sub-unf01']

training_transform_dict = {
"Resample":
Expand Down
18 changes: 16 additions & 2 deletions testing/test_bounding_box.py
Expand Up @@ -14,7 +14,7 @@
LOG_DIR = "log"


@pytest.mark.parametrize('train_lst', [['sub-test001']])
@pytest.mark.parametrize('train_lst', [['sub-unf01']])
@pytest.mark.parametrize('target_lst', [["_lesion-manual"]])
@pytest.mark.parametrize('config', [
{
Expand All @@ -23,7 +23,9 @@
"safety_factor": [1.0, 1.0, 1.0],
"log_directory": LOG_DIR
},
"transforms_params": {"NumpyToTensor": {}},
"transforms_params": {
"Resample": {"wspace": 0.75, "hspace": 0.75},
"NumpyToTensor": {}},
"roi_params": {"suffix": "_seg-manual", "slice_filter_roi": 10},
"contrast_params": {"contrast_lst": ['T2w'], "balance": {}},
"multichannel": False,
Expand Down Expand Up @@ -95,3 +97,15 @@ def test_bounding_box(train_lst, target_lst, config):
assert seg_pair['input'][0].shape[-2:] == (mx2 - mx1, my2 - my1)

shutil.rmtree(LOG_DIR)


# testing adjust bb size
def test_adjust_bb_size():
test_coord = (0, 10, 0, 10, 0, 10)
imed_obj_detect.adjust_bb_size(test_coord, (2, 2, 2), True)


# testing bb statistic
def test_compute_bb_statistics():
imed_obj_detect.compute_bb_statistics("testing_data/bounding_box_dict.json")

5 changes: 3 additions & 2 deletions testing/test_inference.py
Expand Up @@ -22,6 +22,7 @@
PATH_BIDS = 'testing_data'
PATH_OUT = 'tmp'


@pytest.mark.parametrize('transforms_dict', [{
"Resample":
{
Expand All @@ -35,7 +36,7 @@
"NumpyToTensor": {},
"NormalizeInstance": {"applied_to": ["im"]}
}])
@pytest.mark.parametrize('test_lst', [['sub-test001']])
@pytest.mark.parametrize('test_lst', [['sub-unf01']])
@pytest.mark.parametrize('target_lst', [["_lesion-manual"], ["_seg-manual"]])
@pytest.mark.parametrize('roi_params', [{"suffix": "_seg-manual", "slice_filter_roi": 10}])
@pytest.mark.parametrize('testing_params', [{
Expand All @@ -55,7 +56,7 @@ def test_inference(transforms_dict, test_lst, target_lst, roi_params, testing_pa
"data_list": test_lst,
"dataset_type": "testing",
"requires_undo": True,
"contrast_params": {"contrast_lst": ['T2w', 'T2star'], "balance": {}},
"contrast_params": {"contrast_lst": ['T2w'], "balance": {}},
"bids_path": PATH_BIDS,
"target_suffix": target_lst,
"roi_params": roi_params,
Expand Down
133 changes: 132 additions & 1 deletion testing/test_losses.py
Expand Up @@ -7,7 +7,8 @@
import pytest
import torch

from ivadomed.losses import GeneralizedDiceLoss, MultiClassDiceLoss, TverskyLoss, FocalTverskyLoss, DiceLoss
from ivadomed.losses import GeneralizedDiceLoss, MultiClassDiceLoss, TverskyLoss, FocalTverskyLoss, DiceLoss, \
AdapWingLoss, L2loss, LossCombination, FocalDiceLoss


@pytest.mark.parametrize('params', [
Expand Down Expand Up @@ -207,3 +208,133 @@ def test_focaltverskyloss(params):
input, target, expected_value, loss_fct = params
loss = loss_fct.forward(input, target)
assert isclose(loss.detach().cpu().numpy(), expected_value, rel_tol=1e-2)


@pytest.mark.parametrize('params', [
(torch.tensor([[[[[0.0, 1.0], [0.0, 0.0]], [[0.0, 1.0], [0.0, 0.0]]]]]),
torch.tensor([[[[[0.0, 1.0], [0.0, 0.0]], [[0.0, 1.0], [0.0, 0.0]]]]]),
0.,
L2loss()),
(torch.tensor([[[[1.0, 0.0], [0.0, 1.0]]]]),
torch.tensor([[[[1.0, 0.0], [0.0, 1.0]]]]),
0.,
L2loss()),
(torch.tensor([[[[0.0, 0.0], [0.0, 0.0]]]]),
torch.tensor([[[[1.0, 0.0], [0.0, 1.0]]]]),
1.0,
L2loss()),
(torch.tensor([[[[0.5, 0.5], [0.5, 0.5]]]]),
torch.tensor([[[[0.5, 1.0], [1.0, 1.0]]]]),
0.375,
L2loss()),
])
def test_L2loss(params):
"""
test L2 loss
Args:
params (tuple): containing input tensor, target tensor, expected value, loss function
"""

input, target, expected_value, loss_fct = params
loss = loss_fct.forward(input, target)
assert isclose(loss.detach().cpu().numpy(), expected_value, rel_tol=1e-2)


@pytest.mark.parametrize('params', [
(torch.tensor([[[[1.0, 1.0], [0.0, 0.0]]]]),
torch.tensor([[[[1.0, 1.0], [0.0, 0.0]]]]),
0.,
AdapWingLoss()),
(torch.tensor([[[[1.0, 1.0], [0.0, 0.0]]]]),
torch.tensor([[[[1.0, 0.0], [1.0, 1.0]]]]),
29.0147,
AdapWingLoss()),
(torch.tensor([[[[1.0, 1.0], [0.0, 0.0]]]]),
torch.tensor([[[[1.0, 0.0], [1.0, 1.0]]]]),
41.4496,
AdapWingLoss(omega=20)),
(torch.tensor([[[[0.5, 0.5], [0.5, 0.5]]]]),
torch.tensor([[[[0.5, 1.0], [1.0, 1.0]]]]),
8.2703,
AdapWingLoss(epsilon=2)),
])
def test_adapwingloss(params):
"""
test AdapWingLoss
Args:
params (tuple): containing input tensor, target tensor, expected value, loss function
"""

input, target, expected_value, loss_fct = params
loss = loss_fct.forward(input, target)
assert isclose(loss.detach().cpu().numpy(), expected_value, rel_tol=1e-2)


@pytest.mark.parametrize('params', [
(torch.tensor([[[[1.0, 1.0], [0.0, 0.0]]]]),
torch.tensor([[[[1.0, 1.0], [0.0, 0.0]]]]),
-1.0,
LossCombination(["DiceLoss", "L2loss"], [None, None])),
(torch.tensor([[[[1.0, 1.0], [0.0, 0.0]]]]),
torch.tensor([[[[1.0, 0.0], [1.0, 1.0]]]]),
1.0,
LossCombination(["DiceLoss", "L2loss"], [None, None])),
(torch.tensor([[[[0.5, 0.5], [0.5, 0.5]]]]),
torch.tensor([[[[0.5, 1.0], [1.0, 1.0]]]]),
-0.3173,
LossCombination(["DiceLoss", "L2loss"], [None, None])),
])
def test_losscombination(params):
"""
test LossCombination
Args:
params (tuple): containing input tensor, target tensor, expected value, loss function
"""

input, target, expected_value, loss_fct = params
loss = loss_fct.forward(input, target)
assert isclose(loss.detach().cpu().numpy(), expected_value, rel_tol=1e-2)


@pytest.mark.parametrize('params', [
(torch.tensor([[[[1.0, 1.0], [0.0, 0.0]]]]),
torch.tensor([[[[1.0, 1.0], [0.0, 0.0]]]]),
-16.1181,
FocalDiceLoss()),
(torch.tensor([[[[1.0, 1.0], [0.0, 0.0]]]]),
torch.tensor([[[[1.0, 0.0], [1.0, 1.0]]]]),
3.6897,
FocalDiceLoss()),
(torch.tensor([[[[0.5, 0.5], [0.5, 0.5]]]]),
torch.tensor([[[[0.5, 1.0], [1.0, 1.0]]]]),
-1.1619,
FocalDiceLoss()),
])
def test_focaldiceloss(params):
"""
test focaldiceloss
Args:
params (tuple): containing input tensor, target tensor, expected value, loss function
"""

input, target, expected_value, loss_fct = params
loss = loss_fct.forward(input, target)
assert isclose(loss.detach().cpu().numpy(), expected_value, rel_tol=1e-2)
67 changes: 67 additions & 0 deletions testing/test_metrics.py
@@ -0,0 +1,67 @@
import ivadomed.metrics as imed_metrics
import numpy as np


def test_multi_class_dice_score():
# create fake image
image = np.array([[[1, 1], [1, 1]], [[0, 0], [0, 0]]])
results = imed_metrics.multi_class_dice_score(image, image)


def test_mse():
# create fake image
image = np.array([[[1, 1], [1, 1]], [[0, 0], [0, 0]]])
results = imed_metrics.mse(image, image)


def test_haussdorf_4d():
# create fake image
image = np.array([[[[1, 1], [1, 1]], [[0, 0], [0, 0]]]])
results = imed_metrics.hausdorff_score(image, image)


def test_err_prec():
# create fake image
image = np.array([[[0, 0], [0, 0]], [[0, 0], [0, 0]]])
image_2 = np.array([[[0, 0], [0, 0]], [[0, 0], [0, 0]]])
results = imed_metrics.precision_score(image, image_2)
assert results == 0.0


def test_err_rec():
# create fake image
image = np.array([[[0, 0], [0, 0]], [[0, 0], [0, 0]]])
image_2 = np.array([[[0, 0], [0, 0]], [[0, 0], [0, 0]]])
results = imed_metrics.recall_score(image, image_2, err_value=1)
assert results == 1


def test_err_spec():
# create fake image
image = np.array([[[1, 1], [1, 1]], [[1, 1], [1, 1]]])
image_2 = np.array([[[1, 1], [1, 1]], [[1, 1], [1, 1]]])
results = imed_metrics.specificity_score(image, image_2, err_value=12)
assert results == 12


def test_err_iou():
image = np.array([[[0, 0], [0, 0]], [[0, 0], [0, 0]]])
image_2 = np.array([[[0, 0], [0, 0]], [[0, 0], [0, 0]]])
results = imed_metrics.intersection_over_union(image, image_2, err_value=12)
assert results == 12


def test_plot_roc_curve():
tpr = [0, 0.1, 0.5, 0.6, 0.9]
fpr = [1, 0.8, 0.5, 0.3, 0.1]
opt_thr_idx = 3
imed_metrics.plot_roc_curve(tpr, fpr, opt_thr_idx, "roc_test.png")


def test_dice_plot():
thr_list = [0.1, 0.3, 0.5, 0.7]
dice_list = [0.6, 0.7, 0.8, 0.75]
imed_metrics.plot_dice_thr(thr_list, dice_list, 2, "test_dice.png")



20 changes: 20 additions & 0 deletions testing/test_model.py
@@ -0,0 +1,20 @@
import ivadomed.models as imed_model
import torch


# testing countception model
def test_countception():
a = [[[[0 for i in range(10)] for i in range(10)]]]
inp = torch.tensor(a).float()
model = imed_model.Countception(in_channel=1, out_channel=1)
inf = model(inp)
assert (type(inf) == torch.Tensor)


def test_model_3d_att():
# verifying if 3d attention model can be created
a = [[[[[0 for i in range(48)] for j in range(48)] for k in range(16)]]]
inp = torch.tensor(a).float()
model = imed_model.UNet3D(in_channel=1, out_channel=1, attention=True)
inf = model(inp)
assert(type(inf) == torch.Tensor)
2 changes: 1 addition & 1 deletion testing/test_onnx.py
Expand Up @@ -10,7 +10,7 @@


PATH_BIDS = 'testing_data'
IMAGE_PATH = os.path.join(PATH_BIDS, "sub-test001", "anat", "sub-test001_T1w.nii.gz")
IMAGE_PATH = os.path.join(PATH_BIDS, "sub-unf01", "anat", "sub-unf01_T1w.nii.gz")
PATH_MODEL = os.path.join(PATH_BIDS, 'model')
PATH_MODEL_ONNX = os.path.join(PATH_MODEL, 'model.onnx')
PATH_MODEL_PT = PATH_MODEL_ONNX.replace('onnx', 'pt')
Expand Down

0 comments on commit 3e89082

Please sign in to comment.