spacr.deep_spacr

Workflow inputs and outputs

Activation

Apply the matching image classifier and preprocessing to inspect saliency/model-response maps.

Open: Classify → Activation.

Inputs and outputs below include conditional alternatives. The guidance and handoff notes say which route applies.

Inputs

  • Trained image classifier — Saved classifier checkpoint, model settings and matching channel/preprocessing configuration.

  • Object crops — data/**/*_png when save_png is enabled; png_list indexes saved crops. Supported workflows can instead stream crops from merged arrays and masks. Relevant tables, depending on the route: png_list. Relevant columns, depending on the route: png_path, prcfo.

Outputs

  • Image attribution maps — Saved model-response/saliency images for the matching classifier and input preprocessing.

Before this module

  • Classify: Also provide the matching crops and channel preprocessing.

API reference.

Module tutorial.

Computer Vision

Train an image classifier from labelled object crops, archives or supported streamed crops. Match channels and preprocessing when applying its checkpoint.

Open: Classify → Computer Vision.

Inputs and outputs below include conditional alternatives. The guidance and handoff notes say which route applies.

Inputs

  • Measured objects — measurements/measurements.db; object tables depend on the enabled cell, nucleus, pathogen and organelle masks. Relevant tables, depending on the route: cell, nucleus, pathogen, cytoplasm. Relevant columns, depending on the route: plateID, rowID, columnID, fieldID.

  • Object crops — data/**/*_png when save_png is enabled; png_list indexes saved crops. Supported workflows can instead stream crops from merged arrays and masks. Relevant tables, depending on the route: png_list. Relevant columns, depending on the route: png_path, prcfo.

  • Training annotations — A chosen annotation column in measurements/measurements.db, table png_list; labels belong to object identities. Relevant tables, depending on the route: png_list. Relevant columns, depending on the route: prcfo.

Outputs

  • Object classification scores — Saved score CSVs and, when merged, measurements/measurements.db, table png_list. Relevant tables, depending on the route: png_list. Relevant columns, depending on the route: pred, cv_predictions, ml_pred, predictions.

  • Trained image classifier — Saved classifier checkpoint, model settings and matching channel/preprocessing configuration.

  • Classifier evaluation bundle — Held-out predictions, labels, split metadata and calibration/leakage metrics for a saved classifier run.

API reference.

Module tutorial.

PyTorch dataset generation, classification, inference, and attribution.

Classes

SmoothGrad

SmoothGrad attribution: average gradients over noisy copies of the input.

Functions

analyze_activation_maps(model, images[, methods, ...])

Compute and evaluate attribution maps for one or more images.

annotate_filter_vision(settings)

Annotate and filter vision-model score CSVs, then optionally drop training images.

apply_model(src, model_path[, image_size, batch_size, ...])

Apply a trained PyTorch model to images in a directory.

apply_model_to_tar([settings])

Apply a trained PyTorch model to images stored in a tar archive.

attach_per_class_columns(metrics[, classes])

Add flat acc_class_<name> keys to metrics, in place.

autocasting(on, device)

Half precision for the block, or nothing at all.

build_model_card(model_path, *[, settings, classes, ...])

Assemble the record that travels with a checkpoint.

class_labels(metrics[, classes])

Names for the classes metrics describes, one per class.

cv_metric_keys(→ list)

Which metric columns to carry across folds, for THIS class count.

dataset_class_balance(src[, classes])

Count the images the classifier was trained on, per split, per class.

deep_spacr([settings])

Run the full spacr deep-learning pipeline: build dataset, train, apply model, merge predictions into the measurements DB.

evaluate_model_performance(model, loader, epoch[, ...])

Evaluate a binary or multiclass classifier and return metrics plus raw probs/labels.

format_model_card(card)

Render a card as Markdown — the version a human reads first.

format_per_class_accuracy(metrics[, classes, prefix])

One line naming every class and how it actually did.

generate_activation_map(settings)

Generate saliency or Grad-CAM activation maps for every image in a tar dataset.

held_out_report(y_true, probs[, classes])

Everything the card says about held-out performance, recomputable.

merge_predictions_into_db(df, db_path[, table, ...])

Write per-image prediction scores back into a spacr SQLite database.

model_card(model_path, *[, registry, project, inputs, ...])

Build, write and register a card for model_path in one call.

model_fusion(model_paths, save_path[, device, ...])

Fuse the weights of several identically-shaped model checkpoints into one.

model_knowledge_transfer(teacher_paths, ...[, device, ...])

Distil an ensemble of teacher models into a single student TorchModel.

per_class_accuracy(metrics[, classes])

[(name, accuracy, support), …] for one epoch's metrics.

pick_device([room_mb, what])

Select CUDA when sufficient memory is available, otherwise select CPU.

read_model_card(model_path)

The card beside model_path, or None when there is not one.

register_model_card(model_path, card, *[, project, ...])

Register the checkpoint and its card in the artifact registry.

resolve_class_balance_loss(loss_type, class_balance, ...)

Translate class_balance='weighted_loss' into a concrete loss type.

resolve_mixed_precision(asked, device)

(on, note). Whether to train in half precision on THIS machine.

save_top_class_examples(df, tar_path, dst[, n, classes])

Extract the n most confident images per class from a tar into class-labelled folders.

summarize_cv_metrics(fold_df[, metric_keys])

Reduce per-fold metrics to mean plus the spread around it.

test_model_core(model, loader, loader_name, epoch, ...)

Core test loop over loader, compatible with binary & multiclass.

test_model_performance(loaders, model, ...)

Evaluate model on a single loader and report the metrics as a frame.

