patchworks 1.4.3__tar.gz → 1.4.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. {patchworks-1.4.3 → patchworks-1.4.4}/PKG-INFO +1 -1
  2. {patchworks-1.4.3 → patchworks-1.4.4}/src/patchworks/plugins/cellpose.py +81 -2
  3. {patchworks-1.4.3 → patchworks-1.4.4}/.github/workflows/docs.yml +0 -0
  4. {patchworks-1.4.3 → patchworks-1.4.4}/.github/workflows/lint.yml +0 -0
  5. {patchworks-1.4.3 → patchworks-1.4.4}/.github/workflows/release.yml +0 -0
  6. {patchworks-1.4.3 → patchworks-1.4.4}/.gitignore +0 -0
  7. {patchworks-1.4.3 → patchworks-1.4.4}/.markdownlint-cli2.yaml +0 -0
  8. {patchworks-1.4.3 → patchworks-1.4.4}/LICENSE +0 -0
  9. {patchworks-1.4.3 → patchworks-1.4.4}/README.md +0 -0
  10. {patchworks-1.4.3 → patchworks-1.4.4}/cliff.toml +0 -0
  11. {patchworks-1.4.3 → patchworks-1.4.4}/docs/api/chunks.md +0 -0
  12. {patchworks-1.4.3 → patchworks-1.4.4}/docs/api/cluster.md +0 -0
  13. {patchworks-1.4.3 → patchworks-1.4.4}/docs/api/io.md +0 -0
  14. {patchworks-1.4.3 → patchworks-1.4.4}/docs/api/merge_tile_labels.md +0 -0
  15. {patchworks-1.4.3 → patchworks-1.4.4}/docs/api/plugins/cellpose.md +0 -0
  16. {patchworks-1.4.3 → patchworks-1.4.4}/docs/api/plugins/dog.md +0 -0
  17. {patchworks-1.4.3 → patchworks-1.4.4}/docs/api/plugins/napari.md +0 -0
  18. {patchworks-1.4.3 → patchworks-1.4.4}/docs/api/plugins/ome_zarr.md +0 -0
  19. {patchworks-1.4.3 → patchworks-1.4.4}/docs/api/postprocess.md +0 -0
  20. {patchworks-1.4.3 → patchworks-1.4.4}/docs/api/relabel.md +0 -0
  21. {patchworks-1.4.3 → patchworks-1.4.4}/docs/api/tile_process.md +0 -0
  22. {patchworks-1.4.3 → patchworks-1.4.4}/docs/assets/logo.png +0 -0
  23. {patchworks-1.4.3 → patchworks-1.4.4}/docs/examples/cellpose_2d.md +0 -0
  24. {patchworks-1.4.3 → patchworks-1.4.4}/docs/examples/cellpose_2d.py +0 -0
  25. {patchworks-1.4.3 → patchworks-1.4.4}/docs/examples/cellpose_3d.md +0 -0
  26. {patchworks-1.4.3 → patchworks-1.4.4}/docs/examples/cellpose_3d.py +0 -0
  27. {patchworks-1.4.3 → patchworks-1.4.4}/docs/examples/custom.md +0 -0
  28. {patchworks-1.4.3 → patchworks-1.4.4}/docs/examples/custom_method.py +0 -0
  29. {patchworks-1.4.3 → patchworks-1.4.4}/docs/examples/dog.md +0 -0
  30. {patchworks-1.4.3 → patchworks-1.4.4}/docs/examples/dog.py +0 -0
  31. {patchworks-1.4.3 → patchworks-1.4.4}/docs/examples/standalone_merge.md +0 -0
  32. {patchworks-1.4.3 → patchworks-1.4.4}/docs/examples/stardist.md +0 -0
  33. {patchworks-1.4.3 → patchworks-1.4.4}/docs/examples/stardist_2d.py +0 -0
  34. {patchworks-1.4.3 → patchworks-1.4.4}/docs/getting_started.md +0 -0
  35. {patchworks-1.4.3 → patchworks-1.4.4}/docs/guide/custom_segmentation.md +0 -0
  36. {patchworks-1.4.3 → patchworks-1.4.4}/docs/guide/gpu_distributed.md +0 -0
  37. {patchworks-1.4.3 → patchworks-1.4.4}/docs/guide/label_relations.md +0 -0
  38. {patchworks-1.4.3 → patchworks-1.4.4}/docs/guide/measurements.md +0 -0
  39. {patchworks-1.4.3 → patchworks-1.4.4}/docs/guide/merging.md +0 -0
  40. {patchworks-1.4.3 → patchworks-1.4.4}/docs/guide/ome_zarr_napari.md +0 -0
  41. {patchworks-1.4.3 → patchworks-1.4.4}/docs/guide/performance.md +0 -0
  42. {patchworks-1.4.3 → patchworks-1.4.4}/docs/guide/pitfalls.md +0 -0
  43. {patchworks-1.4.3 → patchworks-1.4.4}/docs/guide/skip_empty.md +0 -0
  44. {patchworks-1.4.3 → patchworks-1.4.4}/docs/guide/snakemake.md +0 -0
  45. {patchworks-1.4.3 → patchworks-1.4.4}/docs/guide/tiling.md +0 -0
  46. {patchworks-1.4.3 → patchworks-1.4.4}/docs/index.md +0 -0
  47. {patchworks-1.4.3 → patchworks-1.4.4}/mkdocs.yml +0 -0
  48. {patchworks-1.4.3 → patchworks-1.4.4}/pyproject.toml +0 -0
  49. {patchworks-1.4.3 → patchworks-1.4.4}/src/patchworks/__init__.py +0 -0
  50. {patchworks-1.4.3 → patchworks-1.4.4}/src/patchworks/_chunks.py +0 -0
  51. {patchworks-1.4.3 → patchworks-1.4.4}/src/patchworks/_cluster.py +0 -0
  52. {patchworks-1.4.3 → patchworks-1.4.4}/src/patchworks/_core.py +0 -0
  53. {patchworks-1.4.3 → patchworks-1.4.4}/src/patchworks/_distributed.py +0 -0
  54. {patchworks-1.4.3 → patchworks-1.4.4}/src/patchworks/_io.py +0 -0
  55. {patchworks-1.4.3 → patchworks-1.4.4}/src/patchworks/_merge.py +0 -0
  56. {patchworks-1.4.3 → patchworks-1.4.4}/src/patchworks/_postprocess.py +0 -0
  57. {patchworks-1.4.3 → patchworks-1.4.4}/src/patchworks/_relabel.py +0 -0
  58. {patchworks-1.4.3 → patchworks-1.4.4}/src/patchworks/_relations.py +0 -0
  59. {patchworks-1.4.3 → patchworks-1.4.4}/src/patchworks/plugins/__init__.py +0 -0
  60. {patchworks-1.4.3 → patchworks-1.4.4}/src/patchworks/plugins/dog.py +0 -0
  61. {patchworks-1.4.3 → patchworks-1.4.4}/src/patchworks/plugins/napari.py +0 -0
  62. {patchworks-1.4.3 → patchworks-1.4.4}/src/patchworks/plugins/ome_zarr.py +0 -0
  63. {patchworks-1.4.3 → patchworks-1.4.4}/tests/test_core.py +0 -0
  64. {patchworks-1.4.3 → patchworks-1.4.4}/tests/test_distributed.py +0 -0
  65. {patchworks-1.4.3 → patchworks-1.4.4}/tests/test_dog.py +0 -0
  66. {patchworks-1.4.3 → patchworks-1.4.4}/tests/test_napari.py +0 -0
  67. {patchworks-1.4.3 → patchworks-1.4.4}/tests/test_ome_zarr.py +0 -0
  68. {patchworks-1.4.3 → patchworks-1.4.4}/tests/test_postprocess.py +0 -0
  69. {patchworks-1.4.3 → patchworks-1.4.4}/tests/test_relations.py +0 -0
  70. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/README.md +0 -0
  71. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/Snakefile +0 -0
  72. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/config/config.yaml +0 -0
  73. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/config/config_cilia.yaml +0 -0
  74. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/config/config_cyto.yaml +0 -0
  75. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/config/config_nuclei.yaml +0 -0
  76. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/config/multi.yaml +0 -0
  77. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/pixi.toml +0 -0
  78. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/profile/slurm/config.yaml +0 -0
  79. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/rules/common.smk +0 -0
  80. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/rules/convert.smk +0 -0
  81. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/rules/merge.smk +0 -0
  82. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/rules/segment.smk +0 -0
  83. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/scripts/_pw.py +0 -0
  84. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/scripts/convert.py +0 -0
  85. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/scripts/fetch_model.py +0 -0
  86. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/scripts/merge.py +0 -0
  87. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/scripts/prepare_tiles.py +0 -0
  88. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/scripts/run_multi.py +0 -0
  89. {patchworks-1.4.3 → patchworks-1.4.4}/workflow/scripts/segment_tile.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: patchworks
