tyriaa commited on
Commit
66953ca
1 Parent(s): 5ff1fa1

Initialisation 8

Browse files
Files changed (2) hide show
  1. app.py +2 -1
  2. build_sam.py +167 -0
app.py CHANGED
@@ -4,7 +4,7 @@ import os
4
  import shutil
5
  import numpy as np
6
  from PIL import Image
7
- from sam2.build_sam import build_sam2
8
  from sam2.sam2_image_predictor import SAM2ImagePredictor
9
 
10
  class Predictor:
@@ -42,6 +42,7 @@ import subprocess
42
  import time
43
  import logging
44
  import multiprocessing
 
45
 
46
 
47
  # Initialize Flask app and SocketIO
 
4
  import shutil
5
  import numpy as np
6
  from PIL import Image
7
+ from build_sam import build_sam2
8
  from sam2.sam2_image_predictor import SAM2ImagePredictor
9
 
10
  class Predictor:
 
42
  import time
43
  import logging
44
  import multiprocessing
45
+ import json
46
 
47
 
48
  # Initialize Flask app and SocketIO
build_sam.py ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+
4
+ # This source code is licensed under the license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ import logging
8
+ import os
9
+
10
+ import torch
11
+ from hydra import compose
12
+ from hydra.utils import instantiate
13
+ from omegaconf import OmegaConf
14
+
15
+ import sam2
16
+
17
+ # Check if the user is running Python from the parent directory of the sam2 repo
18
+ # (i.e. the directory where this repo is cloned into) -- this is not supported since
19
+ # it could shadow the sam2 package and cause issues.
20
+ if os.path.isdir(os.path.join(sam2.__path__[0], "sam2")):
21
+ # If the user has "sam2/sam2" in their path, they are likey importing the repo itself
22
+ # as "sam2" rather than importing the "sam2" python package (i.e. "sam2/sam2" directory).
23
+ # This typically happens because the user is running Python from the parent directory
24
+ # that contains the sam2 repo they cloned.
25
+ raise RuntimeError(
26
+ "You're likely running Python from the parent directory of the sam2 repository "
27
+ "(i.e. the directory where https://github.com/facebookresearch/sam2 is cloned into). "
28
+ "This is not supported since the `sam2` Python package could be shadowed by the "
29
+ "repository name (the repository is also named `sam2` and contains the Python package "
30
+ "in `sam2/sam2`). Please run Python from another directory (e.g. from the repo dir "
31
+ "rather than its parent dir, or from your home directory) after installing SAM 2."
32
+ )
33
+
34
+
35
+ HF_MODEL_ID_TO_FILENAMES = {
36
+ "facebook/sam2-hiera-tiny": (
37
+ "configs/sam2/sam2_hiera_t.yaml",
38
+ "sam2_hiera_tiny.pt",
39
+ ),
40
+ "facebook/sam2-hiera-small": (
41
+ "configs/sam2/sam2_hiera_s.yaml",
42
+ "sam2_hiera_small.pt",
43
+ ),
44
+ "facebook/sam2-hiera-base-plus": (
45
+ "configs/sam2/sam2_hiera_b+.yaml",
46
+ "sam2_hiera_base_plus.pt",
47
+ ),
48
+ "facebook/sam2-hiera-large": (
49
+ "configs/sam2/sam2_hiera_l.yaml",
50
+ "sam2_hiera_large.pt",
51
+ ),
52
+ "facebook/sam2.1-hiera-tiny": (
53
+ "configs/sam2.1/sam2.1_hiera_t.yaml",
54
+ "sam2.1_hiera_tiny.pt",
55
+ ),
56
+ "facebook/sam2.1-hiera-small": (
57
+ "configs/sam2.1/sam2.1_hiera_s.yaml",
58
+ "sam2.1_hiera_small.pt",
59
+ ),
60
+ "facebook/sam2.1-hiera-base-plus": (
61
+ "configs/sam2.1/sam2.1_hiera_b+.yaml",
62
+ "sam2.1_hiera_base_plus.pt",
63
+ ),
64
+ "facebook/sam2.1-hiera-large": (
65
+ "configs/sam2.1/sam2.1_hiera_l.yaml",
66
+ "sam2.1_hiera_large.pt",
67
+ ),
68
+ }
69
+
70
+
71
+ def build_sam2(
72
+ config_file,
73
+ ckpt_path=None,
74
+ device="cuda",
75
+ mode="eval",
76
+ hydra_overrides_extra=[],
77
+ apply_postprocessing=True,
78
+ **kwargs,
79
+ ):
80
+
81
+ if apply_postprocessing:
82
+ hydra_overrides_extra = hydra_overrides_extra.copy()
83
+ hydra_overrides_extra += [
84
+ # dynamically fall back to multi-mask if the single mask is not stable
85
+ "++model.sam_mask_decoder_extra_args.dynamic_multimask_via_stability=true",
86
+ "++model.sam_mask_decoder_extra_args.dynamic_multimask_stability_delta=0.05",
87
+ "++model.sam_mask_decoder_extra_args.dynamic_multimask_stability_thresh=0.98",
88
+ ]
89
+ # Read config and init model
90
+ cfg = compose(config_name=config_file, overrides=hydra_overrides_extra)
91
+ OmegaConf.resolve(cfg)
92
+ model = instantiate(cfg.model, _recursive_=True)
93
+ _load_checkpoint(model, ckpt_path)
94
+ model = model.to(device)
95
+ if mode == "eval":
96
+ model.eval()
97
+ return model
98
+
99
+
100
+ def build_sam2_video_predictor(
101
+ config_file,
102
+ ckpt_path=None,
103
+ device="cuda",
104
+ mode="eval",
105
+ hydra_overrides_extra=[],
106
+ apply_postprocessing=True,
107
+ **kwargs,
108
+ ):
109
+ hydra_overrides = [
110
+ "++model._target_=sam2.sam2_video_predictor.SAM2VideoPredictor",
111
+ ]
112
+ if apply_postprocessing:
113
+ hydra_overrides_extra = hydra_overrides_extra.copy()
114
+ hydra_overrides_extra += [
115
+ # dynamically fall back to multi-mask if the single mask is not stable
116
+ "++model.sam_mask_decoder_extra_args.dynamic_multimask_via_stability=true",
117
+ "++model.sam_mask_decoder_extra_args.dynamic_multimask_stability_delta=0.05",
118
+ "++model.sam_mask_decoder_extra_args.dynamic_multimask_stability_thresh=0.98",
119
+ # the sigmoid mask logits on interacted frames with clicks in the memory encoder so that the encoded masks are exactly as what users see from clicking
120
+ "++model.binarize_mask_from_pts_for_mem_enc=true",
121
+ # fill small holes in the low-res masks up to `fill_hole_area` (before resizing them to the original video resolution)
122
+ "++model.fill_hole_area=8",
123
+ ]
124
+ hydra_overrides.extend(hydra_overrides_extra)
125
+
126
+ # Read config and init model
127
+ cfg = compose(config_name=config_file, overrides=hydra_overrides)
128
+ OmegaConf.resolve(cfg)
129
+ model = instantiate(cfg.model, _recursive_=True)
130
+ _load_checkpoint(model, ckpt_path)
131
+ model = model.to(device)
132
+ if mode == "eval":
133
+ model.eval()
134
+ return model
135
+
136
+
137
+ def _hf_download(model_id):
138
+ from huggingface_hub import hf_hub_download
139
+
140
+ config_name, checkpoint_name = HF_MODEL_ID_TO_FILENAMES[model_id]
141
+ ckpt_path = hf_hub_download(repo_id=model_id, filename=checkpoint_name)
142
+ return config_name, ckpt_path
143
+
144
+
145
+ def build_sam2_hf(model_id, **kwargs):
146
+ config_name, ckpt_path = _hf_download(model_id)
147
+ return build_sam2(config_file=config_name, ckpt_path=ckpt_path, **kwargs)
148
+
149
+
150
+ def build_sam2_video_predictor_hf(model_id, **kwargs):
151
+ config_name, ckpt_path = _hf_download(model_id)
152
+ return build_sam2_video_predictor(
153
+ config_file=config_name, ckpt_path=ckpt_path, **kwargs
154
+ )
155
+
156
+
157
+ def _load_checkpoint(model, ckpt_path):
158
+ if ckpt_path is not None:
159
+ sd = torch.load(ckpt_path, map_location="cpu", weights_only=True)["model"]
160
+ missing_keys, unexpected_keys = model.load_state_dict(sd)
161
+ if missing_keys:
162
+ logging.error(missing_keys)
163
+ raise RuntimeError()
164
+ if unexpected_keys:
165
+ logging.error(unexpected_keys)
166
+ raise RuntimeError()
167
+ logging.info("Loaded checkpoint sucessfully")