train_model(src, dst, model_type, train_loaders[, ...])

Train a classifier and return it together with its checkpoint path.

train_test_model(settings)

Train a vision classifier on a spacr training dataset and/or evaluate it on the held-out test/ split.

visualize_classes(model, dtype, class_names, **kwargs)

Show one synthesised class-visualisation image for class 0 and class 1.

visualize_integrated_gradients(src, model_path[, ...])

Compute and plot Integrated Gradients maps for every PNG under src.

visualize_smooth_grad(src, model_path, target_label_idx)

Compute and plot SmoothGrad maps for every PNG under src.

write_model_card(model_path, card, *[, markdown])

Write card beside model_path; return the JSON card's path.

Module Contents

class spacr.deep_spacr.SmoothGrad(model, n_samples=50, stdev_spread=0.15)[source]

SmoothGrad attribution: average gradients over noisy copies of the input.

Parameters:
  • model – PyTorch classifier used for gradient computation.

  • n_samples – Number of noisy samples to average over. Default 50.

  • stdev_spread – Noise standard deviation as a fraction of the input’s dynamic range. Default 0.15.

Store the model and noise parameters.

compute_smooth_grad(input_tensor, target_class)[source]

Return the averaged gradient map for target_class given input_tensor.

Parameters:
  • input_tensor – Input tensor to attribute (single sample or batch).

  • target_class – Class index whose logit is differentiated.

Returns:

Tensor of the same shape as input_tensor holding the averaged gradients.

spacr.deep_spacr.analyze_activation_maps(model, images, methods=None, *, masks=None, target=None, target_layer=None, model_type=None, n_steps=12, baseline='blur', sanity_check=True, sanity_threshold=0.5, verbose=True)[source]

Compute and evaluate attribution maps for one or more images.

By default, the analysis evaluates gradcam, saliency, integrated_gradients, and occlusion. For each successful attribution it computes deletion and insertion AUC; when an object mask is supplied it also evaluates the pointing game. Rank correlation summarizes agreement between non-flat methods for the first image.

When sanity_check is enabled, the first image is re-attributed while model parameters are randomized layer by layer. A map that remains too similar after randomization has insufficient sensitivity to the learned parameters and should not be interpreted as a model-specific explanation.

Parameters:
  • model – Trained classifier.

  • images – Image tensor or iterable of tensors with shape (C, H, W).

  • methods – Attribution methods from spacr.attribution.ATTRIBUTION_METHODS. None uses gradcam, saliency, integrated_gradients, and occlusion.

  • masks – Optional per-image boolean object masks used by the pointing game.

  • target – Class index to explain. None uses each image’s predicted class.

  • target_layer – CAM target layer. None selects the final convolutional layer.

  • model_type – Optional architecture name used in diagnostic messages.

  • n_steps – Number of perturbation steps for deletion and insertion curves.

  • baseline – Replacement used for removed pixels: "blur", "zero", "mean", or "uniform".

  • sanity_check – Whether to run parameter-randomization analysis on the first image.

  • sanity_threshold – Maximum rank correlation at which a randomized map is considered sufficiently different.

  • verbose – Whether to print per-method validation results.

Returns:

Mapping with table, attributions, agreement, sanity, and notes.

spacr.deep_spacr.annotate_filter_vision(settings)[source]

Annotate and filter vision-model score CSVs, then optionally drop training images.

For every src CSV the plate metadata is corrected and annotated, rows whose filter_column value lies between lower_threshold and upper_threshold are dropped, and the result is written to <src>_annotated_filtered.csv. Only afterwards, and only when remove_train is set, are rows matching a PNG under the sibling datasets/training/train folders removed and the same CSV rewritten.

Parameters:

settings – Settings dict with src (path or list of paths); the annotate_conditions keys cells, cell_loc, pathogens, pathogen_loc, treatments and treatment_loc; the filter keys filter_column (None, or a name absent from the frame, leaves it unfiltered), upper_threshold and lower_threshold; and remove_train.

Returns:

None

spacr.deep_spacr.apply_model(src, model_path, image_size=224, batch_size=64, normalize=True, n_jobs=10, input_statistics='symmetric', *, tta_enabled=False, tta_rotations=False, tta_horizontal_flip=False, tta_vertical_flip=False, tta_aggregation='probability_mean', tta_min_agreement=0.75, tta_max_std=0.15, score_threshold=0.5)[source]

Apply a trained PyTorch model to images in a directory.

The function loads a saved model, builds a dataset from the input images, runs batched inference, and saves prediction scores to a CSV file.

Parameters:
  • src (str or os.PathLike) – Path to the directory containing the input images.

  • model_path (str) – Path to the saved PyTorch model.

  • image_size (int) – Final square crop size used before inference.

  • batch_size (int) – Number of images processed per batch.

  • normalize (bool) – Whether to normalize the image channels using mean 0.5 and standard deviation 0.5.

  • n_jobs (int) – Number of worker processes used by the DataLoader.

  • input_statistics – Normalization convention used when normalize is True.

  • tta_enabled – Enable multi-view scoring; False preserves ordinary inference.

  • tta_rotations – Include 90, 180 and 270-degree rotations; default False.

  • tta_horizontal_flip – Include left/right reflected views; default False.

  • tta_vertical_flip – Include up/down reflected views; default False.

  • tta_aggregation – probability_mean or majority_vote; ties prefer mean probability.

  • tta_min_agreement – Flag agreement below this fraction; default 0.75.

  • tta_max_std – Flag probability standard deviation above this value; default 0.15.

  • score_threshold – Positive-class cutoff used for binary TTA view labels.

Returns:

