Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Models refactoring #83

Merged
merged 28 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ jobs:
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}


deploy:
# this will run when you have tagged a commit, starting with "v*"
# and requires that you have put your twine API key in your
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,6 @@ dmypy.json
.idea/

.DS_Store
data/
BentoML/

13 changes: 7 additions & 6 deletions docs/source/dcp_server_installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,18 @@ The models are currently integrated into DCP:

- **Instance** Segmentation:

- ``CustomCellposeModel``: Inherits from cellpose.models.CellposeModel, see `here <https://cellpose.readthedocs.io/en/latest/api.html#cellposemodel>`__ for more information.
- ``CustomCellpose``: Inherits from cellpose.models.CellposeModel, see `here <https://cellpose.readthedocs.io/en/latest/api.html#cellposemodel>`__ for more information.
- **Semantic** Segmentation:

- ``UNet``: A vanilla U-Net model, trained on the full images
- **Panoptic** Segmentation:
- **Multi Class Instance** Segmentation:

- ``CellposePatchCNN``: Includes a segmentor for instance segmentation, sequentially followed by a classifier for semantic segmentation. The segmentor can only be ``CustomCellposeModel`` model, while the classifier can be one of:
- ``Inst2MultiSeg``: Includes a segmentor for instance segmentation, sequentially followed by a classifier for semantic segmentation. The segmentor can only be ``CustomCellposeModel`` model, while the classifier can be one of:

- ``CellClassifierFCNN`` or "FCNN" (in config): A CNN model for obtaining class labels, trained on images patches of individual objects, extarcted using the instance mask from the previous step
- ``CellClassifierShallowModel`` or "RandomForest" (in config): A Random Forest model for obtaining class labels, trained on shape and intensity features of the objects, extracted using the instance mask from the previous step.
- UNet: If the post-processing argument is set, then the instance mask is deduced from the labels mask. Will not be able to handle touching objects
- ``PatchClassifier`` or "FCNN" (in config): A CNN model for obtaining class labels, trained on images patches of individual objects, extarcted using the instance mask from the previous step
- ``FeatureClassifier`` or "RandomForest" (in config): A Random Forest model for obtaining class labels, trained on shape and intensity features of the objects, extracted using the instance mask from the previous step.
- ``MultiCellpose``: Includes **n** CustomCellpose models, where n equals the number of classes, stacked such that each model predicts only the object corresponding to each class.
- ``UNet``: If the post-processing argument is set, then the instance mask is deduced from the labels mask. Will not be able to handle touching objects


Running with Docker
Expand Down
2 changes: 1 addition & 1 deletion docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ DCP handles all kinds of **segmentation tasks**! Try it out if you need to do:

- **Instance** segmentation
- **Semantic** segmentation
- **Panoptic** segmentation
- **Multi-class instance** segmentation

Toy data
--------
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions src/client/dcp_client/gui/napari_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def __init__(self, app: Application):
layout.addWidget(main_window, 0, 0, 1, 4)

# select the first seg as the currently selected layer if there are any segs
if len(self.seg_files):
if len(self.seg_files) and len(self.viewer.layers[get_path_stem(self.seg_files[0])].data.shape) > 2:
self.cur_selected_seg = self.viewer.layers.selection.active.name
self.layer = self.viewer.layers[self.cur_selected_seg]
self.viewer.layers.selection.events.changed.connect(self.on_seg_channel_changed)
Expand All @@ -68,7 +68,7 @@ def __init__(self, app: Application):

self.qctrl = self.viewer.window.qt_viewer.controls.widgets[self.layer]

if self.layer.data.shape[0] >= 2:
if len(self.layer.data.shape) > 2:
# User hint
message_label = QLabel('Choose an active mask')
message_label.setAlignment(Qt.AlignRight)
Expand Down
2 changes: 1 addition & 1 deletion src/client/dcp_client/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
def main():
settings.init()
dir_name = path.dirname(path.abspath(sys.argv[0]))
server_config = read_config('server', config_path = path.join(dir_name, 'config.cfg'))
server_config = read_config('server', config_path = path.join(dir_name, 'config.yaml'))

image_storage = FilesystemImageStorage()
ml_model = BentomlModel()
Expand Down
32 changes: 17 additions & 15 deletions src/client/dcp_client/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from skimage.draw import polygon_perimeter

from pathlib import Path, PurePath
import json
import yaml

from dcp_client.utils import settings

Expand Down Expand Up @@ -36,18 +36,18 @@
else:
return super().icon(type)

def read_config(name, config_path = 'config.cfg') -> dict:
""" Reads the configuration file
def read_config(name, config_path = 'config.yaml') -> dict:
"""Reads the configuration file

