use serde::{Deserialize, Serialize};
use crate::{Error, Result, Tensor};
use super::ops::{canonical_zero, combine};
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[serde(try_from = "NoiseLevelRepr")]
pub struct NoiseLevel {
signal_variance: f32,
}
#[derive(Deserialize)]
struct NoiseLevelRepr {
signal_variance: f32,
}
impl TryFrom<NoiseLevelRepr> for NoiseLevel {
type Error = Error;
fn try_from(repr: NoiseLevelRepr) -> Result<Self> {
Self::from_signal_variance(repr.signal_variance)
}
}
impl NoiseLevel {
pub fn from_signal_variance(signal_variance: f32) -> Result<Self> {
if !signal_variance.is_finite() || !(0.0..=1.0).contains(&signal_variance) {
return Err(Error::validation(format!(
"signal variance must be finite and in [0, 1], got {signal_variance}"
)));
}
Ok(Self {
signal_variance: canonical_zero(signal_variance),
})
}
pub fn pure_signal() -> Self {
Self {
signal_variance: 1.0,
}
}
pub fn pure_noise() -> Self {
Self {
signal_variance: 0.0,
}
}
pub fn signal_variance(&self) -> f32 {
self.signal_variance
}
pub fn signal(&self) -> f32 {
self.signal_variance.sqrt()
}
pub fn noise(&self) -> f32 {
(1.0 - self.signal_variance).sqrt()
}
pub fn diffuse(&self, x0: &Tensor, eps: &Tensor) -> Result<Tensor> {
combine(x0, eps, self.signal(), self.noise())
}
pub fn velocity_target(&self, x0: &Tensor, eps: &Tensor) -> Result<Tensor> {
combine(eps, x0, self.signal(), -self.noise())
}
pub fn signal_from_velocity(&self, x_t: &Tensor, v: &Tensor) -> Result<Tensor> {
combine(x_t, v, self.signal(), -self.noise())
}
pub fn noise_from_velocity(&self, x_t: &Tensor, v: &Tensor) -> Result<Tensor> {
combine(x_t, v, self.noise(), self.signal())
}
pub fn velocity_min_snr_weight(&self, clip: MinSnrGamma) -> f32 {
let gamma = self.signal_variance;
gamma.min(clip.get() * (1.0 - gamma))
}
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[serde(try_from = "f32")]
pub struct MinSnrGamma(f32);
impl MinSnrGamma {
pub const DEFAULT: f32 = 5.0;
pub fn new(clip: f32) -> Result<Self> {
if !clip.is_finite() || clip <= 0.0 {
return Err(Error::validation(format!(
"min-SNR gamma clip must be finite and positive, got {clip}"
)));
}
Ok(Self(clip))
}
pub fn get(self) -> f32 {
self.0
}
}
impl TryFrom<f32> for MinSnrGamma {
type Error = Error;
fn try_from(clip: f32) -> Result<Self> {
Self::new(clip)
}
}