DataFrame with image paths and prediction scores.

Return type:

pandas.DataFrame

The returned DataFrame always contains the columns path and pred. A single-logit head is converted with torch.sigmoid, so pred is the positive-class probability; a multi-logit head is converted with torch.softmax, so pred is the probability of class 1 for two classes and the winning class’s confidence for more. With more than two classes the frame also carries predicted_label and one prob_class_<i> column per class. Results are also written to a CSV file derived from model_path and the current date.

With tta_enabled, both binary and multiclass outputs also retain original_pred, original_predicted_label, per-class original and mean probabilities, prediction_std, transform_agreement, review_flag and tta_views. Orientation stability is not calibrated confidence. Training and held-out evaluation are unchanged.

spacr.deep_spacr.apply_model_to_tar(settings=None)[source]

Apply a trained PyTorch model to images stored in a tar archive.

The function loads a saved model, reads images from a tar-based dataset, performs batched inference, post-processes prediction scores, and saves the results to a CSV file.

Parameters:

settings (dict) – Dictionary of inference settings. Expected keys include tar_path, model_path, image_size, batch_size, normalize, n_jobs, verbose, and score_threshold. Optional tta_enabled, tta_rotations, tta_horizontal_flip, tta_vertical_flip, tta_aggregation, tta_min_agreement and tta_max_std use the same meanings and defaults as apply_model().

Returns:

DataFrame with processed prediction results.

Return type:

pandas.DataFrame

The returned DataFrame contains at least the columns path and pred, plus the columns added by process_vision_results. A single-logit head is converted with torch.sigmoid; a multi-logit head with torch.softmax, giving the probability of class 1 for two classes and the winning class’s confidence for more. With more than two classes the frame also carries predicted_label and one prob_class_<i> column per class, and its cv_predictions column holds the predicted class index rather than a threshold on pred.

Enabled test-time augmentation adds original predictions and stability diagnostics for every head type. cv_predictions follows the selected aggregation method; with majority voting it can differ from thresholding the mean probability stored in pred.

spacr.deep_spacr.attach_per_class_columns(metrics, classes=None)[source]

Add flat acc_class_<name> keys to metrics, in place.

Called on every epoch dict before it reaches train.csv / validation.csv. The key set is fixed by the head size, which does not change inside a run, so the appended CSV keeps one stable header — see spacr.io._save_progress(), which writes the header only for the first chunk.

Parameters:
  • metrics – one epoch’s metrics dict; mutated and returned.

  • classes – optional class names in head order.

spacr.deep_spacr.autocasting(on, device)[source]

Half precision for the block, or nothing at all.

A context manager either way, so the training loop has ONE shape rather than a branch around every forward pass.

Parameters:
  • on – whether to autocast; falsy makes the block run unchanged.

  • device – the torch.device the block runs on; its type is the autocast device type, and CPU uses bfloat16 where other devices use float16.

spacr.deep_spacr.build_model_card(model_path, *, settings=None, classes=None, split_rule='', held_out=None, train_metrics=None, dataset_src=None, class_balance=None, module='train', epochs=None, history=None, extra=None)[source]

Assemble the record that travels with a checkpoint.

Answers, for a .pth somebody finds in six months: what was it trained on, how was the held-out split drawn, how balanced were the classes, how did it do per class, which spaCR wrote it, under which settings, when.

Parameters:
  • model_path – the checkpoint the card describes.

  • settings – the run’s settings; only the material ones are hashed and stored (spacr.artifacts.material_settings()).

  • classes – class names in head order.

  • split_rule – how the held-out set was drawn, in words — the field most often left implicit and most often the reason a number is wrong (“random 20 % of objects” leaks across wells; “grouped by well” does not).

  • held_out – a held_out_report() dict.

  • train_metrics – the training-split metrics of the same epoch.

  • dataset_src – dataset root, for the class balance on disk.

  • class_balance – override for the counted balance.

  • module – producing module key for the registry.

  • epochs – epochs requested, when known.

  • history – per-epoch metrics, trimmed into the card as a curve.

  • extra – anything else worth recording.

Returns:

a JSON-safe dict.

spacr.deep_spacr.class_labels(metrics, classes=None)[source]

Names for the classes metrics describes, one per class.

Parameters:
  • metrics – a dict from _binary_metrics() / _multiclass_metrics().

  • classes – the folder names training read the classes from, in head order, when they are known. Omitted, the names attach_per_class_columns() stamped into metrics are used — which is what lets the live plot and the model card name the classes without every helper having to be handed the list again.

Returns:

list of str, length num_classes. Falls back to class_0, class_1, … — never to an empty list, because the caller is about to index it per class.

spacr.deep_spacr.cv_metric_keys(metrics) → list[source]

Which metric columns to carry across folds, for THIS class count.

CV_METRIC_KEYS plus every acc_class_<name> the epoch metrics carry – named by PER_CLASS_ACC_PREFIX, which is already the one spelling of that prefix in this module. Two classes get what they always got; three or more get their per-class accuracies as well, which is the only part of the summary that says anything about the classes.

Parameters:

metrics – a collection of metric names (a per-epoch metrics dict or a fold DataFrame’s columns), tested with in and iterated for per-class accuracy keys.

spacr.deep_spacr.dataset_class_balance(src, classes=None)[source]

Count the images the classifier was trained on, per split, per class.

Reads the train/<class>/ and test/<class>/ folder tree spacr.io.generate_dataset() writes, because that tree is the training set — a class balance quoted from the settings would describe what was requested rather than what ended up on disk.

Parameters:
  • src – dataset root holding train/ (and optionally test/).

  • classes – class names to count; discovered from the folder names when omitted.

