Skip to content

Add Cellpose-SAM retrain worker#152

Open
arjunrajlab wants to merge 5 commits into
masterfrom
claude/cellpose-sam-retrain-worker-qzmt9k
Open

Add Cellpose-SAM retrain worker#152
arjunrajlab wants to merge 5 commits into
masterfrom
claude/cellpose-sam-retrain-worker-qzmt9k

Conversation

@arjunrajlab

@arjunrajlab arjunrajlab commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a new cellposesam_train annotation worker that fine-tunes Cellpose-SAM models on user-corrected annotations, producing custom models that appear directly in the Cellpose-SAM inference worker's Model dropdown.

We already had a cellpose_train (retrain for the older Cellpose) and a cellposesam (inference on the latest Cellpose-SAM), but no retrain counterpart for Cellpose-SAM. This fills that gap.

What's kept from the existing cellpose_train paradigm

  • Training tag + optional Training Region tags to select ground-truth annotations and the crops to train on.
  • Same flow: pull polygon + rectangle annotations, group by location, rasterize each into a label mask via skimage.draw.polygon2mask(), crop to region bounding boxes, then upload the trained model to the user's Girder folder for reuse.

What's new for Cellpose-SAM (differs from earlier versions)

  • Channel-slot input (Slot 1 required, Slots 2/3 optional) matching the cellposesam inference worker, replacing the cyto/nucleus Primary/Secondary channels + "Nuclear Model?" checkbox. Cellpose-SAM ingests up to three channels natively, so there is no separate cytoplasm/nucleus concept — training on the same channel layout used at inference is what matters.
  • cellpose 4.x train.train_seg API: no channels argument (stacks channels-last and passes channel_axis=-1), AdamW optimizer (the old SGD flag is deprecated), learning_rate default 1e-5, weight_decay default 0.1, bsize=256, and native-resolution training (no diameter).
  • Model instantiation via CellposeModel(pretrained_model=...) from the cpsam/cpsam_v2 checkpoints (shared models_config.py) or a custom Girder model path, replacing the removed model_type= argument. Models are saved to .cellposesam/models.

Files

  • workers/annotations/cellposesam_train/: entrypoint.py, Dockerfile, environment.yml (cellpose 4.2.1.1), download_models.py, girder_utils.py, models_config.py, utils.py, CELLPOSESAM_TRAIN.md, and tests/test_models_config.py.
  • Registered in build_machine_learning_workers.sh and REGISTRY.md.

Bug fixes (from code review)

