Spaces:
Running on Zero
Running on Zero
Upload app.py
Browse filesFixed both in to_upload\app.py:
duration=30 instead of 120
The GPU section is now timed separately, so the results box reports:
Segmentation time: 7.02 s (GPU 2.14 s, queue+CPU 4.88 s)
That split tells you what you actually need to know. If GPU is ~2 s and queue+CPU is ~5 s, the compute is fine and you're waiting for hardware. If GPU is ~6 s, the model itself is the cost.
app.py
CHANGED
|
@@ -572,7 +572,7 @@ def _segment_patch(args):
|
|
| 572 |
return mask, row_start, col_start
|
| 573 |
|
| 574 |
|
| 575 |
-
@spaces.GPU(duration=
|
| 576 |
def run_segmentation_patched(image_np, model_filename):
|
| 577 |
"""
|
| 578 |
Split image into overlapping patches, run Cellpose on each in parallel,
|
|
@@ -586,6 +586,7 @@ def run_segmentation_patched(image_np, model_filename):
|
|
| 586 |
Falls back to whole-image segmentation if the image is small enough
|
| 587 |
that patching adds overhead without benefit.
|
| 588 |
"""
|
|
|
|
| 589 |
h, w = image_np.shape[:2]
|
| 590 |
model_path = hf_hub_download(repo_id=HF_REPO_ID, filename=model_filename)
|
| 591 |
if model_filename in loaded_models:
|
|
@@ -597,7 +598,7 @@ def run_segmentation_patched(image_np, model_filename):
|
|
| 597 |
# Small images: no benefit from patching
|
| 598 |
if max(h, w) <= MIN_PATCH_DIM * 2:
|
| 599 |
mask, _, _ = model.eval(image_np, diameter=None, channels=[0, 0])
|
| 600 |
-
return mask, 1
|
| 601 |
|
| 602 |
patches = _split_patches(image_np)
|
| 603 |
n_patches = len(patches)
|
|
@@ -621,7 +622,7 @@ def run_segmentation_patched(image_np, model_filename):
|
|
| 621 |
patch_results.sort(key=lambda x: (x[1], x[2]))
|
| 622 |
|
| 623 |
full_mask = _merge_patch_masks(patch_results, h, w)
|
| 624 |
-
return full_mask, n_patches
|
| 625 |
|
| 626 |
|
| 627 |
def render_segmentation(base_masks, processed_image_np,
|
|
@@ -701,7 +702,8 @@ def run_segmentation(image, model_choice, min_cell_size, max_cell_size,
|
|
| 701 |
processed_image_np = image_np
|
| 702 |
|
| 703 |
# Run patch-parallel Cellpose segmentation
|
| 704 |
-
masks_raw, n_patches = run_segmentation_patched(
|
|
|
|
| 705 |
|
| 706 |
# Same single pass feeds the log line and the recommendation below;
|
| 707 |
# this used to be computed from scratch twice.
|
|
@@ -783,7 +785,10 @@ def run_segmentation(image, model_choice, min_cell_size, max_cell_size,
|
|
| 783 |
info_msg += "Now run the viability classification model for viability assessment."
|
| 784 |
|
| 785 |
seg_seconds = time.perf_counter() - _t_start
|
| 786 |
-
|
|
|
|
|
|
|
|
|
|
| 787 |
|
| 788 |
return (
|
| 789 |
cell_count,
|
|
|
|
| 572 |
return mask, row_start, col_start
|
| 573 |
|
| 574 |
|
| 575 |
+
@spaces.GPU(duration=30)
|
| 576 |
def run_segmentation_patched(image_np, model_filename):
|
| 577 |
"""
|
| 578 |
Split image into overlapping patches, run Cellpose on each in parallel,
|
|
|
|
| 586 |
Falls back to whole-image segmentation if the image is small enough
|
| 587 |
that patching adds overhead without benefit.
|
| 588 |
"""
|
| 589 |
+
_t_gpu = time.perf_counter()
|
| 590 |
h, w = image_np.shape[:2]
|
| 591 |
model_path = hf_hub_download(repo_id=HF_REPO_ID, filename=model_filename)
|
| 592 |
if model_filename in loaded_models:
|
|
|
|
| 598 |
# Small images: no benefit from patching
|
| 599 |
if max(h, w) <= MIN_PATCH_DIM * 2:
|
| 600 |
mask, _, _ = model.eval(image_np, diameter=None, channels=[0, 0])
|
| 601 |
+
return mask, 1, time.perf_counter() - _t_gpu
|
| 602 |
|
| 603 |
patches = _split_patches(image_np)
|
| 604 |
n_patches = len(patches)
|
|
|
|
| 622 |
patch_results.sort(key=lambda x: (x[1], x[2]))
|
| 623 |
|
| 624 |
full_mask = _merge_patch_masks(patch_results, h, w)
|
| 625 |
+
return full_mask, n_patches, time.perf_counter() - _t_gpu
|
| 626 |
|
| 627 |
|
| 628 |
def render_segmentation(base_masks, processed_image_np,
|
|
|
|
| 702 |
processed_image_np = image_np
|
| 703 |
|
| 704 |
# Run patch-parallel Cellpose segmentation
|
| 705 |
+
masks_raw, n_patches, gpu_seconds = run_segmentation_patched(
|
| 706 |
+
processed_image_np, model_filename)
|
| 707 |
|
| 708 |
# Same single pass feeds the log line and the recommendation below;
|
| 709 |
# this used to be computed from scratch twice.
|
|
|
|
| 785 |
info_msg += "Now run the viability classification model for viability assessment."
|
| 786 |
|
| 787 |
seg_seconds = time.perf_counter() - _t_start
|
| 788 |
+
other = max(0.0, seg_seconds - gpu_seconds)
|
| 789 |
+
info_msg = (f"Segmentation time: {seg_seconds:.2f} s "
|
| 790 |
+
f"(GPU {gpu_seconds:.2f} s, queue+CPU {other:.2f} s)\n"
|
| 791 |
+
+ info_msg)
|
| 792 |
|
| 793 |
return (
|
| 794 |
cell_count,
|