TSRDA / visuals /finetuning_walkthrough_transcript.md
Dhruv1000's picture
Explain pretrained-to-finetuned lineage with detailed architecture and animated code walkthrough
e926596 verified
|
Raw History Blame Contribute Delete
10.8 kB
# Animation transcript
All animated arrows are schematic. Scores are historical measurements, not simulated training curves.
## 1. Read the unlabeled satellite sequence
**Stage:** Pretraining. 496 fold5 patches; crop labels are not loaded.
- **PASTISPatchDataset:** load_target=False; normalize ten bands
- **Sixteen fixed tiles:** 4×4 grid; each tile is32×32
- **Separate crop updates:** Batch4; 1,984 optimizer steps/epoch
Pretraining learns a representation of spectral and temporal structure. It does not directly learn the eighteen crop labels.
Code: `pretrain.py: main() → dataset.py: crop_ij()`.
## 2. Mask eligible observations
**Stage:** Pretraining. Historical NDVI-style frame gate, calculated on normalized bands.
- **Eligibility gate:** NDVI index6/2 >0.2; vegetation fraction >0.9
- **Random spatial mask:** Nominal40% masking in eligible frames
- **Learned mask token:** Same pixel mask spans all ten spectral bands
Frames failing the gate remain visible. Controlled pilots found roughly3% effective masking; nominal40% is not whole-dataset coverage.
Code: `model.py: UTAEPrediction.forward()`.
## 3. Reconstruct the hidden spectral values
**Stage:** Pretraining. The encoder sees corrupted inputs and predicts original ten-band values.
- **Spatial encoder:** Full-resolution convolutions + ASPP + SE
- **Temporal encoder:** Three reduced dual-attention blocks
- **Reconstruction head:** Linear256→10 at every pixel and time
Masked-value mean-squared error supplies the gradients. The auxiliary reconstruction head exists, but DEEP_SUP=False disables its extra loss.
Code: `UTAE_ASPP.forward() → UTAEPrediction.forward()`.
## 4. Save the encoder checkpoint
**Stage:** Pretraining. The supplied encoder artifact records epoch99.
- **latest.tar:** Full wrapper + optimizer/scaler/RNG state
- **latest.utae.tar:** Encoder weights only
- **Transferable representation:** Original pretrained folder retained untouched
We used the supplied pretrained artifact. This animation is not a claim that its original100-epoch pretraining was rerun in this session.
Code: `pretrain.py: main() → torch.save()`.
## 5. Load your encoder; attach the supervised task
**Stage:** Fine-tuning. Reconstruction heads are replaced by a segmentation wrapper.
- **Strict encoder load:** Reuse spatial + temporal pretrained weights
- **Fresh supervised layers:** STA, semantic, boundary, gated refinement
- **Train the complete model:** Encoder and new layers both receive gradients
At the original supervised start, the task layers are new. Later continuation stages load the entire selected fine-tuned model, including its heads.
Code: `train_spatial_temporal.py: main() / --init_finetuned`.
## 6. Keep the labeled sampling protocol fixed
**Stage:** Fine-tuning. Training fold1:76 entries /72 unique; validation fold2:76/71.
- **Batch of2 patches:** X:2×T×10×128×128; preserve duplicate IDs
- **Two fixed diagonal crops:** [0:32,0:32] and [32:64,32:64]
- **76 updates per epoch:** 38 batches ×2 separate crop steps
Training transforms operate inside these selected windows. Validation uses the same fixed windows without those random transformations.
Code: `dataset.py: pad_collate(), crop_ij()`.
## 7. Apply the recorded training transforms
**Stage:** Fine-tuning. Augmentations are method-specific; sample IDs and crop windows stay fixed.
- **Spatial transform:** Paired flips /90-degree rotations of X and Y
- **Temporal transform:** Observation subsampling and frame dropout
- **Spectral transform:** Per-band gain/bias jitter plus noise
Subsampling keeps the retained observation positions. Label geometry follows the spatial transformation; validation and test are not augmented.
Code: `aug_dihedral(), aug_temporal_subsample(), aug_frame_dropout(), aug_spectral()`.
## 8. Extract spatial features for every acquisition
**Stage:** Fine-tuning. The spatial encoder preserves H×W instead of downsampling the crop.
- **Stem10→64:** 3×3 convolution; second convolution dilation2
- **ASPP64→256:** Dilations1/2/4 plus global pooling
- **Channel attention:** SE weighting; reshape to per-pixel sequences
Each pixel now has a256-dimensional feature vector at every acquisition. Spatial context and temporal modeling have separate roles.
Code: `AtrousSpatialEncoder.forward() / ASPP.forward()`.
## 9. Model crop evolution with temporal dual attention
**Stage:** Fine-tuning. Index positions are encoded; actual acquisition-day gaps are not used.
- **Reduced KV tokens:** 256→64; group4 observations→256
- **Two attention operations:** Reduced self-attention; full-T queries to reduced KV
- **Three residual blocks:** Eight heads; GELU + parallel depthwiseConv1D MLP
The winning backbone preserves its original padding behavior. Explicit padding-mask variants existed, but they are not the deployed encoder.
Code: `TemporalSRDABlock.forward() / TemporalSRDAEncoder.forward()`.
## 10. Collapse time and predict class / boundary outputs
**Stage:** Fine-tuning. STA pools time; three spatial convolutions refine the pooled map.
- **Learned temporal pooling:** softmax scores over T → weighted feature sum
- **Semantic + boundary heads:** 20 class logits and1 boundary logit
- **Gated refinement:** Features ×(1+sigmoid(boundary)); residual class correction
Boundary predictions directly affect the refined class logits inside the network. They are not an external mask-cleaning stage.
Code: `STA.forward() → UTAEClassificationDual.forward()`.
## 11. Compute the supervised objective
**Stage:** Fine-tuning. Two segmentation losses and auxiliary boundary supervision.
- **Semantic objective:** CE +0.75 Lovász
- **Refined objective:** CE +0.75 Lovász
- **Boundary objective:** 0.5 BCE; local max/min label-gradient target
CE/Lovász ignore GT0/19; label smoothing0.05. Boundary BCE is applied to the constructed boundary map without that foreground mask.
Code: `training_loss(), compute_boundary_target(), LovaszSoftmaxLoss.forward()`.
## 12. Backpropagate; update encoder and task layers
**Stage:** Fine-tuning. AdamW parameter groups give the encoder a lower learning rate.
- **Gradient computation:** FP16 forward + GradScaler backward
- **Stabilize the update:** Unscale gradients; clip norm5
- **Parameter update:** Encoder LR0.5×head LR; update EMA copy
Raw and EMA weights are evaluated, but the final SAM component uses the selected raw checkpoint. EMA maintenance is not proof of an EMA gain.
Code: `build_param_groups(), lr_factor(), ModelEMA.update()`.
## 13. Continue from the low-learning-rate checkpoint
**Stage:** SAM refinement. Same architecture and losses; change the optimization step.
- **Selected low-LR model:** Load encoder AND supervised heads
- **Low learning rates:** Head1e-5; encoder5e-6
- **SAM budget:** 20 epochs; radius0.02; batch2; fixed32
The SAM run starts from a previously fine-tuned checkpoint, not directly from a bare pretrained encoder. Its optimizer and schedule start fresh.
Code: `main(): --init_finetuned ... --research sam`.
## 14. First SAM pass: find a weight perturbation
**Stage:** SAM refinement. Calculate the gradient at current weights θ.
- **Loss atθ:** Forward → loss → backward
- **Normalize gradient:** g /(||g|| + epsilon)
- **Temporary perturbation:** θtemporary = θ +0.02 ×normalized gradient
This is Sharpness-Aware Minimization. No Segment Anything encoder, prompt, mask generator, or extra architecture is introduced.
Code: `train_spatial_temporal.py: main(), research==sam branch`.
## 15. Second SAM pass: restore and update
**Stage:** SAM refinement. Compute a new gradient at the temporarily perturbed weights.
- **Second loss/backward:** Same crop; BatchNorm held in eval mode
- **Restore originalθ:** Subtract stored perturbations
- **AdamW update:** Apply second-pass gradient; update scaler/EMA
Select raw epoch11 using validation. Once saved, the network needs only its ordinary forward pass at inference.
Code: `research==sam: offsets → second_loss → restore → scaler.step()`.
## 16. Freeze the SAM encoder and collect earlier features
**Stage:** Feature clusters. Reuse its first temporal block, rather than training another encoder.
- **Forward hook:** DepthCollector captures block1 output
- **Valid-time statistics:** Mean256 +standard deviation256 =vector512
- **Training normalization:** Fit mean/std on training features; then L2 normalize
The readout shares the network forward pass. Hooks summarize real features; the diagram does not visualize measured feature activations.
Code: `DepthCollector.begin(), hook(), end(); train_normalizer()`.
## 17. Fit three feature-cluster centres per crop class
**Stage:** Feature clusters. Use labeled training pixels only; no validation/test labels fit centres.
- **Balanced memory:** 32 pixels per supporting training patch/class
- **KMeans fitting:** 18 classes ×3 centres; seed3407; n_init3
- **Similarity classifier:** Similarity/0.1 → logsumexp over3 → softmax18
Repeated patch/crop occurrences are deduplicated for the memory bank only. The supervised dataset list itself retains duplicate entries.
Code: `make_prototypes() / probability()`.
## 18. Train the original independent temporal specialist
**Stage:** Temporal CNNs. A small model of each pixel’s spectral evolution, trained from scratch.
- **Input projection:** T×10 → T×64; valid-time mask
- **Four Conv1D blocks:** Kernel3; depthwise; dilation1/2/4/8
- **Mean +max classifier:** Vector128 →64 →18 crop classes
100 epochs; AdamW1e-3, WD0.01, CE smoothing0.05, warmup3/cosine. Combine25% CNN probabilities with75% SAM/cluster blend.
Code: `TemporalCNN.forward(); historical original CNN training`.
## 19. Add the new plain-CNN control
**Stage:** Temporal CNNs. A separate training run with the same architecture and seed value.
- **Matched control:** Same data, fixed32 crops,100-epoch budget
- **Distinct training trajectory:** New trainer resets RNG after model construction
- **Validation-selected blend:** 75% reference +25% new CNN probabilities
The CNN is weaker alone but changes useful class rankings. A matched attention alternative replaces mean pooling and adds65 parameters.
Code: `train_temporal_cnn.py: train(); AttentionCNN.forward()`.
## 20. Run the complete system on full128 test patches
**Stage:** Final evaluation. 482 fold4 patches; no TTA or external mask post-processing.
- **Four probability sources:** SAM /shared-feature clusters /old CNN /new CNN
- **Recommended weights:** 28.125% /28.125% /18.75% /25%
- **Final argmax +metrics:** Full20×20 matrix; score GT classes1–18
Recommended: validation52.5640%, test49.4555%. Attention alternative: validation51.8368%, highest observed test49.5298%; reported separately.
Code: `evaluate.py: load_models(), main(); metrics_cm()`.