Skip to content

Commit

Permalink
Rc4 fixes (#879)
Browse files Browse the repository at this point in the history
* minor fixes for rc4 dependency

Signed-off-by: Sachidanand Alle <[email protected]>

* add integration tests for pathology app/models

Signed-off-by: Sachidanand Alle <[email protected]>
  • Loading branch information
SachidanandAlle authored Jul 19, 2022
1 parent afd0d27 commit 02e4fe4
Show file tree
Hide file tree
Showing 20 changed files with 202 additions and 45 deletions.
2 changes: 1 addition & 1 deletion monailabel/interfaces/tasks/infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ def _get_network(self, device):
model_state_dict = checkpoint.get(self.model_state_dict, checkpoint)
network.load_state_dict(model_state_dict, strict=self.load_strict)
else:
network = torch.jit.load(path, map_location=torch.device(device)).to(torch.device)
network = torch.jit.load(path, map_location=torch.device(device))

network.eval()
self._networks[device] = (network, statbuf.st_mtime if statbuf else 0)
Expand Down
13 changes: 1 addition & 12 deletions monailabel/scribbles/infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from monai.transforms import (
Compose,
EnsureChannelFirstd,
FromMetaTensord,
LoadImaged,
ScaleIntensityRanged,
Spacingd,
ToMetaTensord,
)
from monai.transforms import Compose, EnsureChannelFirstd, LoadImaged, ScaleIntensityRanged, Spacingd

from monailabel.interfaces.tasks.infer import InferTask, InferType
from monailabel.scribbles.transforms import (
Expand Down Expand Up @@ -72,13 +64,11 @@ def pre_transforms(self, data):
return [
LoadImaged(keys=["image", "label"]),
EnsureChannelFirstd(keys=["image", "label"]),
FromMetaTensord(keys=["image", "label"]),
AddBackgroundScribblesFromROId(
scribbles="label",
scribbles_bg_label=self.scribbles_bg_label,
scribbles_fg_label=self.scribbles_fg_label,
),
ToMetaTensord(keys=["image", "label"]),
Spacingd(keys=["image", "label"], pixdim=self.pix_dim, mode=["bilinear", "nearest"]),
ScaleIntensityRanged(
keys="image",
Expand Down Expand Up @@ -112,7 +102,6 @@ def post_transforms(self, data):
lamda=self.lamda,
sigma=self.sigma,
),
FromMetaTensord(keys=["image"]),
Restored(keys="pred", ref_image="image"),
BoundingBoxd(keys="pred", result="result", bbox="bbox"),
]
Expand Down
3 changes: 2 additions & 1 deletion monailabel/scribbles/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import numpy as np
import torch
from monai.data import MetaTensor
from monai.networks.blocks import CRF
from monai.transforms import Transform
from scipy.special import softmax
Expand All @@ -39,7 +40,7 @@ def _fetch_data(self, data, key):
if key not in data.keys():
raise ValueError(f"Key {key} not found, present keys {data.keys()}")

return data[key].numpy() if isinstance(data[key], torch.Tensor) else data[key]
return data[key].array if isinstance(data[key], MetaTensor) else data[key]

def _normalise_logits(self, data, axis=0):
# check if logits is a true prob, if not then apply softmax
Expand Down
10 changes: 8 additions & 2 deletions monailabel/transform/post.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import numpy as np
import skimage.measure as measure
from monai.config import KeysCollection
from monai.data import MetaTensor
from monai.transforms import MapTransform, Resize, generate_spatial_bounding_box, get_extreme_points
from monai.utils import InterpolateMode, ensure_tuple_rep

Expand Down Expand Up @@ -102,11 +103,16 @@ def __init__(

def __call__(self, data):
d = dict(data)
meta_dict = d[f"{self.ref_image}_{self.meta_key_postfix}"]
meta_dict = (
d[self.ref_image].meta
if d.get(self.ref_image) is not None and isinstance(d[self.ref_image], MetaTensor)
else d.get(f"{self.ref_image}_{self.meta_key_postfix}", {})
)

for idx, key in enumerate(self.keys):
result = d[key]
current_size = result.shape[1:] if self.has_channel else result.shape
spatial_shape = meta_dict["spatial_shape"]
spatial_shape = meta_dict.get("spatial_shape", current_size)
spatial_size = spatial_shape[-len(current_size) :]

# Undo Spacing
Expand Down
16 changes: 10 additions & 6 deletions monailabel/transform/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import nrrd
import numpy as np
import torch
from monai.data import write_nifti
from monai.data import MetaTensor, write_nifti

from monailabel.utils.others.generic import file_ext
from monailabel.utils.others.pathology import create_asap_annotations_xml, create_dsa_annotations_json
Expand Down Expand Up @@ -185,13 +185,17 @@ def __call__(self, data):
ext = ext if ext else ".nii.gz"
logger.info(f"Result ext: {ext}; write_to_file: {write_to_file}; dtype: {dtype}")

image_np = data[self.label]
if isinstance(image_np, torch.Tensor):
image_np = image_np.numpy()
if isinstance(data[self.label], MetaTensor):
image_np = data[self.label].array
else:
image_np = data[self.label]

# Always using Restored as the last transform before writing
meta_dict = data.get(f"{self.ref_image}_{self.meta_key_postfix}")
affine = meta_dict.get("affine") if meta_dict else None
if isinstance(affine, torch.Tensor):
affine = affine.numpy()
if affine is None and isinstance(data[self.ref_image], MetaTensor):
affine = data[self.ref_image].affine

logger.debug(f"Image: {image_np.shape}; Data Image: {data[self.label].shape}")

output_file = None
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
torch>=1.7
monai[nibabel, skimage, pillow, tensorboard, gdown, ignite, torchvision, itk, tqdm, lmdb, psutil, openslide]>=0.9.1rc3
monai[nibabel, skimage, pillow, tensorboard, gdown, ignite, torchvision, itk, tqdm, lmdb, psutil, openslide]>=0.9.1rc4
uvicorn==0.17.6
pydantic==1.9.1
python-dotenv==0.20.0
Expand Down
28 changes: 17 additions & 11 deletions runtests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -426,20 +426,20 @@ function check_server_running() {
echo ${code}
}

# network training/inference/eval integration tests
if [ $doNetTests = true ]; then

function run_integration_tests() {
echo "${separator}${blue}integration${noColor}"
torch_validate

${cmdPrefix}${PY_EXE} tests/setup.py
echo "Starting MONAILabel server..."
echo "$1 - Starting MONAILabel server..."
rm -rf tests/data/apps
monailabel apps -n radiology -o tests/data/apps -d
monailabel start_server -a tests/data/apps/radiology -c models all -s tests/data/dataset/local/spleen -p ${MONAILABEL_SERVER_PORT:-8000} &
monailabel apps -n $1 -o tests/data/apps -d
monailabel start_server -a tests/data/apps/$1 -c models all -s $2 -p ${MONAILABEL_SERVER_PORT:-8000} &

wait_time=0
server_is_up=0
start_time_out=180
start_time_out=240

while [[ $wait_time -le ${start_time_out} ]]; do
if [ "$(check_server_running)" == "200" ]; then
Expand All @@ -448,18 +448,24 @@ if [ $doNetTests = true ]; then
fi
sleep 5
wait_time=$((wait_time + 5))
echo "Waiting for MONAILabel to be up and running..."
echo "$1 - Waiting for MONAILabel to be up and running..."
done
echo ""

if [ "$server_is_up" == "1" ]; then
echo "MONAILabel server is up and running."
echo "$1 - MONAILabel server is up and running."
else
echo "Failed to start MONAILabel server. Exiting..."
echo "$1 - Failed to start MONAILabel server. Exiting..."
exit 1
fi

${cmdPrefix}${cmd} -m pytest -v tests/integration --no-summary -x
echo "Finished All Integration Tests; Stop/Kill MONAILabel Server..."
${cmdPrefix}${cmd} -m pytest -v tests/integration/$1 --no-summary -x
echo "$1 - Finished All Integration Tests; Stop/Kill MONAILabel Server..."
kill -9 $(ps -ef | grep monailabel | grep start_server | grep -v grep | awk '{print $2}')
}

# network training/inference/eval integration tests
if [ $doNetTests = true ]; then
run_integration_tests "radiology" "tests/data/dataset/local/spleen"
run_integration_tests "pathology" "tests/data/pathology"
fi
10 changes: 10 additions & 0 deletions sample-apps/endoscopy/lib/net/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright (c) MONAI Consortium
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
12 changes: 12 additions & 0 deletions sample-apps/radiology/lib/activelearning/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright (c) MONAI Consortium
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from .first import First
7 changes: 0 additions & 7 deletions sample-apps/radiology/lib/infers/deepedit.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,11 @@
AsDiscreted,
EnsureChannelFirstd,
EnsureTyped,
FromMetaTensord,
LoadImaged,
Orientationd,
Resized,
ScaleIntensityRanged,
SqueezeDimd,
ToMetaTensord,
ToNumpyd,
)

Expand Down Expand Up @@ -85,22 +83,18 @@ def pre_transforms(self, data=None):
AddGuidanceFromPointsDeepEditd(ref_image="image", guidance="guidance", label_names=self.labels),
Resized(keys="image", spatial_size=self.spatial_size, mode="area"),
ResizeGuidanceMultipleLabelDeepEditd(guidance="guidance", ref_image="image"),
FromMetaTensord(keys="image"),
AddGuidanceSignalDeepEditd(
keys="image", guidance="guidance", number_intensity_ch=self.number_intensity_ch
),
ToMetaTensord(keys="image"),
]
)
else:
t.extend(
[
Resized(keys="image", spatial_size=self.spatial_size, mode="area"),
FromMetaTensord(keys="image"),
DiscardAddGuidanced(
keys="image", label_names=self.labels, number_intensity_ch=self.number_intensity_ch
),
ToMetaTensord(keys="image"),
]
)