Returns:

{split: {class: count}} for the splits that exist.

spacr.deep_spacr.deep_spacr(settings=None)[source]

Run the full spacr deep-learning pipeline: build dataset, train, apply model, merge predictions into the measurements DB.

High-level driver that chains spacr.io.generate_training_dataset() -> train_test_model() -> spacr.io.generate_dataset() (tar) -> apply_model_to_tar() -> save_top_class_examples() -> merge_predictions_into_db(). Each stage is toggled by a flag in settings so the same call can (re)train from scratch, only apply a saved model, or only merge predictions.

Parameters:

settings –

Settings dict; canonicalized via spacr.settings.deep_spacr_defaults(). Key flags/inputs:

Returns:

None. Writes model checkpoints, DL_model_settings.csv, a dataset tar, top_examples/ and updates the measurements.db in-place.

Example

from spacr.deep_spacr import deep_spacr
settings = {
    'src': '/data/plate01',
    'generate_training_dataset': True,
    'train': True, 'test': True,
    'apply_model_to_dataset': True,
    'model_type': 'maxvit_t', 'classes': ['neg','pos'],
    'epochs': 25, 'batch_size': 32,
}
deep_spacr(settings)

See also

train_test_model() — training-only entry point. spacr.io.generate_training_dataset() — labeling from annotation rules. apply_model_to_tar() — inference on a packed dataset.

spacr.deep_spacr.evaluate_model_performance(model, loader, epoch, loss_type='auto', loss_fn=None, num_classes=None)[source]

Evaluate a binary or multiclass classifier and return metrics plus raw probs/labels.

Head size is inferred from the first batch — a single-logit head is treated as binary (BCE + sigmoid), otherwise softmax + CE metrics apply. If loss_fn is None, one is constructed via build_loss.

Parameters:
  • model – PyTorch classifier.

  • loader – DataLoader yielding (input, target, meta) batches.

  • epoch – Current epoch (recorded in the returned dict).

  • loss_type – Loss selection passed to build_loss when loss_fn is None. Default 'auto'.

  • loss_fn – Optional callable (logits, target) -> Tensor.

  • num_classes – Class count when the loader is empty.

Returns:

(metrics_dict, [probs, labels]) — metrics include loss, epoch and Accuracy. probs is shape (N,) for binary or (N, C) for multiclass.

spacr.deep_spacr.format_model_card(card)[source]

Render a card as Markdown — the version a human reads first.

Parameters:

card – the model card dict, as built by build_model_card(); missing keys render as ? or “not recorded”.

spacr.deep_spacr.format_per_class_accuracy(metrics, classes=None, prefix='')[source]

One line naming every class and how it actually did.

A 96 % aggregate hiding a class at 40 % is the commonest way a classifier looks finished and is not, and the aggregate is the only number the epoch line used to print. The worst class is flagged explicitly so it does not have to be spotted in a row of numbers.

Parameters:
  • metrics – one epoch’s metrics dict.

  • classes – optional class names in head order.

  • prefix – text put in front of the line (“Train “, “Val “).

Returns:

the line, or '' when there is no per-class breakdown.

spacr.deep_spacr.generate_activation_map(settings)[source]

Generate saliency or Grad-CAM activation maps for every image in a tar dataset.

Loads the model, iterates the dataset, computes the requested map type per batch, saves per-image maps into class/plate/well folders, optionally plots batch grids, computes activation-image correlations, and pushes both maps and correlations into the measurement database.

Parameters:

settings – Settings dict — see settings.get_default_generate_activation_map_settings for keys (dataset, model_path, cam_type, target_layer, image_size, batch_size, channels, normalize, save, plot, correlation, …). With counterfactuals on, up to counterfactual_crops of the crops also train a small class-conditional generator against the loaded model, and the held-out crops are morphed toward the other class with the classifier’s score written at every step (see _run_counterfactuals).

Returns:

None

spacr.deep_spacr.held_out_report(y_true, probs, classes=None)[source]

Everything the card says about held-out performance, recomputable.

The card must not be the only place a number exists — a card that reports 0.96 with nothing to check it against is a claim, not a record. So this returns the confusion matrix alongside every derived figure, and each figure is exactly the standard function of that matrix: accuracy = trace / total and per_class_accuracy[c] = M[c, c] / M[c, :].sum(). Recomputing them from confusion_matrix must reproduce them exactly, and the test suite pins that.

Parameters:
  • y_true – integer class ids, shape (N,).

  • probs – (N,) positive-class probabilities for a single-logit head, or (N, C) softmax rows for a C-logit head. The same two shapes evaluate_model_performance() returns.

  • classes – class names in head order, when known.

Returns:

dict with n, num_classes, classes, accuracy, f1_macro, per_class_accuracy, class_support, predicted_support and confusion_matrix.

The implementation lives in spacr.active_learning.holdout_report(), which is torch-free, so a card written by a CNN round and a card written by an in-Annotate classical round carry the identical shape and are comparable side by side. Imported lazily: that module deliberately does not pull torch, and this one already has.

spacr.deep_spacr.merge_predictions_into_db(df, db_path, table='png_list', pred_col='pred', class_col='cv_predictions')[source]

Write per-image prediction scores back into a spacr SQLite database.

Thin wrapper over spacr.predictions.merge_cv_predictions(), which is the one merge path Classify (CV) and Classify (ML) share. It used to be implemented here, keyed on basename(png_path), and collapsed repeated basenames with a plain dict assignment – so a run over two source folders whose plates were both called plate1 scored one plate with the other one’s predictions and said nothing. The replacement keys on prcfo, refuses a key that arrives with two different values instead of letting the last one win, counts every row it could not place, and runs in one transaction. See spacr.predictions.

