cellmap_flow.finetune
Human-in-the-loop finetuning for CellMap-Flow models.
This package provides lightweight LoRA-based finetuning for pre-trained models using user corrections as training data.
Submodules
- cellmap_flow.finetune.correction_dataset
- cellmap_flow.finetune.crop_loader
- cellmap_flow.finetune.finetune_cli
- cellmap_flow.finetune.finetune_job_manager
- cellmap_flow.finetune.finetuned_model_templates
- cellmap_flow.finetune.lora_trainer
- cellmap_flow.finetune.lora_wrapper
- cellmap_flow.finetune.target_transforms
- cellmap_flow.finetune.virtual_dataset
Classes
PyTorch Dataset for user corrections stored in Zarr format. |
|
Trainer for finetuning models with LoRA adapters. |
|
Dice Loss for segmentation tasks. |
|
Combined Dice + BCE loss for better convergence. |
Functions
|
Automatically detect layers suitable for LoRA adaptation. |
|
Wrap a PyTorch model with LoRA adapters using HuggingFace PEFT. |
|
Print statistics about trainable and total parameters in a LoRA model. |
|
Load a pretrained LoRA adapter into a base model. |
|
Save only the LoRA adapter parameters (not the full model). |
|
Package Contents
- cellmap_flow.finetune.detect_adaptable_layers(model: torch.nn.Module, include_patterns: List[str] | None = None, exclude_patterns: List[str] | None = None) List[str]
Automatically detect layers suitable for LoRA adaptation.
Searches for Conv2d, Conv3d, and Linear layers, filtering by name patterns. By default, only excludes batch/layer-norm style modules. Output/head layers are deliberately INCLUDED so the model can fully adapt its feature→output mapping for cross-domain finetuning. (Previously ‘final’, ‘head’, ‘output’ were excluded; that left the output projection frozen, which prevented learning when the base model’s predictions on the target dataset were poor.)
- Parameters:
model – PyTorch model to inspect
include_patterns – List of regex patterns for layer names to include If None, includes all Conv/Linear layers
exclude_patterns – List of substrings for layer names to exclude Default: [‘bn’, ‘norm’]
- Returns:
List of layer names suitable for LoRA adaptation
- cellmap_flow.finetune.wrap_model_with_lora(model: torch.nn.Module, target_modules: List[str] | None = None, lora_r: int = 8, lora_alpha: int = 16, lora_dropout: float = 0.1, modules_to_save: List[str] | None = None, task_type: str | None = None) torch.nn.Module
Wrap a PyTorch model with LoRA adapters using HuggingFace PEFT.
This creates a PEFT model with LoRA adapters on specified layers. The base model is frozen, and only LoRA parameters are trainable.
- Parameters:
model – PyTorch model to wrap (e.g., UNet, CNN)
target_modules – List of layer names to adapt. If None, auto-detects.
lora_r – LoRA rank (number of low-rank dimensions) Higher = more capacity, more parameters Typical values: 4-32, default 8
lora_alpha – LoRA alpha (scaling factor) Controls strength of LoRA updates Typical: 2*r, default 16
lora_dropout – Dropout probability for LoRA layers (0.0-0.5, default 0.1)
modules_to_save – Additional modules to make trainable (e.g., final layer)
task_type – PEFT task type. Options: - “FEATURE_EXTRACTION” (default, for general models) - “SEQ_CLS” (sequence classification) - “TOKEN_CLS” (token classification) - “CAUSAL_LM” (causal language modeling)
- Returns:
PEFT model with LoRA adapters
- Raises:
ImportError – If peft library is not installed
ValueError – If no adaptable layers found
Examples
>>> # Auto-detect and wrap all Conv/Linear layers >>> lora_model = wrap_model_with_lora(model, lora_r=8)
>>> # Wrap specific layers with custom config >>> lora_model = wrap_model_with_lora( ... model, ... target_modules=["encoder.conv1", "encoder.conv2"], ... lora_r=16, ... lora_alpha=32, ... modules_to_save=["final_conv"] ... )
>>> # Check trainable parameters >>> print_lora_parameters(lora_model)
- cellmap_flow.finetune.print_lora_parameters(model: torch.nn.Module)
Print statistics about trainable and total parameters in a LoRA model.
- Parameters:
model – PEFT model with LoRA adapters
Examples
>>> lora_model = wrap_model_with_lora(model) >>> print_lora_parameters(lora_model) Trainable params: 294,912 (1.2% of total) Total params: 24,567,890
- cellmap_flow.finetune.load_lora_adapter(model: torch.nn.Module, adapter_path: str, is_trainable: bool = False) torch.nn.Module
Load a pretrained LoRA adapter into a base model.
- Parameters:
model – Base PyTorch model (without LoRA)
adapter_path – Path to saved LoRA adapter directory
is_trainable – If True, adapter parameters are trainable (for continued training) If False, adapter parameters are frozen (for inference)
- Returns:
PEFT model with loaded adapter
Examples
>>> # Load adapter for inference >>> model = load_lora_adapter( ... base_model, ... "models/fly_organelles/v1.1.0/lora_adapter" ... )
>>> # Load adapter for continued training >>> model = load_lora_adapter( ... base_model, ... "models/fly_organelles/v1.1.0/lora_adapter", ... is_trainable=True ... )
- cellmap_flow.finetune.save_lora_adapter(model: torch.nn.Module, output_path: str)
Save only the LoRA adapter parameters (not the full model).
This saves only the trained LoRA weights (~5-20 MB) rather than the entire model (~200-500 MB).
- Parameters:
model – PEFT model with LoRA adapters
output_path – Directory to save adapter
Examples
>>> save_lora_adapter( ... lora_model, ... "models/fly_organelles/v1.1.0/lora_adapter" ... )
- class cellmap_flow.finetune.CorrectionDataset(corrections_zarr_path: str, patch_shape: Tuple[int, int, int] | None = None, augment: bool = True, model_name: str | None = None)
PyTorch Dataset for user corrections stored in Zarr format.
Loads raw EM data and corrected masks from corrections.zarr/, with optional 3D augmentation.
- Parameters:
corrections_zarr_path – Path to corrections.zarr directory
patch_shape – Shape of patches to extract (Z, Y, X) If None, uses full correction size
augment – Whether to apply 3D augmentation
model_name – If specified, only load corrections for this model
Examples
>>> dataset = CorrectionDataset( ... "test_corrections.zarr", ... patch_shape=(64, 64, 64), ... augment=True ... ) >>> print(f"Dataset size: {len(dataset)}") >>> raw, target = dataset[0] >>> print(f"Raw shape: {raw.shape}, Target shape: {target.shape}")
- corrections_path
- patch_shape = None
- augment = True
- model_name = None
- corrections = []
- cellmap_flow.finetune.create_dataloader(corrections_zarr_path: str, batch_size: int = 2, patch_shape: Tuple[int, int, int] | None = None, augment: bool = True, num_workers: int = 4, shuffle: bool = True, model_name: str | None = None) torch.utils.data.DataLoader
- class cellmap_flow.finetune.LoRAFinetuner(model: torch.nn.Module, dataloader: torch.utils.data.DataLoader, output_dir: str, learning_rate: float = 0.0001, num_epochs: int = 10, gradient_accumulation_steps: int = 1, use_mixed_precision: bool = True, loss_type: str = 'combined', device: str | None = None, select_channel: int | None = None, mask_unannotated: bool = True, label_smoothing: float = 0.0, distillation_lambda: float = 0.0, distillation_all_voxels: bool = False, margin: float = 0.3, balance_classes: bool = False, target_transform=None)
Trainer for finetuning models with LoRA adapters.
Features: - Mixed precision (FP16) training for memory efficiency - Gradient accumulation to simulate larger batch sizes - Checkpointing with best model tracking - Progress logging - Partial annotation support (mask unannotated regions)
- Parameters:
model – PEFT model with LoRA adapters
dataloader – DataLoader for training data
output_dir – Directory to save checkpoints and logs
learning_rate – Learning rate (default: 1e-4)
num_epochs – Number of training epochs (default: 10)
gradient_accumulation_steps – Steps to accumulate gradients (default: 1)
use_mixed_precision – Enable FP16 training (default: True)
loss_type – Loss function (“dice”, “bce”, or “combined”)
device – Training device (“cuda” or “cpu”, auto-detected if None)
select_channel – Optional channel index to select from multi-channel output (default: None)
mask_unannotated – If True (default), only compute loss on annotated regions (target > 0). Targets are shifted down by 1 (e.g., 1->0, 2->1) after masking. This allows partial annotations where 0=unannotated, 1=background, 2=foreground, etc. Ignored if target_transform is provided.
target_transform – Optional TargetTransform instance that converts raw annotations to (target, mask) pairs. Overrides mask_unannotated when provided. See cellmap_flow.finetune.target_transforms.
Examples
>>> lora_model = wrap_model_with_lora(model) >>> dataloader = create_dataloader("corrections.zarr") >>> trainer = LoRAFinetuner( ... lora_model, ... dataloader, ... output_dir="output/fly_organelles_v1.1" ... ) >>> trainer.train() >>> trainer.save_adapter()
- model
- dataloader
- output_dir
- num_epochs = 10
- gradient_accumulation_steps = 1
- use_mixed_precision = True
- select_channel = None
- mask_unannotated = True
- label_smoothing = 0.0
- distillation_lambda = 0.0
- distillation_all_voxels = False
- balance_classes = False
- target_transform = None
- optimizer
- scaler
- current_epoch = 0
- global_step = 0
- best_loss
- training_stats = []
- train() Dict[str, Any]
Run the training loop.
- Returns:
final_loss: Final epoch loss
best_loss: Best loss achieved
total_epochs: Number of epochs trained
total_steps: Total training steps
- Return type:
Training statistics dictionary with
- save_checkpoint(is_best: bool = False)
Save training checkpoint.
- Parameters:
is_best – If True, saves as “best_model.pth”
- save_adapter(adapter_path: str | None = None)
Save only the LoRA adapter (not the full model).
Automatically loads the best checkpoint weights before saving so the exported adapter reflects the best training epoch.
- Parameters:
adapter_path – Path to save adapter. If None, uses output_dir/lora_adapter
- load_checkpoint(checkpoint_path: str)
Load training checkpoint to resume training.
- Parameters:
checkpoint_path – Path to checkpoint file
- class cellmap_flow.finetune.DiceLoss(smooth: float = 1.0)
Dice Loss for segmentation tasks.
Dice loss is effective for imbalanced datasets where the target class may be sparse (e.g., mitochondria in EM images).
Formula: 1 - (2 * |X ∩ Y| + smooth) / (|X| + |Y| + smooth)
- smooth = 1.0
- apply_sigmoid = True
- forward(pred: torch.Tensor, target: torch.Tensor, mask: torch.Tensor | None = None) torch.Tensor
Compute Dice loss.
- Parameters:
pred – Predictions (B, C, Z, Y, X) - raw logits or probabilities
target – Targets (B, C, Z, Y, X) - binary masks [0, 1]
mask – Optional mask (B, 1, Z, Y, X) - if provided, only compute loss on masked regions
- Returns:
Dice loss value (scalar)
- class cellmap_flow.finetune.CombinedLoss(dice_weight: float = 0.5, bce_weight: float = 0.5)
Combined Dice + BCE loss for better convergence.
Uses both Dice loss (for overlap) and BCE loss (for pixel-wise accuracy).
- dice_loss
- bce_loss
- dice_weight = 0.5
- bce_weight = 0.5
- forward(pred: torch.Tensor, target: torch.Tensor, mask: torch.Tensor | None = None) torch.Tensor
Compute combined loss.
- Parameters:
pred – Predictions (B, C, Z, Y, X) - raw logits
target – Targets (B, C, Z, Y, X) - binary masks [0, 1]
mask – Optional mask (B, 1, Z, Y, X) - if provided, only compute loss on masked regions
- Returns:
Combined loss value (scalar)