Skip to content

Commit 872cc66

Browse files
committed
Merge remote-tracking branch 'origin/main' into package-without-editable-flag
2 parents a2a8762 + 48f1fb1 commit 872cc66

14 files changed

+283
-176
lines changed

cli/medperf/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.1.0"
1+
__version__ = "0.1.2"

docs/mlcubes/mlcube_models.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ docker_image_name [docker/image:latest]: # (6)!
5555
2. Determines how the MLCube root folder will be named.
5656
3. Gives a Human-readable description to the MLCube Project.
5757
4. Documents the MLCube implementation by specifying the author.
58-
5. Indicates how many GPUs should be visible by the MLCube.
58+
5. Set it to 0. This is now ignored and will be removed in the next release. Please check the last section to learn how to use MLCube with GPUs.
5959
6. MLCubes use Docker containers under the hood. Here, you can provide an image tag to the image that will be created by this MLCube. **You should use a valid name that allows you to upload it to a Docker registry.**
6060

6161
After filling the configuration options, the following directory structure will be generated:
@@ -232,9 +232,6 @@ accelerator_count [0]: 0
232232
docker_image_name [docker/image:latest]: repository/model-tutorial:0.0.0
233233
```
234234

235-
!!! note
236-
This example is built to be used with a CPU. See the [last section](#using-the-example-with-gpus) to know how to configure this example with a GPU.
237-
238235
Note that `docker_image_name` is arbitrarily chosen. Use a valid docker image.
239236

240237
### Move your Codebase
@@ -355,6 +352,11 @@ The provided example codebase runs only on CPU. You can modify it to have `pytor
355352

356353
The general instructions for building an MLCube to work with a GPU are the same as the provided instructions, but with the following slight modifications:
357354

358-
- Use a number different than `0` for the `accelerator_count` that you will be prompted with when creating the MLCube template.
359-
- Inside the `docker` section of the `mlcube.yaml`, add a key value pair: `gpu_args: --gpus=all`. These `gpu_args` will be passed to `docker run` under the hood by MLCube. You may add more than just `--gpus=all`.
360355
- Make sure you install the required GPU dependencies in the docker image. For instance, this may be done by simply modifying the `pip` dependencies in the `requirements.txt` file to download `pytorch` with cuda, or by changing the base image of the dockerfile.
356+
357+
For testing your MLCube with GPUs using the MLCube tool as in the previous section, make sure you run the `mlcube run` command with a `--gpus` argument. Example: `mlcube run --gpus=all ...`
358+
359+
For testing your MLCube with GPUs using MedPerf, make sure you pass as well the `--gpus` argument to the MedPerf command. Example: `medperf --gpus=all <subcommand> ...`.
360+
361+
!!!tip
362+
Run `medperf --help` to see the possible options you can use for the `--gpus` argument.

scripts/get_dataset_hashes.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import hashlib
2+
import os
3+
import yaml
4+
5+
from medperf import config
6+
from medperf.init import initialize
7+
from typer import Option
8+
9+
10+
def sha256sum(filename):
11+
h = hashlib.sha256()
12+
b = bytearray(128 * 1024)
13+
mv = memoryview(b)
14+
with open(filename, "rb", buffering=0) as f:
15+
while n := f.readinto(mv):
16+
h.update(mv[:n])
17+
return h.hexdigest()
18+
19+
20+
def generate_hash_dict(path):
21+
hash_dict = {}
22+
contents = os.listdir(path)
23+
24+
for item in contents:
25+
item_path = os.path.join(path, item)
26+
if os.path.isdir(item_path):
27+
hash_dict[item] = generate_hash_dict(item_path)
28+
else:
29+
hash_dict[item] = sha256sum(item_path)
30+
31+
return hash_dict
32+
33+
34+
def main(
35+
dataset_uid: str = Option(None, "-d", "--dataset"),
36+
output_file: str = Option("dataset_hashes.yaml", "-f", "--file"),
37+
):
38+
initialize()
39+
dset_path = os.path.join(config.datasets_folder, dataset_uid)
40+
41+
# Get hashes of tree
42+
hash_dict = generate_hash_dict(dset_path)
43+
44+
# Write results to a file
45+
with open(output_file, "w") as f:
46+
yaml.dump(hash_dict, f)
47+
48+
49+
if __name__ == "__main__":
50+
run(main)