Self-review + the Codex reviewer surfaced three real issues, fixed here:

  1. Model save would crash on the default path. cellpose 4.x train_seg saves to save_path/models/model_name but only calls (save_path/"models").mkdir(exist_ok=True) without parents=True. On the default base-model path nothing creates /root/.cellposesam beforehand (the build downloads checkpoints into cellpose's own ~/.cellpose/models), so the save would raise FileNotFoundError. The worker now creates the models directory up front.
  2. Empty-region fallback. If a Training Region tag is supplied but matches no annotations, the code warned "training will use the entire image" but still took the region-cropping branch, produced zero crops, and handed train_seg an empty training set. The branch now hinges on whether region annotations were actually found, so an unmatched tag genuinely falls back to full-image training.
  3. min_train_masks. cellpose 4's train_seg defaults min_train_masks=5, silently dropping any crop/image with fewer than five labeled objects — common for user-corrected crops. Now passes min_train_masks=1.

Also fixed in cellpose_train

Issues 2 and 3 were latent in the original cellpose_train worker (the region-branch structure was copied from it), so the same two fixes are applied there as well.

Testing

models_config mapping is unit-tested (tests/test_models_config.py) and passes in the lightweight local venv. Full Docker build/train validation on a GPU host has not been run in this environment.

🤖 Generated with Claude Code

https://claude.ai/code/session_0199mMkZxJV7p7p8zTs7wYFe

claude added 2 commits July 7, 2026 04:55
Adds a cellposesam_train worker that fine-tunes Cellpose-SAM models on
user-corrected annotations, mirroring the cellpose_train paradigm (training
tag + optional training regions, saved to Girder for reuse by the inference
worker) while adopting the Cellpose-SAM interface and training API.

Key differences from the older cellpose_train worker:
- Channel-slot input (Slot 1 required, Slots 2/3 optional) matching the
  cellposesam inference worker, instead of the cyto/nucleus Primary/Secondary
  channels + Nuclear Model checkbox. Cellpose-SAM ingests up to 3 channels
  natively, so there is no separate cytoplasm/nucleus concept.
- Training via cellpose 4.x train.train_seg: no `channels` arg (uses
  channel_axis=-1 on channels-last stacks), AdamW (SGD deprecated),
  learning_rate default 1e-5, weight_decay default 0.1, bsize=256, native
  resolution (no diameter).
- Model instantiated with CellposeModel(pretrained_model=...) from the cpsam
  checkpoints (models_config.py, shared with the inference worker) or a custom
  Girder model path; saved to .cellposesam/models.

Registers the worker in build_machine_learning_workers.sh and REGISTRY.md,
and includes models_config unit tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0199mMkZxJV7p7p8zTs7wYFe
cellpose 4.x train_seg saves to save_path/models/model_name and only calls
(save_path/"models").mkdir(exist_ok=True) without parents=True. On the default
base-model fine-tune path nothing creates /root/.cellposesam beforehand, so the
save would raise FileNotFoundError. Create the models directory up front.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0199mMkZxJV7p7p8zTs7wYFe

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 80e6083b05

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +250 to +253
if len(regionAnnotationList) == 0 and training_regions and len(training_regions) > 0:
sendWarning("No region annotations found.",
info="No annotations with the training region tag were found.")
print("No region annotations found. Training will be performed on entire image that the annotations are in.")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use full-image fallback when no regions are found

When a user selects a Training Region tag that matches no annotations, this block warns that training will use the entire image, but it leaves training_regions non-empty. The later if training_regions is None or len(training_regions) == 0 check therefore enters the region-cropping branch, iterates an empty grouped_region_annotations[location_key], appends no samples, and calls train_seg with zero training images instead of the promised full-image fallback.

Useful? React with 👍 / 👎.

# - AdamW is always used (the old SGD flag is deprecated), so we do not pass SGD.
# - bsize must be 256 for cpsam.
# - training uses native resolution (rescale=False), so no diameter is needed.
model_path, train_losses, test_losses = train.train_seg(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Pass min_train_masks for sparse training crops

Cellpose 4 train_seg defaults min_train_masks to 5, so any crop or full image with fewer than five labeled objects is removed before training. For this worker's user-corrected annotations and optional region crops, one-to-four annotated objects in a crop is a valid and likely input; those samples will be silently ignored, and if all crops are sparse the training set becomes empty. Pass an explicit lower threshold or reject sparse crops before starting training.

Useful? React with 👍 / 👎.

claude added 3 commits July 7, 2026 09:33
- Fall back to full-image training when a Training Region tag is supplied but
  matches no annotations. Previously the region-cropping branch was chosen based
  on whether a tag was given, so an unmatched tag produced zero crops and handed
  train_seg an empty training set despite the "using entire image" warning. The
  branch now hinges on whether region annotations were actually found.
- Pass min_train_masks=1 to train_seg. cellpose 4's default of 5 silently drops
  any crop/image with fewer than five labeled objects, which is common for
  user-corrected crops and could empty the training set.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0199mMkZxJV7p7p8zTs7wYFe
The cellposesam_train worker inherited two latent bugs from cellpose_train;
fix them at the source too:
- Fall back to full-image training when a Training Region tag matches no
  annotations, rather than producing zero crops and training on an empty set.
  (Also avoids a latent len(None) crash when no region tag is set.)
- Pass min_train_masks=1 so crops with fewer than five labeled objects are not
  silently dropped.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0199mMkZxJV7p7p8zTs7wYFe
- Remove two __pycache__/*.pyc files accidentally committed during local
  py_compile checks (nothing else in the repo tracks compiled artifacts).
- Create .cellposesam/models once, up front in compute(), before it is used as
  the download destination for a custom base model and before the glob that
  lists it — not only just before train_seg. Avoids relying on the Girder
  client to create the destination directory on the custom-model path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0199mMkZxJV7p7p8zTs7wYFe
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants