diffract-core 0.2.1__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 (193) hide show
  1. diffract/__init__.py +52 -0
  2. diffract/configs/fast_speed_without_disk.ini +48 -0
  3. diffract/configs/hybrid.ini +74 -0
  4. diffract/configs/sqlite.ini +62 -0
  5. diffract/containers.py +405 -0
  6. diffract/core/__init__.py +23 -0
  7. diffract/core/cache/__init__.py +24 -0
  8. diffract/core/cache/containers.py +93 -0
  9. diffract/core/cache/interface.py +117 -0
  10. diffract/core/cache/redis_manager.py +464 -0
  11. diffract/core/cache/simple_manager.py +478 -0
  12. diffract/core/compute/__init__.py +46 -0
  13. diffract/core/compute/config.py +48 -0
  14. diffract/core/compute/containers.py +81 -0
  15. diffract/core/compute/decorator.py +125 -0
  16. diffract/core/compute/exceptions.py +31 -0
  17. diffract/core/compute/execution/__init__.py +14 -0
  18. diffract/core/compute/execution/_types.py +70 -0
  19. diffract/core/compute/execution/aggregation.py +74 -0
  20. diffract/core/compute/execution/aggregation_runner.py +362 -0
  21. diffract/core/compute/execution/enums.py +38 -0
  22. diffract/core/compute/execution/executor.py +125 -0
  23. diffract/core/compute/execution/parameter_runner.py +125 -0
  24. diffract/core/compute/execution/restrictions.py +61 -0
  25. diffract/core/compute/execution/strategy.py +118 -0
  26. diffract/core/compute/execution/utils.py +112 -0
  27. diffract/core/compute/extensions/__init__.py +0 -0
  28. diffract/core/compute/extensions/power_law.py +1051 -0
  29. diffract/core/compute/extensions/rmt.py +150 -0
  30. diffract/core/compute/extensions/utils.py +36 -0
  31. diffract/core/compute/field_signature.py +183 -0
  32. diffract/core/compute/kernels/__init__.py +48 -0
  33. diffract/core/compute/kernels/alignment.py +106 -0
  34. diffract/core/compute/kernels/heavy_tailed.py +394 -0
  35. diffract/core/compute/kernels/marchenko_pastur.py +99 -0
  36. diffract/core/compute/kernels/mat_decomposition.py +101 -0
  37. diffract/core/compute/kernels/mat_properties.py +53 -0
  38. diffract/core/compute/kernels/model_quality.py +27 -0
  39. diffract/core/compute/kernels/norms.py +88 -0
  40. diffract/core/compute/kernels/ranks.py +35 -0
  41. diffract/core/compute/kernels/tracy_widom.py +36 -0
  42. diffract/core/compute/metadata.py +67 -0
  43. diffract/core/compute/registry.py +485 -0
  44. diffract/core/constants.py +147 -0
  45. diffract/core/data/__init__.py +32 -0
  46. diffract/core/data/interface.py +304 -0
  47. diffract/core/data/metadata/__init__.py +15 -0
  48. diffract/core/data/metadata/containers.py +60 -0
  49. diffract/core/data/metadata/interface.py +208 -0
  50. diffract/core/data/metadata/sqlite_index.py +604 -0
  51. diffract/core/data/nn/__init__.py +43 -0
  52. diffract/core/data/nn/aggregates/__init__.py +35 -0
  53. diffract/core/data/nn/aggregates/metadata.py +96 -0
  54. diffract/core/data/nn/aggregates/proxy.py +57 -0
  55. diffract/core/data/nn/aggregates/repository.py +87 -0
  56. diffract/core/data/nn/aggregates/view.py +307 -0
  57. diffract/core/data/nn/containers.py +86 -0
  58. diffract/core/data/nn/extractors/__init__.py +49 -0
  59. diffract/core/data/nn/extractors/base.py +300 -0
  60. diffract/core/data/nn/extractors/factory.py +234 -0
  61. diffract/core/data/nn/extractors/flax.py +112 -0
  62. diffract/core/data/nn/extractors/handlers/__init__.py +39 -0
  63. diffract/core/data/nn/extractors/handlers/base.py +110 -0
  64. diffract/core/data/nn/extractors/handlers/flax_handlers.py +71 -0
  65. diffract/core/data/nn/extractors/handlers/numpy_handlers.py +63 -0
  66. diffract/core/data/nn/extractors/handlers/onnx_handlers.py +67 -0
  67. diffract/core/data/nn/extractors/handlers/tensorflow_handlers.py +82 -0
  68. diffract/core/data/nn/extractors/handlers/torch_handlers.py +124 -0
  69. diffract/core/data/nn/extractors/interface.py +56 -0
  70. diffract/core/data/nn/extractors/numpy.py +94 -0
  71. diffract/core/data/nn/extractors/onnx.py +108 -0
  72. diffract/core/data/nn/extractors/tensorflow.py +99 -0
  73. diffract/core/data/nn/extractors/torch.py +204 -0
  74. diffract/core/data/nn/params/__init__.py +27 -0
  75. diffract/core/data/nn/params/interface.py +402 -0
  76. diffract/core/data/nn/params/metadata.py +110 -0
  77. diffract/core/data/nn/params/proxy.py +93 -0
  78. diffract/core/data/nn/params/repository.py +45 -0
  79. diffract/core/data/nn/params/schema.py +82 -0
  80. diffract/core/data/nn/params/view.py +393 -0
  81. diffract/core/data/proxy.py +246 -0
  82. diffract/core/data/repository.py +227 -0
  83. diffract/core/data/utils.py +33 -0
  84. diffract/core/data/view.py +389 -0
  85. diffract/core/export/__init__.py +27 -0
  86. diffract/core/export/containers.py +47 -0
  87. diffract/core/export/exporters.py +191 -0
  88. diffract/core/export/formatters/__init__.py +23 -0
  89. diffract/core/export/formatters/base.py +68 -0
  90. diffract/core/export/formatters/dict_formatter.py +38 -0
  91. diffract/core/export/formatters/json_formatter.py +58 -0
  92. diffract/core/export/formatters/list_formatter.py +41 -0
  93. diffract/core/export/formatters/pandas_formatter.py +86 -0
  94. diffract/core/export/formatters/polars_formatter.py +86 -0
  95. diffract/core/export/formatters/registry.py +84 -0
  96. diffract/core/export/interface.py +105 -0
  97. diffract/core/parallel/__init__.py +21 -0
  98. diffract/core/parallel/containers.py +57 -0
  99. diffract/core/parallel/execution.py +91 -0
  100. diffract/core/parallel/runtime.py +91 -0
  101. diffract/core/storage/__init__.py +35 -0
  102. diffract/core/storage/base_manager.py +330 -0
  103. diffract/core/storage/containers.py +122 -0
  104. diffract/core/storage/hdf5_manager.py +856 -0
  105. diffract/core/storage/hybrid_manager.py +218 -0
  106. diffract/core/storage/interface.py +222 -0
  107. diffract/core/storage/metadata.py +89 -0
  108. diffract/core/storage/ram_manager.py +159 -0
  109. diffract/core/storage/sqlite_manager.py +1062 -0
  110. diffract/core/storage/zarr_manager.py +992 -0
  111. diffract/core/utils/__init__.py +45 -0
  112. diffract/core/utils/build.py +46 -0
  113. diffract/core/utils/exceptions.py +11 -0
  114. diffract/core/utils/hashing.py +90 -0
  115. diffract/core/utils/imports.py +292 -0
  116. diffract/core/utils/math.py +15 -0
  117. diffract/py.typed +0 -0
  118. diffract/session/__init__.py +24 -0
  119. diffract/session/errors.py +17 -0
  120. diffract/session/field_cache.py +216 -0
  121. diffract/session/namespaces/__init__.py +15 -0
  122. diffract/session/namespaces/compute/__init__.py +219 -0
  123. diffract/session/namespaces/models/__init__.py +282 -0
  124. diffract/session/namespaces/models/parameters/__init__.py +133 -0
  125. diffract/session/namespaces/models/parameters/meta_patcher.py +167 -0
  126. diffract/session/namespaces/results/__init__.py +378 -0
  127. diffract/session/namespaces/results/eraser.py +129 -0
  128. diffract/session/namespaces/results/injester.py +249 -0
  129. diffract/session/namespaces/utils/__init__.py +141 -0
  130. diffract/session/namespaces/utils/merger.py +295 -0
  131. diffract/session/namespaces/viz/__init__.py +91 -0
  132. diffract/session/namespaces/viz/_utils.py +14 -0
  133. diffract/session/namespaces/viz/box.py +207 -0
  134. diffract/session/namespaces/viz/grid.py +160 -0
  135. diffract/session/namespaces/viz/heatmap.py +164 -0
  136. diffract/session/namespaces/viz/scatter.py +202 -0
  137. diffract/session/namespaces/viz/sparkline.py +270 -0
  138. diffract/session/namespaces/viz/violin.py +212 -0
  139. diffract/session/session.py +260 -0
  140. diffract/session/utils.py +81 -0
  141. diffract/viz/__init__.py +42 -0
  142. diffract/viz/data/__init__.py +34 -0
  143. diffract/viz/data/detection.py +57 -0
  144. diffract/viz/data/extraction.py +117 -0
  145. diffract/viz/data/filtering.py +57 -0
  146. diffract/viz/data/ordering.py +129 -0
  147. diffract/viz/data/provider.py +99 -0
  148. diffract/viz/data/types.py +98 -0
  149. diffract/viz/plots/__init__.py +37 -0
  150. diffract/viz/plots/base/__init__.py +20 -0
  151. diffract/viz/plots/base/axis.py +219 -0
  152. diffract/viz/plots/base/coloraxis.py +133 -0
  153. diffract/viz/plots/base/configurator.py +18 -0
  154. diffract/viz/plots/base/jitter.py +368 -0
  155. diffract/viz/plots/base/line.py +197 -0
  156. diffract/viz/plots/base/marker.py +278 -0
  157. diffract/viz/plots/base/overlay.py +14 -0
  158. diffract/viz/plots/base/plot.py +110 -0
  159. diffract/viz/plots/base/update.py +50 -0
  160. diffract/viz/plots/boxplot.py +283 -0
  161. diffract/viz/plots/cluster.py +374 -0
  162. diffract/viz/plots/heatmap.py +168 -0
  163. diffract/viz/plots/scatter.py +233 -0
  164. diffract/viz/plots/sparkline.py +405 -0
  165. diffract/viz/plots/subplots/__init__.py +32 -0
  166. diffract/viz/plots/subplots/coloraxis.py +339 -0
  167. diffract/viz/plots/subplots/factory.py +713 -0
  168. diffract/viz/plots/subplots/grid.py +214 -0
  169. diffract/viz/plots/subplots/layout.py +370 -0
  170. diffract/viz/plots/subplots/spec.py +39 -0
  171. diffract/viz/plots/violin.py +298 -0
  172. diffract/viz/renderer.py +513 -0
  173. diffract/viz/styling/__init__.py +78 -0
  174. diffract/viz/styling/palettes/__init__.py +20 -0
  175. diffract/viz/styling/palettes/bundle.py +16 -0
  176. diffract/viz/styling/palettes/color.py +83 -0
  177. diffract/viz/styling/palettes/dashes.py +27 -0
  178. diffract/viz/styling/palettes/symbols.py +42 -0
  179. diffract/viz/styling/resolvers/__init__.py +11 -0
  180. diffract/viz/styling/resolvers/categorical.py +68 -0
  181. diffract/viz/styling/resolvers/color.py +77 -0
  182. diffract/viz/styling/resolvers/numeric.py +108 -0
  183. diffract/viz/styling/sources.py +27 -0
  184. diffract/viz/styling/theme/__init__.py +29 -0
  185. diffract/viz/styling/theme/applier.py +114 -0
  186. diffract/viz/styling/theme/components.py +66 -0
  187. diffract/viz/styling/theme/presets.py +58 -0
  188. diffract/viz/styling/theme/theme.py +36 -0
  189. diffract_core-0.2.1.dist-info/METADATA +530 -0
  190. diffract_core-0.2.1.dist-info/RECORD +193 -0
  191. diffract_core-0.2.1.dist-info/WHEEL +4 -0
  192. diffract_core-0.2.1.dist-info/licenses/LICENSE +201 -0
  193. diffract_core-0.2.1.dist-info/licenses/NOTICE +2 -0