scripts/get_reviewed_cases_hashes.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import tarfile
2+
import hashlib
3+
import shutil
4+
import os
5+
import yaml
6+
7+
8+
def sha256sum(filename):
9+
h = hashlib.sha256()
10+
b = bytearray(128 * 1024)
11+
mv = memoryview(b)
12+
with open(filename, "rb", buffering=0) as f:
13+
while n := f.readinto(mv):
14+
h.update(mv[:n])
15+
return h.hexdigest()
16+
17+
18+
def generate_hash_dict(path):
19+
hash_dict = {}
20+
contents = os.listdir(path)
21+
22+
for item in contents:
23+
item_path = os.path.join(path, item)
24+
if os.path.isdir(item_path):
25+
hash_dict[item] = generate_hash_dict(item_path)
26+
else:
27+
hash_dict[item] = sha256sum(item_path)
28+
29+
return hash_dict
30+
31+
32+
def main():
33+
dst = ".reviewed_cases_contents"
34+
hashes_file = "reviewed_cases_hashes.yaml"
35+
36+
# Create destination folder
37+
shutil.rmtree(dst, ignore_errors=True)
38+
os.makedirs(dst, exist_ok=True)
39+
40+
# Extract contents
41+
with tarfile.open("reviewed_cases.tar.gz") as file:
42+
file.extractall(dst)
43+
44+
# Get hashes of tree
45+
hash_dict = generate_hash_dict(dst)
46+
47+
# Write results to a file
48+
with open(hashes_file, "w") as f:
49+
yaml.dump(hash_dict, f)
50+
51+
# Delete generated files and folders
52+
shutil.rmtree(dst, ignore_errors=True)
53+
54+
55+
if __name__ == "__main__":
56+
main()

scripts/monitor/rano_monitor/__main__.py

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@
77
DEFAULT_STAGES_PATH,
88
STAGES_HELP,
99
DSET_LOC_HELP,
10-
OUT_HELP
10+
OUT_HELP,
1111
)
1212
from rano_monitor.dataset_browser import DatasetBrowser
1313
from rano_monitor.handlers import InvalidHandler
1414
from rano_monitor.handlers import PromptHandler
1515
from rano_monitor.handlers import ReportHandler, ReportState
16-
from rano_monitor.handlers import ReviewedHandler
1716
from rano_monitor.handlers import TarballReviewedHandler
1817
from rano_monitor.tarball_browser import TarballBrowser
1918
from typer import Option
@@ -40,13 +39,11 @@ def run_dset_app(dset_path, stages_path, output_path):
4039
report_state = ReportState(report_path, t_app)
4140
report_watchdog = ReportHandler(report_state)
4241
prompt_watchdog = PromptHandler(dset_data_path, t_app)
43-
reviewed_watchdog = ReviewedHandler(dset_data_path, t_app)
4442
invalid_watchdog = InvalidHandler(invalid_path, t_app)
4543