Parameters:
  • df – DataFrame with columns path, pred and cv_predictions.

  • db_path – SQLite database file.

  • table – Target table. Default 'png_list'.

  • pred_col – Database column for the probability. Default 'pred'.

  • class_col – Database column for the class label. Default 'cv_predictions'.

Returns:

Number of DB rows updated, or None if the database is missing.

See also

spacr.predictions.merge_prediction_results() – the shared implementation, and the full MergeReport.

spacr.deep_spacr.model_card(model_path, *, registry=None, project=None, inputs=(), run_id='', **card_kwargs)[source]

Build, write and register a card for model_path in one call.

Parameters:
  • model_path – the checkpoint the card describes. Only the path is used: a checkpoint that does not exist still gets a card written beside it (its folder is created) and still registers, but with an empty content fingerprint, so that row is not content-addressed.

  • registry – an open spacr.artifacts.Registry to store the row in; without one, a registry is opened at project.

  • project – project root recorded on the artifact, and where the registry is opened when registry is None. Defaults to the checkpoint’s own folder, which is where an artifacts.db then appears. It still sets the recorded root when registry is passed.

  • inputs – upstream artifact ids or spacr.artifacts.Artifact objects this checkpoint was derived from.

  • run_id – the run this came out of, stored on the artifact row.

  • card_kwargs – passed to build_model_card() — settings, classes, split_rule, held_out and the rest.

Returns:

(card, card_path, artifact_or_None). On a successful registration the card is written twice, the second time carrying artifact_id. If the registry cannot be reached the artifact is None and the card keeps no artifact_id; nothing raises either way, because losing the card must not lose the weights.

spacr.deep_spacr.model_fusion(model_paths, save_path, device='cpu', model_name='maxvit_t', pretrained=True, dropout_rate=None, use_checkpoint=False, aggregator='mean')[source]

Fuse the weights of several identically-shaped model checkpoints into one.

Parameters:
  • model_paths – Paths to source checkpoints (dicts or TorchModel objects).

  • save_path – Base output path; suffix _<aggregator>.pth is appended.

  • device – Torch device string. Default 'cpu'.

  • model_name – TorchModel architecture name for the fused model.

  • pretrained – Whether pretrained weights are expected.

  • dropout_rate – Optional dropout rate.

  • use_checkpoint – Whether to enable gradient checkpointing.

  • aggregator – Reduction over stacked weights — one of 'mean', 'geomean', 'median', 'sum', 'max', 'min'. Default 'mean'.

Returns:

The fused TorchModel.

Raises:

ValueError – on unsupported aggregator, mismatched state dict keys, or unsupported checkpoint types.

spacr.deep_spacr.model_knowledge_transfer(teacher_paths, student_save_path, data_loader, device='cpu', student_model_name='maxvit_t', pretrained=True, dropout_rate=None, use_checkpoint=False, alpha=0.5, temperature=2.0, lr=0.0001, epochs=10)[source]

Distil an ensemble of teacher models into a single student TorchModel.

Parameters:
  • teacher_paths – Paths to the teacher checkpoints (each either a saved TorchModel or a state dict).

  • student_save_path – Destination for the trained student; the suffix _KD.pth is appended.

  • data_loader – Training DataLoader used during distillation.

  • device – Torch device string. Default 'cpu'.

  • student_model_name – TorchModel architecture name for the student. Default 'maxvit_t'.

  • pretrained – Whether the student uses pretrained weights.

  • dropout_rate – Optional dropout rate for the student.

  • use_checkpoint – Whether to enable gradient checkpointing.

  • alpha – Weight on the true-label loss vs. distillation loss. Default 0.5.

  • temperature – Softmax temperature for distillation. Default 2.0.

  • lr – Adam learning rate. Default 1e-4.

  • epochs – Training epochs. Default 10.

Returns:

The trained student model.

Raises:

ValueError – on unsupported checkpoint types.

spacr.deep_spacr.per_class_accuracy(metrics, classes=None)[source]

[(name, accuracy, support), …] for one epoch’s metrics.

The single place that knows a binary head reports two classes and a multiclass head reports C, so nothing downstream branches on head shape.

Parameters:
  • metrics – one epoch’s metrics dict.

  • classes – optional class names in head order.

Returns:

list of (name, float accuracy, int support); empty when the metrics carry no per-class breakdown at all.

spacr.deep_spacr.pick_device(room_mb: int = GPU_ROOM_MB, what: str = 'this run')[source]

Select CUDA when sufficient memory is available, otherwise select CPU.

Availability alone does not ensure that a shared GPU has enough free memory for a new workload. When CUDA reports less than room_mb free, this function selects CPU and returns a user-facing note describing the available and required memory. If CUDA memory information is unavailable, CUDA is retained and allocation errors are allowed to surface from the workload.

Parameters:
  • room_mb – Minimum free GPU memory, in MiB, required to select CUDA.

  • what – Workload name included in the CPU-fallback note.

Returns:

(torch.device, note). note is empty unless low free GPU memory causes a CPU fallback.

spacr.deep_spacr.read_model_card(model_path)[source]

The card beside model_path, or None when there is not one.

Parameters:

model_path – path to the model weights; the card is the JSON file with the same stem and the .card.json suffix.

spacr.deep_spacr.register_model_card(model_path, card, *, project=None, registry=None, inputs=(), run_id='')[source]

Register the checkpoint and its card in the artifact registry.

