Coverage for widitapp/diffusion/diffusion_utils.py: 100.00%
33 statements
« prev ^ index » next coverage.py v7.10.6, created at 2026-09-22 07:22 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2026-09-22 07:22 +0000
1# Modified from OpenAI's diffusion repos
2# GLIDE: https://github.com/openai/glide-text2im/blob/main/glide_text2im/gaussian_diffusion.py
3# ADM: https://github.com/openai/guided-diffusion/blob/main/guided_diffusion
4# IDDPM: https://github.com/openai/improved-diffusion/blob/main/improved_diffusion/gaussian_diffusion.py
6import torch as th
7import numpy as np
10def normal_kl(mean1, logvar1, mean2, logvar2):
11 """
12 Compute the KL divergence between two gaussians.
13 Shapes are automatically broadcasted, so batches can be compared to
14 scalars, among other use cases.
15 """
16 tensor = None
17 for obj in (mean1, logvar1, mean2, logvar2):
18 if isinstance(obj, th.Tensor):
19 tensor = obj
20 break
21 assert tensor is not None, "at least one argument must be a Tensor"
23 # Force variances to be Tensors. Broadcasting helps convert scalars to
24 # Tensors, but it does not work for th.exp().
25 logvar1, logvar2 = [
26 x if isinstance(x, th.Tensor) else th.tensor(x).to(tensor)
27 for x in (logvar1, logvar2)
28 ]
30 return 0.5 * (
31 -1.0
32 + logvar2
33 - logvar1
34 + th.exp(logvar1 - logvar2)
35 + ((mean1 - mean2) ** 2) * th.exp(-logvar2)
36 )
39def approx_standard_normal_cdf(x):
40 """
41 A fast approximation of the cumulative distribution function of the
42 standard normal.
43 """
44 return 0.5 * (1.0 + th.tanh(np.sqrt(2.0 / np.pi) * (x + 0.044715 * th.pow(x, 3))))
47def continuous_gaussian_log_likelihood(x, *, means, log_scales):
48 """
49 Compute the log-likelihood of a continuous Gaussian distribution.
50 :param x: the targets
51 :param means: the Gaussian mean Tensor.
52 :param log_scales: the Gaussian log stddev Tensor.
53 :return: a tensor like x of log probabilities (in nats).
54 """
55 centered_x = x - means
56 inv_stdv = th.exp(-log_scales)
57 normalized_x = centered_x * inv_stdv
58 log_probs = th.distributions.Normal(th.zeros_like(x), th.ones_like(x)).log_prob(normalized_x)
59 return log_probs
62def discretized_gaussian_log_likelihood(x, *, means, log_scales):
63 """
64 Compute the log-likelihood of a Gaussian distribution discretizing to a
65 given image.
66 :param x: the target images. It is assumed that this was uint8 values,
67 rescaled to the range [-1, 1].
68 :param means: the Gaussian mean Tensor.
69 :param log_scales: the Gaussian log stddev Tensor.
70 :return: a tensor like x of log probabilities (in nats).
71 """
72 assert x.shape == means.shape == log_scales.shape
73 centered_x = x - means
74 inv_stdv = th.exp(-log_scales)
75 plus_in = inv_stdv * (centered_x + 1.0 / 255.0)
76 cdf_plus = approx_standard_normal_cdf(plus_in)
77 min_in = inv_stdv * (centered_x - 1.0 / 255.0)
78 cdf_min = approx_standard_normal_cdf(min_in)
79 log_cdf_plus = th.log(cdf_plus.clamp(min=1e-12))
80 log_one_minus_cdf_min = th.log((1.0 - cdf_min).clamp(min=1e-12))
81 cdf_delta = cdf_plus - cdf_min
82 log_probs = th.where(
83 x < -0.999,
84 log_cdf_plus,
85 th.where(x > 0.999, log_one_minus_cdf_min, th.log(cdf_delta.clamp(min=1e-12))),
86 )
87 assert log_probs.shape == x.shape
88 return log_probs