Skip to content

Commit 241f0c4

Browse files
Fix Release Build/setup.py for SAM2 dependency (#1779)
* SAM-2 as extra dependency for PyPi Signed-off-by: Sachidanand Alle <salle@nvidia.com> * Disable release test once Signed-off-by: Sachidanand Alle <salle@nvidia.com> * Fix release build Signed-off-by: Sachidanand Alle <salle@nvidia.com> * Fix release build Signed-off-by: Sachidanand Alle <salle@nvidia.com> * Fix github sam2 packaging for PyPI release Signed-off-by: Sachidanand Alle <salle@nvidia.com> * Fix build error Signed-off-by: Sachidanand Alle <salle@nvidia.com> * Fix build error Signed-off-by: Sachidanand Alle <salle@nvidia.com> --------- Signed-off-by: Sachidanand Alle <salle@nvidia.com>
1 parent ea9e302 commit 241f0c4

12 files changed

Lines changed: 70 additions & 29 deletions

File tree

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ __pycache__
1414
.vscode
1515
.webpack
1616
node_modules/
17+
*.log
1718

1819
# Environments
1920
.env

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ jobs:
9191
run: |
9292
rm dist/monai*.tar.gz
9393
94-
- name: Publish distribution to Test PyPI
94+
- name: Publish distribution to Test
9595
if: ${{ github.event.inputs.test_py == 'true' }}
9696
uses: pypa/gh-action-pypi-publish@master
9797
with:

Dockerfile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,12 @@ RUN BUILD_OHIF=false python setup.py bdist_wheel --build-number $(date +'%Y%m%d%
3636
FROM ${FINAL_IMAGE}
3737
LABEL maintainer="monai.contact@gmail.com"
3838
WORKDIR /opt/monailabel
39+
COPY requirements.txt /opt/monailabel/requirements.txt
40+
3941
RUN apt update -y && apt install -y git curl openslide-tools python3 python-is-python3 python3-pip
4042
RUN python -m pip install --no-cache-dir pytest torch torchvision torchaudio
43+
4144
COPY --from=build /opt/monailabel/dist/monailabel* /opt/monailabel/dist/
42-
RUN python -m pip install --no-cache-dir /opt/monailabel/dist/monailabel*.whl
45+
RUN python -m pip install -v --no-cache-dir /opt/monailabel/dist/monailabel*.whl
46+
RUN python -m pip uninstall sam2 -y
47+
RUN python -m pip install -v --no-cache-dir -r /opt/monailabel/requirements.txt

README.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,12 +167,6 @@ In addition, you can find a table of the basic supported fields, modalities, vie
167167
<tr>
168168
</table>
169169

170-
> [**SAM2**](https://github.com/facebookresearch/sam2/)
171-
>
172-
> By default, SAM2 is included for all the above Apps only when **_python >= 3.10_**
173-
> - **sam_2d**: for any organ or tissue and others over a given slice/2D image.
174-
> - **sam_3d**: to support SAM2 propagation over multiple slices (Radiology/MONAI-Bundle).
175-
176170
# Getting Started with MONAI Label
177171
### MONAI Label requires a few steps to get started:
178172
- Step 1: [Install MONAI Label](#step-1-installation)
@@ -219,6 +213,19 @@ To install the _**latest features**_ using one of the following options:
219213
<pre>docker run --gpus all --rm -ti --ipc=host --net=host projectmonai/monailabel:latest bash</pre>
220214
</details>
221215

216+
### SAM-2
217+
218+
> By default, [**SAM2**](https://github.com/facebookresearch/sam2/) model is included for all the Apps when **_python >= 3.10_**
219+
> - **sam_2d**: for any organ or tissue and others over a given slice/2D image.
220+
> - **sam_3d**: to support SAM2 propagation over multiple slices (Radiology/MONAI-Bundle).
221+
222+
If you are using `pip install monailabel` by default it uses [SAM-2](https://huggingface.co/facebook/sam2-hiera-large) models.
223+
<br/>
224+
To use [SAM-2.1](https://huggingface.co/facebook/sam2.1-hiera-large) use one of following options.
225+
- Use monailabel [Docker](https://hub.docker.com/r/projectmonai/monailabel) instead of pip package
226+
- Run monailabel in dev mode (git checkout)
227+
- If you have installed monailabel via pip then uninstall **_sam2_** package `pip uninstall sam2` and then run `pip install -r requirements.txt` or install latest **SAM-2** from it's [github](https://github.com/facebookresearch/sam2/tree/main?tab=readme-ov-file#installation).
228+
222229
## Step 2 MONAI Label Sample Applications
223230

224231
<h3>Radiology</h3>

monailabel/config.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,18 @@
88
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
99
# See the License for the specific language governing permissions and
1010
# limitations under the License.
11-
1211
import os
12+
from importlib.util import find_spec
1313
from typing import Any, Dict, List, Optional
1414

1515
from pydantic import AnyHttpUrl
1616
from pydantic_settings import BaseSettings, SettingsConfigDict
1717

1818

19+
def is_package_installed(name):
20+
return False if find_spec(name) is None else True
21+
22+
1923
class Settings(BaseSettings):
2024
MONAI_LABEL_API_STR: str = ""
2125
MONAI_LABEL_PROJECT_NAME: str = "MONAILabel"
@@ -98,6 +102,19 @@ class Settings(BaseSettings):
98102
MONAI_ZOO_REPO: str = "Project-MONAI/model-zoo/hosting_storage_v1"
99103
MONAI_ZOO_AUTH_TOKEN: str = ""
100104

105+
# Refer: https://github.com/facebookresearch/sam2?tab=readme-ov-file#model-description
106+
# Refer: https://huggingface.co/facebook/sam2-hiera-large
107+
MONAI_SAM_MODEL_PT: str = (
108+
"https://huggingface.co/facebook/sam2.1-hiera-large/resolve/main/sam2.1_hiera_large.pt"
109+
if is_package_installed("SAM-2")
110+
else "https://huggingface.co/facebook/sam2-hiera-large/resolve/main/sam2_hiera_large.pt"
111+
)
112+
MONAI_SAM_MODEL_CFG: str = (
113+
"https://huggingface.co/facebook/sam2.1-hiera-large/resolve/main/sam2.1_hiera_l.yaml"
114+
if is_package_installed("SAM-2")
115+
else "https://huggingface.co/facebook/sam2-hiera-large/resolve/main/sam2_hiera_l.yaml"
116+
)
117+
101118
model_config = SettingsConfigDict(
102119
env_file=".env",
103120
case_sensitive=True,

monailabel/sam2/infer.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import pylab
2323
import schedule
2424
import torch
25+
from hydra import initialize_config_dir
26+
from hydra.core.global_hydra import GlobalHydra
2527
from monai.transforms import KeepLargestConnectedComponent, LoadImaged
2628
from PIL import Image
2729
from sam2.build_sam import build_sam2, build_sam2_video_predictor
@@ -114,13 +116,21 @@ def __init__(
114116
self._config.update(config)
115117

116118
# Download PreTrained Model
117-
# https://github.com/facebookresearch/sam2?tab=readme-ov-file#model-description
118-
pt = "sam2.1_hiera_large.pt"
119-
url = f"https://dl.fbaipublicfiles.com/segment_anything_2/092824/{pt}"
120-
self.path = os.path.join(model_dir, f"pretrained_{pt}")
121-
download_file(url, self.path)
119+
pt_url = settings.MONAI_SAM_MODEL_PT
120+
conf_url = settings.MONAI_SAM_MODEL_CFG
121+
sam_pt = pt_url.split("/")[-1]
122+
sam_conf = conf_url.split("/")[-1]
123+
124+
self.path = os.path.join(model_dir, sam_pt)
125+
self.config_path = os.path.join(model_dir, sam_conf)
126+
127+
GlobalHydra.instance().clear()
128+
initialize_config_dir(config_dir=model_dir)
129+
130+
download_file(pt_url, self.path)
131+
download_file(conf_url, self.config_path)
132+
self.config_path = sam_conf
122133

123-
self.config_path = "configs/sam2.1/sam2.1_hiera_l.yaml"
124134
self.predictors = {}
125135
self.image_cache = {}
126136
self.inference_state = None
@@ -393,8 +403,8 @@ def main():
393403
force=True,
394404
)
395405
396-
app_name = "pathology"
397-
app_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..", "sample-apps", app_name))
406+
app_name = "radiology"
407+
app_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sample-apps", app_name))
398408
model_dir = os.path.join(app_dir, "model")
399409
logger.info(f"Model Dir: {model_dir}")
400410
if app_name == "pathology":

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ scikit-learn
4545
scipy
4646
google-auth==2.29.0
4747
SAM-2 @ git+https://github.com/facebookresearch/sam2.git@c2ec8e14a185632b0a5d8b161928ceb50197eddc ; python_version >= '3.10'
48-
48+
#sam2>=0.4.1; python_version >= '3.10'
4949

5050
# scipy and scikit-learn latest packages are missing on python 3.8
5151
# sudo apt-get install openslide-tools -y

sample-apps/endoscopy/main.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ def __init__(self, app_dir, studies, conf):
5858
print(f" all, {', '.join(configs.keys())}")
5959
print("---------------------------------------------------------------------------------------")
6060
print("")
61-
exit(-1)
61+
# exit(-1)
6262

63-
models = models.split(",")
63+
models = models.split(",") if models else []
6464
models = [m.strip() for m in models]
6565
invalid = [m for m in models if m != "all" and not configs.get(m)]
6666
if invalid:
@@ -85,7 +85,7 @@ def __init__(self, app_dir, studies, conf):
8585

8686
logger.info(f"+++ Using Models: {list(self.models.keys())}")
8787

88-
self.sam = strtobool(conf.get("sam", "true"))
88+
self.sam = strtobool(conf.get("sam2", "true"))
8989
super().__init__(
9090
app_dir=app_dir,
9191
studies=studies,

sample-apps/monaibundle/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def __init__(self, app_dir, studies, conf):
4646
self.epistemic_simulation_size = int(conf.get("epistemic_simulation_size", "5"))
4747
self.epistemic_dropout = float(conf.get("epistemic_dropout", "0.2"))
4848

49-
self.sam = strtobool(conf.get("sam", "true"))
49+
self.sam = strtobool(conf.get("sam2", "true"))
5050
super().__init__(
5151
app_dir=app_dir,
5252
studies=studies,

sample-apps/pathology/main.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def __init__(self, app_dir, studies, conf):
5454

5555
configs = {k: v for k, v in sorted(configs.items())}
5656

57-
models = conf.get("models", "all")
57+
models = conf.get("models")
5858
if not models:
5959
print("")
6060
print("---------------------------------------------------------------------------------------")
@@ -63,9 +63,9 @@ def __init__(self, app_dir, studies, conf):
6363
print(f" all, {', '.join(configs.keys())}")
6464
print("---------------------------------------------------------------------------------------")
6565
print("")
66-
exit(-1)
66+
# exit(-1)
6767

68-
models = models.split(",")
68+
models = models.split(",") if models else []
6969
models = [m.strip() for m in models]
7070
invalid = [m for m in models if m != "all" and not configs.get(m)]
7171
if invalid:
@@ -90,7 +90,7 @@ def __init__(self, app_dir, studies, conf):
9090

9191
logger.info(f"+++ Using Models: {list(self.models.keys())}")
9292

93-
self.sam = strtobool(conf.get("sam", "true"))
93+
self.sam = strtobool(conf.get("sam2", "true"))
9494
super().__init__(
9595
app_dir=app_dir,
9696
studies=studies,

0 commit comments

Comments
 (0)