Skip to content

Add normalizer option to remove global mean surface temperature#1191

Closed
mcgibbon wants to merge 3 commits into
mainfrom
feature/remove-global-mean-surface-temperature-normalizer
Closed

Add normalizer option to remove global mean surface temperature#1191
mcgibbon wants to merge 3 commits into
mainfrom
feature/remove-global-mean-surface-temperature-normalizer

Conversation

@mcgibbon
Copy link
Copy Markdown
Contributor

Atmospheric warming/cooling signals show up as large temperature anomalies across many vertical levels at once. Normalizing each temperature field by its global mean leaves a slowly-varying global temperature offset embedded in every channel, which the network has to re-learn at every layer. This PR adds an opt-in normalization mode that strips the global-mean surface temperature anomaly from all temperature fields before normalization (and restores it after denormalization), so the network sees temperature gradients rather than absolute global temperatures.

The offset is computed per sample as surface_temperature_norm_mean - sample.surface_temperature.mean(spatial dims) and added to every temperature field on normalize(), then subtracted back on denormalize(). Cross-channel and horizontal gradients are preserved; only the global mean shifts. The flag is meaningful only for the network normalizer (paired normalize/denormalize); the loss normalizer always strips it because offsets computed independently from target vs. prediction inputs would not cancel cleanly.

Changes:

  • fme.core.normalizer.NormalizationConfig.remove_global_mean_surface_temperature: new opt-in bool flag (default False).

  • fme.core.normalizer.StandardNormalizer: caches the per-sample offset during normalize() and inverts it in denormalize(); raises if surface_temperature is missing from means or input tensors, or if denormalize() runs before normalize().

  • fme.core.normalizer.NetworkAndLossNormalizationConfig.get_loss_normalizer: strips the flag from the loss normalizer via the new _disable_global_mean_surface_temperature_removal helper.

  • fme.core.normalizer._GLOBAL_MEAN_SURFACE_TEMPERATURE_REFERENCE / _TEMPERATURE_FIELD_NAMES: hard-coded reference field and target field list.

  • StandardNormalizer.from_state reads the legacy use_shared_temperature_offset state-dict key as a fallback so existing checkpoints continue to load.

  • Tests added

  • If dependencies changed, "deps only" image rebuilt and "latest_deps_only_image.txt" file updated

mcgibbon and others added 2 commits May 21, 2026 21:07
Adds an opt-in flag on NormalizationConfig that, on the network normalizer
only, computes a per-sample offset from the input surface_temperature
(surface_temperature norm mean minus the sample's cell-wise mean) and adds
it to every temperature field on normalize / subtracts it on denormalize.
Preserves cross-channel and horizontal temperature gradients while pulling
the normalized surface_temperature near zero. Temperature field list is
hard-coded; the loss normalizer always strips the flag since offsets do
not cancel cleanly across separate target/prediction normalize() calls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…mperature

Renames the NormalizationConfig field and the corresponding
StandardNormalizer parameter, attribute, property, and helper for a
clearer description of what the feature does. The module-level
constant _SHARED_TEMPERATURE_OFFSET_REFERENCE becomes
_GLOBAL_MEAN_SURFACE_TEMPERATURE_REFERENCE.

StandardNormalizer.from_state still reads the legacy
"use_shared_temperature_offset" state-dict key as a fallback so
existing checkpoints continue to load.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@mcgibbon
Copy link
Copy Markdown
Contributor Author

I'm still not sure the normalization is the right place for the code, as I'm wondering if I should add the global mean surface temperature back in as a separate (constant) field, and the normalizer wouldn't be the right level to do that.

@mcgibbon
Copy link
Copy Markdown
Contributor Author

Superceded by #1193.

@mcgibbon mcgibbon closed this May 27, 2026
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.

1 participant