4644
t_app.set_vars(
4745
dset_data_path,
4846
stages_path,
49-
reviewed_watchdog,
5047
output_path,
5148
invalid_path,
5249
invalid_watchdog,
@@ -56,7 +53,6 @@ def run_dset_app(dset_path, stages_path, output_path):
5653
observer = Observer()
5754
observer.schedule(report_watchdog, dset_path)
5855
observer.schedule(prompt_watchdog, os.path.join(dset_path, "data"))
59-
observer.schedule(reviewed_watchdog, ".")
6056
observer.schedule(invalid_watchdog, os.path.dirname(invalid_path))
6157
observer.start()
6258
t_app.run()
@@ -89,13 +85,8 @@ def run_tarball_app(tarball_path):
8985

9086
@app.command()
9187
def main(
92-
dataset_uid: str = Option(None, "-d", "--dataset", help=DSET_HELP),
93-
stages_path: str = Option(
94-
DEFAULT_STAGES_PATH,
95-
"-s",
96-
"--stages",
97-
help=STAGES_HELP
98-
),
88+
dataset_uid: str = Option(..., "-d", "--dataset", help=DSET_HELP),
89+
stages_path: str = Option(DEFAULT_STAGES_PATH, "-s", "--stages", help=STAGES_HELP),
9990
dset_path: str = Option(
10091
None,
10192
"-p",

scripts/monitor/rano_monitor/assets/subject-browser.tcss

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,6 @@ SubjectDetails Button {
7171
column-span: 2;
7272
}
7373

74-
SubjectDetails {
75-
overflow-y: scroll;
76-
height: 100%;
77-
}
78-
7974
SubjectDetails CopyableItem {
8075
layout: grid;
8176
grid-size: 12 1;
@@ -121,7 +116,6 @@ Summary {
121116
padding: 3;
122117
align: center middle;
123118
content-align: center middle;
124-
overflow-y: scroll;
125119
}
126120

127121
Summary Static {
@@ -148,4 +142,9 @@ ListItem .subtitle {
148142
MarkdownViewer {
149143
height: auto;
150144
min-height: 2;
145+
}
146+
147+
.review-btn {
148+
width: 100%;
149+
margin: 1;
151150
}

scripts/monitor/rano_monitor/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,5 @@
2929
LISTITEM_MAX_LEN = 30
3030

3131
REVIEWED_PATTERN = r".*\/(.*)\/(.*)\/finalized\/(.*\.nii\.gz)"
32+
UNDER_REVIEW_PATTERN = r".*\/(.*)\/(.*)\/under_review\/(.*\.nii\.gz)"
3233
BRAINMASK_PATTERN = r".*\/(.*)\/(.*)\/brainMask_fused.nii.gz"

scripts/monitor/rano_monitor/dataset_browser.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from rano_monitor.widgets.summary import Summary
1212
from textual.app import App, ComposeResult
1313
from textual.binding import Binding
14-
from textual.containers import Container, Horizontal
14+
from textual.containers import Container, Horizontal, VerticalScroll
1515
from textual.reactive import reactive, var
1616
from textual.widgets import (
1717
Button,
@@ -42,15 +42,13 @@ def set_vars(
4242
self,
4343
dset_data_path,
4444
stages_path,
45-
reviewed_watchdog,
4645
output_path,
4746
invalid_path,
4847
invalid_watchdog,
4948
prompt_watchdog,
5049
):
5150
self.dset_data_path = dset_data_path
5251
self.stages_path = stages_path
53-
self.reviewed_watchdog = reviewed_watchdog
5452
self.output_path = output_path
5553
self.invalid_path = invalid_path
5654
self.invalid_watchdog = invalid_watchdog
@@ -65,8 +63,9 @@ def compose(self) -> ComposeResult:
6563
with Container():
6664
with Container(id="list-container"):
6765
yield SubjectListView(id="subjects-list")
68-
yield Summary(id="summary")
69-
yield SubjectDetails(id="details")
66+
with VerticalScroll():
67+
yield Summary(id="summary")
68+
yield SubjectDetails(id="details")
7069
with Container(id="confirm-prompt"):
7170
yield Static(self.prompt, id="confirm-details")
7271
yield Horizontal(
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
from .invalid_handler import InvalidHandler
22
from .prompt_handler import PromptHandler
33
from .report_handler import ReportHandler, ReportState
4-
from .reviewed_handler import ReviewedHandler
54
from .tarball_reviewed_watchdog import TarballReviewedHandler
65

76
__all__ = [
87
InvalidHandler,
98
PromptHandler,
109
ReportHandler,
1110
ReportState,
12-
ReviewedHandler,
1311
TarballReviewedHandler,
1412
]

0 commit comments

Comments
 (0)