Registering the weights with the card as extra — rather than only dropping a JSON file next to them — is what makes the provenance real: the row carries the content fingerprint of the .pth, the settings hash, the spaCR version and the ids of the artifacts it was derived from, so “is this model stale?” has an answer that a hand-written note cannot give.

Parameters:
Returns:

the stored spacr.artifacts.Artifact, or None when the registry could not be written (a card on disk is still worth having, so this never raises the run down).

spacr.deep_spacr.resolve_class_balance_loss(loss_type, class_balance, num_classes)[source]

Translate class_balance='weighted_loss' into a concrete loss type.

The weighted losses already exist in spacr.utils.build_loss(); this only steers to them, so nothing about the loss maths changes here.

Parameters:
  • loss_type – the loss the user asked for.

  • class_balance – one of spacr.io.CLASS_BALANCE_MODES.

  • num_classes – size of the classifier head.

Returns:

(loss_type, message) — message is ‘’ when nothing changed.

spacr.deep_spacr.resolve_mixed_precision(asked, device)[source]

(on, note). Whether to train in half precision on THIS machine.

WHY IT IS WORTH HAVING. The forward pass and the loss run in float16 while the weights and the optimiser stay in float32. Measured on an RTX 3090 over 30 training steps after 5 warm-up, at 224 px (bench_amp.py in the GPU queue folder reproduces it):

model

speedup

peak memory

resnet50, batch 32

1.77x

0.58x

resnet50, batch 64

1.78x

0.55x

maxvit_t, batch 16

1.62x

0.60x

vit_b_16, batch 32

2.46x

0.67x

Half the memory is not a nicety on a screen: it is the difference between a batch of 32 and a batch of 64 at the same crop size.

CUDA ONLY, AND SAID SO. torch.autocast accepts a CPU device type and bfloat16, but on the CPUs spaCR runs on it is slower rather than faster, so asking for it there is answered rather than obeyed.

Parameters:
  • asked – what the amp setting says.

  • device – the device training will actually run on.

Returns:

(on, note) – the note is ‘’ when nothing needs saying.

spacr.deep_spacr.save_top_class_examples(df, tar_path, dst, n=20, classes=None)[source]

Extract the n most confident images per class from a tar into class-labelled folders.

For binary classification, class 0 keeps the lowest pred scores and class 1 keeps the highest. Multiclass output is ranked using the corresponding prob_class_<index> column.

Parameters:
  • df – DataFrame with columns path (tar member name) and pred (probability). Multiclass results also contain predicted_label and one prob_class_<index> column per class.

  • tar_path – Tar archive containing the images.

  • dst – Output root; dst/class_<label>/ subfolders are created.

  • n – Number of images to keep per class. Default 20.

  • classes – Optional display labels, in model-output order. When omitted, multiclass labels are inferred from the probability columns; binary output defaults to [0, 1].

Returns:

dst — for chaining.

spacr.deep_spacr.summarize_cv_metrics(fold_df, metric_keys=None)[source]

Reduce per-fold metrics to mean plus the spread around it.

The spread is the whole point of k-fold: a single split can be lucky, and only the fold-to-fold standard deviation and range say by how much.

Parameters:
  • fold_df – DataFrame with one row per fold.

  • metric_keys – metric columns to summarise. Defaults to CV_METRIC_KEYS intersected with the columns present.

Returns:

DataFrame indexed by metric with n_folds, mean, std, min, max, range and cv_percent columns.

spacr.deep_spacr.test_model_core(model, loader, loader_name, epoch, loss_type)[source]

Core test loop over loader, compatible with binary & multiclass.

Parameters:
  • model – PyTorch classifier. Mutated in place: left in eval mode and moved to CUDA whenever one is visible.

  • loader – DataLoader yielding (data, target, filenames) — a two-item batch raises. The third item is copied into the frame verbatim, so a tensor of ids stays a tensor rather than becoming a path. An empty loader takes the binary branch whatever the head is: num_classes 2, accuracy NaN, loss 0.0 and a class_1_probability column.

  • epoch – Recorded as int(epoch) and used for nothing else, so 2.7 lands as 2 and None raises TypeError.

  • loader_name – Accepted and ignored; no line of the body reads it.

  • loss_type – Accepted and ignored. The loss is always spacr.utils.calculate_loss() with prefer_focal=True (gamma 2.0, alpha 1.0), so the reported loss is a focal loss and is not on the same scale as the train/validation loss that loss_type selected — for the same logits it read 0.49 where plain cross-entropy read 0.95.

Returns:

the 4-tuple (metrics, probs, labels, results_df). metrics is the summary dict, with loss, epoch and Accuracy added. probs is shape (N,) for a single-logit head and (N, C) otherwise. labels is the list of true class ids. results_df holds one row per image with filename, true_label, predicted_label and either class_1_probability (single-logit head) or one prob_class_<k> column per class. predicted_label thresholds a single-logit head at 0.5, not at the optimal_threshold the metrics report.

Raises:

ValueError – when a batch does not unpack into three items.

spacr.deep_spacr.test_model_performance(loaders, model, loader_name_list, epoch, loss_type)[source]

Evaluate model on a single loader and report the metrics as a frame.

Thin wrapper around test_model_core(), kept for API compatibility.

Parameters:
  • loaders – One DataLoader despite the plural name; passed straight through as the loader of test_model_core().

  • model – PyTorch classifier; the inner call leaves it in eval mode on the evaluation device.

  • loader_name_list – Forwarded to test_model_core, which ignores it — no value of this changes the result.

  • epoch – Copied into the summary row as int(epoch).

  • loss_type – Forwarded and likewise ignored; the reported loss is the focal loss test_model_core always computes, not this one.

