hypergan 2.0.0a1__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.
- hypergan/__init__.py +39 -0
- hypergan/__main__.py +5 -0
- hypergan/_build_provenance.json +1 -0
- hypergan/_file_lock.py +32 -0
- hypergan/api.py +2221 -0
- hypergan/artifacts.py +334 -0
- hypergan/autoencoder_components.py +60 -0
- hypergan/background_poll.py +74 -0
- hypergan/bounded_cli_output.py +562 -0
- hypergan/bounded_observer.py +278 -0
- hypergan/checkpoint_compatibility.py +203 -0
- hypergan/checkpoints.py +902 -0
- hypergan/cli.py +2165 -0
- hypergan/color_words.py +288 -0
- hypergan/colorization_components.py +360 -0
- hypergan/colorization_data.py +256 -0
- hypergan/colorization_metrics.py +168 -0
- hypergan/config.py +1041 -0
- hypergan/console_settings.py +87 -0
- hypergan/cpu_worker_service.py +575 -0
- hypergan/cpu_workers.py +125 -0
- hypergan/data.py +429 -0
- hypergan/datasets.py +6 -0
- hypergan/diff_augment.py +131 -0
- hypergan/distributed.py +110 -0
- hypergan/distributed_checkpoints.py +558 -0
- hypergan/distributed_commit.py +297 -0
- hypergan/distributed_training.py +733 -0
- hypergan/diversity_metrics.py +175 -0
- hypergan/evaluation_cli.py +22 -0
- hypergan/evaluation_snapshot.py +28 -0
- hypergan/event_views.py +500 -0
- hypergan/execution.py +360 -0
- hypergan/execution_preflight.py +264 -0
- hypergan/execution_profiles.py +142 -0
- hypergan/gpu_inventory.py +687 -0
- hypergan/hndl_augmentation.py +40 -0
- hypergan/hndl_networks.py +42 -0
- hypergan/image_cache.py +66 -0
- hypergan/image_components.py +326 -0
- hypergan/image_data.py +96 -0
- hypergan/image_grids.py +151 -0
- hypergan/image_metrics.py +121 -0
- hypergan/inspection.py +1956 -0
- hypergan/interval_evaluation.py +294 -0
- hypergan/item_data.py +165 -0
- hypergan/metric_evaluation.py +425 -0
- hypergan/metric_evaluation_worker.py +136 -0
- hypergan/metric_examples.py +81 -0
- hypergan/metric_plugins.py +339 -0
- hypergan/metrics.py +407 -0
- hypergan/metrics_reducer/__init__.py +12 -0
- hypergan/model_description.py +651 -0
- hypergan/model_file.py +1014 -0
- hypergan/models/gaussian-grid.toml +48 -0
- hypergan/network_config.py +131 -0
- hypergan/networks/autoencoder_offset.hndl +1 -0
- hypergan/networks/colorization_conv_head.hndl +6 -0
- hypergan/networks/colorization_dcgan256.hndl +14 -0
- hypergan/networks/colorization_dinov3_multidepth.hndl +20 -0
- hypergan/networks/colorization_dinov3_patch_tokens.hndl +19 -0
- hypergan/networks/colorization_encoder_features.hndl +19 -0
- hypergan/networks/colorization_feature_concat.hndl +2 -0
- hypergan/networks/colorization_feature_project.hndl +3 -0
- hypergan/networks/colorization_generator16.hndl +69 -0
- hypergan/networks/colorization_generator32.hndl +69 -0
- hypergan/networks/colorization_joint_score.hndl +2 -0
- hypergan/networks/colorization_linear_head.hndl +3 -0
- hypergan/networks/colorization_multidepth_projection.hndl +18 -0
- hypergan/networks/colorization_multiscale_score.hndl +2 -0
- hypergan/networks/colorization_pixel_features.hndl +8 -0
- hypergan/networks/colorization_pixel_head.hndl +17 -0
- hypergan/networks/colorization_query.hndl +2 -0
- hypergan/networks/colorization_random_project.hndl +2 -0
- hypergan/networks/colorization_scale_head16.hndl +8 -0
- hypergan/networks/colorization_scale_head32.hndl +10 -0
- hypergan/networks/colorization_scale_head4.hndl +4 -0
- hypergan/networks/colorization_scale_head8.hndl +6 -0
- hypergan/networks/image_attention.hndl +15 -0
- hypergan/networks/image_critic_score.hndl +6 -0
- hypergan/networks/image_encoder.hndl +17 -0
- hypergan/networks/image_feature_head.hndl +9 -0
- hypergan/networks/image_generator.hndl +13 -0
- hypergan/networks/image_pixel.hndl +7 -0
- hypergan/networks/image_pixel_block.hndl +16 -0
- hypergan/networks/image_resnet_stage1.hndl +7 -0
- hypergan/networks/image_resnet_stage2.hndl +2 -0
- hypergan/networks/image_resnet_stage3.hndl +2 -0
- hypergan/networks/reference.hndl +6 -0
- hypergan/numerical_policy.py +95 -0
- hypergan/objective_program.py +425 -0
- hypergan/observation_io.py +150 -0
- hypergan/particlegan_integration.py +134 -0
- hypergan/plugin_functions.py +94 -0
- hypergan/ports.py +9 -0
- hypergan/pretrained_providers.py +104 -0
- hypergan/preview_snapshot.py +229 -0
- hypergan/preview_worker.py +128 -0
- hypergan/previews.py +590 -0
- hypergan/provenance.py +187 -0
- hypergan/queue.py +819 -0
- hypergan/recipe_generator.py +691 -0
- hypergan/recipes.py +279 -0
- hypergan/registry.py +1337 -0
- hypergan/replicated_execution.py +487 -0
- hypergan/replicated_worker.py +184 -0
- hypergan/run_controller.py +990 -0
- hypergan/run_events.py +185 -0
- hypergan/run_requests.py +277 -0
- hypergan/run_signals.py +42 -0
- hypergan/run_state.py +80 -0
- hypergan/single_execution.py +225 -0
- hypergan/snapshot_renderer.py +71 -0
- hypergan/summary.py +336 -0
- hypergan/toml_writer.py +125 -0
- hypergan/training.py +543 -0
- hypergan/web_assets/THIRD_PARTY_LICENSES.txt +289 -0
- hypergan/web_assets/__init__.py +25 -0
- hypergan/web_assets/app.js +22 -0
- hypergan/web_assets/index.html +225 -0
- hypergan/web_assets/logo.png +0 -0
- hypergan/web_assets/runs.css +75 -0
- hypergan/web_assets/runs.js +203 -0
- hypergan/web_assets/style.css +871 -0
- hypergan/web_assets/view-worker.js +204 -0
- hypergan/web_autostart.py +1283 -0
- hypergan/web_dev.py +132 -0
- hypergan/web_files.py +83 -0
- hypergan/web_launch.py +272 -0
- hypergan/web_schema.py +165 -0
- hypergan/web_server.py +1323 -0
- hypergan/web_service.py +651 -0
- hypergan/web_session.py +191 -0
- hypergan/workspace.py +325 -0
- hypergan-2.0.0a1.dist-info/METADATA +328 -0
- hypergan-2.0.0a1.dist-info/RECORD +140 -0
- hypergan-2.0.0a1.dist-info/WHEEL +5 -0
- hypergan-2.0.0a1.dist-info/entry_points.txt +2 -0
- hypergan-2.0.0a1.dist-info/licenses/LICENSE +21 -0
- hypergan-2.0.0a1.dist-info/top_level.txt +1 -0
hypergan/recipes.py
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"""Small torch component registry and explicit forward bindings."""
|
|
2
|
+
import importlib
|
|
3
|
+
import torch
|
|
4
|
+
from torch import nn
|
|
5
|
+
from .data import ImageFolder
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class MLP(nn.Module):
|
|
9
|
+
"""Legacy argument adapter; every layer is compiled by HNDL."""
|
|
10
|
+
def __init__(self, input_dim=None, output_dim=None, hidden=(64, 64), negative_slope=0.2,
|
|
11
|
+
source=None, input_shape=None, output_shape=None, **kwargs):
|
|
12
|
+
super().__init__()
|
|
13
|
+
from .hndl_networks import build_network
|
|
14
|
+
if source is None:
|
|
15
|
+
source = '\n'.join(f'linear({width})\nleaky_relu({negative_slope!r})' for width in hidden)
|
|
16
|
+
source += '\nlinear()'
|
|
17
|
+
self.network = build_network(source, input_shape=input_shape or ('B', input_dim),
|
|
18
|
+
output_shape=output_shape or ('B', output_dim), **kwargs)
|
|
19
|
+
|
|
20
|
+
def forward(self, x, **inputs):
|
|
21
|
+
return self.network(x=x, **inputs) if inputs else self.network(x)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def linear(in_features, out_features, bias=True):
|
|
25
|
+
from .hndl_networks import HNDLNetwork
|
|
26
|
+
return HNDLNetwork(f'linear(bias={bias!r})', ('B', in_features), ('B', out_features))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class Identity(nn.Module):
|
|
30
|
+
"""Shape-polymorphic binding adapter for legacy identity components."""
|
|
31
|
+
def forward(self, input):
|
|
32
|
+
# Identity carries no architecture or parameters.
|
|
33
|
+
return input
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class GaussianGrid:
|
|
37
|
+
def __init__(self, side=10, noise=0.015):
|
|
38
|
+
if type(side) is not int or side < 1 or noise < 0:
|
|
39
|
+
raise ValueError("gaussian_grid requires positive side and nonnegative noise")
|
|
40
|
+
self.centers = torch.cartesian_prod(torch.linspace(-1, 1, side), torch.linspace(-1, 1, side))
|
|
41
|
+
self.noise = noise
|
|
42
|
+
|
|
43
|
+
def __call__(self, batch_size, *, generator):
|
|
44
|
+
ids = torch.randint(len(self.centers), (batch_size,), generator=generator)
|
|
45
|
+
return {"real": self.centers[ids] + self.noise * torch.randn(batch_size, 2, generator=generator)}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class PairedLinear:
|
|
49
|
+
"""Synthetic paired-input fixture; deliberately makes no application claim."""
|
|
50
|
+
def __init__(self, dimensions=2, scale=2.0, offset=0.0):
|
|
51
|
+
self.dimensions, self.scale, self.offset = dimensions, scale, offset
|
|
52
|
+
|
|
53
|
+
def __call__(self, batch_size, *, generator):
|
|
54
|
+
condition = torch.randn(batch_size, self.dimensions, generator=generator)
|
|
55
|
+
return {"condition": condition, "real": condition * self.scale + self.offset}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
BUILTINS = {"mlp": MLP, "linear": linear, "identity": Identity, "mse": nn.MSELoss, "l1": nn.L1Loss, "gaussian_grid": GaussianGrid, "paired_linear": PairedLinear, "image_folder": ImageFolder}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def execution_device(value, fallback=True):
|
|
62
|
+
"""Resolve an explicit native device; falls back to visible device on unavailable hardware."""
|
|
63
|
+
device = torch.device(value)
|
|
64
|
+
if device.type not in ('cpu', 'cuda'):
|
|
65
|
+
raise ValueError('Native execution requires cpu or cuda[:index]')
|
|
66
|
+
if device.type == 'cuda':
|
|
67
|
+
if not torch.cuda.is_available():
|
|
68
|
+
if fallback:
|
|
69
|
+
from .checkpoint_compatibility import HyperGANHardwareWarning
|
|
70
|
+
import warnings
|
|
71
|
+
warnings.warn(
|
|
72
|
+
f"CUDA device requested ({value!r}) but CUDA is unavailable on this host; falling back to cpu",
|
|
73
|
+
HyperGANHardwareWarning,
|
|
74
|
+
stacklevel=2,
|
|
75
|
+
)
|
|
76
|
+
return torch.device('cpu')
|
|
77
|
+
raise ValueError('CUDA was requested but is unavailable; install a CUDA-enabled PyTorch build and check the NVIDIA driver, or explicitly select cpu')
|
|
78
|
+
index = 0 if device.index is None else device.index
|
|
79
|
+
if not 0 <= index < torch.cuda.device_count():
|
|
80
|
+
if fallback and torch.cuda.device_count() > 0:
|
|
81
|
+
from .checkpoint_compatibility import HyperGANHardwareWarning
|
|
82
|
+
import warnings
|
|
83
|
+
warnings.warn(
|
|
84
|
+
f"CUDA device index {index} is unavailable; falling back to cuda:0",
|
|
85
|
+
HyperGANHardwareWarning,
|
|
86
|
+
stacklevel=2,
|
|
87
|
+
)
|
|
88
|
+
return torch.device('cuda', 0)
|
|
89
|
+
elif fallback:
|
|
90
|
+
from .checkpoint_compatibility import HyperGANHardwareWarning
|
|
91
|
+
import warnings
|
|
92
|
+
warnings.warn(
|
|
93
|
+
f"CUDA device index {index} is unavailable; falling back to cpu",
|
|
94
|
+
HyperGANHardwareWarning,
|
|
95
|
+
stacklevel=2,
|
|
96
|
+
)
|
|
97
|
+
return torch.device('cpu')
|
|
98
|
+
raise ValueError(f'CUDA device index {index} is unavailable')
|
|
99
|
+
device = torch.device('cuda', index)
|
|
100
|
+
return device
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def move_tensors(value, device):
|
|
105
|
+
if isinstance(value, torch.Tensor):
|
|
106
|
+
return value.to(device)
|
|
107
|
+
if isinstance(value, dict):
|
|
108
|
+
return {key: move_tensors(item, device) for key, item in value.items()}
|
|
109
|
+
if isinstance(value, (tuple, list)):
|
|
110
|
+
return type(value)(move_tensors(item, device) for item in value)
|
|
111
|
+
return value
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def make_prior(spec, *, device=None, recipe=None):
|
|
115
|
+
from particlegan import GaussianPrior, MoGParticlePrior, ParticlePrior, calibrate_mog_sigma
|
|
116
|
+
args = dict(spec['args'])
|
|
117
|
+
initial_device = 'cpu' if spec.get('initialization_device') == 'cpu' else device
|
|
118
|
+
if initial_device is not None:
|
|
119
|
+
args['device'] = initial_device
|
|
120
|
+
if spec.get('initialization_seed') is not None:
|
|
121
|
+
args['generator'] = torch.Generator(device=initial_device or 'cpu').manual_seed(spec['initialization_seed'])
|
|
122
|
+
if spec['kind'] == 'mog':
|
|
123
|
+
sigma_rel = args.pop('sigma_rel', .025)
|
|
124
|
+
sigma = args.pop('sigma', None)
|
|
125
|
+
if spec.get('fixed_sigma') is not None:
|
|
126
|
+
if sigma is not None:
|
|
127
|
+
raise ValueError('Choose prior.fixed_sigma or prior.args.sigma, not both')
|
|
128
|
+
sigma = spec['fixed_sigma']
|
|
129
|
+
prior = MoGParticlePrior(sigma=0.0 if sigma is None else sigma, **args)
|
|
130
|
+
if sigma is None:
|
|
131
|
+
# Preserve historical relative-noise recipes explicitly. Fixed-noise
|
|
132
|
+
# recipes never search neighbors, including during checkpoint setup.
|
|
133
|
+
value, distance = calibrate_mog_sigma(prior.means(), sigma_rel)
|
|
134
|
+
prior.set_sigma(value)
|
|
135
|
+
prior.d0.copy_(distance)
|
|
136
|
+
prior.sigma_rel = float(sigma_rel)
|
|
137
|
+
else:
|
|
138
|
+
prior = {"particles": ParticlePrior, "gaussian": GaussianPrior}[spec["kind"]](**args)
|
|
139
|
+
prior = prior.to(device) if device is not None else prior
|
|
140
|
+
if recipe:
|
|
141
|
+
# Inference workers must reconstruct persistent recipe-owned buffers
|
|
142
|
+
# before strict loading, including initial prior reference buffers.
|
|
143
|
+
from particlegan import Recipe
|
|
144
|
+
Recipe(**recipe).apply_prior_policy(prior)
|
|
145
|
+
return prior
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def construct(spec):
|
|
149
|
+
name = spec["factory"]
|
|
150
|
+
if name == "hndl":
|
|
151
|
+
from .hndl_networks import HNDLNetwork
|
|
152
|
+
return HNDLNetwork(**spec["args"])
|
|
153
|
+
if name in BUILTINS:
|
|
154
|
+
constructor = BUILTINS[name]
|
|
155
|
+
else:
|
|
156
|
+
module, attribute = name.split(":")
|
|
157
|
+
try:
|
|
158
|
+
constructor = importlib.import_module(module)
|
|
159
|
+
for part in attribute.split("."):
|
|
160
|
+
constructor = getattr(constructor, part)
|
|
161
|
+
except (ImportError, AttributeError) as exc:
|
|
162
|
+
raise ValueError(f"Unavailable custom constructor {name}: {exc}") from exc
|
|
163
|
+
try:
|
|
164
|
+
return constructor(**spec.get("args", {}))
|
|
165
|
+
except TypeError as exc:
|
|
166
|
+
raise ValueError(f"Invalid constructor arguments for {name}: {exc}") from exc
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def detach(value):
|
|
170
|
+
if isinstance(value, torch.Tensor):
|
|
171
|
+
return value.detach()
|
|
172
|
+
if isinstance(value, dict):
|
|
173
|
+
return {k: detach(v) for k, v in value.items()}
|
|
174
|
+
if isinstance(value, (list, tuple)):
|
|
175
|
+
return type(value)(detach(v) for v in value)
|
|
176
|
+
return value
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def generation_output(graph, context, sampling):
|
|
180
|
+
"""Select inference output without changing the adversarial generated binding."""
|
|
181
|
+
return graph.resolve(sampling.get('generated', 'generated'), context)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def generation_particle_ids(graph, context, prior_ids, sampling):
|
|
185
|
+
"""Resolve explicitly declared routed IDs without reporting unused prior draws."""
|
|
186
|
+
if 'particle_ids' not in sampling:
|
|
187
|
+
return prior_ids
|
|
188
|
+
ids = graph.resolve(sampling['particle_ids'], context)
|
|
189
|
+
if (not isinstance(ids, torch.Tensor) or ids.ndim != 1
|
|
190
|
+
or len(ids) != len(generation_output(graph, context, sampling))
|
|
191
|
+
or ids.dtype not in (torch.int32, torch.int64) or (ids < 0).any()):
|
|
192
|
+
raise ValueError('sampling.particle_ids must produce one nonnegative integer per generated sample')
|
|
193
|
+
return ids
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
class ComponentGraph(nn.Module):
|
|
197
|
+
"""Auxiliary components execute on demand; all trainable auxiliaries belong to G.
|
|
198
|
+
|
|
199
|
+
A discriminator sees detached conditioning. Only its candidate is differentiated
|
|
200
|
+
during a generator update or candidate-only gradient penalty.
|
|
201
|
+
"""
|
|
202
|
+
def __init__(self, specs):
|
|
203
|
+
super().__init__()
|
|
204
|
+
self.specs = specs
|
|
205
|
+
modules = {}
|
|
206
|
+
order = [name for name in ('generator', 'discriminator') if name in specs]
|
|
207
|
+
order += sorted(set(specs) - set(order))
|
|
208
|
+
for name in order:
|
|
209
|
+
spec = specs[name]
|
|
210
|
+
if 'reuse' in spec:
|
|
211
|
+
continue
|
|
212
|
+
module = construct(spec)
|
|
213
|
+
if not isinstance(module, nn.Module):
|
|
214
|
+
raise ValueError(f"Component {name} must construct a torch.nn.Module")
|
|
215
|
+
if not spec["trainable"]:
|
|
216
|
+
module.requires_grad_(False)
|
|
217
|
+
module.eval()
|
|
218
|
+
modules[name] = module
|
|
219
|
+
self.models = nn.ModuleDict(modules)
|
|
220
|
+
|
|
221
|
+
def resolve(self, path, context, active=None):
|
|
222
|
+
parts = path.split(".")
|
|
223
|
+
if parts[0] == 'prior' and parts[1] not in context['prior']:
|
|
224
|
+
prior = context.get('_prior')
|
|
225
|
+
if prior is None:
|
|
226
|
+
raise ValueError('This component binding requires the current prior')
|
|
227
|
+
context['prior'][parts[1]] = prior.means() if parts[1] == 'means' else prior.sigma
|
|
228
|
+
if parts[0] == "components" and parts[1] not in context["components"]:
|
|
229
|
+
self.call(parts[1], context, active)
|
|
230
|
+
value = context
|
|
231
|
+
try:
|
|
232
|
+
for part in parts:
|
|
233
|
+
value = value[int(part)] if isinstance(value, (list, tuple)) else value[part]
|
|
234
|
+
except (KeyError, IndexError, TypeError, ValueError) as exc:
|
|
235
|
+
raise ValueError(f"Unavailable I/O binding '{path}'") from exc
|
|
236
|
+
return value
|
|
237
|
+
|
|
238
|
+
def call(self, name, context, active=None):
|
|
239
|
+
active = set() if active is None else active
|
|
240
|
+
if name in active:
|
|
241
|
+
raise ValueError(f"Cyclic component binding at {name}")
|
|
242
|
+
active.add(name)
|
|
243
|
+
try:
|
|
244
|
+
kwargs = {arg: self.resolve(path, context, active) for arg, path in self.specs[name]["inputs"].items()}
|
|
245
|
+
spec = self.specs[name]
|
|
246
|
+
model = self.models[spec.get('reuse', name)]
|
|
247
|
+
flags = [parameter.requires_grad for parameter in model.parameters()]
|
|
248
|
+
if spec.get('freeze_parameters', False):
|
|
249
|
+
model.requires_grad_(False)
|
|
250
|
+
try:
|
|
251
|
+
value = model(**kwargs)
|
|
252
|
+
finally:
|
|
253
|
+
if spec.get('freeze_parameters', False):
|
|
254
|
+
for parameter, flag in zip(model.parameters(), flags):
|
|
255
|
+
parameter.requires_grad_(flag)
|
|
256
|
+
context["components"][name] = value
|
|
257
|
+
return value
|
|
258
|
+
finally:
|
|
259
|
+
active.remove(name)
|
|
260
|
+
|
|
261
|
+
def generate(self, latent, batch, *, prior=None):
|
|
262
|
+
context = {"latent": latent, "batch": batch, "components": {}, 'prior': {}, '_prior': prior}
|
|
263
|
+
context["generated"] = self.call("generator", context)
|
|
264
|
+
return context
|
|
265
|
+
|
|
266
|
+
def critic(self, candidate, context, module=None):
|
|
267
|
+
# Auxiliary conditioning runs with detached inputs and contributes no D loss
|
|
268
|
+
# gradients to G/encoder parameters. The candidate path remains attached.
|
|
269
|
+
# ``module`` replaces the discriminator (the penalty passes its EMA).
|
|
270
|
+
fixed = detach(context)
|
|
271
|
+
fixed["candidate"] = candidate
|
|
272
|
+
kwargs = {}
|
|
273
|
+
for arg, path in self.specs["discriminator"]["inputs"].items():
|
|
274
|
+
value = self.resolve(path, fixed)
|
|
275
|
+
kwargs[arg] = value if path == "candidate" else detach(value)
|
|
276
|
+
return (self.models["discriminator"] if module is None else module)(**kwargs)
|
|
277
|
+
|
|
278
|
+
def generator_parameters(self):
|
|
279
|
+
return [p for name, model in self.models.items() if name != "discriminator" for p in model.parameters() if p.requires_grad]
|