Expand All @@ -120,6 +114,5 @@ def post_transforms(self, data=None) -> Sequence[Callable]:
AsDiscreted(keys="pred", argmax=True),
SqueezeDimd(keys="pred", dim=0),
ToNumpyd(keys="pred"),
FromMetaTensord(keys="image"),
Restored(keys="pred", ref_image="image"),
]
2 changes: 1 addition & 1 deletion sample-apps/radiology/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from typing import Dict

import lib.configs
from lib.activelearning.first import First
from lib.activelearning import First

from monailabel.interfaces.app import MONAILabelApp
from monailabel.interfaces.config import TaskConfig
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ setup_requires =
ninja
install_requires =
torch>=1.7
monai[nibabel, skimage, pillow, tensorboard, gdown, ignite, torchvision, itk, tqdm, lmdb, psutil, openslide]>=0.9.1rc3
monai[nibabel, skimage, pillow, tensorboard, gdown, ignite, torchvision, itk, tqdm, lmdb, psutil, openslide]>=0.9.1rc4
uvicorn==0.17.6
pydantic==1.9.1
python-dotenv==0.20.0
Expand Down
10 changes: 10 additions & 0 deletions tests/integration/pathology/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright (c) MONAI Consortium
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
79 changes: 79 additions & 0 deletions tests/integration/pathology/test_infer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Copyright (c) MONAI Consortium
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest

