Source code for physicsnemo.diffusion.noise_schedulers.edm_log_uniform
# SPDX-FileCopyrightText: Copyright (c) 2023 - 2026 NVIDIA CORPORATION & AFFILIATES.
# SPDX-FileCopyrightText: All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""EDM noise scheduler with log-uniform time sampling."""
import math
import torch
from jaxtyping import Float
from torch import Tensor
from .edm import EDMNoiseScheduler
[docs]
class EDMLogUniformNoiseScheduler(EDMNoiseScheduler):
r"""
EDM noise scheduler with log-uniform sigma sampling for training.
Inherits time-step generation, noise addition, and loss weighting from
:class:`EDMNoiseScheduler`. The only difference is the training-time
sampling strategy: instead of drawing :math:`\ln(\sigma)` from a normal
distribution, this scheduler draws :math:`\sigma` *uniformly in
log-space* between ``sigma_min`` and ``sigma_max``:
.. math::
\ln(\sigma) \sim \mathcal{U}\!\bigl[\ln(\sigma_{\min}),\;
\ln(\sigma_{\max})\bigr]
This can be preferable when the useful noise range is well characterised
and you want equal probability density across the full range in log-space.
Parameters
----------
sigma_min : float, optional
Minimum noise level, by default 0.002.
sigma_max : float, optional
Maximum noise level, by default 80.
rho : float, optional
Exponent controlling time-step spacing. By default 7.
sigma_data : float or Tensor, optional
Expected standard deviation of the training data, by default 0.5.
Accepts per-channel values; see :class:`EDMNoiseScheduler`.
Examples
--------
>>> import torch
>>> from physicsnemo.diffusion.noise_schedulers import (
... EDMLogUniformNoiseScheduler,
... )
>>>
>>> scheduler = EDMLogUniformNoiseScheduler(sigma_min=0.002, sigma_max=80.0)
>>> t = scheduler.sample_time(8)
>>> t.shape
torch.Size([8])
>>> ((t >= 0.002).all() and (t <= 80.0).all()).item()
True
Per-channel ``sigma_data`` works the same as :class:`EDMNoiseScheduler`:
>>> scheduler_ch = EDMLogUniformNoiseScheduler(
... sigma_data=torch.tensor([0.3, 0.5, 0.7])
... )
>>> w = scheduler_ch.loss_weight(t)
>>> w.shape
torch.Size([8, 3])
"""
def __init__(
self,
sigma_min: float = 0.002,
sigma_max: float = 80.0,
rho: float = 7.0,
sigma_data: float | Float[Tensor, " C"] = 0.5,
) -> None:
super().__init__(
sigma_min=sigma_min,
sigma_max=sigma_max,
rho=rho,
sigma_data=sigma_data,
)
[docs]
def sample_time(
self,
N: int,
*,
device: torch.device | None = None,
dtype: torch.dtype | None = None,
) -> Float[Tensor, " N"]:
r"""
Sample N diffusion times uniformly in log-space:
:math:`\ln(\sigma) \sim \mathcal{U}[\ln(\sigma_{\min}),
\ln(\sigma_{\max})]`.
Parameters
----------
N : int
Number of time values to sample.
device : torch.device, optional
Device to place the tensor on.
dtype : torch.dtype, optional
Data type of the tensor.
Returns
-------
Tensor
Sampled diffusion times of shape :math:`(N,)`.
"""
u = torch.rand(N, device=device, dtype=dtype)
log_min = math.log(self.sigma_min)
log_max = math.log(self.sigma_max)
return (log_min + u * (log_max - log_min)).exp()