File size: 7,312 Bytes
b64c182 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | ---
license: cc-by-nc-sa-4.0
library_name: nnunetv2
pipeline_tag: image-segmentation
tags:
- biology
- microscopy
- cell-segmentation
- microridge
- nnunet
- zebrafish
---
# MicroridgeVectorAI β v3
A 2D nnU-Net that segments **actin microridges**, **cell regions** and **cell
membranes** in projected single-channel microscopy of epithelial tissue.
Companion application: <https://github.com/LBK888/MicroridgeVectorAI> (CellVector,
AGPL-3.0). The model runs standalone with nnU-Net v2 alone β CellVector is not
required.
| | |
|---|---|
| Model id | `a619b15c-e00f-489b-887c-6386e3836c11` |
| Task | 2D semantic segmentation, 4 classes |
| Architecture | nnU-Net v2 PlainConvUNet, 8 stages, patch 512x512 |
| Trainer / folds | `nnUNetTrainer_100epochs`, fold 0 |
| Input | single-channel 2D image, any size |
| Snapshot hash | `dbe134f83c52b8ecae6cb62182310205496497ec297406ed8a2c912b60ba8cc9` |
| Label policy | `membrane-first-v2`, membrane 3 px, microridge 5 px |
Labels: `0` background, `1` cell_region, `2` cell_membrane, `3` microridge.
## Scores
Frozen test β 36 tiles from **3 fields the model never saw**. Splits are grouped
by source field, so no tile of a training field appears in the test set.
| Metric | Value | v2 |
|---|---|---|
| cell_region Dice | 0.943 | 0.944 |
| cell_membrane Dice | **0.707** | 0.471 |
| cell_membrane boundary F1 (1 px tolerance) | **0.874** | 0.659 |
| microridge Dice | 0.852 | 0.877 |
| microridge precision / recall | 0.899 / 0.822 | 0.911 / 0.855 |
| microridge skeleton length error | 0.105 | 0.100 |
nnU-Net's own fold-0 validation (89 tiles): cell_region 0.964, cell_membrane
0.696, microridge 0.886.
v2 was trained on labels in which the microridge class had erased 69.6% of the
membrane: classes are mutually exclusive and microridges were stroked last, so a
ridge running beside a cell edge overwrote it. v3 reverses that contest. The
membrane keeps all of its pixels and the microridge class yields 7.2% of its
own, which it can afford at a quarter of the frame. Nothing else changed β same
data, same architecture, same 100 epochs.
**Reading the membrane number.** Dice on a 3-pixel line covering under 3% of the
frame collapses when a prediction is offset by a pixel even where it follows the
right path, so it understates a thin structure. The boundary F1 of 0.874, which
allows one pixel of tolerance, is the more informative figure; the gap between
0.707 and 0.874 is the residual sub-pixel offset, not missing membrane.
## Limitations
- **Cell instances are approximate.** Cells are recovered as connected
components separated by the predicted membrane. On a frozen-test tile holding
10 cells this returns 9, against 1 for v2, whose membrane was too broken to
separate anything. Expect near-misses where the membrane is faint, not exact
instance segmentation.
- **The ground truth was not human-reviewed.** Labels were imported from
published raster masks and corrected only for import artifacts, not by an
expert. Treat this model as a proposal generator to be corrected, which is how
the companion application uses it.
- **Trained on 13 fields.** Train and validation loss diverge (-0.782 vs
-0.636), which is what a small number of independent acquisitions looks like.
More fields will help more than more epochs.
- **One fold, not an ensemble.** Only fold 0 was trained.
- Validated on zebrafish periderm-style epithelial microridge imagery. Behaviour
on other tissue, magnification or modality is unknown.
## Training data
Wide-field frames cut into 477 tiles of at most 512x512 from 19 fields, keeping
only regions whose raster truth is trustworthy. Uneven illumination leaves part
of such a frame too dark for the upstream segmentation to resolve anything, and
that failure is silent β the skeleton mask is empty while the cell mask still
looks complete. Blocks were kept only where skeleton density cleared both an
absolute floor and a share of the frame's own 90th percentile, **and** at least
95% of the block was attributed to a cell. 68.3% of the field pixels survived.
Labels were rasterized from vector geometry with a 3 px membrane and a 5 px
microridge stroke.
## Files
```text
registry.json provenance record, metrics, checksums
nnUNet_results/Dataset503_MicroridgeMembraneFirst/
ββ nnUNetTrainer_100epochs__nnUNetPlans__2d/
ββ dataset.json channel names and label map
ββ plans.json preprocessing and architecture
ββ fold_0/checkpoint_final.pth weights
```
Those three files under the trainer folder are the complete inference set. The
directory names encode the configuration β nnU-Net parses
`Dataset<ID>_<name>/<trainer>__<plans>__<configuration>` β so do not rename them.
The checkpoint is shipped unmodified so the `checkpoint_sha256` in
`registry.json` verifies. About half of it is optimizer state; stripping to
`network_weights`, `init_args`, `trainer_name` and
`inference_allowed_mirroring_axes` halves the size but invalidates that
checksum.
## Usage
```bash
pip install nnunetv2 huggingface_hub
hf download leobk/MicroridgeVectorAI --local-dir microridge-model
```
```python
import torch, numpy as np, tifffile
from nnunetv2.inference.predict_from_raw_data import nnUNetPredictor
MODEL = ("microridge-model/nnUNet_results/Dataset503_MicroridgeMembraneFirst"
"/nnUNetTrainer_100epochs__nnUNetPlans__2d")
predictor = nnUNetPredictor(device=torch.device("cuda"))
predictor.initialize_from_trained_model_folder(
MODEL, use_folds=(0,), checkpoint_name="checkpoint_final.pth"
)
image = tifffile.imread("frame.tif").astype("float32")
segmentation = predictor.predict_single_npy_array(
image[None, None], {"spacing": (999.0, 1.0, 1.0)}, None, None, False
)
```
No nnU-Net environment variables are needed for this path. Roughly 13 s for a
512x512 tile on an RTX 4080 SUPER.
### Reimplementing the pipeline
The network takes `(1, 1, H, W)` and returns 4 logit channels, and exports to
TorchScript. If you drive it yourself, reproduce all of:
- **Normalization** β z-score using *each image's own* mean and standard
deviation (`use_mask_for_norm=False`). No dataset statistics;
`foreground_intensity_properties_per_channel` in `plans.json` is for CT
normalization and unused here.
- **Sliding window** β 512x512 patches, step 0.5, Gaussian-weighted overlap.
- **Test-time augmentation** β mirroring over axes `(0, 1)`.
- **Output** β argmax over the 4 channels.
Skipping the normalization or the Gaussian window degrades results noticeably
and without any error.
## Licensing note
These weights are released under **CC BY-NC-SA 4.0**: attribution required,
**non-commercial use only**, derivatives under the same terms. Note that this
differs from the companion application's code licence (AGPL-3.0) β the code and
the weights are covered separately.
The weights were trained on third-party imagery; if that source data carries its
own terms, they may constrain redistribution of this model independently of this
label.
|