Returns:

(summary_metrics_dataframe, per_file_results_dataframe) — the first is the one-row frame of summary metrics, the second holds one row per image. per_class_accuracy and class_support are list-valued cells in that one row, which reach a CSV as their repr.

spacr.deep_spacr.train_model(src, dst, model_type, train_loaders, epochs=100, learning_rate=0.0001, weight_decay=0.05, amsgrad=False, optimizer_type='adamw', use_checkpoint=False, dropout_rate=0, n_jobs=20, val_loaders=None, test_loaders=None, init_weights='imagenet', intermedeate_save=None, chan_dict=None, schedule=None, loss_type='auto', gradient_accumulation=False, gradient_accumulation_steps=4, channels=None, verbose=False, num_classes=2, image_size=224, plot=False, tensorboard=True, early_stopping_patience=0, custom_model_path=None, resume_checkpoint=None, preprocessing=None, classes=None, label_smoothing=0.1, focal_gamma=2.0, focal_alpha=None, logit_adjust_tau=1.0, settings=None, split_rule='', write_card=True)[source]

Train a classifier and return it together with its checkpoint path.

Supports 2-class and >2-class heads via CrossEntropy and a single-logit head via BCE; the loss itself is built by spacr.utils.build_loss().

Parameters:
  • src – Dataset root. When <src>/train exists, its subfolder names become the class list and override classes.

  • dst – Output folder for checkpoints, progress CSVs and TensorBoard logs.

  • model_type – Architecture name passed to spacr.utils.choose_model().

  • train_loaders – DataLoader yielding (data, target, filenames).

  • epochs – Final epoch number to train through. Default 100.

  • learning_rate – Optimizer learning rate. Default 0.0001.

  • weight_decay – Optimizer weight decay. Default 0.05.

  • amsgrad – AMSGrad variant, honoured by adamw and adam only.

  • optimizer_type – One of 'adamw', 'adam', 'adamax', 'adagrad', 'adadelta', 'asgd', 'sgd', 'rmsprop', 'nadam', 'radam'. Default 'adamw'.

  • use_checkpoint – Enable gradient checkpointing in the architecture.

  • dropout_rate – Dropout rate passed to the architecture.

  • n_jobs – Unused; accepted for call-site compatibility.

  • val_loaders – Validation loader driving best-checkpoint selection and early stopping. Without one, training accuracy is used instead.

  • test_loaders – Only its batch count is printed; it is not evaluated here.

  • init_weights – Pretrained-weight selection, ignored (passed as False) when custom_model_path or resume_checkpoint is set.

  • intermedeate_save – Accuracy thresholds that trigger intermediate checkpoints, forwarded to spacr.io._save_model().

  • chan_dict – Unused; accepted for call-site compatibility.

  • schedule – None, 'step_lr', 'reduce_lr_on_plateau', 'cosine', 'cosine_warm_restarts', 'exponential' or 'linear'.

  • loss_type – Loss identifier passed to spacr.utils.build_loss(); 'auto' picks one from the head.

  • gradient_accumulation – Accumulate gradients over several batches.

  • gradient_accumulation_steps – Batches per optimizer step when gradient_accumulation is on. Default 4.

  • channels – Channel names recorded with the checkpoint. Default ['r', 'g', 'b'].

  • verbose – Verbose architecture construction.

  • num_classes – Size of the classifier head; 1 selects the binary BCE path. Default 2.

  • image_size – Square input size in pixels. Default 224.

  • plot – Refresh a live training-curve figure after every epoch.

  • tensorboard – Write TensorBoard event files into dst.

  • early_stopping_patience – Number of epochs with no val improvement before stopping. Set to 0 to disable (original behavior).

  • custom_model_path – Checkpoint whose weights are fine-tuned.

  • resume_checkpoint – spaCR training artifact whose weights, optimizer, scheduler and epoch counter are restored.

  • preprocessing – Preprocessing description stored in the checkpoint.

  • classes – Class names, used when <src>/train does not exist.

  • label_smoothing – Label-smoothing epsilon for the smoothed losses. Default 0.1.

  • focal_gamma – Focal-loss focusing parameter. Default 2.0.

  • focal_alpha – Focal-loss class-balancing factor.

  • logit_adjust_tau – Strength of the logit adjustment; 0 disables it. Default 1.0.

  • settings – the run’s settings dict, recorded (hashed) in the model card.

  • split_rule – how the held-out set was drawn, in words, for the card.

  • write_card – write <model>.card.json beside the weights and register it as an artifact. On by default: an uncarded checkpoint is a file nobody can audit six months later.

Returns:

(model, model_path) — the trained model and the best checkpoint, which on a resumed run where no epoch beat the restored best metric is resume_checkpoint itself, or (None, None) when model_type could not be built.

Raises:
  • ValueError – on an unknown optimizer_type, a checkpoint whose class count differs from num_classes, a resume_checkpoint carrying no optimizer state, or a checkpoint that already completed epochs.

  • FileNotFoundError – if custom_model_path or resume_checkpoint does not exist.

spacr.deep_spacr.train_test_model(settings)[source]

Train a vision classifier on a spacr training dataset and/or evaluate it on the held-out test/ split.

