ClementP commited on
Commit
65281a5
·
verified ·
1 Parent(s): 4d64525

Front page: model card of reg_upernet_convnext_t_bmlines

Browse files
Files changed (1) hide show
  1. README.md +166 -0
README.md ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ library_name: pytorch
3
+ tags:
4
+ - medical-imaging
5
+ - ophthalmology
6
+ - oct
7
+ - choroid
8
+ - image-registration
9
+ - motion-correction
10
+ - unsupervised
11
+ - video
12
+ - pytorch_model_hub_mixin
13
+ - model_hub_mixin
14
+ ---
15
+
16
+ # OCT B-scan video registration (`reg_upernet_convnext_t_bmlines`)
17
+
18
+ A learned, **fully unsupervised** registration model for OCT B-scan videos, where
19
+ one B-scan location is imaged repeatedly over time. It predicts the motion of each
20
+ frame against a reference frame:
21
+
22
+ - **`dx`:** one lateral shift per frame;
23
+ - **`dy(x)`:** one axial shift per A-scan column.
24
+
25
+ It is the second stage of the OcularRigidity pipeline (choroid segmentation, then
26
+ registration, then pulsation analysis). The registered videos are used to measure
27
+ the pulsatile choroid thickness change.
28
+
29
+ The model has no image encoder of its own. It works on the features of the
30
+ **frozen encoder of the choroid segmentation model**
31
+ [`ClementP/ChoroidSegmentationModule@version-3.0.0`](https://huggingface.co/ClementP/ChoroidSegmentationModule/tree/version-3.0.0)
32
+ (UPerNet ConvNeXt-T). The two models must be used together, at these revisions.
33
+
34
+ | | |
35
+ |---|---|
36
+ | Parameters | 4.6 M (plus the frozen 37 M segmentation model) |
37
+ | Input | Encoder feature pyramids (channels [96, 192, 384, 768]) of a fixed and a moving frame |
38
+ | Frame format | uint8, 1536 rows × 1024 columns, PLEX Elite pixel size (1.95 µm axial × 5.9 µm lateral) |
39
+ | Output | `dx` (B,) and `dy` (B, W), in pixels of the input frame |
40
+ | Checkpoint | epoch 10 of 10, step 167,360 (best validation objective) |
41
+
42
+ ## Motion convention
43
+
44
+ The warped frame is
45
+
46
+ out(x, y) = moving(x - dx, y + dy(x))
47
+
48
+ so `dy(x)` is the axial displacement of the moving frame's tissue relative to
49
+ the reference (positive means the tissue sits lower in the moving frame), and
50
+ `dx` is the lateral shift.
51
+
52
+ ## Usage
53
+
54
+ Through the OcularRigidity package. The fused pass runs the shared encoder once
55
+ per frame for both segmentation and registration:
56
+
57
+ ```python
58
+ from ocularrigidity.registration.config import RegistrationConfig
59
+ from ocularrigidity.registration.fused import segment_and_register
60
+ from ocularrigidity.segmentation.trainer.pl_module import ChoroidSegmentationModule
61
+ from ocularrigidity.registration.deep_learning.models.regressor import RegistrationRegressor
62
+
63
+ seg = ChoroidSegmentationModule.from_pretrained("ClementP/ChoroidSegmentationModule", revision="version-3.0.0").eval().cuda()
64
+ reg = RegistrationRegressor.from_pretrained("ClementP/OCTVideoRegistration", revision="reg_upernet_convnext_t_bmlines").eval().cuda()
65
+
66
+ # frames: (T, H, W) uint8 video at the PLEX pixel size (Spectralis resampled to the
67
+ # PLEX grid and padded to 1536x1024)
68
+ res = segment_and_register(frames, seg, reg, RegistrationConfig(method="learned"))
69
+ res.registered_frames # (T, H, W) uint8
70
+ res.transform["dx"] # (T,)
71
+ res.transform["dy"] # (T, W)
72
+ res.registered_masks # (T, H, W) bool, registered choroid masks
73
+ ```
74
+
75
+ **Calling the model directly:** `reg(fixed_feats, moving_feats)` takes the
76
+ encoder outputs `seg.model.encoder(x)[2:]`, with `x = (frame / 255 - 0.5) / 0.5`
77
+ of shape (B, 1, H, W).
78
+
79
+ **Reference frame:** by default it is picked automatically (the frame closest to
80
+ the median choroid area, then the motion medoid). Pass `ref_idx=` to fix it.
81
+
82
+ ## Training data
83
+
84
+ All the data is unlabelled. Each video contributes 40 frames drawn at random
85
+ without replacement, with a reproducible seed per video. For PLEX the first 20
86
+ and last 10 frames are excluded, the same trim as the pipeline; Spectralis series
87
+ are used whole:
88
+
89
+
90
+ | Device | Scan | Videos | Patients |
91
+ |---|---|---|---|
92
+ | Zeiss PLEX Elite 9000 | Macula | 400 | 338 |
93
+ | Zeiss PLEX Elite 9000 | Optic nerve head | 400 | 362 |
94
+ | Heidelberg Spectralis | Macula | 400 | 400 |
95
+
96
+ - **Total:** 1,200 videos and 48,000 frames.
97
+ - **Spectralis frames:** resampled to the PLEX grid.
98
+ - **Validation:** 5% of the videos, split by patient, with 40 pairs per video.
99
+
100
+ ## Training procedure
101
+
102
+ There are no ground-truth displacements and no classical registration targets.
103
+
104
+ **Training samples**
105
+ - **Pairs:** within-video pairs, 120 per video per epoch.
106
+ - **Triplets:** 40 per video, for cycle consistency.
107
+ - **Synthetic shifts:** 40 per video, up to ±8 px, for shift equivariance.
108
+ - **Crops:** random 768 × 512 crops.
109
+
110
+ **Objective** (weights in brackets):
111
+
112
+ | Term | Weight | What it does |
113
+ |---|---|---|
114
+ | Feature | 1.0 | Similarity of frozen encoder features after warping |
115
+ | Photometric | 1.0 | Multi-scale local normalised cross-correlation |
116
+ | Lateral | 1.0 | Lateral alignment term |
117
+ | Bruch's membrane (BM) | 0.1 | Distance between the fixed BM line and the analytically warped moving BM line |
118
+ | Smoothness | 0.05 | Penalises jumps in `dy(x)` between columns |
119
+ | Curvature | 0.02 | Penalises curvature in `dy(x)` |
120
+ | Coverage | 0.5 | Keeps the warped choroid inside the frame |
121
+ | Cycle | 0.3 | A to B to C must equal A to C on triplets |
122
+ | Shift equivariance | 1.0 | A known synthetic shift must be recovered |
123
+
124
+ The BM lines come from the segmentation model, run once on every full,
125
+ unaugmented frame and stored with the dataset. They are cropped with the same
126
+ window as the frames.
127
+
128
+ **Architecture:** a cascade of one stage per encoder level, coarse to fine. Each
129
+ stage builds a local correlation volume (±6 px axially,
130
+ ±10 steps of 8.0 px laterally) and refines the
131
+ global `dx` and the per-column `dy`. The `dy` is a bulk shift plus a
132
+ zero-mean residual. Training also uses a coarse-to-fine progress schedule.
133
+
134
+ **Optimisation**
135
+ - **Optimiser:** AdamW, learning rate 0.0005, weight decay 0.0001.
136
+ - **Batches:** batch size 4 per GPU, 10 epochs.
137
+ - **Hardware:** 2 GPUs (PyTorch Lightning DDP), bf16 encoder.
138
+
139
+ ## Evaluation
140
+
141
+ Unsupervised validation objective on held-out patients, at the released checkpoint:
142
+
143
+ | Metric | Value |
144
+ |---|---|
145
+ | Total objective | 2.327 |
146
+ | BM line error after warping | 3.59 px (about 7 µm) |
147
+ | Cycle inconsistency | 0.13 px |
148
+ | Synthetic-shift error | 0.07 px |
149
+
150
+ These are self-consistency measures, not errors against ground-truth motion,
151
+ which doesn't exist for these videos.
152
+
153
+ ## Limitations
154
+
155
+ - **Motion model:** only a global lateral shift and a per-column axial shift. No
156
+ rotation, no lateral warp within the frame, no out-of-plane motion: frames
157
+ where the eye moved out of the B-scan plane can't be corrected, only flagged.
158
+ - **Segmentation dependency:** the model is tied to the segmentation encoder it
159
+ was trained with. A different segmentation revision needs retraining.
160
+ - **Training domain:** PLEX Elite (macula and optic nerve head) and Spectralis
161
+ (macula) only.
162
+ - **Research use only.** This is not a medical device.
163
+
164
+ ## Citation
165
+
166
+ OcularRigidity (reference to come).