@@ -0,0 +1,300 @@
1
+ """Base classes and utilities for parameter extraction.
2
+
3
+ This module provides the foundational infrastructure for parameter extraction
4
+ from neural network models. It implements a handler-based architecture that
5
+ allows for extensible and framework-specific parameter processing.
6
+
7
+ Key Components:
8
+ - ExtractorOverrides: Configuration for customizing parameter metadata
9
+ - ParameterOverrides: Per-parameter override specifications
10
+ - BaseParameterExtractor: Abstract base class for all extractors
11
+
12
+ The handler-based approach allows different parameter types to be processed
13
+ by specialized handlers while maintaining a consistent extraction interface.
14
+ This design supports extensibility for new parameter types and frameworks.
15
+
16
+ Example:
17
+ >>> overrides = ExtractorOverrides(
18
+ ... model_id="custom_model",
19
+ ... parameter_overrides={"layer1.weight": ParameterOverrides(ptype="CUSTOM")},
20
+ ... )
21
+ >>> extractor = ConcreteExtractor(model, overrides=overrides)
22
+ >>> parameters = extractor.extract_parameters(storage, cache)
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ import logging
28
+ from abc import ABC, abstractmethod
29
+ from contextlib import suppress
30
+ from dataclasses import dataclass, field
31
+ from typing import TYPE_CHECKING, Any
32
+
33
+ from diffract.core.constants import WEIGHTS_FIELD
34
+ from diffract.core.data.nn.params.interface import IParameterRepository
35
+ from diffract.core.data.nn.params.metadata import ParameterMetadata
36
+ from diffract.core.data.nn.params.proxy import ParameterDataProxy
37
+ from diffract.core.data.nn.params.schema import ParameterType
38
+ from diffract.core.utils.hashing import get_unique_id
39
+
40
+ from .interface import IParameterExtractor
41
+
42
+ if TYPE_CHECKING:
43
+ from collections.abc import Generator
44
+
45
+ from .handlers.base import ParameterHandler, ParameterHandlerRegistry
46
+
47
+ logger = logging.getLogger(__name__)
48
+
49
+
50
+ @dataclass
51
+ class ExtractorOverrides:
52
+ """Configuration for customizing parameter extraction behavior.
53
+
54
+ Provides a mechanism to override default parameter metadata and
55
+ model identification during the extraction process. This allows
56
+ for custom naming, typing, and categorization of parameters.
57
+
58
+ Attributes:
59
+ model_id: Custom model identifier to override default.
60
+ parameter_overrides: Per-parameter override specifications.
61
+ """
62
+
63
+ @dataclass
64
+ class ParameterOverrides:
65
+ """Override specifications for individual parameters.
66
+
67
+ Allows customization of parameter metadata on a per-parameter
68
+ basis, including name changes, type reclassification, and extra metadata.
69
+
70
+ Attributes:
71
+ name: Custom parameter name to override default.
72
+ ptype: Custom parameter type to override default.
73
+ other_meta: Additional metadata to merge into ParameterMetadata.other_meta.
74
+ """
75
+
76
+ name: str | None = field(default=None)
77
+ ptype: str | ParameterType | None = field(default=None)
78
+ other_meta: dict[str, Any] | None = field(default=None)
79
+
80
+ model_id: str | None = field(default=None)
81
+ parameter_overrides: dict[str, ParameterOverrides] = field(default_factory=dict)
82
+
83
+
84
+ ParameterOverrides = ExtractorOverrides.ParameterOverrides
85
+
86
+
87
+ class BaseParameterExtractor(IParameterExtractor, ABC):
88
+ """Abstract base class for parameter extractors with handler-based processing.
89
+
90
+ Provides a common framework for extracting parameters from neural network
91
+ models using a pluggable handler system. Handles parameter iteration,
92
+ metadata construction, override application, and error management.
93
+
94
+ The extractor uses a registry of parameter handlers to process different
95
+ types of parameters. Each handler specializes in extracting weights and
96
+ metadata from specific parameter types (e.g., dense layers, convolutions).
97
+
98
+ Attributes:
99
+ model: The neural network model to extract parameters from.
100
+ overrides: Configuration for customizing extraction behavior.
101
+ skip_not_implemented_types: Whether to skip unsupported parameter types.
102
+ handler_registry: Registry of parameter handlers for processing.
103
+ """
104
+
105
+ def __init__(
106
+ self,
107
+ model: Any,
108
+ overrides: ExtractorOverrides | None = None,
109
+ skip_not_implemented_types: bool = True,
110
+ custom_handlers: list[ParameterHandler] | None = None,
111
+ ) -> None:
112
+ """Initialize the base parameter extractor.
113
+
114
+ Args:
115
+ model: Neural network model to extract parameters from.
116
+ overrides: Optional extraction behavior overrides.
117
+ skip_not_implemented_types: Whether to skip unsupported parameters.
118
+ custom_handlers: Optional list of custom parameter handlers.
119
+ """
120
+ self.model = model
121
+ self.overrides = overrides or ExtractorOverrides()
122
+ self.skip_not_implemented_types = skip_not_implemented_types
123
+
124
+ # Import here to avoid circular imports
125
+ from .handlers.base import ParameterHandlerRegistry
126
+
127
+ self.handler_registry: ParameterHandlerRegistry[Any] = ParameterHandlerRegistry[
128
+ Any
129
+ ]()
130
+ self._register_default_handlers()
131
+
132
+ if custom_handlers:
133
+ for handler in custom_handlers:
134
+ self.handler_registry.register_handler(handler)
135
+
136
+ @abstractmethod
137
+ def _register_default_handlers(self) -> None:
138
+ """Register default parameter handlers for this extractor.
139
+
140
+ Subclasses must implement this method to register the appropriate
141
+ handlers for their specific framework and parameter types.
142
+ """
143
+
144
+ def extract_parameters(
145
+ self,
146
+ parameter_repository: IParameterRepository,
147
+ ) -> None:
148
+ """Extract all parameters from the model using registered handlers.
149
+
150
+ Iterates through model parameters, processes each with appropriate
151
+ handlers, constructs metadata with overrides, and creates parameter
152
+ proxies for storage and caching.
153
+
154
+ Args:
155
+ parameter_repository: Repository that owns storage/cache and receives
156
+ extracted parameters.
157
+
158
+ Raises:
159
+ NotImplementedError: If parameter type unsupported and not skipping.
160
+ Exception: If handler processing fails and not skipping.
161
+ """
162
+ with parameter_repository:
163
+ model_id = get_unique_id()
164
+
165
+ for param_idx, (param_name, parameter) in enumerate(
166
+ self._iter_parameters()
167
+ ):
168
+ try:
169
+ result = self.handler_registry.process_parameter(
170
+ parameter, param_name
171
+ )
172
+ except Exception:
173
+ # Preserve error context; decide policy: skip or raise
174
+ logger.exception('Handler failed for "%s"', param_name)
175
+ if self.skip_not_implemented_types:
176
+ continue
177
+ raise
178
+
179
+ if result is None:
180
+ if self.skip_not_implemented_types:
181
+ logger.debug('Skipping unsupported parameter "%s"', param_name)
182
+ continue
183
+ msg = (
184
+ f'No handler found for parameter "{param_name}" of type '
185
+ f"{type(parameter)}"
186
+ )
187
+ raise NotImplementedError(msg)
188
+
189
+ ptype, weights, handler = result
190
+
191
+ param_meta = self._build_metadata(
192
+ parameter, model_id, param_name, param_idx, ptype, handler
193
+ )
194
+ param_proxy = ParameterDataProxy.create_and_store(
195
+ meta=param_meta,
196
+ repository=parameter_repository,
197
+ )
198
+ param_proxy.set_field(WEIGHTS_FIELD, weights)
199
+
200
+ logger.debug(
201
+ 'Extracted parameter "%s" with type %s (handler=%s)',
202
+ param_meta.name,
203
+ param_meta.ptype,
204
+ type(handler).__name__,
205
+ )
206
+
207
+ parameter_repository.append(param_proxy)
208
+
209
+ def _build_metadata(
210
+ self,
211
+ parameter: Any,
212
+ model_id: str,
213
+ param_name: str,
214
+ param_idx: int,
215
+ ptype: ParameterType,
216
+ handler: ParameterHandler,
217
+ ) -> ParameterMetadata:
218
+ """Build parameter metadata with handler input and overrides.
219
+
220
+ Constructs base metadata, enriches it with handler-provided additional
221
+ metadata, and applies any configured overrides.
222
+
223
+ Args:
224
+ parameter: The original parameter object.
225
+ model_id: Identifier of the model the parameter belongs to.
226
+ param_name: Name of the parameter.
227
+ param_idx: Index of parameter in model iteration order.
228
+ ptype: Parameter type determined by handler.
229
+ handler: Handler that processed this parameter.
230
+
231
+ Returns:
232
+ Complete parameter metadata with overrides applied.
233
+ """
234
+ metadata: dict[str, Any] = {
235
+ "name": param_name,
236
+ "ptype": ptype,
237
+ "model_id": model_id,
238
+ "other_meta": {"in_model_idx": param_idx},
239
+ }
240
+
241
+ # Best-effort metadata from the selected handler (no exceptions)
242
+ with suppress(Exception):
243
+ extra = handler.get_additional_metadata(parameter, param_name) or {}
244
+ metadata["other_meta"].update(extra)
245
+
246
+ self._apply_overrides(metadata)
247
+ return ParameterMetadata(**metadata)
248
+
249
+ def _apply_overrides(self, metadata: dict[str, Any]) -> None:
250
+ """Apply configured overrides to parameter metadata.
251
+
252
+ Modifies the metadata dictionary in-place based on configured
253
+ parameter-specific and global overrides. Preserves original
254
+ values in other_meta for traceability.
255
+
256
+ Args:
257
+ metadata: Parameter metadata dictionary to modify.
258
+ """
259
+ param_name = metadata["name"]
260
+
261
+ if param_name in self.overrides.parameter_overrides:
262
+ param_overrides = self.overrides.parameter_overrides[param_name]
263
+
264
+ if param_overrides.name:
265
+ metadata["name"] = param_overrides.name
266
+ metadata.setdefault("other_meta", {})["original_name"] = param_name
267
+
268
+ if param_overrides.ptype is not None:
269
+ metadata.setdefault("other_meta", {})["original_ptype"] = metadata[
270
+ "ptype"
271
+ ].name
272
+ metadata["ptype"] = (
273
+ ParameterType.from_string(param_overrides.ptype)
274
+ if isinstance(param_overrides.ptype, str)
275
+ else param_overrides.ptype
276
+ )
277
+
278
+ if param_overrides.other_meta:
279
+ metadata.setdefault("other_meta", {}).update(param_overrides.other_meta)
280
+
281
+ if self.overrides.model_id:
282
+ metadata.setdefault("other_meta", {})["original_model_id"] = metadata[
283
+ "model_id"
284
+ ]
285
+ metadata["model_id"] = self.overrides.model_id
286
+
287
+ @abstractmethod
288
+ def _iter_parameters(self) -> Generator[tuple[str, Any], None, None]:
289
+ """Iterate over model parameters yielding (name, parameter) tuples.
290
+
291
+ Subclasses must implement this method to provide framework-specific
292
+ parameter iteration logic.
293
+
294
+ Yields:
295
+ Tuples of (parameter_name, parameter_object) for each parameter.
296
+
297
+ Raises:
298
+ NotImplementedError: Must be implemented by subclasses.
299
+ """
300
+ raise NotImplementedError
@@ -0,0 +1,234 @@
1
+ """Factory pattern for creating framework-specific parameter extractors.
2
+
3
+ This module implements the factory pattern for automatically detecting neural
4
+ network model types and creating appropriate parameter extractors. It provides
5
+ a unified interface that abstracts away framework-specific details while
6
+ enabling extensible handler-based parameter processing.
7
+
8
+ The factory automatically detects supported frameworks and model types,
9
+ creating the most appropriate extractor implementation. It supports custom
10
+ handlers for specialized parameter processing and provides comprehensive
11
+ error handling for unsupported model types.
12
+
13
+ Supported Frameworks:
14
+ - NumPy: dict[str, numpy.ndarray] mappings (no framework required)
15
+ - PyTorch: torch.nn.Module and state_dict objects
16
+ - Extensible: Easy to add support for additional frameworks
17
+
18
+ Key Features:
19
+ - Automatic model type detection
20
+ - Framework-specific extractor creation
21
+ - Custom handler support for specialized processing
22
+ - Comprehensive error reporting with supported types
23
+ - Runtime framework availability checking
24
+
25
+ Example:
26
+ >>> import torch
27
+ >>> model = torch.nn.Linear(10, 5)
28
+ >>> extractor = create_extractor(model)
29
+ >>> # With custom handlers:
30
+ >>> extractor = create_extractor(model, custom_handlers=[MyHandler()])
31
+ >>> parameters = extractor.extract_parameters(storage, cache)
32
+ """
33
+
34
+ from __future__ import annotations
35
+
36
+ import logging
37
+ from typing import Any
38
+
39
+ import numpy as np
40
+
41
+ import diffract.core.utils.imports as import_utils
42
+
43
+ from .interface import IParameterExtractor
44
+
45
+ torch = import_utils.get_module("torch")
46
+ onnx = import_utils.get_module("onnx")
47
+ tf = import_utils.get_module("tensorflow")
48
+ flax = import_utils.get_module("flax")
49
+
50
+ logger = logging.getLogger(__name__)
51
+
52
+
53
+ def create_extractor(model: Any, *args: Any, **kwargs: Any) -> IParameterExtractor:
54
+ """Create appropriate parameter extractor based on model type.
55
+
56
+ Automatically detects the model type and framework, then creates the
57
+ most suitable parameter extractor. Supports custom handlers and
58
+ extractor overrides for specialized parameter processing.
59
+
60
+ Args:
61
+ model: Neural network model to extract parameters from.
62
+ *args: Additional positional arguments passed to extractor.
63
+ **kwargs: Additional keyword arguments passed to extractor.
64
+
65
+ Returns:
66
+ Parameter extractor instance appropriate for the model type.
67
+
68
+ Raises:
69
+ ImportError: If the model is not a NumPy dict and no supported
70
+ frameworks are available.
71
+ TypeError: If model type is not supported by any available framework.
72
+
73
+ Example:
74
+ >>> extractor = create_extractor(torch_model)
75
+ >>> extractor = create_extractor({"encoder.weight": np.random.rand(10, 5)})
76
+ >>> extractor = create_extractor(state_dict, custom_handlers=[handler])
77
+ """
78
+ if isinstance(model, dict) and all(
79
+ isinstance(name, str) and isinstance(value, np.ndarray)
80
+ for name, value in model.items()
81
+ ):
82
+ from .numpy import NumpyDictExtractor
83
+
84
+ logger.debug(
85
+ "Creating NumpyDictExtractor for array dict with %d parameters",
86
+ len(model),
87
+ )
88
+
89
+ return NumpyDictExtractor(*args, model=model, **kwargs)
90
+
91
+ if not get_supported_frameworks():
92
+ msg = (
93
+ "No supported deep learning frameworks available. "
94
+ "Please install PyTorch (torch) or other supported frameworks, "
95
+ "or pass a dict[str, numpy.ndarray] of weight matrices."
96
+ )
97
+ raise ImportError(msg)
98
+
99
+ if torch:
100
+ # PyTorch state_dict (dictionary of tensors)
101
+ if (
102
+ isinstance(model, dict)
103
+ and model
104
+ and all(isinstance(v, torch.Tensor) for v in model.values())
105
+ ):
106
+ from .torch import TorchStateDictExtractor
107
+
108
+ logger.debug(
109
+ "Creating TorchStateDictExtractor for state dict with %d parameters",
110
+ len(model),
111
+ )
112
+
113
+ return TorchStateDictExtractor(*args, model=model, **kwargs)
114
+
115
+ # PyTorch nn.Module (standard PyTorch models)
116
+ if isinstance(model, torch.nn.Module):
117
+ from .torch import TorchModuleExtractor
118
+
119
+ logger.debug(
120
+ "Creating TorchModuleExtractor for %s model", type(model).__name__
121
+ )
122
+
123
+ return TorchModuleExtractor(*args, model=model, **kwargs)
124
+
125
+ if onnx and isinstance(model, onnx.ModelProto):
126
+ # ONNX model
127
+ from .onnx import OnnxModelExtractor
128
+
129
+ logger.debug("Creating OnnxModelExtractor for ONNX ModelProto")
130
+ return OnnxModelExtractor(*args, model=model, **kwargs)
131
+
132
+ if tf and isinstance(model, (tf.keras.Model, tf.keras.layers.Layer)):
133
+ # TensorFlow / Keras model or layer
134
+ from .tensorflow import TensorFlowModelExtractor
135
+
136
+ logger.debug("Creating TensorFlowModelExtractor for %s", type(model).__name__)
137
+ return TensorFlowModelExtractor(*args, model=model, **kwargs)
138
+
139
+ if flax:
140
+ # Flax variables/params: mapping with "params" key or params mapping itself.
141
+ # We avoid importing JAX types here; rely on duck-typing for mappings.
142
+ try:
143
+ from collections.abc import Mapping
144
+ except ImportError:
145
+ mapping_type = None # type: ignore[assignment]
146
+ else:
147
+ mapping_type = Mapping
148
+
149
+ if mapping_type is not None and isinstance(model, mapping_type):
150
+ from .flax import FlaxParamsExtractor
151
+
152
+ logger.debug("Creating FlaxParamsExtractor for params/variables mapping")
153
+ return FlaxParamsExtractor(*args, model=model, **kwargs)
154
+
155
+ if hasattr(model, "variables"):
156
+ from .flax import FlaxParamsExtractor
157
+
158
+ logger.debug("Creating FlaxParamsExtractor for bound Flax module")
159
+ return FlaxParamsExtractor(*args, model=model, **kwargs)
160
+
161
+ error_msg = f"Unsupported model type: {type(model).__name__}. "
162
+
163
+ if supported_types := get_supported_types():
164
+ error_msg += f"Supported types: {', '.join(supported_types)}"
165
+ else:
166
+ error_msg += "No frameworks available."
167
+
168
+ raise TypeError(error_msg)
169
+
170
+
171
+ def get_supported_frameworks() -> list[str]:
172
+ """Get list of available deep learning frameworks.
173
+
174
+ Checks for the availability of supported deep learning frameworks
175
+ and returns their names. This is useful for diagnostics and
176
+ conditional feature availability.
177
+
178
+ Returns:
179
+ List of names of available frameworks.
180
+
181
+ Example:
182
+ >>> frameworks = get_supported_frameworks()
183
+ >>> print(f"Available frameworks: {', '.join(frameworks)}")
184
+ """
185
+ frameworks: list[str] = []
186
+ if torch:
187
+ frameworks.append("PyTorch")
188
+ if tf:
189
+ frameworks.append("TensorFlow")
190
+ if flax:
191
+ frameworks.append("Flax")
192
+ if onnx:
193
+ frameworks.append("ONNX")
194
+ return frameworks
195
+
196
+
197
+ def get_supported_types() -> list[str]:
198
+ """Get list of supported model types across all frameworks.
199
+
200
+ Returns a list of human-readable descriptions of supported model
201
+ types. This is useful for error messages and documentation.
202
+
203
+ Returns:
204
+ List of supported model type descriptions.
205
+
206
+ Example:
207
+ >>> types = get_supported_types()
208
+ >>> print(f"Supported types: {', '.join(types)}")
209
+ """
210
+ types: list[str] = ["dict[str, numpy.ndarray] (NumPy weight matrices)"]
211
+ if torch:
212
+ types.extend(
213
+ [
214
+ "torch.nn.Module (PyTorch models)",
215
+ "dict[str, torch.Tensor] (PyTorch state_dict)",
216
+ ]
217
+ )
218
+ if tf:
219
+ types.extend(
220
+ [
221
+ "tf.keras.Model (TensorFlow/Keras models)",
222
+ "tf.keras.layers.Layer (TensorFlow/Keras layers)",
223
+ ]
224
+ )
225
+ if flax:
226
+ types.extend(
227
+ [
228
+ 'Mapping[str, Any] (Flax params tree / variables with key "params")',
229
+ "Bound module with `.variables['params']` (Flax Linen bound module)",
230
+ ]
231
+ )
232
+ if onnx:
233
+ types.append("onnx.ModelProto (ONNX model)")
234
+ return types
@@ -0,0 +1,112 @@
1
+ """Flax/JAX parameter extractors.
2
+
3
+ Provides a parameter extractor for Flax models by reading a variables/params tree.
4
+ Currently supports only dense (fully-connected) kernel weights.
5
+
6
+ Supported inputs:
7
+ - A mapping with key `"params"` (e.g. flax variables FrozenDict)
8
+ - A bound Flax Linen module with `.variables` containing `"params"`
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import logging
14
+ from collections.abc import Mapping
15
+ from typing import TYPE_CHECKING, Any, Self
16
+
17
+ import diffract.core.utils.imports as import_utils
18
+
19
+ from .base import BaseParameterExtractor
20
+
21
+ if TYPE_CHECKING:
22
+ from collections.abc import Generator
23
+
24
+ from .base import ExtractorOverrides
25
+ from .handlers.base import ParameterHandler
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+
30
+ def _flatten_mapping(
31
+ mapping: Mapping[str, Any],
32
+ *,
33
+ prefix: str = "",
34
+ ) -> Generator[tuple[str, Any], None, None]:
35
+ """Flatten nested mappings into dot-separated key paths."""
36
+ for k, v in mapping.items():
37
+ name = f"{prefix}.{k}" if prefix else str(k)
38
+ if isinstance(v, Mapping):
39
+ yield from _flatten_mapping(v, prefix=name)
40
+ else:
41
+ yield name, v
42
+
43
+
44
+ if not (import_utils.is_available("flax") and import_utils.is_available("jax")):
45
+ logger.debug("Flax/JAX not available, disabling Flax extractors")
46
+
47
+ class FlaxParamsExtractor(BaseParameterExtractor):
48
+ """Stub implementation when Flax/JAX is not available."""
49
+
50
+ def __new__(cls, *_args: Any, **_kwargs: Any) -> Self: # noqa: D102
51
+ msg = "Flax/JAX packages not available"
52
+ raise ImportError(msg)
53
+
54
+ else:
55
+ from .handlers import FlaxDenseHandler
56
+
57
+ class FlaxParamsExtractor(BaseParameterExtractor):
58
+ """Flax params/variables extractor (DENSE only)."""
59
+
60
+ def __init__(
61
+ self,
62
+ model: Any,
63
+ overrides: ExtractorOverrides | None = None,
64
+ skip_not_implemented_types: bool = True,
65
+ custom_handlers: list[ParameterHandler] | None = None,
66
+ ) -> None:
67
+ super().__init__(
68
+ model, overrides, skip_not_implemented_types, custom_handlers
69
+ )
70
+
71
+ def _register_default_handlers(self) -> None:
72
+ self.handler_registry.register_handler_class(FlaxDenseHandler)
73
+ logger.debug(
74
+ "Registered %d default handlers for Flax params (DENSE only)",
75
+ len(self.handler_registry.list_handlers()),
76
+ )
77
+
78
+ def _iter_parameters(self) -> Generator[tuple[str, Any], None, None]:
79
+ """Iterate params leaves.
80
+
81
+ We extract only params named `*.kernel` (Dense convention). Other leaves
82
+ (bias, embeddings, etc.) are ignored by handlers.
83
+ """
84
+ obj = self.model
85
+
86
+ # Case 1: bound module with variables dict.
87
+ if hasattr(obj, "variables"):
88
+ variables = obj.variables
89
+ if isinstance(variables, Mapping) and "params" in variables:
90
+ params = variables["params"]
91
+ else:
92
+ params = None
93
+ else:
94
+ params = None
95
+
96
+ # Case 2: variables mapping or params mapping passed directly.
97
+ if params is None:
98
+ if isinstance(obj, Mapping) and "params" in obj:
99
+ params = obj["params"]
100
+ elif isinstance(obj, Mapping):
101
+ # Treat passed object as the params tree.
102
+ params = obj
103
+
104
+ if not isinstance(params, Mapping):
105
+ msg = (
106
+ "FlaxParamsExtractor expects a mapping of params (or variables "
107
+ 'mapping containing key "params"), got '
108
+ f"{type(self.model)}"
109
+ )
110
+ raise TypeError(msg)
111
+
112
+ yield from _flatten_mapping(params)
@@ -0,0 +1,39 @@
1
+ """Parameter handlers for extensible parameter processing.
2
+
3
+ This subpackage implements a handler-based architecture for processing neural
4
+ network parameters across frameworks. Handlers detect whether they can process
5
+ an input parameter and, if so, convert it to standardized NumPy weights and
6
+ provide optional metadata.
7
+
8
+ Components:
9
+ - base: Abstract handler interface and lightweight registry
10
+ - numpy_handlers: NumPy handlers for dense parameters
11
+ - torch_handlers: PyTorch handlers for dense parameters
12
+
13
+ Example:
14
+ >>> from diffract.core.data.nn.extractors.handlers import (
15
+ ... ParameterHandlerRegistry,
16
+ ... TorchDenseHandler,
17
+ ... )
18
+ >>> registry = ParameterHandlerRegistry()
19
+ >>> registry.register_handler_class(TorchDenseHandler)
20
+ >>> # Later: handler = registry.process_parameter(module, name)
21
+ """
22
+
23
+ from .base import ParameterHandler, ParameterHandlerRegistry
24
+ from .flax_handlers import FlaxDenseHandler
25
+ from .numpy_handlers import NumpyDenseHandler
26
+ from .onnx_handlers import OnnxDenseHandler
27
+ from .tensorflow_handlers import TensorFlowDenseHandler
28
+ from .torch_handlers import TorchDenseHandler, TorchStateDictDenseHandler
29
+
30
+ __all__ = [
31
+ "FlaxDenseHandler",
32
+ "NumpyDenseHandler",
33
+ "OnnxDenseHandler",
34
+ "ParameterHandler",
35
+ "ParameterHandlerRegistry",
36
+ "TensorFlowDenseHandler",
37
+ "TorchDenseHandler",
38
+ "TorchStateDictDenseHandler",
39
+ ]