Spaces:
Sleeping
Sleeping
Update requirements.txt
Browse files- app.py +167 -55
- requirements.txt +3 -2
app.py
CHANGED
@@ -8,8 +8,18 @@ import os
|
|
8 |
import subprocess
|
9 |
import sys
|
10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
# Imports Hugging Face
|
12 |
from huggingface_hub import hf_hub_download, login
|
|
|
13 |
|
14 |
# Imports locaux
|
15 |
from modeling.BaseModel import BaseModel
|
@@ -21,75 +31,174 @@ from inference_utils.inference import interactive_infer_image
|
|
21 |
from inference_utils.output_processing import check_mask_stats
|
22 |
from inference_utils.processing_utils import read_rgb, get_instances
|
23 |
|
24 |
-
|
25 |
def init_huggingface():
|
26 |
-
"""
|
27 |
hf_token = os.getenv('HF_TOKEN')
|
28 |
if hf_token is None:
|
29 |
raise ValueError("Hugging Face token not found. Please set the HF_TOKEN environment variable.")
|
30 |
login(hf_token)
|
31 |
-
|
32 |
-
|
33 |
-
'libopenmpi-dev'
|
34 |
-
]
|
35 |
-
command = ['sudo', 'apt-get', 'install', '-y'] + packages
|
36 |
-
subprocess.run(
|
37 |
-
command,
|
38 |
-
check=True,
|
39 |
-
stdout=subprocess.PIPE,
|
40 |
-
stderr=subprocess.PIPE,
|
41 |
-
text=True
|
42 |
-
)
|
43 |
-
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'mpi4py'])
|
44 |
-
return hf_hub_download(
|
45 |
repo_id="microsoft/BiomedParse",
|
46 |
filename="biomedparse_v1.pt",
|
47 |
local_dir="pretrained"
|
48 |
)
|
|
|
49 |
|
50 |
-
def
|
51 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
opt = init_distributed(opt)
|
54 |
-
|
55 |
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
)
|
61 |
-
return model
|
62 |
-
|
63 |
-
def process_image(image, prompts, model):
|
64 |
-
"""Traite l'image avec les prompts donnés."""
|
65 |
-
if isinstance(image, str):
|
66 |
-
image = Image.open(image)
|
67 |
-
else:
|
68 |
-
image = Image.fromarray(image)
|
69 |
|
70 |
-
|
|
|
71 |
|
72 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
|
74 |
-
|
75 |
-
|
76 |
-
plt.imshow(image)
|
77 |
-
plt.title('Image originale')
|
78 |
-
plt.axis('off')
|
79 |
-
|
80 |
-
for i, mask in enumerate(pred_masks):
|
81 |
-
plt.subplot(1, len(pred_masks) + 1, i+2)
|
82 |
-
plt.imshow(image)
|
83 |
-
plt.imshow(mask, alpha=0.5, cmap='Reds')
|
84 |
-
plt.title(prompts[i])
|
85 |
-
plt.axis('off')
|
86 |
|
87 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
|
89 |
def setup_gradio_interface(model):
|
90 |
"""Configure l'interface Gradio."""
|
91 |
return gr.Interface(
|
92 |
-
theme=gr.Theme.from_hub("allenai/gradio-theme"),
|
93 |
fn=lambda img, txt: process_image(img, txt, model),
|
94 |
inputs=[
|
95 |
gr.Image(type="numpy", label="Image médicale"),
|
@@ -104,7 +213,6 @@ def setup_gradio_interface(model):
|
|
104 |
description="Chargez une image médicale et spécifiez les éléments à segmenter",
|
105 |
examples=[
|
106 |
["examples/144DME_as_F.jpeg", "Dans cette image donne moi l'œdème"],
|
107 |
-
["examples/ISIC_0015551.jpg", "Cherche une lésion"],
|
108 |
["examples/T0011.jpg", "disque optique, cupule optique"],
|
109 |
["examples/C3_EndoCV2021_00462.jpg", "Trouve moi le polyp"],
|
110 |
["examples/covid_1585.png", "Qu'est ce qui ne va pas ici ?"],
|
@@ -113,11 +221,15 @@ def setup_gradio_interface(model):
|
|
113 |
)
|
114 |
|
115 |
def main():
|
116 |
-
"""
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
|
|
|
|
|
|
|
|
121 |
|
122 |
if __name__ == "__main__":
|
123 |
-
main()
|
|
|
8 |
import subprocess
|
9 |
import sys
|
10 |
|
11 |
+
# Installation des dépendances nécessaires
|
12 |
+
subprocess.run(['apt-get', 'update'], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
13 |
+
packages = ['openmpi-bin', 'libopenmpi-dev']
|
14 |
+
command = ['apt-get', 'install', '-y'] + packages
|
15 |
+
subprocess.run(command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
16 |
+
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'mpi4py'])
|
17 |
+
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'pydicom'])
|
18 |
+
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'SimpleITK'])
|
19 |
+
|
20 |
# Imports Hugging Face
|
21 |
from huggingface_hub import hf_hub_download, login
|
22 |
+
import spaces
|
23 |
|
24 |
# Imports locaux
|
25 |
from modeling.BaseModel import BaseModel
|
|
|
31 |
from inference_utils.output_processing import check_mask_stats
|
32 |
from inference_utils.processing_utils import read_rgb, get_instances
|
33 |
|
|
|
34 |
def init_huggingface():
|
35 |
+
"""Initialize Hugging Face connection and download the model."""
|
36 |
hf_token = os.getenv('HF_TOKEN')
|
37 |
if hf_token is None:
|
38 |
raise ValueError("Hugging Face token not found. Please set the HF_TOKEN environment variable.")
|
39 |
login(hf_token)
|
40 |
+
|
41 |
+
pretrained_path = hf_hub_download(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
repo_id="microsoft/BiomedParse",
|
43 |
filename="biomedparse_v1.pt",
|
44 |
local_dir="pretrained"
|
45 |
)
|
46 |
+
return pretrained_path
|
47 |
|
48 |
+
def apply_distributed(opt):
|
49 |
+
"""Applique les paramètres distribués pour le mode multi-processus."""
|
50 |
+
print(f"Configuration distribuée appliquée : {opt}")
|
51 |
+
|
52 |
+
def init_distributed(opt):
|
53 |
+
"""Initialize distributed mode without premature CUDA initialization."""
|
54 |
+
opt['CUDA'] = opt.get('CUDA', True) and torch.cuda.is_available()
|
55 |
+
if 'OMPI_COMM_WORLD_SIZE' not in os.environ:
|
56 |
+
# Application started without MPI
|
57 |
+
opt['env_info'] = 'no MPI'
|
58 |
+
opt['world_size'] = 1
|
59 |
+
opt['local_size'] = 1
|
60 |
+
opt['rank'] = 0
|
61 |
+
opt['local_rank'] = 0 # Ensure this is set to 0
|
62 |
+
opt['master_address'] = '127.0.0.1'
|
63 |
+
opt['master_port'] = '8673'
|
64 |
+
else:
|
65 |
+
# Application started with MPI
|
66 |
+
opt['world_size'] = int(os.environ['OMPI_COMM_WORLD_SIZE'])
|
67 |
+
opt['local_size'] = int(os.environ['OMPI_COMM_WORLD_LOCAL_SIZE'])
|
68 |
+
opt['rank'] = int(os.environ['OMPI_COMM_WORLD_RANK'])
|
69 |
+
opt['local_rank'] = int(os.environ['OMPI_COMM_WORLD_LOCAL_RANK'])
|
70 |
|
71 |
+
if not opt['CUDA']:
|
72 |
+
assert opt['world_size'] == 1, 'Multi-GPU training without CUDA is not supported since we use NCCL as communication backend'
|
73 |
+
opt['device'] = torch.device("cpu")
|
74 |
+
else:
|
75 |
+
opt['device'] = torch.device("cuda", opt['local_rank']) # Ensure local_rank is integer
|
76 |
+
|
77 |
+
apply_distributed(opt)
|
78 |
+
return opt
|
79 |
+
|
80 |
+
def setup_model():
|
81 |
+
"""Initialize the model on CPU without CUDA initialization."""
|
82 |
+
opt = load_opt_from_config_files(["configs/biomedparse_inference.yaml"])
|
83 |
opt = init_distributed(opt)
|
84 |
+
opt['device'] = 'cpu'
|
85 |
|
86 |
+
pretrained_path = init_huggingface()
|
87 |
+
model = BaseModel(opt, build_model(opt))
|
88 |
+
state_dict = torch.load(pretrained_path, map_location='cpu', weights_only=True)
|
89 |
+
model.load_state_dict(state_dict, strict=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
|
91 |
+
# Initialize train_class_names
|
92 |
+
model.train_class_names = BIOMED_CLASSES + ["background"]
|
93 |
|
94 |
+
return model.eval()
|
95 |
+
|
96 |
+
import numpy as np
|
97 |
+
from PIL import Image
|
98 |
+
|
99 |
+
def preprocess_image(image):
|
100 |
+
"""Preprocess image for SEEM model input."""
|
101 |
+
if isinstance(image, Image.Image):
|
102 |
+
# Convert PIL Image to numpy array
|
103 |
+
image = np.array(image)
|
104 |
|
105 |
+
# Ensure image is float32 and normalized
|
106 |
+
image = image.astype(np.float32) / 255.0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
|
108 |
+
# Ensure correct dimensions (B, C, H, W)
|
109 |
+
if len(image.shape) == 3:
|
110 |
+
image = np.transpose(image, (2, 0, 1)) # HWC -> CHW
|
111 |
+
image = np.expand_dims(image, axis=0) # Add batch dimension
|
112 |
+
|
113 |
+
return image
|
114 |
+
|
115 |
+
@spaces.GPU
|
116 |
+
def predict_image(model, image, prompts):
|
117 |
+
"""Process image prediction with proper formatting."""
|
118 |
+
try:
|
119 |
+
# Convert PIL Image to numpy array if needed
|
120 |
+
if isinstance(image, Image.Image):
|
121 |
+
image = np.array(image)
|
122 |
+
|
123 |
+
# Ensure image is in float32 and normalized
|
124 |
+
image = image.astype(np.float32) / 255.0
|
125 |
+
|
126 |
+
# Transpose from HWC to CHW format
|
127 |
+
if len(image.shape) == 3:
|
128 |
+
image = np.transpose(image, (2, 0, 1))
|
129 |
+
|
130 |
+
# Add batch dimension if needed
|
131 |
+
if len(image.shape) == 3:
|
132 |
+
image = np.expand_dims(image, axis=0)
|
133 |
+
|
134 |
+
# Convert to tensor
|
135 |
+
image_tensor = torch.from_numpy(image)
|
136 |
+
|
137 |
+
# Move to GPU if available
|
138 |
+
if torch.cuda.is_available():
|
139 |
+
device = torch.device("cuda", 0)
|
140 |
+
model = model.to(device)
|
141 |
+
image_tensor = image_tensor.to(device)
|
142 |
+
else:
|
143 |
+
device = torch.device("cpu")
|
144 |
+
|
145 |
+
# Create batched input
|
146 |
+
batched_inputs = [{
|
147 |
+
"image": image_tensor,
|
148 |
+
"prompt": prompts,
|
149 |
+
"height": image_tensor.shape[-2],
|
150 |
+
"width": image_tensor.shape[-1]
|
151 |
+
}]
|
152 |
+
|
153 |
+
with torch.no_grad():
|
154 |
+
pred_masks = model(batched_inputs)
|
155 |
+
|
156 |
+
# Move back to CPU if needed
|
157 |
+
if device.type == "cuda":
|
158 |
+
model = model.to("cpu")
|
159 |
+
pred_masks = [mask.cpu() for mask in pred_masks]
|
160 |
+
|
161 |
+
return pred_masks
|
162 |
+
|
163 |
+
except Exception as e:
|
164 |
+
print(f"Error processing image: {str(e)}")
|
165 |
+
raise
|
166 |
+
|
167 |
+
def process_image(image, text, model):
|
168 |
+
"""Process image with proper error handling."""
|
169 |
+
try:
|
170 |
+
prompts = [p.strip() for p in text.split(',') if p.strip()]
|
171 |
+
if not prompts:
|
172 |
+
raise ValueError("No valid prompts provided")
|
173 |
+
|
174 |
+
pred_masks = predict_image(model, image, prompts)
|
175 |
+
|
176 |
+
# Create visualization
|
177 |
+
fig = plt.figure(figsize=(5 * (len(pred_masks) + 1), 5))
|
178 |
+
|
179 |
+
# Show original image
|
180 |
+
plt.subplot(1, len(pred_masks) + 1, 1)
|
181 |
+
plt.imshow(preprocess_image(image))
|
182 |
+
plt.title("Original")
|
183 |
+
plt.axis('off')
|
184 |
+
|
185 |
+
# Show predictions
|
186 |
+
for i, mask in enumerate(pred_masks):
|
187 |
+
plt.subplot(1, len(pred_masks) + 1, i+2)
|
188 |
+
plt.imshow(preprocess_image(image))
|
189 |
+
plt.imshow(mask.cpu().numpy(), alpha=0.5, cmap='Reds')
|
190 |
+
plt.title(prompts[i])
|
191 |
+
plt.axis('off')
|
192 |
+
|
193 |
+
return fig
|
194 |
+
|
195 |
+
except Exception as e:
|
196 |
+
print(f"Error in process_image: {str(e)}")
|
197 |
+
raise
|
198 |
|
199 |
def setup_gradio_interface(model):
|
200 |
"""Configure l'interface Gradio."""
|
201 |
return gr.Interface(
|
|
|
202 |
fn=lambda img, txt: process_image(img, txt, model),
|
203 |
inputs=[
|
204 |
gr.Image(type="numpy", label="Image médicale"),
|
|
|
213 |
description="Chargez une image médicale et spécifiez les éléments à segmenter",
|
214 |
examples=[
|
215 |
["examples/144DME_as_F.jpeg", "Dans cette image donne moi l'œdème"],
|
|
|
216 |
["examples/T0011.jpg", "disque optique, cupule optique"],
|
217 |
["examples/C3_EndoCV2021_00462.jpg", "Trouve moi le polyp"],
|
218 |
["examples/covid_1585.png", "Qu'est ce qui ne va pas ici ?"],
|
|
|
221 |
)
|
222 |
|
223 |
def main():
|
224 |
+
"""Entry point avoiding CUDA initialization in main process."""
|
225 |
+
try:
|
226 |
+
init_huggingface()
|
227 |
+
model = setup_model() # Load on CPU
|
228 |
+
interface = setup_gradio_interface(model)
|
229 |
+
interface.launch(debug=True)
|
230 |
+
except Exception as e:
|
231 |
+
print(f"Error during initialization: {str(e)}")
|
232 |
+
raise
|
233 |
|
234 |
if __name__ == "__main__":
|
235 |
+
main()
|
requirements.txt
CHANGED
@@ -14,7 +14,7 @@ sentencepiece==0.1.99
|
|
14 |
ftfy==6.1.1
|
15 |
regex==2023.10.3
|
16 |
nltk==3.8.1
|
17 |
-
mpi4py
|
18 |
vision-datasets==0.2.2
|
19 |
cython==3.0.2
|
20 |
pycocotools==2.0.7
|
@@ -30,7 +30,8 @@ deepspeed==0.10.3
|
|
30 |
#wandb==0.15.12
|
31 |
infinibatch==0.1.1
|
32 |
open-clip-torch==2.26.1
|
33 |
-
|
|
|
34 |
gradio
|
35 |
#torch==2.3.1 #2.0.1
|
36 |
#torchvision==0.15.2
|
|
|
14 |
ftfy==6.1.1
|
15 |
regex==2023.10.3
|
16 |
nltk==3.8.1
|
17 |
+
#mpi4py
|
18 |
vision-datasets==0.2.2
|
19 |
cython==3.0.2
|
20 |
pycocotools==2.0.7
|
|
|
30 |
#wandb==0.15.12
|
31 |
infinibatch==0.1.1
|
32 |
open-clip-torch==2.26.1
|
33 |
+
nibabel==5.1.0
|
34 |
+
git+https://github.com/facebookresearch/detectron2
|
35 |
gradio
|
36 |
#torch==2.3.1 #2.0.1
|
37 |
#torchvision==0.15.2
|