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.
- diffract/__init__.py +52 -0
- diffract/configs/fast_speed_without_disk.ini +48 -0
- diffract/configs/hybrid.ini +74 -0
- diffract/configs/sqlite.ini +62 -0
- diffract/containers.py +405 -0
- diffract/core/__init__.py +23 -0
- diffract/core/cache/__init__.py +24 -0
- diffract/core/cache/containers.py +93 -0
- diffract/core/cache/interface.py +117 -0
- diffract/core/cache/redis_manager.py +464 -0
- diffract/core/cache/simple_manager.py +478 -0
- diffract/core/compute/__init__.py +46 -0
- diffract/core/compute/config.py +48 -0
- diffract/core/compute/containers.py +81 -0
- diffract/core/compute/decorator.py +125 -0
- diffract/core/compute/exceptions.py +31 -0
- diffract/core/compute/execution/__init__.py +14 -0
- diffract/core/compute/execution/_types.py +70 -0
- diffract/core/compute/execution/aggregation.py +74 -0
- diffract/core/compute/execution/aggregation_runner.py +362 -0
- diffract/core/compute/execution/enums.py +38 -0
- diffract/core/compute/execution/executor.py +125 -0
- diffract/core/compute/execution/parameter_runner.py +125 -0
- diffract/core/compute/execution/restrictions.py +61 -0
- diffract/core/compute/execution/strategy.py +118 -0
- diffract/core/compute/execution/utils.py +112 -0
- diffract/core/compute/extensions/__init__.py +0 -0
- diffract/core/compute/extensions/power_law.py +1051 -0
- diffract/core/compute/extensions/rmt.py +150 -0
- diffract/core/compute/extensions/utils.py +36 -0
- diffract/core/compute/field_signature.py +183 -0
- diffract/core/compute/kernels/__init__.py +48 -0
- diffract/core/compute/kernels/alignment.py +106 -0
- diffract/core/compute/kernels/heavy_tailed.py +394 -0
- diffract/core/compute/kernels/marchenko_pastur.py +99 -0
- diffract/core/compute/kernels/mat_decomposition.py +101 -0
- diffract/core/compute/kernels/mat_properties.py +53 -0
- diffract/core/compute/kernels/model_quality.py +27 -0
- diffract/core/compute/kernels/norms.py +88 -0
- diffract/core/compute/kernels/ranks.py +35 -0
- diffract/core/compute/kernels/tracy_widom.py +36 -0
- diffract/core/compute/metadata.py +67 -0
- diffract/core/compute/registry.py +485 -0
- diffract/core/constants.py +147 -0
- diffract/core/data/__init__.py +32 -0
- diffract/core/data/interface.py +304 -0
- diffract/core/data/metadata/__init__.py +15 -0
- diffract/core/data/metadata/containers.py +60 -0
- diffract/core/data/metadata/interface.py +208 -0
- diffract/core/data/metadata/sqlite_index.py +604 -0
- diffract/core/data/nn/__init__.py +43 -0
- diffract/core/data/nn/aggregates/__init__.py +35 -0
- diffract/core/data/nn/aggregates/metadata.py +96 -0
- diffract/core/data/nn/aggregates/proxy.py +57 -0
- diffract/core/data/nn/aggregates/repository.py +87 -0
- diffract/core/data/nn/aggregates/view.py +307 -0
- diffract/core/data/nn/containers.py +86 -0
- diffract/core/data/nn/extractors/__init__.py +49 -0
- diffract/core/data/nn/extractors/base.py +300 -0
- diffract/core/data/nn/extractors/factory.py +234 -0
- diffract/core/data/nn/extractors/flax.py +112 -0
- diffract/core/data/nn/extractors/handlers/__init__.py +39 -0
- diffract/core/data/nn/extractors/handlers/base.py +110 -0
- diffract/core/data/nn/extractors/handlers/flax_handlers.py +71 -0
- diffract/core/data/nn/extractors/handlers/numpy_handlers.py +63 -0
- diffract/core/data/nn/extractors/handlers/onnx_handlers.py +67 -0
- diffract/core/data/nn/extractors/handlers/tensorflow_handlers.py +82 -0
- diffract/core/data/nn/extractors/handlers/torch_handlers.py +124 -0
- diffract/core/data/nn/extractors/interface.py +56 -0
- diffract/core/data/nn/extractors/numpy.py +94 -0
- diffract/core/data/nn/extractors/onnx.py +108 -0
- diffract/core/data/nn/extractors/tensorflow.py +99 -0
- diffract/core/data/nn/extractors/torch.py +204 -0
- diffract/core/data/nn/params/__init__.py +27 -0
- diffract/core/data/nn/params/interface.py +402 -0
- diffract/core/data/nn/params/metadata.py +110 -0
- diffract/core/data/nn/params/proxy.py +93 -0
- diffract/core/data/nn/params/repository.py +45 -0
- diffract/core/data/nn/params/schema.py +82 -0
- diffract/core/data/nn/params/view.py +393 -0
- diffract/core/data/proxy.py +246 -0
- diffract/core/data/repository.py +227 -0
- diffract/core/data/utils.py +33 -0
- diffract/core/data/view.py +389 -0
- diffract/core/export/__init__.py +27 -0
- diffract/core/export/containers.py +47 -0
- diffract/core/export/exporters.py +191 -0
- diffract/core/export/formatters/__init__.py +23 -0
- diffract/core/export/formatters/base.py +68 -0
- diffract/core/export/formatters/dict_formatter.py +38 -0
- diffract/core/export/formatters/json_formatter.py +58 -0
- diffract/core/export/formatters/list_formatter.py +41 -0
- diffract/core/export/formatters/pandas_formatter.py +86 -0
- diffract/core/export/formatters/polars_formatter.py +86 -0
- diffract/core/export/formatters/registry.py +84 -0
- diffract/core/export/interface.py +105 -0
- diffract/core/parallel/__init__.py +21 -0
- diffract/core/parallel/containers.py +57 -0
- diffract/core/parallel/execution.py +91 -0
- diffract/core/parallel/runtime.py +91 -0
- diffract/core/storage/__init__.py +35 -0
- diffract/core/storage/base_manager.py +330 -0
- diffract/core/storage/containers.py +122 -0
- diffract/core/storage/hdf5_manager.py +856 -0
- diffract/core/storage/hybrid_manager.py +218 -0
- diffract/core/storage/interface.py +222 -0
- diffract/core/storage/metadata.py +89 -0
- diffract/core/storage/ram_manager.py +159 -0
- diffract/core/storage/sqlite_manager.py +1062 -0
- diffract/core/storage/zarr_manager.py +992 -0
- diffract/core/utils/__init__.py +45 -0
- diffract/core/utils/build.py +46 -0
- diffract/core/utils/exceptions.py +11 -0
- diffract/core/utils/hashing.py +90 -0
- diffract/core/utils/imports.py +292 -0
- diffract/core/utils/math.py +15 -0
- diffract/py.typed +0 -0
- diffract/session/__init__.py +24 -0
- diffract/session/errors.py +17 -0
- diffract/session/field_cache.py +216 -0
- diffract/session/namespaces/__init__.py +15 -0
- diffract/session/namespaces/compute/__init__.py +219 -0
- diffract/session/namespaces/models/__init__.py +282 -0
- diffract/session/namespaces/models/parameters/__init__.py +133 -0
- diffract/session/namespaces/models/parameters/meta_patcher.py +167 -0
- diffract/session/namespaces/results/__init__.py +378 -0
- diffract/session/namespaces/results/eraser.py +129 -0
- diffract/session/namespaces/results/injester.py +249 -0
- diffract/session/namespaces/utils/__init__.py +141 -0
- diffract/session/namespaces/utils/merger.py +295 -0
- diffract/session/namespaces/viz/__init__.py +91 -0
- diffract/session/namespaces/viz/_utils.py +14 -0
- diffract/session/namespaces/viz/box.py +207 -0
- diffract/session/namespaces/viz/grid.py +160 -0
- diffract/session/namespaces/viz/heatmap.py +164 -0
- diffract/session/namespaces/viz/scatter.py +202 -0
- diffract/session/namespaces/viz/sparkline.py +270 -0
- diffract/session/namespaces/viz/violin.py +212 -0
- diffract/session/session.py +260 -0
- diffract/session/utils.py +81 -0
- diffract/viz/__init__.py +42 -0
- diffract/viz/data/__init__.py +34 -0
- diffract/viz/data/detection.py +57 -0
- diffract/viz/data/extraction.py +117 -0
- diffract/viz/data/filtering.py +57 -0
- diffract/viz/data/ordering.py +129 -0
- diffract/viz/data/provider.py +99 -0
- diffract/viz/data/types.py +98 -0
- diffract/viz/plots/__init__.py +37 -0
- diffract/viz/plots/base/__init__.py +20 -0
- diffract/viz/plots/base/axis.py +219 -0
- diffract/viz/plots/base/coloraxis.py +133 -0
- diffract/viz/plots/base/configurator.py +18 -0
- diffract/viz/plots/base/jitter.py +368 -0
- diffract/viz/plots/base/line.py +197 -0
- diffract/viz/plots/base/marker.py +278 -0
- diffract/viz/plots/base/overlay.py +14 -0
- diffract/viz/plots/base/plot.py +110 -0
- diffract/viz/plots/base/update.py +50 -0
- diffract/viz/plots/boxplot.py +283 -0
- diffract/viz/plots/cluster.py +374 -0
- diffract/viz/plots/heatmap.py +168 -0
- diffract/viz/plots/scatter.py +233 -0
- diffract/viz/plots/sparkline.py +405 -0
- diffract/viz/plots/subplots/__init__.py +32 -0
- diffract/viz/plots/subplots/coloraxis.py +339 -0
- diffract/viz/plots/subplots/factory.py +713 -0
- diffract/viz/plots/subplots/grid.py +214 -0
- diffract/viz/plots/subplots/layout.py +370 -0
- diffract/viz/plots/subplots/spec.py +39 -0
- diffract/viz/plots/violin.py +298 -0
- diffract/viz/renderer.py +513 -0
- diffract/viz/styling/__init__.py +78 -0
- diffract/viz/styling/palettes/__init__.py +20 -0
- diffract/viz/styling/palettes/bundle.py +16 -0
- diffract/viz/styling/palettes/color.py +83 -0
- diffract/viz/styling/palettes/dashes.py +27 -0
- diffract/viz/styling/palettes/symbols.py +42 -0
- diffract/viz/styling/resolvers/__init__.py +11 -0
- diffract/viz/styling/resolvers/categorical.py +68 -0
- diffract/viz/styling/resolvers/color.py +77 -0
- diffract/viz/styling/resolvers/numeric.py +108 -0
- diffract/viz/styling/sources.py +27 -0
- diffract/viz/styling/theme/__init__.py +29 -0
- diffract/viz/styling/theme/applier.py +114 -0
- diffract/viz/styling/theme/components.py +66 -0
- diffract/viz/styling/theme/presets.py +58 -0
- diffract/viz/styling/theme/theme.py +36 -0
- diffract_core-0.2.1.dist-info/METADATA +530 -0
- diffract_core-0.2.1.dist-info/RECORD +193 -0
- diffract_core-0.2.1.dist-info/WHEEL +4 -0
- diffract_core-0.2.1.dist-info/licenses/LICENSE +201 -0
- 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
|
+
]
|