:param name: name of the section you want to read (e.g. 'setup','train')
:type name: string
:param config_path: path to the configuration file, defaults to 'config.cfg'
:param config_path: path to the configuration file, defaults to 'config.yaml'
:type config_path: str, optional
:return: dictionary from the config section given by name
:rtype: dict
"""
with open(config_path) as config_file:
config_dict = json.load(config_file)
config_dict = yaml.safe_load(config_file) # json.load(config_file) for .cfg file

Check warning on line 50 in src/client/dcp_client/utils/utils.py

View check run for this annotation

Codecov / codecov/patch

src/client/dcp_client/utils/utils.py#L50

Added line #L50 was not covered by tests
# Check if config file has main mandatory keys
assert all([i in config_dict.keys() for i in ['server']])
return config_dict[name]
Expand Down Expand Up @@ -140,16 +140,18 @@
# get a binary mask only of object
single_obj_mask = np.zeros_like(instance_mask)
single_obj_mask[instance_mask==instance_id] = 1
# compute contours for mask
contours = find_contours(single_obj_mask, contours_level)
# sometimes little dots appeas as additional contours so remove these
if len(contours)>1:
contour_sizes = [contour.shape[0] for contour in contours]
contour = contours[contour_sizes.index(max(contour_sizes))].astype(int)
else: contour = contours[0]
# and draw onto contours mask
rr, cc = polygon_perimeter(contour[:, 0], contour[:, 1], contour_mask.shape)
contour_mask[rr, cc] = instance_id
try:
# compute contours for mask
contours = find_contours(single_obj_mask, contours_level)
# sometimes little dots appeas as additional contours so remove these
if len(contours)>1:
contour_sizes = [contour.shape[0] for contour in contours]
contour = contours[contour_sizes.index(max(contour_sizes))].astype(int)

Check warning on line 149 in src/client/dcp_client/utils/utils.py

View check run for this annotation

Codecov / codecov/patch

src/client/dcp_client/utils/utils.py#L148-L149

Added lines #L148 - L149 were not covered by tests
else: contour = contours[0]
# and draw onto contours mask
rr, cc = polygon_perimeter(contour[:, 0], contour[:, 1], contour_mask.shape)
contour_mask[rr, cc] = instance_id
except: print("Could not create contour for instance id", instance_id)

Check warning on line 154 in src/client/dcp_client/utils/utils.py

View check run for this annotation

Codecov / codecov/patch

src/client/dcp_client/utils/utils.py#L154

Added line #L154 was not covered by tests
return contour_mask

@staticmethod
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,40 @@
{
"setup": {
"segmentation": "GeneralSegmentation",
"model_to_use": "CellposePatchCNN",
"model_to_use": "Inst2MultiSeg",
"accepted_types": [".jpg", ".jpeg", ".png", ".tiff", ".tif"],
"seg_name_string": "_seg"
},

"service": {
"runner_name": "bento_runner",
"bento_model_path": "cppcnn",
"bento_model_path": "cells",
"service_name": "data-centric-platform",
"port": 7010
},

"model": {
"segmentor_name": "Cellpose",
"segmentor": {
"model_type": "cyto"

},
"classifier_name": "PatchClassifier",
"classifier":{
"model_class": "FCNN",
"in_channels": 1,
"num_classes": 2,
"black_bg": "False",
"include_mask": "False"
"features":[64,128,256,512],
"black_bg": False,
"include_mask": True
}
},

"data": {
"data_root": "data"
"data_root": "data",
"patch_size": 64,
"noise_intensity": 5,
"gray": True,
"rescale": True
},

"train":{
Expand All @@ -38,12 +44,7 @@
"min_train_masks": 1
},
"classifier":{
"train_data":{
"patch_size": 64,
"noise_intensity": 5,
"num_classes": 2
},
"n_epochs": 10,
"n_epochs": 100,
"lr": 0.001,
"batch_size": 1,
"optimizer": "Adam"
Expand All @@ -58,10 +59,6 @@
"batch_size": 1
},
"classifier": {
"data":{
"patch_size": 64,
"noise_intensity": 5
}
},
"mask_channel_axis": 0
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"setup": {
"segmentation": "GeneralSegmentation",
"model_to_use": "CustomCellposeModel",
"model_to_use": "CustomCellpose",
"accepted_types": [".jpg", ".jpeg", ".png", ".tiff", ".tif"],
"seg_name_string": "_seg"
},

"service": {
"runner_name": "cellpose_runner",
"bento_model_path": "cells",
"runner_name": "bento_runner",
"bento_model_path": "cells",
"service_name": "data-centric-platform",
"port": 7010
},
Expand All @@ -20,12 +20,14 @@
},

"data": {
"data_root": "data"
"data_root": "data",
"gray": True,
"rescale": True
},

"train":{
"segmentor":{
"n_epochs": 10,
"n_epochs": 5,
"channels": [0,0],
"min_train_masks": 1
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@

"model": {
"classifier":{
"model_class": "UNet",
"in_channels": 1,
"num_classes": 3,
"num_classes": 2,
"features":[64,128,256,512]
}
},

"data": {
"data_root": "data"
"data_root": "data",
"gray": True,
"rescale": True
},

"train":{
Expand All @@ -37,7 +38,9 @@

"eval":{
"classifier": {

},
"mask_channel_axis": null
"compute_instance": True,
"mask_channel_axis": 0
}
}
4 changes: 2 additions & 2 deletions src/server/dcp_server/main.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import subprocess
from os import path
import sys
from utils import read_config
from dcp_server.utils.helpers import read_config

def main():
"""
Expand All @@ -17,7 +17,7 @@ def main():

local_path = path.join(__file__, '..')
dir_name = path.dirname(path.abspath(sys.argv[0]))
service_config = read_config('service', config_path = path.join(dir_name, 'config.cfg'))
service_config = read_config('service', config_path = path.join(dir_name, 'config.yaml'))
port = str(service_config['port'])

subprocess.run([
Expand Down
Loading
Loading