|
1 | | -"""Snakemake script: segment ONE tile and write it to the shared stage. |
| 1 | +"""Snakemake script: segment one BATCH of tiles into the shared stage. |
2 | 2 |
|
3 | | -Scattered over tile indices, so each tile is its own SLURM job and many GPUs |
4 | | -run in parallel. Each job writes a disjoint chunk of the stage store. |
| 3 | +Scattered over batches, so several batches run as separate SLURM jobs and many |
| 4 | +GPUs work in parallel. Within a batch the tiles run sequentially in this one |
| 5 | +process: CUDA is initialised once and the Cellpose model is loaded once (see |
| 6 | +``patchworks.plugins.cellpose._model_cache``), instead of once per tile. Each |
| 7 | +batch writes disjoint chunks of the stage store, so batches never collide. |
5 | 8 | """ |
6 | 9 |
|
| 10 | +import json |
| 11 | + |
7 | 12 | from patchworks import stage_tile |
8 | 13 |
|
9 | 14 | from _pw import build_fn, load_tiles_json, open_image, stage_path, start_log |
10 | 15 |
|
11 | 16 | start_log(snakemake.log[0]) # noqa: F821 |
12 | 17 | cfg = snakemake.config # noqa: F821 |
13 | | -index = int(snakemake.wildcards.index) # noqa: F821 |
| 18 | +batch = int(snakemake.wildcards.batch) # noqa: F821 |
14 | 19 | work_dir = cfg["work_dir"] |
15 | 20 | label_name = cfg.get("label_name", "labels") |
16 | 21 |
|
17 | 22 | manifest = load_tiles_json(snakemake.input.tiles) # noqa: F821 |
18 | 23 | image = open_image(work_dir, cfg["channel"], cfg["level"]) |
| 24 | +indices = manifest["batches"][batch] |
| 25 | + |
| 26 | +# Built once for the whole batch: this is what makes the model load amortize. |
| 27 | +fn = build_fn(cfg) |
| 28 | +stage = stage_path(work_dir, label_name) |
| 29 | +tile_shape = tuple(manifest["tile_shape"]) |
| 30 | + |
| 31 | +for index in indices: |
| 32 | + stage_tile( |
| 33 | + image, |
| 34 | + fn, |
| 35 | + stage, |
| 36 | + index, |
| 37 | + tile_shape=tile_shape, |
| 38 | + # Scalar (older manifests) or per-axis list; stage_tile normalizes both. |
| 39 | + overlap=manifest["overlap"], |
| 40 | + ) |
| 41 | + print(f"[patchworks] segmented tile {index}") |
19 | 42 |
|
20 | | -stage_tile( |
21 | | - image, |
22 | | - build_fn(cfg), |
23 | | - stage_path(work_dir, label_name), |
24 | | - index, |
25 | | - tile_shape=tuple(manifest["tile_shape"]), |
26 | | - # Scalar (older manifests) or per-axis list; stage_tile normalizes both. |
27 | | - overlap=manifest["overlap"], |
28 | | -) |
29 | | - |
30 | | -open(snakemake.output[0], "w").close() # noqa: F821 |
31 | | -print(f"[patchworks] segmented tile {index}") |
| 43 | +with open(snakemake.output[0], "w") as fh: # noqa: F821 |
| 44 | + json.dump({"batch": batch, "tiles": indices}, fh) |
| 45 | +print(f"[patchworks] batch {batch}: {len(indices)} tile(s) done") |
0 commit comments