3
- Version: 1.4.3
3
+ Version: 1.4.4
4
4
  Summary: Tiled processing of arbitrarily large images with globally consistent labels
5
5
  Project-URL: Homepage, https://github.com/imcf/patchworks
6
6
  Project-URL: Issues, https://github.com/imcf/patchworks/issues
@@ -196,6 +196,82 @@ def _get_model(cellpose_dict: dict[str, Any]) -> Any:
196
196
  return _model_cache[key]
197
197
 
198
198
 
199
+ def _is_cuda_oom(exc: Exception) -> bool:
200
+ """Return whether *exc* looks like a CUDA out-of-memory error.
201
+
202
+ Parameters
203
+ ----------
204
+ exc : Exception
205
+ Exception raised by ``model.eval``.
206
+
207
+ Returns
208
+ -------
209
+ bool
210
+ True if the exception is a CUDA OOM.
211
+ """
212
+ return "out of memory" in str(exc).lower()
213
+
214
+
215
+ _OOM_RETRIES = 4
216
+ _OOM_BACKOFF_SECONDS = 30
217
+
218
+
219
+ def _eval_with_oom_fallback(
220
+ model: Any, img: np.ndarray, kwargs: dict[str, Any], cellpose_dict: dict[str, Any]
221
+ ) -> np.ndarray:
222
+ """Run ``model.eval``, surviving transient GPU contention.
223
+
224
+ Cluster GPUs are often shared: another job's memory footprint can grow
225
+ mid-run and push an otherwise-fine tile size over the edge. Staying on
226
+ GPU matters — this tile can take well over an hour, so falling back to
227
+ CPU would be far worse than waiting. Instead this clears the allocator
228
+ cache (fixes fragmentation) and retries with a backoff, giving the
229
+ cotenant job time to free memory, before finally giving up.
230
+
231
+ Parameters
232
+ ----------
233
+ model : Any
234
+ Cellpose model instance.
235
+ img : np.ndarray
236
+ Image to segment.
237
+ kwargs : dict
238
+ Keyword arguments for ``model.eval``.
239
+ cellpose_dict : dict
240
+ Configuration from :func:`_make_config`.
241
+
242
+ Returns
243
+ -------
244
+ np.ndarray
245
+ Label array from ``model.eval``.
246
+ """
247
+ import time
248
+
249
+ for attempt in range(_OOM_RETRIES + 1):
250
+ try:
251
+ return model.eval(img, **kwargs)[0]
252
+ except RuntimeError as exc:
253
+ if not cellpose_dict.get("gpu", False) or not _is_cuda_oom(exc):
254
+ raise
255
+ import torch
256
+
257
+ torch.cuda.empty_cache()
258
+ if attempt == _OOM_RETRIES:
259
+ logger.error(
260
+ "CUDA OOM persisted after %d retries; giving up on tile.",
261
+ _OOM_RETRIES,
262
+ )
263
+ raise
264
+ wait = _OOM_BACKOFF_SECONDS * (attempt + 1)
265
+ logger.warning(
266
+ "CUDA OOM on tile (likely GPU contention); cleared cache, "
267
+ "retrying in %ds (attempt %d/%d).",
268
+ wait,
269
+ attempt + 1,
270
+ _OOM_RETRIES,
271
+ )
272
+ time.sleep(wait)
273
+
274
+
199
275
  def _run(block: np.ndarray, cellpose_dict: dict[str, Any]) -> np.ndarray:
200
276
  """Segment one tile with a cached Cellpose model.
201
277
 
@@ -231,12 +307,15 @@ def _run(block: np.ndarray, cellpose_dict: dict[str, Any]) -> np.ndarray:
231
307
 
232
308
  if do_3D:
233
309
  kwargs["z_axis"] = 0
234
- return model.eval(block, **kwargs)[0].astype("int32")
310
+ masks = _eval_with_oom_fallback(model, block, kwargs, cellpose_dict)
311
+ return masks.astype("int32")
235
312
  else:
236
313
  # Squeeze singleton z so Cellpose gets a clean 2-D image
237
314
  squeeze = block.ndim == 3 and block.shape[0] == 1
238
315
  img = block[0] if squeeze else block
239
- masks = model.eval(img, **kwargs)[0].astype("int32")
316
+ masks = _eval_with_oom_fallback(model, img, kwargs, cellpose_dict).astype(
317
+ "int32"
318
+ )
240
319
  return masks[np.newaxis] if squeeze else masks
241
320
 
242
321
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes