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().