chuchichaestli 0.0.1.dev18__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. chuchichaestli/__about__.py +1 -0
  2. chuchichaestli/__init__.py +17 -0
  3. chuchichaestli/debug/__init__.py +92 -0
  4. chuchichaestli/debug/memory_usage.py +99 -0
  5. chuchichaestli/debug/visitor.py +137 -0
  6. chuchichaestli/diffusion/__init__.py +23 -0
  7. chuchichaestli/diffusion/ddpm/__init__.py +28 -0
  8. chuchichaestli/diffusion/ddpm/base.py +161 -0
  9. chuchichaestli/diffusion/ddpm/bbdm.py +152 -0
  10. chuchichaestli/diffusion/ddpm/cfg_ddpm.py +191 -0
  11. chuchichaestli/diffusion/ddpm/ddim.py +103 -0
  12. chuchichaestli/diffusion/ddpm/ddpm.py +136 -0
  13. chuchichaestli/diffusion/ddpm/indi.py +145 -0
  14. chuchichaestli/diffusion/ddpm/prior_grad.py +141 -0
  15. chuchichaestli/diffusion/ddpm/shift_ddpm.py +139 -0
  16. chuchichaestli/diffusion/distributions.py +83 -0
  17. chuchichaestli/models/__init__.py +1 -0
  18. chuchichaestli/models/activations.py +30 -0
  19. chuchichaestli/models/attention/__init__.py +29 -0
  20. chuchichaestli/models/attention/attention_gate.py +111 -0
  21. chuchichaestli/models/attention/self_attention.py +65 -0
  22. chuchichaestli/models/downsampling.py +52 -0
  23. chuchichaestli/models/maps.py +33 -0
  24. chuchichaestli/models/resnet.py +111 -0
  25. chuchichaestli/models/unet/__init__.py +5 -0
  26. chuchichaestli/models/unet/blocks.py +183 -0
  27. chuchichaestli/models/unet/time_embeddings.py +183 -0
  28. chuchichaestli/models/unet/unet.py +282 -0
  29. chuchichaestli/models/upsampling.py +52 -0
  30. chuchichaestli-0.0.1.dev18.dist-info/METADATA +720 -0
  31. chuchichaestli-0.0.1.dev18.dist-info/RECORD +33 -0
  32. chuchichaestli-0.0.1.dev18.dist-info/WHEEL +4 -0
  33. chuchichaestli-0.0.1.dev18.dist-info/licenses/LICENSE +674 -0