import requests
import torch

from tests.integration import SERVER_URI


class EndPointInfer(unittest.TestCase):
def test_deepedit_nuclei(self):
if not torch.cuda.is_available():
return

model = "deepedit_nuclei"
image = "JP2K-33003-1"
body = {
"level": 0,
"location": [2206, 4925],
"size": [360, 292],
"tile_size": [2048, 2048],
"min_poly_area": 30,
"params": {"foreground": [], "background": []},
}

response = requests.post(f"{SERVER_URI}/infer/wsi/{model}?image={image}&output=dsa", json=body)
assert response.status_code == 200

def test_segmentation_nuclei(self):
if not torch.cuda.is_available():
return

model = "segmentation_nuclei"
image = "JP2K-33003-1"
body = {
"level": 0,
"location": [2206, 4925],
"size": [360, 292],
"tile_size": [2048, 2048],
"min_poly_area": 30,
"params": {"foreground": [], "background": []},
}

response = requests.post(f"{SERVER_URI}/infer/wsi/{model}?image={image}&output=asap", json=body)
assert response.status_code == 200

def test_nuclick(self):
if not torch.cuda.is_available():
return

model = "nuclick"
image = "JP2K-33003-1"
body = {
"level": 0,
"location": [2206, 4925],
"size": [360, 292],
"tile_size": [2048, 2048],
"min_poly_area": 30,
"params": {
"foreground": [[2427, 4976], [2341, 5033], [2322, 5207], [2305, 5212], [2268, 5182]],
"background": [],
},
}

response = requests.post(f"{SERVER_URI}/infer/wsi/{model}?image={image}&output=asap", json=body)
assert response.status_code == 200


if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import requests

from . import SERVER_URI
from tests.integration import SERVER_URI


class EndPointInfo(unittest.TestCase):
Expand Down
10 changes: 10 additions & 0 deletions tests/integration/radiology/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright (c) MONAI Consortium
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import requests
import torch

from . import SERVER_URI
from tests.integration import SERVER_URI


class EndPointInfer(unittest.TestCase):
Expand Down
Loading

0 comments on commit 02e4fe4

Please sign in to comment.