From a6960f8799bd3837d68b3216b2157821dda8894e Mon Sep 17 00:00:00 2001 From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Thu, 16 Feb 2023 13:10:30 +0000 Subject: [PATCH 01/14] :sparkles: NEW: Add Nucleus Detection Engine - Add Nucleus Detection Engine - Fix documentation in patch_predictor.py --- tiatoolbox/models/engine/__init__.py | 1 + tiatoolbox/models/engine/nucleus_detection.py | 136 ++++++++++++++++++ tiatoolbox/models/engine/patch_predictor.py | 38 ++--- 3 files changed, 157 insertions(+), 18 deletions(-) create mode 100644 tiatoolbox/models/engine/nucleus_detection.py diff --git a/tiatoolbox/models/engine/__init__.py b/tiatoolbox/models/engine/__init__.py index 2cba98a32..7574d6e7e 100644 --- a/tiatoolbox/models/engine/__init__.py +++ b/tiatoolbox/models/engine/__init__.py @@ -1,5 +1,6 @@ """Engines to run models implemented in tiatoolbox.""" from tiatoolbox.models.engine import ( + nucleus_detection, nucleus_instance_segmentor, patch_predictor, semantic_segmentor, diff --git a/tiatoolbox/models/engine/nucleus_detection.py b/tiatoolbox/models/engine/nucleus_detection.py new file mode 100644 index 000000000..bca6aa20a --- /dev/null +++ b/tiatoolbox/models/engine/nucleus_detection.py @@ -0,0 +1,136 @@ +"""This module implements nucleus detection engine.""" + + +from tiatoolbox.models.architecture import get_pretrained_model +from tiatoolbox.models.engine.patch_predictor import PatchPredictor + + +class NucleusDetector(PatchPredictor): + r"""Nucleus detection engine. + + The models provided by tiatoolbox should give the following results: + + .. list-table:: Nucleus detection performance on the (add models list here) + :widths: 15 15 + :header-rows: 1 + + Args: + model (nn.Module): + Use externally defined PyTorch model for prediction with. + weights already loaded. Default is `None`. If provided, + `pretrained_model` argument is ignored. + pretrained_model (str): + Name of the existing models support by tiatoolbox for + processing the data. For a full list of pretrained models, + refer to the `docs + `_ + By default, the corresponding pretrained weights will also + be downloaded. However, you can override with your own set + of weights via the `pretrained_weights` argument. Argument + is case-insensitive. + pretrained_weights (str): + Path to the weight of the corresponding `pretrained_model`. + + >>> predictor = NucleusDetector( + ... pretrained_model="resnet18-kather100k", + ... pretrained_weights="resnet18_local_weight") + + batch_size (int): + Number of images fed into the model each time. + num_loader_workers (int): + Number of workers to load the data. Take note that they will + also perform preprocessing. + verbose (bool): + Whether to output logging information. + + Attributes: + imgs (:obj:`str` or :obj:`pathlib.Path` or :obj:`numpy.ndarray`): + A HWC image or a path to WSI. + mode (str): + Type of input to process. Choose from either `patch`, `tile` + or `wsi`. + model (nn.Module): + Defined PyTorch model. + pretrained_model (str): + Name of the existing models support by tiatoolbox for + processing the data. For a full list of pretrained models, + refer to the `docs + `_ + By default, the corresponding pretrained weights will also + be downloaded. However, you can override with your own set + of weights via the `pretrained_weights` argument. Argument + is case insensitive. + batch_size (int): + Number of images fed into the model each time. + num_loader_workers (int): + Number of workers used in torch.utils.data.DataLoader. + verbose (bool): + Whether to output logging information. + + Examples: + >>> # list of 2 image patches as input + >>> data = [img1, img2] + >>> predictor = PatchPredictor(pretrained_model="resnet18-kather100k") + >>> output = predictor.predict(data, mode='patch') + + >>> # array of list of 2 image patches as input + >>> data = np.array([img1, img2]) + >>> predictor = PatchPredictor(pretrained_model="resnet18-kather100k") + >>> output = predictor.predict(data, mode='patch') + + >>> # list of 2 image patch files as input + >>> data = ['path/img.png', 'path/img.png'] + >>> predictor = PatchPredictor(pretrained_model="resnet18-kather100k") + >>> output = predictor.predict(data, mode='patch') + + >>> # list of 2 image tile files as input + >>> tile_file = ['path/tile1.png', 'path/tile2.png'] + >>> predictor = PatchPredictor(pretraind_model="resnet18-kather100k") + >>> output = predictor.predict(tile_file, mode='tile') + + >>> # list of 2 wsi files as input + >>> wsi_file = ['path/wsi1.svs', 'path/wsi2.svs'] + >>> predictor = PatchPredictor(pretraind_model="resnet18-kather100k") + >>> output = predictor.predict(wsi_file, mode='wsi') + + References: + [1] Kather, Jakob Nikolas, et al. "Predicting survival from colorectal cancer + histology slides using deep learning: A retrospective multicenter study." + PLoS medicine 16.1 (2019): e1002730. + + [2] Veeling, Bastiaan S., et al. "Rotation equivariant CNNs for digital + pathology." International Conference on Medical image computing and + computer-assisted intervention. Springer, Cham, 2018. + + """ # noqa: W605 + + def __init__( + self, + batch_size=8, + num_loader_workers=0, + model=None, + pretrained_model=None, + pretrained_weights=None, + verbose=True, + ): + super().__init__() + + self.imgs = None + self.mode = None + + if model is None and pretrained_model is None: + raise ValueError("Must provide either `model` or `pretrained_model`.") + + if model is not None: + self.model = model + ioconfig = None # retrieve iostate from provided model ? + else: + model, ioconfig = get_pretrained_model(pretrained_model, pretrained_weights) + + self.ioconfig = ioconfig # for storing original + self._ioconfig = None # for storing runtime + self.model = model # for runtime, such as after wrapping with nn.DataParallel + self.pretrained_model = pretrained_model + self.batch_size = batch_size + self.num_loader_worker = num_loader_workers + self.verbose = verbose diff --git a/tiatoolbox/models/engine/patch_predictor.py b/tiatoolbox/models/engine/patch_predictor.py index f8bccdf84..d9ef18312 100644 --- a/tiatoolbox/models/engine/patch_predictor.py +++ b/tiatoolbox/models/engine/patch_predictor.py @@ -246,7 +246,7 @@ def __init__( self.model = model # for runtime, such as after wrapping with nn.DataParallel self.pretrained_model = pretrained_model self.batch_size = batch_size - self.num_loader_worker = num_loader_workers + self.num_loader_workers = num_loader_workers self.verbose = verbose @staticmethod @@ -398,7 +398,7 @@ def _predict_engine( # preprocessing must be defined with the dataset dataloader = torch.utils.data.DataLoader( dataset, - num_workers=self.num_loader_worker, + num_workers=self.num_loader_workers, batch_size=self.batch_size, drop_last=False, shuffle=False, @@ -463,22 +463,24 @@ def _update_ioconfig( Args: ioconfig (IOPatchPredictorConfig): - patch_input_shape (tuple): - Size of patches input to the model. Patches are at - requested read resolution, not with respect to level 0, - and must be positive. - stride_shape (tuple): - Stride using during tile and WSI processing. Stride is - at requested read resolution, not with respect to - level 0, and must be positive. If not provided, - `stride_shape=patch_input_shape`. - resolution (float): - Resolution used for reading the image. Please see - :obj:`WSIReader` for details. - units (str): - Units of resolution used for reading the image. Choose - from either `level`, `power` or `mpp`. Please see - :obj:`WSIReader` for details. + Object defines information about input and output placement + of patches for patch prediction. + patch_input_shape (tuple): + Size of patches input to the model. Patches are at + requested read resolution, not with respect to level 0, + and must be positive. + stride_shape (tuple): + Stride using during tile and WSI processing. Stride is + at requested read resolution, not with respect to + level 0, and must be positive. If not provided, + `stride_shape=patch_input_shape`. + resolution (float): + Resolution used for reading the image. Please see + :obj:`WSIReader` for details. + units (str): + Units of resolution used for reading the image. Choose + from either `level`, `power` or `mpp`. Please see + :obj:`WSIReader` for details. Returns: Updated Patch Predictor IO configuration. From 6c4750666ae38d7252ffb35725c20ca30d0387f5 Mon Sep 17 00:00:00 2001 From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Thu, 16 Feb 2023 13:25:05 +0000 Subject: [PATCH 02/14] :art: DEV: Improve structure of init - Improve structure of init --- tiatoolbox/models/engine/nucleus_detection.py | 30 +++++-------------- tiatoolbox/models/engine/patch_predictor.py | 2 +- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/tiatoolbox/models/engine/nucleus_detection.py b/tiatoolbox/models/engine/nucleus_detection.py index bca6aa20a..b31e11d7d 100644 --- a/tiatoolbox/models/engine/nucleus_detection.py +++ b/tiatoolbox/models/engine/nucleus_detection.py @@ -1,7 +1,6 @@ """This module implements nucleus detection engine.""" -from tiatoolbox.models.architecture import get_pretrained_model from tiatoolbox.models.engine.patch_predictor import PatchPredictor @@ -113,24 +112,11 @@ def __init__( pretrained_weights=None, verbose=True, ): - super().__init__() - - self.imgs = None - self.mode = None - - if model is None and pretrained_model is None: - raise ValueError("Must provide either `model` or `pretrained_model`.") - - if model is not None: - self.model = model - ioconfig = None # retrieve iostate from provided model ? - else: - model, ioconfig = get_pretrained_model(pretrained_model, pretrained_weights) - - self.ioconfig = ioconfig # for storing original - self._ioconfig = None # for storing runtime - self.model = model # for runtime, such as after wrapping with nn.DataParallel - self.pretrained_model = pretrained_model - self.batch_size = batch_size - self.num_loader_worker = num_loader_workers - self.verbose = verbose + super().__init__( + batch_size=batch_size, + num_loader_workers=num_loader_workers, + model=model, + pretrained_model=pretrained_model, + pretrained_weights=pretrained_weights, + verbose=verbose, + ) diff --git a/tiatoolbox/models/engine/patch_predictor.py b/tiatoolbox/models/engine/patch_predictor.py index d9ef18312..4215c9794 100644 --- a/tiatoolbox/models/engine/patch_predictor.py +++ b/tiatoolbox/models/engine/patch_predictor.py @@ -158,7 +158,7 @@ class PatchPredictor: Whether to output logging information. Attributes: - img (:obj:`str` or :obj:`pathlib.Path` or :obj:`numpy.ndarray`): + imgs (:obj:`str` or :obj:`pathlib.Path` or :obj:`numpy.ndarray`): A HWC image or a path to WSI. mode (str): Type of input to process. Choose from either `patch`, `tile` From 584e43a12bd424501e9909703166e91cf0eea13b Mon Sep 17 00:00:00 2001 From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Mon, 20 Feb 2023 16:57:17 +0000 Subject: [PATCH 03/14] :memo: DOC: Add documentation for mapde and sccnn - Add documentation for mapde and sccnn - Add a test for nucleus detection - Fix input in patch predictor test --- docs/pretrained.rst | 81 +++++++++++++++++++ tests/models/test_nucleus_detection_engine.py | 8 ++ tests/models/test_patch_predictor.py | 4 +- tiatoolbox/data/pretrained_model.yaml | 22 +++++ 4 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 tests/models/test_nucleus_detection_engine.py diff --git a/docs/pretrained.rst b/docs/pretrained.rst index ec516fbe0..eb959b9b5 100644 --- a/docs/pretrained.rst +++ b/docs/pretrained.rst @@ -275,6 +275,87 @@ input output configuration: - hovernet_original_kumar +Nucleus Detection +^^^^^^^^^^^^^^^^^ + +CRCHisto Dataset +-------------- + +We provide the following models trained using the `CoNSeP dataset `_, which uses the following +input output configuration: + +.. collapse:: Input Output Configuration Details + + .. code-block:: python + + from tiatoolbox.models import IOPatchPredictorConfig + ioconfig = IOPatchPredictorConfig( + patch_input_shape=(31, 31), + stride_shape=(8, 8), + input_resolutions=[{"resolution": 0.25, "units": "mpp"}] + ) + + +.. collapse:: Model names + + - sccnn-crchisto + +.. collapse:: Input Output Configuration Details + + .. code-block:: python + + from tiatoolbox.models import IOPatchPredictorConfig + ioconfig = IOPatchPredictorConfig( + patch_input_shape=(252, 252), + stride_shape=(150, 150), + input_resolutions=[{"resolution": 0.25, "units": "mpp"}] + ) + + +.. collapse:: Model names + + - mapde-crchisto + + +CoNIC Dataset +-------------- + +We provide the following models trained using the `CoNIC dataset `_, which uses the following +input output configuration: + +.. collapse:: Input Output Configuration Details + + .. code-block:: python + + from tiatoolbox.models import IOPatchPredictorConfig + ioconfig = IOPatchPredictorConfig( + patch_input_shape=(31, 31), + stride_shape=(8, 8), + input_resolutions=[{"resolution": 0.25, "units": "mpp"}] + ) + + +.. collapse:: Model names + + - sccnn-conic + +.. collapse:: Input Output Configuration Details + + .. code-block:: python + + from tiatoolbox.models import IOPatchPredictorConfig + ioconfig = IOPatchPredictorConfig( + patch_input_shape=(252, 252), + stride_shape=(150, 150), + input_resolutions=[{"resolution": 0.25, "units": "mpp"}] + ) + + +.. collapse:: Model names + + - mapde-conic + + Multi-Task Segmentation ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/models/test_nucleus_detection_engine.py b/tests/models/test_nucleus_detection_engine.py new file mode 100644 index 000000000..bcb94bdb5 --- /dev/null +++ b/tests/models/test_nucleus_detection_engine.py @@ -0,0 +1,8 @@ +"""Tests for NucleusDetector.""" + +from tiatoolbox.models.engine.nucleus_detection import NucleusDetector + + +def test_nucleus_detector_engine(sample_svs): + """Test for nucleus detection engine.""" + _ = NucleusDetector(pretrained_model="mapde-conic") diff --git a/tests/models/test_patch_predictor.py b/tests/models/test_patch_predictor.py index 03d135cd8..465dd1f27 100644 --- a/tests/models/test_patch_predictor.py +++ b/tests/models/test_patch_predictor.py @@ -546,7 +546,7 @@ def test_io_config_delegation(remote_sample, tmp_path): predictor = PatchPredictor(pretrained_model="resnet18-kather100k", batch_size=1) predictor.predict( [mini_wsi_svs], - patch_input_shape=[300, 300], + patch_input_shape=(300, 300), mode="wsi", on_gpu=ON_GPU, save_dir=f"{tmp_path}/dump", @@ -556,7 +556,7 @@ def test_io_config_delegation(remote_sample, tmp_path): predictor.predict( [mini_wsi_svs], - stride_shape=[300, 300], + stride_shape=(300, 300), mode="wsi", on_gpu=ON_GPU, save_dir=f"{tmp_path}/dump", diff --git a/tiatoolbox/data/pretrained_model.yaml b/tiatoolbox/data/pretrained_model.yaml index f9a480de5..2243cebb0 100644 --- a/tiatoolbox/data/pretrained_model.yaml +++ b/tiatoolbox/data/pretrained_model.yaml @@ -777,44 +777,66 @@ mapde-crchisto: architecture: class: mapde.MapDe kwargs: + input_resolutions: + - { "units": "mpp", "resolution": 0.25 } num_input_channels: 3 min_distance: 4 threshold_abs: 250 num_classes: 1 + tile_shape: [ 2048, 2048 ] + patch_input_shape: [ 252, 252 ] + stride_shape: [ 150, 150 ] mapde-conic: url: https://tiatoolbox.dcs.warwick.ac.uk/models/detection/mapde-conic.pth architecture: class: mapde.MapDe kwargs: + input_resolutions: + - { "units": "mpp", "resolution": 0.25 } num_input_channels: 3 min_distance: 3 threshold_abs: 205 num_classes: 1 + tile_shape: [ 2048, 2048 ] + patch_input_shape: [ 252, 252 ] + stride_shape: [ 150, 150 ] sccnn-crchisto: url: https://tiatoolbox.dcs.warwick.ac.uk/models/detection/sccnn-crchisto.pth architecture: class: sccnn.SCCNN kwargs: + input_resolutions: + - { "units": "mpp", "resolution": 0.25 } num_input_channels: 3 out_height: 13 out_width: 13 radius: 12 min_distance: 6 threshold_abs: 0.20 + tile_shape: [ 2048, 2048 ] + patch_input_shape: [ 31, 31 ] + patch_output_shape: [ 13, 13 ] + stride_shape: [ 8, 8 ] sccnn-conic: url: https://tiatoolbox.dcs.warwick.ac.uk/models/detection/sccnn-conic.pth architecture: class: sccnn.SCCNN kwargs: + input_resolutions: + - { "units": "mpp", "resolution": 0.25 } num_input_channels: 3 out_height: 13 out_width: 13 radius: 12 min_distance: 5 threshold_abs: 0.05 + tile_shape: [ 2048, 2048 ] + patch_input_shape: [ 31, 31 ] + patch_output_shape: [ 13, 13 ] + stride_shape: [ 8, 8 ] nuclick_original-pannuke: url: https://tiatoolbox.dcs.warwick.ac.uk/models/seg/nuclick_original-pannuke.pth From 46ffdae3ad2f980be3d189dd403655b3ad40a4a6 Mon Sep 17 00:00:00 2001 From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Mon, 20 Feb 2023 17:33:47 +0000 Subject: [PATCH 04/14] :boom: DEV: Fix mpp for cell detection - Fix mpp for cell detection --- tiatoolbox/data/pretrained_model.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tiatoolbox/data/pretrained_model.yaml b/tiatoolbox/data/pretrained_model.yaml index 2243cebb0..0f67004d8 100644 --- a/tiatoolbox/data/pretrained_model.yaml +++ b/tiatoolbox/data/pretrained_model.yaml @@ -778,7 +778,7 @@ mapde-crchisto: class: mapde.MapDe kwargs: input_resolutions: - - { "units": "mpp", "resolution": 0.25 } + - { "units": "mpp", "resolution": 0.5 } num_input_channels: 3 min_distance: 4 threshold_abs: 250 @@ -793,7 +793,7 @@ mapde-conic: class: mapde.MapDe kwargs: input_resolutions: - - { "units": "mpp", "resolution": 0.25 } + - { "units": "mpp", "resolution": 0.5 } num_input_channels: 3 min_distance: 3 threshold_abs: 205 @@ -808,7 +808,7 @@ sccnn-crchisto: class: sccnn.SCCNN kwargs: input_resolutions: - - { "units": "mpp", "resolution": 0.25 } + - { "units": "mpp", "resolution": 0.5 } num_input_channels: 3 out_height: 13 out_width: 13 @@ -826,7 +826,7 @@ sccnn-conic: class: sccnn.SCCNN kwargs: input_resolutions: - - { "units": "mpp", "resolution": 0.25 } + - { "units": "mpp", "resolution": 0.5 } num_input_channels: 3 out_height: 13 out_width: 13 From 4e2ca8bdd2622c65541f1660efa71508a69032d0 Mon Sep 17 00:00:00 2001 From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Tue, 21 Feb 2023 14:18:49 +0000 Subject: [PATCH 05/14] :bug: BUG: Fix bug with loading NucleusDetector - Fix bug with loading NucleusDetector --- tests/models/test_nucleus_detection_engine.py | 2 +- tiatoolbox/data/pretrained_model.yaml | 55 ++++++--- tiatoolbox/models/engine/nucleus_detection.py | 109 ++++++++++++++---- 3 files changed, 127 insertions(+), 39 deletions(-) diff --git a/tests/models/test_nucleus_detection_engine.py b/tests/models/test_nucleus_detection_engine.py index bcb94bdb5..615873593 100644 --- a/tests/models/test_nucleus_detection_engine.py +++ b/tests/models/test_nucleus_detection_engine.py @@ -5,4 +5,4 @@ def test_nucleus_detector_engine(sample_svs): """Test for nucleus detection engine.""" - _ = NucleusDetector(pretrained_model="mapde-conic") + _ = NucleusDetector(pretrained_model="mapde-conic", batch_size=1) diff --git a/tiatoolbox/data/pretrained_model.yaml b/tiatoolbox/data/pretrained_model.yaml index 0f67004d8..042f3aa5c 100644 --- a/tiatoolbox/data/pretrained_model.yaml +++ b/tiatoolbox/data/pretrained_model.yaml @@ -765,7 +765,6 @@ micronet-consep: - {"units": "mpp", "resolution": 0.25} output_resolutions: - {"units": "mpp", "resolution": 0.25} - margin: 128 tile_shape: [2048, 2048] patch_input_shape: [252, 252] patch_output_shape: [252, 252] @@ -777,30 +776,44 @@ mapde-crchisto: architecture: class: mapde.MapDe kwargs: - input_resolutions: - - { "units": "mpp", "resolution": 0.5 } num_input_channels: 3 min_distance: 4 threshold_abs: 250 num_classes: 1 + ioconfig: + class: semantic_segmentor.IOSegmentorConfig + kwargs: + input_resolutions: + - { "units": "mpp", "resolution": 0.5 } + output_resolutions: + - { "units": "mpp", "resolution": 0.5 } tile_shape: [ 2048, 2048 ] patch_input_shape: [ 252, 252 ] + patch_output_shape: [ 252, 252 ] stride_shape: [ 150, 150 ] + save_resolution: { 'units': 'mpp', 'resolution': 0.5 } mapde-conic: url: https://tiatoolbox.dcs.warwick.ac.uk/models/detection/mapde-conic.pth architecture: class: mapde.MapDe kwargs: - input_resolutions: - - { "units": "mpp", "resolution": 0.5 } num_input_channels: 3 min_distance: 3 threshold_abs: 205 num_classes: 1 + ioconfig: + class: semantic_segmentor.IOSegmentorConfig + kwargs: + input_resolutions: + - { "units": "mpp", "resolution": 0.5 } + output_resolutions: + - { "units": "mpp", "resolution": 0.5 } tile_shape: [ 2048, 2048 ] patch_input_shape: [ 252, 252 ] + patch_output_shape: [ 252, 252 ] stride_shape: [ 150, 150 ] + save_resolution: { 'units': 'mpp', 'resolution': 0.5 } sccnn-crchisto: url: https://tiatoolbox.dcs.warwick.ac.uk/models/detection/sccnn-crchisto.pth @@ -814,11 +827,19 @@ sccnn-crchisto: out_width: 13 radius: 12 min_distance: 6 - threshold_abs: 0.20 + threshold_abs: 0.201 + ioconfig: + class: semantic_segmentor.IOSegmentorConfig + kwargs: + input_resolutions: + - { "units": "mpp", "resolution": 0.5 } + output_resolutions: + - { "units": "mpp", "resolution": 0.5 } tile_shape: [ 2048, 2048 ] - patch_input_shape: [ 31, 31 ] - patch_output_shape: [ 13, 13 ] - stride_shape: [ 8, 8 ] + patch_input_shape: [ 252, 252 ] + patch_output_shape: [ 252, 252 ] + stride_shape: [ 150, 150 ] + save_resolution: { 'units': 'mpp', 'resolution': 0.5 } sccnn-conic: url: https://tiatoolbox.dcs.warwick.ac.uk/models/detection/sccnn-conic.pth @@ -832,11 +853,19 @@ sccnn-conic: out_width: 13 radius: 12 min_distance: 5 - threshold_abs: 0.05 + threshold_abs: 0.051 + ioconfig: + class: semantic_segmentor.IOSegmentorConfig + kwargs: + input_resolutions: + - { "units": "mpp", "resolution": 0.5 } + output_resolutions: + - { "units": "mpp", "resolution": 0.5 } tile_shape: [ 2048, 2048 ] - patch_input_shape: [ 31, 31 ] - patch_output_shape: [ 13, 13 ] - stride_shape: [ 8, 8 ] + patch_input_shape: [ 252, 252 ] + patch_output_shape: [ 252, 252 ] + stride_shape: [ 150, 150 ] + save_resolution: { 'units': 'mpp', 'resolution': 0.5 } nuclick_original-pannuke: url: https://tiatoolbox.dcs.warwick.ac.uk/models/seg/nuclick_original-pannuke.pth diff --git a/tiatoolbox/models/engine/nucleus_detection.py b/tiatoolbox/models/engine/nucleus_detection.py index b31e11d7d..5c35415ae 100644 --- a/tiatoolbox/models/engine/nucleus_detection.py +++ b/tiatoolbox/models/engine/nucleus_detection.py @@ -1,10 +1,66 @@ """This module implements nucleus detection engine.""" -from tiatoolbox.models.engine.patch_predictor import PatchPredictor +from typing import List, Union +import numpy as np -class NucleusDetector(PatchPredictor): +from tiatoolbox.models.engine.semantic_segmentor import ( + IOSegmentorConfig, + SemanticSegmentor, +) + + +class IONucleusDetectorConfig(IOSegmentorConfig): + """Contains NucleusDetector input and output information. + + Args: + input_resolutions (list): + Resolution of each input head of model inference, must be in + the same order as `target model.forward()`. + output_resolutions (list): + Resolution of each output head from model inference, must be + in the same order as target model.infer_batch(). + patch_input_shape (:class:`numpy.ndarray`, list(int)): + Shape of the largest input in (height, width). + patch_output_shape (:class:`numpy.ndarray`, list(int)): + Shape of the largest output in (height, width). + save_resolution (dict): + Resolution to save all output. + + Examples: + >>> # Defining io for a network having 1 input and 1 output at the + >>> # same resolution + >>> ioconfig = IONucleusDetectorConfig( + ... input_resolutions=[{"units": "baseline", "resolution": 1.0}], + ... output_resolutions=[{"units": "baseline", "resolution": 1.0}], + ... patch_input_shape=[2048, 2048], + ... patch_output_shape=[1024, 1024], + ... stride_shape=[512, 512], + ... ) + + """ + + def __init__( + self, + input_resolutions: List[dict], + output_resolutions: List[dict], + patch_input_shape: Union[List[int], np.ndarray], + patch_output_shape: Union[List[int], np.ndarray], + save_resolution: dict = None, + **kwargs, + ): + super().__init__( + input_resolutions=input_resolutions, + output_resolutions=output_resolutions, + patch_input_shape=patch_input_shape, + patch_output_shape=patch_output_shape, + save_resolution=save_resolution, + **kwargs, + ) + + +class NucleusDetector(SemanticSegmentor): r"""Nucleus detection engine. The models provided by tiatoolbox should give the following results: @@ -31,8 +87,8 @@ class NucleusDetector(PatchPredictor): Path to the weight of the corresponding `pretrained_model`. >>> predictor = NucleusDetector( - ... pretrained_model="resnet18-kather100k", - ... pretrained_weights="resnet18_local_weight") + ... pretrained_model="mapde-conic", + ... pretrained_weights="mapde_local_weight") batch_size (int): Number of images fed into the model each time. @@ -40,14 +96,14 @@ class NucleusDetector(PatchPredictor): Number of workers to load the data. Take note that they will also perform preprocessing. verbose (bool): - Whether to output logging information. + Whether to output logging information. default=False. + auto_generate_mask (bool): + To automatically generate tile/WSI tissue mask if is not + provided. default=False. Attributes: imgs (:obj:`str` or :obj:`pathlib.Path` or :obj:`numpy.ndarray`): A HWC image or a path to WSI. - mode (str): - Type of input to process. Choose from either `patch`, `tile` - or `wsi`. model (nn.Module): Defined PyTorch model. pretrained_model (str): @@ -69,37 +125,38 @@ class NucleusDetector(PatchPredictor): Examples: >>> # list of 2 image patches as input >>> data = [img1, img2] - >>> predictor = PatchPredictor(pretrained_model="resnet18-kather100k") - >>> output = predictor.predict(data, mode='patch') + >>> nucleus_detector = NucleusDetector(pretrained_model="mapde-conic") + >>> output = nucleus_detector.predict(data, mode='patch') >>> # array of list of 2 image patches as input >>> data = np.array([img1, img2]) - >>> predictor = PatchPredictor(pretrained_model="resnet18-kather100k") - >>> output = predictor.predict(data, mode='patch') + >>> nucleus_detector = NucleusDetector(pretrained_model="mapde-conic") + >>> output = nucleus_detector.predict(data, mode='patch') >>> # list of 2 image patch files as input >>> data = ['path/img.png', 'path/img.png'] - >>> predictor = PatchPredictor(pretrained_model="resnet18-kather100k") - >>> output = predictor.predict(data, mode='patch') + >>> nucleus_detector = NucleusDetector(pretrained_model="mapde-conic") + >>> output = nucleus_detector.predict(data, mode='patch') >>> # list of 2 image tile files as input >>> tile_file = ['path/tile1.png', 'path/tile2.png'] - >>> predictor = PatchPredictor(pretraind_model="resnet18-kather100k") - >>> output = predictor.predict(tile_file, mode='tile') + >>> nucleus_detector = NucleusDetector(pretraind_model="mapde-conic") + >>> output = nucleus_detector.predict(tile_file, mode='tile') >>> # list of 2 wsi files as input >>> wsi_file = ['path/wsi1.svs', 'path/wsi2.svs'] - >>> predictor = PatchPredictor(pretraind_model="resnet18-kather100k") - >>> output = predictor.predict(wsi_file, mode='wsi') + >>> nucleus_detector = NucleusDetector(pretraind_model="mapde-conic") + >>> output = nucleus_detector.predict(wsi_file, mode='wsi') References: - [1] Kather, Jakob Nikolas, et al. "Predicting survival from colorectal cancer - histology slides using deep learning: A retrospective multicenter study." - PLoS medicine 16.1 (2019): e1002730. + [1] Raza, Shan E. Ahmed, et al. "Deconvolving convolutional neural network + for cell detection." 2019 IEEE 16th International Symposium on Biomedical + Imaging (ISBI 2019). IEEE, 2019. - [2] Veeling, Bastiaan S., et al. "Rotation equivariant CNNs for digital - pathology." International Conference on Medical image computing and - computer-assisted intervention. Springer, Cham, 2018. + [2] Sirinukunwattana, Korsuk, et al. + "Locality sensitive deep learning for detection and classification + of nuclei in routine colon cancer histology images." + IEEE transactions on medical imaging 35.5 (2016): 1196-1206. """ # noqa: W605 @@ -110,7 +167,8 @@ def __init__( model=None, pretrained_model=None, pretrained_weights=None, - verbose=True, + verbose: bool = False, + auto_generate_mask: bool = False, ): super().__init__( batch_size=batch_size, @@ -119,4 +177,5 @@ def __init__( pretrained_model=pretrained_model, pretrained_weights=pretrained_weights, verbose=verbose, + auto_generate_mask=auto_generate_mask, ) From 1af81403acf9a62ea2bc72c3fd8ccb1ce698c38e Mon Sep 17 00:00:00 2001 From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Tue, 21 Feb 2023 14:33:38 +0000 Subject: [PATCH 06/14] :bug: BUG: Fix bug with loading sccnn - Fix bug with loading sccnn --- tests/models/test_nucleus_detection_engine.py | 2 +- tiatoolbox/data/pretrained_model.yaml | 26 +++++++------------ 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/tests/models/test_nucleus_detection_engine.py b/tests/models/test_nucleus_detection_engine.py index 615873593..0e7346e72 100644 --- a/tests/models/test_nucleus_detection_engine.py +++ b/tests/models/test_nucleus_detection_engine.py @@ -5,4 +5,4 @@ def test_nucleus_detector_engine(sample_svs): """Test for nucleus detection engine.""" - _ = NucleusDetector(pretrained_model="mapde-conic", batch_size=1) + _ = NucleusDetector(pretrained_model="sccnn-crchisto") diff --git a/tiatoolbox/data/pretrained_model.yaml b/tiatoolbox/data/pretrained_model.yaml index 042f3aa5c..9eb539efc 100644 --- a/tiatoolbox/data/pretrained_model.yaml +++ b/tiatoolbox/data/pretrained_model.yaml @@ -820,14 +820,11 @@ sccnn-crchisto: architecture: class: sccnn.SCCNN kwargs: - input_resolutions: - - { "units": "mpp", "resolution": 0.5 } num_input_channels: 3 - out_height: 13 - out_width: 13 radius: 12 min_distance: 6 - threshold_abs: 0.201 + threshold_abs: 0.20 + patch_output_shape: [ 13, 13 ] ioconfig: class: semantic_segmentor.IOSegmentorConfig kwargs: @@ -836,9 +833,9 @@ sccnn-crchisto: output_resolutions: - { "units": "mpp", "resolution": 0.5 } tile_shape: [ 2048, 2048 ] - patch_input_shape: [ 252, 252 ] - patch_output_shape: [ 252, 252 ] - stride_shape: [ 150, 150 ] + patch_input_shape: [ 31, 31 ] + patch_output_shape: [ 13, 13 ] + stride_shape: [ 8, 8 ] save_resolution: { 'units': 'mpp', 'resolution': 0.5 } sccnn-conic: @@ -846,14 +843,11 @@ sccnn-conic: architecture: class: sccnn.SCCNN kwargs: - input_resolutions: - - { "units": "mpp", "resolution": 0.5 } num_input_channels: 3 - out_height: 13 - out_width: 13 radius: 12 min_distance: 5 - threshold_abs: 0.051 + threshold_abs: 0.05 + patch_output_shape: [ 13, 13 ] ioconfig: class: semantic_segmentor.IOSegmentorConfig kwargs: @@ -862,9 +856,9 @@ sccnn-conic: output_resolutions: - { "units": "mpp", "resolution": 0.5 } tile_shape: [ 2048, 2048 ] - patch_input_shape: [ 252, 252 ] - patch_output_shape: [ 252, 252 ] - stride_shape: [ 150, 150 ] + patch_input_shape: [ 31, 31 ] + patch_output_shape: [ 13, 13 ] + stride_shape: [ 8, 8 ] save_resolution: { 'units': 'mpp', 'resolution': 0.5 } nuclick_original-pannuke: From 527444a7da96a9ff263addee043c87d9ded4de89 Mon Sep 17 00:00:00 2001 From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Tue, 21 Feb 2023 15:05:25 +0000 Subject: [PATCH 07/14] :bug: BUG: Fix test bug in test_patch_predictor.py - Fix test bug in test_patch_predictor.py --- tests/models/test_patch_predictor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/models/test_patch_predictor.py b/tests/models/test_patch_predictor.py index 465dd1f27..09ab9a9ab 100644 --- a/tests/models/test_patch_predictor.py +++ b/tests/models/test_patch_predictor.py @@ -551,7 +551,7 @@ def test_io_config_delegation(remote_sample, tmp_path): on_gpu=ON_GPU, save_dir=f"{tmp_path}/dump", ) - assert predictor._ioconfig.patch_input_shape == [300, 300] + assert predictor._ioconfig.patch_input_shape == (300, 300) _rm_dir(f"{tmp_path}/dump") predictor.predict( @@ -561,7 +561,7 @@ def test_io_config_delegation(remote_sample, tmp_path): on_gpu=ON_GPU, save_dir=f"{tmp_path}/dump", ) - assert predictor._ioconfig.stride_shape == [300, 300] + assert predictor._ioconfig.stride_shape == (300, 300) _rm_dir(f"{tmp_path}/dump") predictor.predict( From 37b82f9153d17cc8e97d6d1c62b703a7c7b23b4c Mon Sep 17 00:00:00 2001 From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Tue, 21 Feb 2023 17:41:19 +0000 Subject: [PATCH 08/14] :white_check_mark: TST: Add test for NucleusDetector - Add test for NucleusDetector --- tests/models/test_nucleus_detection_engine.py | 22 +++++- tiatoolbox/models/engine/__init__.py | 2 +- ...cleus_detection.py => nucleus_detector.py} | 72 +++++++++++++++++++ 3 files changed, 92 insertions(+), 4 deletions(-) rename tiatoolbox/models/engine/{nucleus_detection.py => nucleus_detector.py} (68%) diff --git a/tests/models/test_nucleus_detection_engine.py b/tests/models/test_nucleus_detection_engine.py index 0e7346e72..762e4ed41 100644 --- a/tests/models/test_nucleus_detection_engine.py +++ b/tests/models/test_nucleus_detection_engine.py @@ -1,8 +1,24 @@ """Tests for NucleusDetector.""" -from tiatoolbox.models.engine.nucleus_detection import NucleusDetector +import pathlib +import pandas as pd +import pytest -def test_nucleus_detector_engine(sample_svs): +from tiatoolbox.models.engine.nucleus_detector import NucleusDetector + + +def test_nucleus_detector_engine(remote_sample, tmp_path): """Test for nucleus detection engine.""" - _ = NucleusDetector(pretrained_model="sccnn-crchisto") + mini_wsi_svs = pathlib.Path(remote_sample("wsi4_512_512_svs")) + + nucleus_detector = NucleusDetector(pretrained_model="mapde-conic") + _ = nucleus_detector.predict( + [mini_wsi_svs], mode="wsi", save_dir=tmp_path / "output" + ) + + coordinates = pd.read_csv(tmp_path / "output" / "0.locations.0.csv") + assert coordinates.x[0] == pytest.approx(53, abs=2) + assert coordinates.x[1] == pytest.approx(55, abs=2) + assert coordinates.y[0] == pytest.approx(107, abs=2) + assert coordinates.y[1] == pytest.approx(127, abs=2) diff --git a/tiatoolbox/models/engine/__init__.py b/tiatoolbox/models/engine/__init__.py index 7574d6e7e..e7936a1c1 100644 --- a/tiatoolbox/models/engine/__init__.py +++ b/tiatoolbox/models/engine/__init__.py @@ -1,6 +1,6 @@ """Engines to run models implemented in tiatoolbox.""" from tiatoolbox.models.engine import ( - nucleus_detection, + nucleus_detector, nucleus_instance_segmentor, patch_predictor, semantic_segmentor, diff --git a/tiatoolbox/models/engine/nucleus_detection.py b/tiatoolbox/models/engine/nucleus_detector.py similarity index 68% rename from tiatoolbox/models/engine/nucleus_detection.py rename to tiatoolbox/models/engine/nucleus_detector.py index 5c35415ae..9eed8e324 100644 --- a/tiatoolbox/models/engine/nucleus_detection.py +++ b/tiatoolbox/models/engine/nucleus_detector.py @@ -4,6 +4,7 @@ from typing import List, Union import numpy as np +import pandas as pd from tiatoolbox.models.engine.semantic_segmentor import ( IOSegmentorConfig, @@ -160,6 +161,8 @@ class NucleusDetector(SemanticSegmentor): """ # noqa: W605 + from tiatoolbox.wsicore.wsireader import WSIReader + def __init__( self, batch_size=8, @@ -179,3 +182,72 @@ def __init__( verbose=verbose, auto_generate_mask=auto_generate_mask, ) + + def _process_predictions( + self, + cum_batch_predictions: List, + wsi_reader: WSIReader, + ioconfig: IOSegmentorConfig, + save_path: str, + cache_dir: str, + ): + """Define how the aggregated predictions are processed. + + This includes merging the prediction if necessary and also saving the + locations afterwards. Note that items within `cum_batch_predictions` will + be consumed during the operation. + + Args: + cum_batch_predictions (list): + List of batch predictions. Each item within the list + should be of (location, patch_predictions). + wsi_reader (:class:`WSIReader`): + A reader for the image where the predictions come from. + ioconfig (:class:`IOSegmentorConfig`): + A configuration object contains input and output + information. + save_path (str): + Root path to save current WSI predictions. + cache_dir (str): + Root path to cache current WSI data. + + """ + if len(cum_batch_predictions) == 0: + return + + # assume predictions is N, each item has L output element + locations, predictions = list(zip(*cum_batch_predictions)) + # Nx4 (N x [tl_x, tl_y, br_x, br_y), denotes the location of + # output patch this can exceed the image bound at the requested + # resolution remove singleton due to split. + locations = np.array([v[0] for v in locations]) + for index, output_resolution in enumerate(ioconfig.output_resolutions): + # assume resolution index to be in the same order as L + merged_resolution = ioconfig.highest_input_resolution + merged_locations = locations + # ! location is w.r.t the highest resolution, hence still need conversion + if ioconfig.save_resolution is not None: + merged_resolution = ioconfig.save_resolution + output_shape = wsi_reader.slide_dimensions(**output_resolution) + merged_shape = wsi_reader.slide_dimensions(**merged_resolution) + fx = merged_shape[0] / output_shape[0] + merged_locations = np.ceil(locations * fx).astype(np.int64) + merged_shape = wsi_reader.slide_dimensions(**merged_resolution) + # 0 idx is to remove singleton without removing other axes singleton + to_merge_predictions = [v[index][0] for v in predictions] + sub_save_path = f"{save_path}.raw.{index}.npy" + sub_count_path = f"{cache_dir}/count.{index}.npy" + cum_canvas = self.merge_prediction( + merged_shape[::-1], # XY to YX + to_merge_predictions, + merged_locations, + save_path=sub_save_path, + cache_count_path=sub_count_path, + ) + + # Coordinates in output resolution for the current canvas. + cum_canvas = np.expand_dims(cum_canvas, axis=0) + coordinates_canvas = pd.DataFrame( + self.model.postproc_func(cum_canvas), columns=["x", "y"] + ) + coordinates_canvas.to_csv(f"{save_path}.locations.{index}.csv", index=False) From 1405fa0a93aec61743b53628810d58621967641e Mon Sep 17 00:00:00 2001 From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Tue, 21 Feb 2023 18:26:51 +0000 Subject: [PATCH 09/14] :bug: TST: Set GPU - Set GPU Signed-off-by: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> --- tests/models/test_nucleus_detection_engine.py | 8 +++++++- tiatoolbox/models/engine/semantic_segmentor.py | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/models/test_nucleus_detection_engine.py b/tests/models/test_nucleus_detection_engine.py index 762e4ed41..a6906720e 100644 --- a/tests/models/test_nucleus_detection_engine.py +++ b/tests/models/test_nucleus_detection_engine.py @@ -6,6 +6,9 @@ import pytest from tiatoolbox.models.engine.nucleus_detector import NucleusDetector +from tiatoolbox.utils import env_detection as toolbox_env + +ON_GPU = not toolbox_env.running_on_ci() and toolbox_env.has_gpu() def test_nucleus_detector_engine(remote_sample, tmp_path): @@ -14,7 +17,10 @@ def test_nucleus_detector_engine(remote_sample, tmp_path): nucleus_detector = NucleusDetector(pretrained_model="mapde-conic") _ = nucleus_detector.predict( - [mini_wsi_svs], mode="wsi", save_dir=tmp_path / "output" + [mini_wsi_svs], + mode="wsi", + save_dir=tmp_path / "output", + on_gpu=ON_GPU, ) coordinates = pd.read_csv(tmp_path / "output" / "0.locations.0.csv") diff --git a/tiatoolbox/models/engine/semantic_segmentor.py b/tiatoolbox/models/engine/semantic_segmentor.py index 7fe749d49..1edf2b92d 100644 --- a/tiatoolbox/models/engine/semantic_segmentor.py +++ b/tiatoolbox/models/engine/semantic_segmentor.py @@ -1531,7 +1531,7 @@ def predict( units (str): Units of resolution used for reading the image. Choose from either `"level"`, `"power"` or `"mpp"`. - save_dir (str): + save_dir (str or pathlib.Path): Output directory when processing multiple tiles and whole-slide images. By default, it is folder `output` where the running script is invoked. From 71cb5c6fd05e8f58aac5e8395290c9d8836d79de Mon Sep 17 00:00:00 2001 From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Wed, 22 Feb 2023 09:50:10 +0000 Subject: [PATCH 10/14] :white_check_mark: TST: Add test to improve coverage - Add test to improve coverage --- tests/models/test_nucleus_detection_engine.py | 49 ++++++++++++++++--- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/tests/models/test_nucleus_detection_engine.py b/tests/models/test_nucleus_detection_engine.py index a6906720e..e9f4e1aec 100644 --- a/tests/models/test_nucleus_detection_engine.py +++ b/tests/models/test_nucleus_detection_engine.py @@ -1,16 +1,35 @@ """Tests for NucleusDetector.""" import pathlib +import shutil import pandas as pd import pytest -from tiatoolbox.models.engine.nucleus_detector import NucleusDetector +from tiatoolbox.models.engine.nucleus_detector import ( + IONucleusDetectorConfig, + NucleusDetector, +) from tiatoolbox.utils import env_detection as toolbox_env ON_GPU = not toolbox_env.running_on_ci() and toolbox_env.has_gpu() +def _rm_dir(path): + """Helper func to remove directory.""" + if pathlib.Path(path).exists(): + shutil.rmtree(path, ignore_errors=True) + + +def check_output(path): + """Check NucleusDetector output.""" + coordinates = pd.read_csv(path) + assert coordinates.x[0] == pytest.approx(53, abs=2) + assert coordinates.x[1] == pytest.approx(55, abs=2) + assert coordinates.y[0] == pytest.approx(107, abs=2) + assert coordinates.y[1] == pytest.approx(127, abs=2) + + def test_nucleus_detector_engine(remote_sample, tmp_path): """Test for nucleus detection engine.""" mini_wsi_svs = pathlib.Path(remote_sample("wsi4_512_512_svs")) @@ -23,8 +42,26 @@ def test_nucleus_detector_engine(remote_sample, tmp_path): on_gpu=ON_GPU, ) - coordinates = pd.read_csv(tmp_path / "output" / "0.locations.0.csv") - assert coordinates.x[0] == pytest.approx(53, abs=2) - assert coordinates.x[1] == pytest.approx(55, abs=2) - assert coordinates.y[0] == pytest.approx(107, abs=2) - assert coordinates.y[1] == pytest.approx(127, abs=2) + check_output(tmp_path / "output" / "0.locations.0.csv") + + _rm_dir(tmp_path / "output") + + ioconfig = IONucleusDetectorConfig( + input_resolutions=[{"units": "mpp", "resolution": 0.5}], + output_resolutions=[{"units": "mpp", "resolution": 0.5}], + save_resolution=None, + patch_input_shape=[252, 252], + patch_output_shape=[252, 252], + stride_shape=[150, 150], + ) + + nucleus_detector = NucleusDetector(pretrained_model="mapde-conic") + _ = nucleus_detector.predict( + [mini_wsi_svs], + mode="wsi", + save_dir=tmp_path / "output", + on_gpu=ON_GPU, + ioconfig=ioconfig, + ) + + check_output(tmp_path / "output" / "0.locations.0.csv") From b11e6f0eeaf2aa85b26a4c802da3cb707e1c2398 Mon Sep 17 00:00:00 2001 From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Tue, 2 May 2023 16:51:02 +0100 Subject: [PATCH 11/14] :memo: Add example models - Add example models --- tiatoolbox/models/engine/nucleus_detector.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tiatoolbox/models/engine/nucleus_detector.py b/tiatoolbox/models/engine/nucleus_detector.py index 9eed8e324..6e8e8615b 100644 --- a/tiatoolbox/models/engine/nucleus_detector.py +++ b/tiatoolbox/models/engine/nucleus_detector.py @@ -109,8 +109,8 @@ class NucleusDetector(SemanticSegmentor): Defined PyTorch model. pretrained_model (str): Name of the existing models support by tiatoolbox for - processing the data. For a full list of pretrained models, - refer to the `docs + processing the data e.g., mapde-conic, sccnn-conic. + For a full list of pretrained models, please refer to the `docs `_ By default, the corresponding pretrained weights will also be downloaded. However, you can override with your own set From 2c3884a826a9d21eafd91a40a902723b75648cdf Mon Sep 17 00:00:00 2001 From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Fri, 2 Jun 2023 10:59:10 +0100 Subject: [PATCH 12/14] :pushpin: Pin `torch` version - Pin `torch` version --- requirements/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 8195c2f32..532b4c182 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -25,7 +25,7 @@ shapely>=2.0.0 SimpleITK>=2.2.1 sphinx>=5.3.0 tifffile>=2022.10.10 -torch>=2.0.0 +torch>=1.13.0, <2.0.0 torchvision>=0.14.1 tqdm>=4.64.1 umap-learn>=0.5.3 From e670455da612fa82b3929655143266aad1a74052 Mon Sep 17 00:00:00 2001 From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Fri, 2 Jun 2023 11:41:53 +0100 Subject: [PATCH 13/14] :pushpin: Pin `torch` version - Pin `torch` version --- requirements/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 532b4c182..22242dc86 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -25,7 +25,7 @@ shapely>=2.0.0 SimpleITK>=2.2.1 sphinx>=5.3.0 tifffile>=2022.10.10 -torch>=1.13.0, <2.0.0 +torch>=1.13.0 torchvision>=0.14.1 tqdm>=4.64.1 umap-learn>=0.5.3 From 7989aa7b06cfdfc186c40a35421155e0dc49be64 Mon Sep 17 00:00:00 2001 From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Sat, 17 Jun 2023 14:57:57 +0100 Subject: [PATCH 14/14] :hammer: Try cuda 11.8 - Try cuda 11.8 to run the tests as it passes locally. Signed-off-by: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> --- requirements/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 22242dc86..719d9551a 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -1,5 +1,5 @@ # torch installation ---extra-index-url https://download.pytorch.org/whl/cu117; sys_platform != "darwin" +--extra-index-url https://download.pytorch.org/whl/cu118; sys_platform != "darwin" albumentations>=1.3.0 Click>=8.1.3 defusedxml>=0.7.1