Skip to content

Gated fusion, feature normalisation, and MAPE metric - to help CY use case#81

Merged
gabrieletijunaityte merged 3 commits into
developfrom
feature/cy-encoder-metrics
Apr 16, 2026
Merged

Gated fusion, feature normalisation, and MAPE metric - to help CY use case#81
gabrieletijunaityte merged 3 commits into
developfrom
feature/cy-encoder-metrics

Conversation

@robknapen

Copy link
Copy Markdown
Collaborator

What does this PR do?

Gated fusion, feature normalisation, and MAPE metric. These implementations are relevant to the crop yield use case. Adding (learnable) gated fusion between encoder branches is more generally usable.

Implementations

  • Gated fusion strategy in EncoderWrapper: Adds a "gated" option alongside "mean", "concat", and "none". Each branch gets a learnable scalar gate logit; at forward time these are softmax-normalised into weights and used to compute a weighted sum of branch embeddings. Requires all branches to have equal output dimensions — use per-branch projectors to align if needed. Gate logits initialise to zero (uniform weights).
  • Per-branch LayerNorm in EncoderWrapper: A LayerNorm is applied after each encoder (+projector) output before fusion. TabularEncoder branches are exempt since they already end with LayerNorm internally.
  • Feature normalisation in TabularEncoder: Registers feat_mean/feat_std as buffers (auto-move to device). When set via set_normalisation_stats(), z-scores inputs in forward(). Stats are populated automatically from BaseDataModule.tabular_normalisation_stats in PredictiveModel.setup().
  • Target standardisation in PredictiveModel: New standardize_targets flag (default False). When enabled, targets are z-scored before the loss and predictions are de-standardised before metrics, so all logged metrics remain in original target units. Stats come from BaseDataModule.target_normalisation_stats.
  • MAPE metric: New src/models/components/metrics/mape.py — epoch-level MAPE using torchmetrics.MeanAbsolutePercentageError with a separate accumulator per mode (train/val/test).
  • RSquared defensive null-check: Guards against batch=None before calling .get("target"), now raises an explicit ValueError instead of an AttributeError.

Tests

  • tests/test_gated_fusion_encoder.py: covers output shape, gate logit learnability, uniform initialisation, single-branch edge case, mismatched-dimension error, TabularEncoder integration, and that concat strategy is unaffected.

Before submitting

  • Did you make sure title is self-explanatory and the description concisely explains the PR?
  • Did you make sure your PR does only one thing, instead of bundling different changes together?
  • Did you list all the breaking changes introduced by this pull request?
  • Did you test your PR locally with pytest command?

@robknapen robknapen linked an issue Apr 15, 2026 that may be closed by this pull request

@gabrieletijunaityte gabrieletijunaityte left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, and thank you for including tests.

I think this will be a bit more difficult to merge, because I have made changes to the setup() function, and we were missing an extra_projector forward pass in geo_encoders. Could you have a look?

@robknapen

Copy link
Copy Markdown
Collaborator Author

I have merged it, and pytest was happy (no failures with the "no slow" selection). But did not yet run any hydra experiments with the updated code.

The gated fusion implemented is also a simple version using global fixed weights. More dynamic / complex versions are also possible and can be considered.

@gabrieletijunaityte gabrieletijunaityte left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@gabrieletijunaityte gabrieletijunaityte merged commit 4de6b4d into develop Apr 16, 2026
4 checks passed
@robknapen

Copy link
Copy Markdown
Collaborator Author

You're welcome :)

@robknapen robknapen deleted the feature/cy-encoder-metrics branch April 16, 2026 14:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a gated fusion strategy to encoder_wrapper

2 participants