Likelihoods¶
Observation-noise models for the Tier I likelihoods: GaussianNoise (the default, today's numbers), StudentTNoise for heavy-tailed retrievals near the detection floor, and HeteroscedasticNoise for a per-pixel retrieval-error map. Pass one as noise= to the plume and puff inference models; log_prob gives the same likelihood in plain JAX for a training loss. Tier I.
likelihoods
¶
Observation-noise models for the Tier I likelihoods (implementation in plumax.gauss_plume._src.likelihoods).
GaussianNoise
¶
Bases: Noise
Homoscedastic Gaussian noise, ε ~ 𝒩(0, σ²).
log p(y | ŷ) = −½ ((y − ŷ)/σ)² − log σ − ½ log 2π.
The Tier I models default to this with σ = obs_noise_std, so their
numbers are unchanged.
Attributes:
| Name | Type | Description |
|---|---|---|
std |
float | Float[Array, '*#obs']
|
Noise standard deviation σ > 0, in the units of y; a scalar or an array that broadcasts against the observations. |
Raises:
| Type | Description |
|---|---|
ParameterError
|
If |
Examples:
The log-density at the mean of a unit Gaussian is −½ log 2π:
>>> import jax.numpy as jnp
>>> noise = GaussianNoise(std=1.0)
>>> value = noise.log_prob(jnp.zeros(3), jnp.zeros(3))
>>> value.shape
(3,)
>>> bool(jnp.allclose(value, -0.5 * jnp.log(2.0 * jnp.pi)))
True
A non-positive scale is rejected:
>>> GaussianNoise(std=0.0)
Traceback (most recent call last):
...
ParameterError: std must be > 0, got 0.0
HeteroscedasticNoise
¶
Bases: Noise
Per-observation Gaussian noise, ε_i ~ 𝒩(0, σ_i²), from a retrieval-error map.
log p(y_i | ŷ_i) = −½ ((y_i − ŷ_i)/σ_i)² − log σ_i − ½ log 2π.
Unlike :class:GaussianNoise, σ must give one value per observation, and
a mismatch with the observations is an error rather than a broadcast.
Attributes:
| Name | Type | Description |
|---|---|---|
std |
Float[Array, ' obs']
|
Per-observation standard deviation σ_i > 0, in the units of y. |
Raises:
| Type | Description |
|---|---|
ParameterError
|
If any |
Examples:
Doubling σ_i halves the weight of a residual:
>>> import jax.numpy as jnp
>>> noise = HeteroscedasticNoise(std=jnp.array([1.0, 2.0]))
>>> value = noise.log_prob(jnp.array([2.0, 4.0]), jnp.zeros(2))
>>> bool(jnp.allclose(value[0] - value[1], jnp.log(2.0)))
True
Build it from variances, e.g. Instrument.observation_variance():
from_variance
classmethod
¶
The noise with σ_i = √(variance_i).
Noise
¶
Bases: Module
Observation-noise model p(y | ŷ) for a Tier I likelihood.
Subclasses define :meth:distribution (the NumPyro distribution, for
models) and :meth:log_prob (plain JAX, for losses); they must agree.
StudentTNoise
¶
Bases: Noise
Heavy-tailed Student-t noise, ε ~ t_ν(0, s), for outliers near the detection floor.
log p(y | ŷ) = log Γ((ν+1)/2) − log Γ(ν/2) − ½ log(ν π) − log s − (ν+1)/2 · log(1 + ((y − ŷ)/s)² / ν).
ν ≈ 5 is the Tier I design's default for low-SNR retrievals; as ν → ∞ it
tends to :class:GaussianNoise with σ = s.
Attributes:
| Name | Type | Description |
|---|---|---|
scale |
float | Float[Array, '*#obs']
|
Scale s > 0, in the units of y; a scalar or an array that broadcasts against the observations. The standard deviation is s √(ν/(ν − 2)) for ν > 2. |
df |
float
|
Degrees of freedom ν > 0. |
Raises:
| Type | Description |
|---|---|
ParameterError
|
If |
Examples:
A 10-scale outlier costs far less than under a Gaussian:
>>> import jax.numpy as jnp
>>> obs, mean = jnp.array([10.0]), jnp.array([0.0])
>>> student = StudentTNoise(scale=1.0).log_prob(obs, mean)
>>> gaussian = GaussianNoise(std=1.0).log_prob(obs, mean)
>>> bool(student[0] > gaussian[0] + 30.0)
True
Large ν recovers the Gaussian:
>>> near = StudentTNoise(scale=1.0, df=1.0e8).log_prob(obs, mean)
>>> bool(jnp.allclose(near, gaussian, rtol=1.0e-6))
True