Given a dataset folder src laid out as train/<class>/*.png and test/<class>/*.png (as produced by spacr.io.generate_dataset()), this function optionally trains a torchvision-style model (model_type), then optionally scores the test split and copies misclassified images into a review folder. Best-checkpoint selection is automatic when train=False and test=True.

Parameters:

settings –

Settings dict, canonicalized via spacr.settings.get_train_test_model_settings(). Key entries:

  • src — dataset root containing train/ and test/.

  • model_type — e.g. 'maxvit_t', 'resnet50'.

  • classes — list of class names, must match subfolder names.

  • epochs, batch_size, learning_rate, weight_decay.

  • image_size, train_channels (e.g. ['r','g','b']), normalize ([low, high] percentiles).

  • val_split — fraction pulled from train/ for validation.

  • loss_type — 'auto', 'cross_entropy', 'binary_cross_entropy_with_logits'.

  • train / test — flip the two halves of the pipeline.

  • cross_validation_enabled / cross_validation_folds — train with k-fold cross-validation over train/ instead of a single validation split (enabling it with fewer than 2 folds uses 5, and 1 fold falls back to the single split); cv_group_by names the grouping level used for the folds and the leakage audits.

  • augment, dropout_rate, optimizer_type, early_stopping_patience, n_jobs, pin_memory.

Returns:

When train=True, the path to the saved best model — or, in cross-validation mode, the path to the per-fold metrics CSV, since there is no single model; None if model_type could not be built. When train=False and test=True, the path to the test-result CSV.

Raises:

ValueError – if settings['classes'] is missing or empty.

Example

from spacr.deep_spacr import train_test_model
settings = {
    'src': '/data/dataset_v1',
    'model_type': 'maxvit_t', 'classes': ['neg', 'pos'],
    'epochs': 25, 'batch_size': 32, 'learning_rate': 1e-4,
    'image_size': 224, 'train_channels': ['r','g','b'],
    'train': True, 'test': True,
}
model_path = train_test_model(settings)

See also

spacr.deep_spacr.deep_spacr() — full end-to-end training + activation-map pipeline. spacr.io.generate_dataset() — build the train//test/ folder tree.

spacr.deep_spacr.visualize_classes(model, dtype, class_names, **kwargs)[source]

Show one synthesised class-visualisation image for class 0 and class 1.

The loop is hard-coded to the first two classes, so a model with more than two classes has only those two visualised.

Parameters:
  • model – Trained classifier.

  • dtype – Tensor dtype used for optimisation.

  • class_names – Ordered class names; at least two are required, since indices 0 and 1 are both looked up.

  • kwargs – Extra keyword arguments forwarded to utils.class_visualization.

Returns:

None

spacr.deep_spacr.visualize_integrated_gradients(src, model_path, target_label_idx=0, image_size=224, channels=None, normalize=True, save_integrated_grads=False, save_dir='integrated_grads')[source]

Compute and plot Integrated Gradients maps for every PNG under src.

Parameters:
  • src – Folder of PNG images.

  • model_path – Path to the trained model checkpoint.

  • target_label_idx – Target class index for the attribution. Default 0.

  • image_size – Square input size in pixels. Default 224.

  • channels – Channel subset to keep. Default [1, 2, 3].

  • normalize – Apply per-channel normalisation. Default True.

  • save_integrated_grads – If True, save each map as PNG. Default False.

  • save_dir – Output folder for saved maps. Default 'integrated_grads'.

Returns:

None

spacr.deep_spacr.visualize_smooth_grad(src, model_path, target_label_idx, image_size=224, channels=None, normalize=True, save_smooth_grad=False, save_dir='smooth_grad')[source]

Compute and plot SmoothGrad maps for every PNG under src.

Parameters:
  • src – Folder of PNG images.

  • model_path – Path to the trained model checkpoint.

  • target_label_idx – Target class index for the attribution.

  • image_size – Square input size in pixels. Default 224.

  • channels – Channel subset to keep. Default [1, 2, 3].

  • normalize – Apply per-channel normalisation. Default True.

  • save_smooth_grad – If True, save each map as PNG. Default False.

  • save_dir – Output folder for saved maps. Default 'smooth_grad'.

Returns:

None

spacr.deep_spacr.write_model_card(model_path, card, *, markdown=True)[source]

Write card beside model_path; return the JSON card’s path.

Parameters:
  • model_path – the checkpoint the card belongs to.

  • card – a build_model_card() dict.

  • markdown – also write the Markdown twin.

Returns:

absolute path of the .card.json.

Nested helpers

_VirtualStainUNet.__init__.block(cin, cout)

Two convolution, normalisation and ReLU layers.

spacr/deep_spacr.py:4292

_cross_validate_model._fit_one(train_loader, validation_loader, destination)

Train one fold model with a validation set not used for final scoring.

spacr/deep_spacr.py:1242

_cross_validate_model._inner_loader(indices, *, training)

Build one inner loader from global indexes into the base dataset.

spacr/deep_spacr.py:1304

_cross_validate_model._metrics_for_probabilities(labels, probabilities)

Compute legacy fold metrics for an ensemble probability matrix.

spacr/deep_spacr.py:1289

_flowview_pipeline.decorate(function)

Return a wrapper that reports function lifecycle for family.

spacr/deep_spacr.py:74

_flowview_pipeline.decorate.observed(*args, **kwargs)

Call the pipeline, preserving its result or error while tracing lifecycle.

spacr/deep_spacr.py:77

_vs_cellpose_segment.segment(plane)

Segment one 0-1 plane with Cellpose.

spacr/deep_spacr.py:4542

annotate_filter_vision.filter_csv_by_png(csv_file)

Return a DataFrame with rows matching any PNG in the sibling training/train folders removed.

Parameters:

csv_file – Path to the score CSV.

Returns:

Filtered DataFrame.

spacr/deep_spacr.py:4144

model_fusion.combine_tensors(tensor_list, mode='mean')

Given a list of Tensors, combine them using the chosen aggregator.

spacr/deep_spacr.py:4078