@@ -0,0 +1 @@
1
+ __version__ = "0.0.1.dev18"
@@ -0,0 +1,17 @@
1
+ """This file is part of Chuchichaestli.
2
+
3
+ Chuchichaestli is free software: you can redistribute it and/or modify
4
+ it under the terms of the GNU General Public License as published by
5
+ the Free Software Foundation, either version 3 of the License, or
6
+ (at your option) any later version.
7
+
8
+ Chuchichaestli is distributed in the hope that it will be useful,
9
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ GNU General Public License for more details.
12
+
13
+ You should have received a copy of the GNU General Public License
14
+ along with Chuchichaestli. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ Developed by the Intelligent Vision Systems Group at ZHAW.
17
+ """
@@ -0,0 +1,92 @@
1
+ """Debugging utilities package.
2
+
3
+ This file is part of Chuchichaestli.
4
+
5
+ Chuchichaestli is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ Chuchichaestli is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with Chuchichaestli. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ Developed by the Intelligent Vision Systems Group at ZHAW.
19
+ """
20
+
21
+
22
+ def as_bytes(byte_str: str = "MB") -> int:
23
+ """Convert bytes strings to integers."""
24
+ match byte_str.lower():
25
+ case "kib":
26
+ return 1 << 10
27
+ case "mib":
28
+ return 1 << 20
29
+ case "gib":
30
+ return 1 << 30
31
+ case "tib":
32
+ return 1 << 40
33
+ case "kb":
34
+ return 1_000
35
+ case "mb":
36
+ return 1_000_000
37
+ case "gb":
38
+ return 1_000_000_000
39
+ case "tb":
40
+ return 1_000_000_000_000
41
+ case _:
42
+ return 1
43
+
44
+
45
+ def cli_pbar(
46
+ r_fill: float,
47
+ prefix: str | list = "",
48
+ postfix: str | list = "",
49
+ bar_length: int = 60,
50
+ fill_symbol: str = "#",
51
+ empty_symbol: str = "-",
52
+ float_fmt: str = "{:.2f}",
53
+ int_fmt: str = "{:4d}",
54
+ ) -> str:
55
+ """Construct/print a progressbar of given relative length, optionally with labels.
56
+
57
+ Args:
58
+ r_fill (float): rate of progress, a number between 0 and 1
59
+ prefix (str | list): label before the progressbar
60
+ postfix (str | list): label after the progressbar
61
+ bar_length (int): maximum length of the progressbar; automatically determined if negative
62
+ fill_symbol (str): symbol indicating the progressbar's filled status
63
+ empty_symbol (str): symbol indicating the progressbar's empty status
64
+ float_fmt (str): string format for floats in prefix
65
+ int_fmt (str): string format for ints in prefix
66
+ """
67
+ if isinstance(prefix, list | tuple):
68
+ for i, p in enumerate(prefix):
69
+ if isinstance(p, float):
70
+ prefix[i] = float_fmt.format(p)
71
+ elif isinstance(p, int):
72
+ prefix[i] = int_fmt.format(p)
73
+ if not isinstance(prefix[i], str):
74
+ prefix[i] = f"{prefix[i]}"
75
+ prefix = " ".join(prefix)
76
+ if isinstance(postfix, list | tuple):
77
+ for i, p in enumerate(postfix):
78
+ if isinstance(p, float):
79
+ postfix[i] = float_fmt.format(p)
80
+ elif isinstance(p, int):
81
+ postfix[i] = int_fmt.format(p)
82
+ if not isinstance(postfix[i], str):
83
+ postfix[i] = f"{postfix[i]}"
84
+ postfix = " ".join(postfix)
85
+ bar = fill_symbol * int(r_fill * bar_length) + empty_symbol * int(
86
+ (1 - r_fill) * bar_length
87
+ )
88
+ if bar_length > 0:
89
+ line = f"{prefix} [{bar}] {postfix}"
90
+ else:
91
+ line = f"{prefix}\t{postfix}"
92
+ return line
@@ -0,0 +1,99 @@
1
+ """Memory debugging utils.
2
+
3
+ This file is part of Chuchichaestli.
4
+
5
+ Chuchichaestli is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ Chuchichaestli is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with Chuchichaestli. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ Developed by the Intelligent Vision Systems Group at ZHAW.
19
+ """
20
+
21
+ import torch
22
+ from torch import nn
23
+ from chuchichaestli.debug.visitor import Visitor, Hook, HookDirection
24
+
25
+
26
+ class CudaMemoryStatsVisitor(Visitor):
27
+ """Visitor that collects memory statistics on CUDA GPUs."""
28
+
29
+ def __init__(self, **kwargs):
30
+ """Initialize the visitor."""
31
+ if "hook_default" in kwargs:
32
+ hook_default = kwargs.pop("hook_default")
33
+ else:
34
+ hook_default = Hook(self._hook, HookDirection.Forward)
35
+ super().__init__(hook_default=hook_default, **kwargs)
36
+
37
+ def _hook(self, module: nn.Module, _input: torch.Tensor, _output: torch.Tensor):
38
+ """Hook that collects the memory statistics."""
39
+ mem_dict = torch.cuda.memory_stats()
40
+ mem_dict["module"] = module._get_name()
41
+ self._memory_stats.append(mem_dict)
42
+
43
+ @staticmethod
44
+ def has_cuda(verbose: bool = False) -> bool:
45
+ """Check if CUDA is built and available."""
46
+ is_avail = torch.cuda.is_available()
47
+ is_built = torch.backends.cuda.is_built()
48
+ is_cuda = is_avail and is_built
49
+ if verbose:
50
+ if not is_built:
51
+ if not is_avail:
52
+ print(
53
+ "CUDA not available most likely because you do not have a CUDA-enabled "
54
+ "device on this machine."
55
+ )
56
+ else:
57
+ print(
58
+ "CUDA not available because the current PyTorch install was not built with "
59
+ "CUDA enabled."
60
+ )
61
+ return is_cuda
62
+
63
+
64
+ class MPSMemoryAllocationVisitor(Visitor):
65
+ """Visitor that collects memory statistics on Apple systems."""
66
+
67
+ def __init__(self, **kwargs):
68
+ """Initialize the visitor."""
69
+ if "hook_default" in kwargs:
70
+ hook_default = kwargs.pop("hook_default")
71
+ else:
72
+ hook_default = Hook(self._hook, HookDirection.Forward)
73
+ super().__init__(hook_default=hook_default, **kwargs)
74
+
75
+ def _hook(self, module: nn.Module, _input: torch.Tensor, _output: torch.Tensor):
76
+ """Hook that collects the memory statistics."""
77
+ allocated = torch.mps.current_allocated_memory()
78
+ mem_dict = {"allocated": allocated, "module": module._get_name()}
79
+ self._memory_stats.append(mem_dict)
80
+
81
+ @staticmethod
82
+ def has_mps(verbose: bool = False) -> bool:
83
+ """Check if MPS is built and available."""
84
+ is_avail = torch.backends.mps.is_available()
85
+ is_built = torch.backends.mps.is_built()
86
+ is_mps = is_avail and is_built
87
+ if verbose:
88
+ if not is_avail:
89
+ if not is_built:
90
+ print(
91
+ "MPS not available because the current PyTorch install was not built with "
92
+ "MPS enabled."
93
+ )
94
+ else:
95
+ print(
96
+ "MPS not available because the current MacOS version is not 12.3+ and/or "
97
+ "you do not have an MPS-enabled device on this machine."
98
+ )
99
+ return is_mps
@@ -0,0 +1,137 @@
1
+ """Visitor pattern implementation for PyTorch models.
2
+
3
+ This file is part of Chuchichaestli.
4
+
5
+ Chuchichaestli is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ Chuchichaestli is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with Chuchichaestli. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ Developed by the Intelligent Vision Systems Group at ZHAW.
19
+ """
20
+
21
+ from dataclasses import dataclass
22
+ from enum import Enum
23
+
24
+ from collections.abc import Callable
25
+ from typing import Any
26
+
27
+ from torch import nn
28
+ from chuchichaestli.debug import as_bytes, cli_pbar
29
+
30
+
31
+ class HookDirection(Enum):
32
+ """Enum that represents the direction of a hook."""
33
+
34
+ Forward: str = "forward"
35
+ Backward: str = "backward"
36
+ Both: str = "both"
37
+
38
+
39
+ @dataclass
40
+ class Hook:
41
+ """Represents a hook (function to call and direction to attach the hook)."""
42
+
43
+ fn: Callable[[nn.Module, Any], Any]
44
+ direction: HookDirection
45
+
46
+
47
+ class Visitor:
48
+ """Generic implementation of a Visitor."""
49
+
50
+ def __init__(
51
+ self,
52
+ hook_default: Hook | None = None,
53
+ hook_map: dict[object, Hook] = {},
54
+ max_depth: int | None = None,
55
+ _memory_stats: list = [],
56
+ ):
57
+ """Initialize the Visitor.
58
+
59
+ Args:
60
+ hook_default: The default hook to use.
61
+ hook_map: A mapping from layer types to hooks.
62
+ max_depth: The maximum depth to visit.
63
+ _memory_stats: Precached memory statistics history.
64
+ """
65
+ self.hook_default = hook_default
66
+ self.hook_map = hook_map
67
+ self.max_depth = max_depth
68
+ self._memory_stats = _memory_stats
69
+
70
+ @property
71
+ def memory_stats(self):
72
+ """Return the collected memory statistics."""
73
+ return self._memory_stats
74
+
75
+ def unlink(self):
76
+ """Unlink hooks and maps."""
77
+ self.hook_default = None
78
+ self.hook_map = {}
79
+
80
+ def visit(self, visitee, depth: int = 0, caller: nn.Module | None = None):
81
+ """Function called when visiting an object."""
82
+ # print(visitee, depth, caller)
83
+ if self.max_depth and depth > self.max_depth:
84
+ return
85
+ for layer in visitee.modules():
86
+ if caller is layer:
87
+ return
88
+ layer_type = type(layer)
89
+ hook = self.hook_map.setdefault(layer_type, self.hook_default)
90
+ match hook.direction:
91
+ case HookDirection.Forward:
92
+ layer.register_forward_hook(hook.fn)
93
+ case HookDirection.Backward:
94
+ layer.register_backward_hook(hook.fn)
95
+ case HookDirection.Both:
96
+ layer.register_forward_hook(hook.fn)
97
+ layer.register_backward_hook(hook.fn)
98
+ self.visit(layer, depth=depth + 1, caller=layer)
99
+
100
+ def report(
101
+ self,
102
+ unit: str = "MB",
103
+ with_bar: bool = True,
104
+ bar_length: int = 60,
105
+ verbose: bool = True,
106
+ ) -> list[str] | None:
107
+ """Report the memory statistics for the visited module(s).
108
+
109
+ Args:
110
+ unit (str): The byte unit; one in [KB, MB, GB, TB, KiB, MiB, GiB, TiB].
111
+ with_bar (bool): Add simple horizontal percentage bars.
112
+ bar_length (int): The length of the percentage bars in number of characters.
113
+ verbose (bool): Directly print lines to stdout.
114
+ """
115
+ if not hasattr(self, "memory_stats"):
116
+ return []
117
+ divisor = as_bytes(unit)
118
+ mem_stats = self.memory_stats.copy()
119
+ if not mem_stats:
120
+ return []
121
+ total_alloc = sum(module["allocated"] for module in mem_stats)
122
+ for stat in mem_stats:
123
+ stat["rel_alloc"] = stat["allocated"] / total_alloc
124
+ stat["allocated"] /= divisor
125
+ total_alloc /= divisor
126
+
127
+ lines = []
128
+ module_name_length = max([len(stat["module"]) for stat in mem_stats])
129
+
130
+ for stat in mem_stats:
131
+ prefix = [stat["module"].ljust(module_name_length), stat["allocated"], unit]
132
+ postfix = [stat["rel_alloc"] * 100, "%"]
133
+ line = cli_pbar(stat["rel_alloc"], prefix, postfix, bar_length=bar_length)
134
+ lines.append(line)
135
+ if verbose:
136
+ print("\n".join(lines))
137
+ return lines
@@ -0,0 +1,23 @@
1
+ """Diffusion schedulers sub-module.
2
+
3
+ This file is part of Chuchichaestli.
4
+
5
+ Chuchichaestli is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ Chuchichaestli is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with Chuchichaestli. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ Developed by the Intelligent Vision Systems Group at ZHAW.
19
+ """
20
+
21
+ from chuchichaestli.diffusion.ddpm import DDPM, InDI, PriorGrad, CFGDDPM, BBDM, DDIM
22
+
23
+ __all__ = ["DDPM", "InDI", "PriorGrad", "CFGDDPM", "BBDM", "DDIM"]
@@ -0,0 +1,28 @@
1
+ """Implementation of DDPM and its variants.
2
+
3
+ This file is part of Chuchichaestli.
4
+
5
+ Chuchichaestli is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ Chuchichaestli is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with Chuchichaestli. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ Developed by the Intelligent Vision Systems Group at ZHAW.
19
+ """
20
+
21
+ from chuchichaestli.diffusion.ddpm.ddpm import DDPM
22
+ from chuchichaestli.diffusion.ddpm.indi import InDI
23
+ from chuchichaestli.diffusion.ddpm.prior_grad import PriorGrad
24
+ from chuchichaestli.diffusion.ddpm.cfg_ddpm import CFGDDPM
25
+ from chuchichaestli.diffusion.ddpm.bbdm import BBDM
26
+ from chuchichaestli.diffusion.ddpm.ddim import DDIM
27
+
28
+ __all__ = ["DDPM", "InDI", "PriorGrad", "CFGDDPM", "BBDM", "DDIM"]
@@ -0,0 +1,161 @@
1
+ """Base class for diffusion processes.
2
+
3
+ This file is part of Chuchichaestli.
4
+
5
+ Chuchichaestli is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ Chuchichaestli is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with Chuchichaestli. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ Developed by the Intelligent Vision Systems Group at ZHAW.
19
+ """
20
+
21
+ from abc import ABC, abstractmethod
22
+ from typing import Any
23
+ from collections.abc import Generator
24
+
25
+ import torch
26
+
27
+ from chuchichaestli.diffusion.distributions import DistributionAdapter
28
+
29
+ SCHEDULES = {
30
+ # A simple linear schedule from `beta_start` to `beta_end`
31
+ "linear": lambda beta_start, beta_end, num_timesteps, device: torch.linspace(
32
+ beta_start, beta_end, num_timesteps, device=device
33
+ ),
34
+ # Scaled linear schedule to account for different step sizes
35
+ "linear_scaled": lambda beta_start, beta_end, num_timesteps, device: torch.linspace(
36
+ (1000 / num_timesteps) * beta_start,
37
+ (1000 / num_timesteps) * beta_end,
38
+ num_timesteps,
39
+ device=device,
40
+ ),
41
+ # A quadratic growth schedule from `beta_min` to `beta_max`
42
+ "squared": lambda beta_min, beta_max, num_timesteps, device: beta_min
43
+ + (
44
+ (beta_max - beta_min)
45
+ * (
46
+ torch.arange(num_timesteps, dtype=torch.float32, device=device)
47
+ / num_timesteps
48
+ )
49
+ ** 2
50
+ ),
51
+ # A sigmoid-shaped schedule to achieve a smoother transition from `beta_start` to `beta_end`
52
+ "sigmoid": lambda beta_start, beta_end, num_timesteps, device: (
53
+ torch.sigmoid(torch.linspace(-6, 6, num_timesteps, device=device))
54
+ * (beta_end - beta_start)
55
+ + beta_start
56
+ ),
57
+ # A cosine-shaped schedule for smoother transitions, emphasizing the start and the end
58
+ "cosine": lambda beta_min, beta_max, num_timesteps, device: beta_min
59
+ + (
60
+ (beta_max - beta_min)
61
+ * (
62
+ 1
63
+ - torch.cos(
64
+ (
65
+ torch.arange(num_timesteps, dtype=torch.float32, device=device)
66
+ / num_timesteps
67
+ )
68
+ * torch.pi
69
+ / 2
70
+ )
71
+ )
72
+ ),
73
+ # An exponential schedule to smoothly increase the beta value over time
74
+ "exponential": lambda beta_min, beta_max, num_timesteps, device: beta_min
75
+ * (
76
+ (beta_max / beta_min)
77
+ ** (
78
+ torch.arange(num_timesteps, dtype=torch.float32, device=device)
79
+ / num_timesteps
80
+ )
81
+ ),
82
+ }
83
+
84
+
85
+ SAMPLERS = {
86
+ "DDIM": "ddim",
87
+ "default": "default",
88
+ }
89
+
90
+
91
+ class DiffusionProcess(ABC):
92
+ """Base class for diffusion processes."""
93
+
94
+ def __init__(
95
+ self,
96
+ timesteps: int,
97
+ device: str = "cpu",
98
+ noise_distribution: DistributionAdapter | None = None,
99
+ *args,
100
+ **kwargs,
101
+ ) -> None:
102
+ """Initialize the diffusion process."""
103
+ self.num_time_steps = timesteps
104
+ self.device = device
105
+ self.noise_distribution = noise_distribution
106
+
107
+ @abstractmethod
108
+ def noise_step(
109
+ self, x_t: torch.Tensor, *args, **kwargs
110
+ ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
111
+ """Noise step for the diffusion process.
112
+
113
+ Args:
114
+ x_t: Tensor of shape (batch_size, *).
115
+ *args: Additional arguments.
116
+ **kwargs: Additional keyword arguments.
117
+
118
+ Returns:
119
+ Tuple of the sampled tensor, noise tensor and timesteps.
120
+ """
121
+ pass
122
+
123
+ @abstractmethod
124
+ def generate(
125
+ self,
126
+ model: Any,
127
+ condition: torch.Tensor,
128
+ n: int = 1,
129
+ yield_intermediate: bool = False,
130
+ *args,
131
+ **kwargs,
132
+ ) -> Generator[torch.Tensor, None, torch.Tensor]:
133
+ """Sample from the diffusion process.
134
+
135
+ Samples n times the number of conditions from the diffusion process.
136
+
137
+ Args:
138
+ model: Model to use for sampling.
139
+ condition: Tensor to condition generation on. For unconditional generation, supply a zero-tensor of the sample shape.
140
+ n: Number of samples to generate (batch size).
141
+ yield_intermediate: Yield intermediate results. This turns the function into a generator.
142
+ *args: Additional arguments.
143
+ **kwargs: Additional keyword
144
+ """
145
+ pass
146
+
147
+ def sample_timesteps(self, n: int) -> torch.Tensor:
148
+ """Sample timesteps for the diffusion process."""
149
+ return torch.randint(0, self.num_time_steps, (n,), device=self.device)
150
+
151
+ def sample_noise(self, shape: torch.Size) -> torch.Tensor:
152
+ """Sample noise for the diffusion process.
153
+
154
+ Args:
155
+ shape: Shape of the noise tensor.
156
+ mean: Mean of the noise tensor.
157
+ scale: Scale of the noise tensor.
158
+ """
159
+ if self.noise_distribution is not None:
160
+ return self.noise_distribution(shape)
161
+ return torch.randn(shape, device=self.device)