morphml 1.0.0__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.
Potentially problematic release.
This version of morphml might be problematic. Click here for more details.
- morphml/__init__.py +14 -0
- morphml/api/__init__.py +26 -0
- morphml/api/app.py +326 -0
- morphml/api/auth.py +193 -0
- morphml/api/client.py +338 -0
- morphml/api/models.py +132 -0
- morphml/api/rate_limit.py +192 -0
- morphml/benchmarking/__init__.py +36 -0
- morphml/benchmarking/comparison.py +430 -0
- morphml/benchmarks/__init__.py +56 -0
- morphml/benchmarks/comparator.py +409 -0
- morphml/benchmarks/datasets.py +280 -0
- morphml/benchmarks/metrics.py +199 -0
- morphml/benchmarks/openml_suite.py +201 -0
- morphml/benchmarks/problems.py +289 -0
- morphml/benchmarks/suite.py +318 -0
- morphml/cli/__init__.py +5 -0
- morphml/cli/commands/experiment.py +329 -0
- morphml/cli/main.py +457 -0
- morphml/cli/quickstart.py +312 -0
- morphml/config.py +278 -0
- morphml/constraints/__init__.py +19 -0
- morphml/constraints/handler.py +205 -0
- morphml/constraints/predicates.py +285 -0
- morphml/core/__init__.py +3 -0
- morphml/core/crossover.py +449 -0
- morphml/core/dsl/README.md +359 -0
- morphml/core/dsl/__init__.py +72 -0
- morphml/core/dsl/ast_nodes.py +364 -0
- morphml/core/dsl/compiler.py +318 -0
- morphml/core/dsl/layers.py +368 -0
- morphml/core/dsl/lexer.py +336 -0
- morphml/core/dsl/parser.py +455 -0
- morphml/core/dsl/search_space.py +386 -0
- morphml/core/dsl/syntax.py +199 -0
- morphml/core/dsl/type_system.py +361 -0
- morphml/core/dsl/validator.py +386 -0
- morphml/core/graph/__init__.py +40 -0
- morphml/core/graph/edge.py +124 -0
- morphml/core/graph/graph.py +507 -0
- morphml/core/graph/mutations.py +409 -0
- morphml/core/graph/node.py +196 -0
- morphml/core/graph/serialization.py +361 -0
- morphml/core/graph/visualization.py +431 -0
- morphml/core/objectives/__init__.py +20 -0
- morphml/core/search/__init__.py +33 -0
- morphml/core/search/individual.py +252 -0
- morphml/core/search/parameters.py +453 -0
- morphml/core/search/population.py +375 -0
- morphml/core/search/search_engine.py +340 -0
- morphml/distributed/__init__.py +76 -0
- morphml/distributed/fault_tolerance.py +497 -0
- morphml/distributed/health_monitor.py +348 -0
- morphml/distributed/master.py +709 -0
- morphml/distributed/proto/README.md +224 -0
- morphml/distributed/proto/__init__.py +74 -0
- morphml/distributed/proto/worker.proto +170 -0
- morphml/distributed/proto/worker_pb2.py +79 -0
- morphml/distributed/proto/worker_pb2_grpc.py +423 -0
- morphml/distributed/resource_manager.py +416 -0
- morphml/distributed/scheduler.py +567 -0
- morphml/distributed/storage/__init__.py +33 -0
- morphml/distributed/storage/artifacts.py +381 -0
- morphml/distributed/storage/cache.py +366 -0
- morphml/distributed/storage/checkpointing.py +329 -0
- morphml/distributed/storage/database.py +459 -0
- morphml/distributed/worker.py +549 -0
- morphml/evaluation/__init__.py +5 -0
- morphml/evaluation/heuristic.py +237 -0
- morphml/exceptions.py +55 -0
- morphml/execution/__init__.py +5 -0
- morphml/execution/local_executor.py +350 -0
- morphml/integrations/__init__.py +28 -0
- morphml/integrations/jax_adapter.py +206 -0
- morphml/integrations/pytorch_adapter.py +530 -0
- morphml/integrations/sklearn_adapter.py +206 -0
- morphml/integrations/tensorflow_adapter.py +230 -0
- morphml/logging_config.py +93 -0
- morphml/meta_learning/__init__.py +66 -0
- morphml/meta_learning/architecture_similarity.py +277 -0
- morphml/meta_learning/experiment_database.py +240 -0
- morphml/meta_learning/knowledge_base/__init__.py +19 -0
- morphml/meta_learning/knowledge_base/embedder.py +179 -0
- morphml/meta_learning/knowledge_base/knowledge_base.py +313 -0
- morphml/meta_learning/knowledge_base/meta_features.py +265 -0
- morphml/meta_learning/knowledge_base/vector_store.py +271 -0
- morphml/meta_learning/predictors/__init__.py +27 -0
- morphml/meta_learning/predictors/ensemble.py +221 -0
- morphml/meta_learning/predictors/gnn_predictor.py +552 -0
- morphml/meta_learning/predictors/learning_curve.py +231 -0
- morphml/meta_learning/predictors/proxy_metrics.py +261 -0
- morphml/meta_learning/strategy_evolution/__init__.py +27 -0
- morphml/meta_learning/strategy_evolution/adaptive_optimizer.py +226 -0
- morphml/meta_learning/strategy_evolution/bandit.py +276 -0
- morphml/meta_learning/strategy_evolution/portfolio.py +230 -0
- morphml/meta_learning/transfer.py +581 -0
- morphml/meta_learning/warm_start.py +286 -0
- morphml/optimizers/__init__.py +74 -0
- morphml/optimizers/adaptive_operators.py +399 -0
- morphml/optimizers/bayesian/__init__.py +52 -0
- morphml/optimizers/bayesian/acquisition.py +387 -0
- morphml/optimizers/bayesian/base.py +319 -0
- morphml/optimizers/bayesian/gaussian_process.py +635 -0
- morphml/optimizers/bayesian/smac.py +534 -0
- morphml/optimizers/bayesian/tpe.py +411 -0
- morphml/optimizers/differential_evolution.py +220 -0
- morphml/optimizers/evolutionary/__init__.py +61 -0
- morphml/optimizers/evolutionary/cma_es.py +416 -0
- morphml/optimizers/evolutionary/differential_evolution.py +556 -0
- morphml/optimizers/evolutionary/encoding.py +426 -0
- morphml/optimizers/evolutionary/particle_swarm.py +449 -0
- morphml/optimizers/genetic_algorithm.py +486 -0
- morphml/optimizers/gradient_based/__init__.py +22 -0
- morphml/optimizers/gradient_based/darts.py +550 -0
- morphml/optimizers/gradient_based/enas.py +585 -0
- morphml/optimizers/gradient_based/operations.py +474 -0
- morphml/optimizers/gradient_based/utils.py +601 -0
- morphml/optimizers/hill_climbing.py +169 -0
- morphml/optimizers/multi_objective/__init__.py +56 -0
- morphml/optimizers/multi_objective/indicators.py +504 -0
- morphml/optimizers/multi_objective/nsga2.py +647 -0
- morphml/optimizers/multi_objective/visualization.py +427 -0
- morphml/optimizers/nsga2.py +308 -0
- morphml/optimizers/random_search.py +172 -0
- morphml/optimizers/simulated_annealing.py +181 -0
- morphml/plugins/__init__.py +35 -0
- morphml/plugins/custom_evaluator_example.py +81 -0
- morphml/plugins/custom_optimizer_example.py +63 -0
- morphml/plugins/plugin_system.py +454 -0
- morphml/reports/__init__.py +30 -0
- morphml/reports/generator.py +362 -0
- morphml/tracking/__init__.py +7 -0
- morphml/tracking/experiment.py +309 -0
- morphml/tracking/logger.py +301 -0
- morphml/tracking/reporter.py +357 -0
- morphml/utils/__init__.py +6 -0
- morphml/utils/checkpoint.py +189 -0
- morphml/utils/comparison.py +390 -0
- morphml/utils/export.py +407 -0
- morphml/utils/progress.py +392 -0
- morphml/utils/validation.py +392 -0
- morphml/version.py +7 -0
- morphml/visualization/__init__.py +50 -0
- morphml/visualization/analytics.py +423 -0
- morphml/visualization/architecture_diagrams.py +353 -0
- morphml/visualization/architecture_plot.py +223 -0
- morphml/visualization/convergence_plot.py +174 -0
- morphml/visualization/crossover_viz.py +386 -0
- morphml/visualization/graph_viz.py +338 -0
- morphml/visualization/pareto_plot.py +149 -0
- morphml/visualization/plotly_dashboards.py +422 -0
- morphml/visualization/population.py +309 -0
- morphml/visualization/progress.py +260 -0
- morphml-1.0.0.dist-info/METADATA +434 -0
- morphml-1.0.0.dist-info/RECORD +158 -0
- morphml-1.0.0.dist-info/WHEEL +4 -0
- morphml-1.0.0.dist-info/entry_points.txt +3 -0
- morphml-1.0.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
"""Serialization utilities for model graphs.
|
|
2
|
+
|
|
3
|
+
Provides functions to save and load ModelGraph objects in various formats:
|
|
4
|
+
- JSON: Human-readable, good for inspection
|
|
5
|
+
- Pickle: Python-native, preserves exact state
|
|
6
|
+
- YAML: Configuration-friendly format
|
|
7
|
+
|
|
8
|
+
Author: Eshan Roy <eshanized@proton.me>
|
|
9
|
+
Organization: TONMOY INFRASTRUCTURE & VISION
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import pickle
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Any, Dict, Optional, Union
|
|
16
|
+
|
|
17
|
+
from morphml.core.graph.graph import ModelGraph
|
|
18
|
+
from morphml.exceptions import GraphError
|
|
19
|
+
from morphml.logging_config import get_logger
|
|
20
|
+
|
|
21
|
+
logger = get_logger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def save_graph(
|
|
25
|
+
graph: ModelGraph,
|
|
26
|
+
path: Union[str, Path],
|
|
27
|
+
format: str = "json",
|
|
28
|
+
indent: int = 2,
|
|
29
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
30
|
+
) -> None:
|
|
31
|
+
"""
|
|
32
|
+
Save model graph to file.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
graph: ModelGraph to save
|
|
36
|
+
path: Output file path
|
|
37
|
+
format: Format ('json', 'pickle', 'yaml')
|
|
38
|
+
indent: JSON indentation (for readability)
|
|
39
|
+
metadata: Additional metadata to save with graph
|
|
40
|
+
|
|
41
|
+
Raises:
|
|
42
|
+
GraphError: If save fails
|
|
43
|
+
|
|
44
|
+
Example:
|
|
45
|
+
>>> graph = ModelGraph()
|
|
46
|
+
>>> save_graph(graph, 'model.json')
|
|
47
|
+
>>> save_graph(graph, 'model.pkl', format='pickle')
|
|
48
|
+
"""
|
|
49
|
+
path = Path(path)
|
|
50
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
if format == "json":
|
|
54
|
+
_save_json(graph, path, indent, metadata)
|
|
55
|
+
elif format == "pickle":
|
|
56
|
+
_save_pickle(graph, path, metadata)
|
|
57
|
+
elif format == "yaml":
|
|
58
|
+
_save_yaml(graph, path, metadata)
|
|
59
|
+
else:
|
|
60
|
+
raise GraphError(f"Unknown format: {format}. Use 'json', 'pickle', or 'yaml'")
|
|
61
|
+
|
|
62
|
+
logger.info(f"Saved graph to {path} (format: {format})")
|
|
63
|
+
|
|
64
|
+
except Exception as e:
|
|
65
|
+
logger.error(f"Failed to save graph: {e}")
|
|
66
|
+
raise GraphError(f"Failed to save graph to {path}: {e}") from e
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def load_graph(path: Union[str, Path], format: Optional[str] = None) -> ModelGraph:
|
|
70
|
+
"""
|
|
71
|
+
Load model graph from file.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
path: Input file path
|
|
75
|
+
format: Format ('json', 'pickle', 'yaml'). If None, infers from extension
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
Loaded ModelGraph
|
|
79
|
+
|
|
80
|
+
Raises:
|
|
81
|
+
GraphError: If load fails
|
|
82
|
+
|
|
83
|
+
Example:
|
|
84
|
+
>>> graph = load_graph('model.json')
|
|
85
|
+
>>> graph = load_graph('model.pkl', format='pickle')
|
|
86
|
+
"""
|
|
87
|
+
path = Path(path)
|
|
88
|
+
|
|
89
|
+
if not path.exists():
|
|
90
|
+
raise GraphError(f"File not found: {path}")
|
|
91
|
+
|
|
92
|
+
# Infer format from extension if not specified
|
|
93
|
+
if format is None:
|
|
94
|
+
format = _infer_format(path)
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
if format == "json":
|
|
98
|
+
graph = _load_json(path)
|
|
99
|
+
elif format == "pickle":
|
|
100
|
+
graph = _load_pickle(path)
|
|
101
|
+
elif format == "yaml":
|
|
102
|
+
graph = _load_yaml(path)
|
|
103
|
+
else:
|
|
104
|
+
raise GraphError(f"Unknown format: {format}")
|
|
105
|
+
|
|
106
|
+
logger.info(f"Loaded graph from {path} (format: {format})")
|
|
107
|
+
return graph
|
|
108
|
+
|
|
109
|
+
except Exception as e:
|
|
110
|
+
logger.error(f"Failed to load graph: {e}")
|
|
111
|
+
raise GraphError(f"Failed to load graph from {path}: {e}") from e
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _save_json(
|
|
115
|
+
graph: ModelGraph, path: Path, indent: int, metadata: Optional[Dict[str, Any]]
|
|
116
|
+
) -> None:
|
|
117
|
+
"""Save graph as JSON."""
|
|
118
|
+
data = graph.to_dict()
|
|
119
|
+
|
|
120
|
+
# Add metadata if provided
|
|
121
|
+
if metadata:
|
|
122
|
+
data["_metadata"] = metadata
|
|
123
|
+
|
|
124
|
+
with open(path, "w") as f:
|
|
125
|
+
json.dump(data, f, indent=indent, sort_keys=False)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _load_json(path: Path) -> ModelGraph:
|
|
129
|
+
"""Load graph from JSON."""
|
|
130
|
+
with open(path, "r") as f:
|
|
131
|
+
data = json.load(f)
|
|
132
|
+
|
|
133
|
+
# Remove metadata if present
|
|
134
|
+
data.pop("_metadata", None)
|
|
135
|
+
|
|
136
|
+
return ModelGraph.from_dict(data)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _save_pickle(graph: ModelGraph, path: Path, metadata: Optional[Dict[str, Any]]) -> None:
|
|
140
|
+
"""Save graph as pickle."""
|
|
141
|
+
data = {"graph": graph, "metadata": metadata}
|
|
142
|
+
|
|
143
|
+
with open(path, "wb") as f:
|
|
144
|
+
pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _load_pickle(path: Path) -> ModelGraph:
|
|
148
|
+
"""Load graph from pickle."""
|
|
149
|
+
with open(path, "rb") as f:
|
|
150
|
+
data = pickle.load(f)
|
|
151
|
+
|
|
152
|
+
# Handle both old and new formats
|
|
153
|
+
if isinstance(data, ModelGraph):
|
|
154
|
+
return data
|
|
155
|
+
elif isinstance(data, dict) and "graph" in data:
|
|
156
|
+
return data["graph"]
|
|
157
|
+
else:
|
|
158
|
+
raise GraphError("Invalid pickle format")
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _save_yaml(graph: ModelGraph, path: Path, metadata: Optional[Dict[str, Any]]) -> None:
|
|
162
|
+
"""Save graph as YAML."""
|
|
163
|
+
try:
|
|
164
|
+
import yaml
|
|
165
|
+
except ImportError:
|
|
166
|
+
raise GraphError("PyYAML not installed. Install with: pip install pyyaml")
|
|
167
|
+
|
|
168
|
+
data = graph.to_dict()
|
|
169
|
+
|
|
170
|
+
# Add metadata if provided
|
|
171
|
+
if metadata:
|
|
172
|
+
data["_metadata"] = metadata
|
|
173
|
+
|
|
174
|
+
with open(path, "w") as f:
|
|
175
|
+
yaml.dump(data, f, default_flow_style=False, sort_keys=False)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _load_yaml(path: Path) -> ModelGraph:
|
|
179
|
+
"""Load graph from YAML."""
|
|
180
|
+
try:
|
|
181
|
+
import yaml
|
|
182
|
+
except ImportError:
|
|
183
|
+
raise GraphError("PyYAML not installed. Install with: pip install pyyaml")
|
|
184
|
+
|
|
185
|
+
with open(path, "r") as f:
|
|
186
|
+
data = yaml.safe_load(f)
|
|
187
|
+
|
|
188
|
+
# Remove metadata if present
|
|
189
|
+
data.pop("_metadata", None)
|
|
190
|
+
|
|
191
|
+
return ModelGraph.from_dict(data)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def _infer_format(path: Path) -> str:
|
|
195
|
+
"""Infer format from file extension."""
|
|
196
|
+
suffix = path.suffix.lower()
|
|
197
|
+
|
|
198
|
+
format_map = {
|
|
199
|
+
".json": "json",
|
|
200
|
+
".pkl": "pickle",
|
|
201
|
+
".pickle": "pickle",
|
|
202
|
+
".yaml": "yaml",
|
|
203
|
+
".yml": "yaml",
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
format = format_map.get(suffix)
|
|
207
|
+
if format is None:
|
|
208
|
+
logger.warning(f"Unknown extension {suffix}, assuming JSON")
|
|
209
|
+
return "json"
|
|
210
|
+
|
|
211
|
+
return format
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def graph_to_json_string(graph: ModelGraph, indent: int = 2) -> str:
|
|
215
|
+
"""
|
|
216
|
+
Convert graph to JSON string.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
graph: ModelGraph to convert
|
|
220
|
+
indent: Indentation level
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
JSON string representation
|
|
224
|
+
|
|
225
|
+
Example:
|
|
226
|
+
>>> json_str = graph_to_json_string(graph)
|
|
227
|
+
>>> print(json_str)
|
|
228
|
+
"""
|
|
229
|
+
return json.dumps(graph.to_dict(), indent=indent, sort_keys=False)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def graph_from_json_string(json_str: str) -> ModelGraph:
|
|
233
|
+
"""
|
|
234
|
+
Create graph from JSON string.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
json_str: JSON string representation
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
ModelGraph instance
|
|
241
|
+
|
|
242
|
+
Example:
|
|
243
|
+
>>> graph = graph_from_json_string(json_str)
|
|
244
|
+
"""
|
|
245
|
+
data = json.loads(json_str)
|
|
246
|
+
return ModelGraph.from_dict(data)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def export_graph_summary(graph: ModelGraph, path: Union[str, Path]) -> None:
|
|
250
|
+
"""
|
|
251
|
+
Export human-readable graph summary.
|
|
252
|
+
|
|
253
|
+
Creates a text file with graph statistics and structure.
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
graph: ModelGraph to summarize
|
|
257
|
+
path: Output file path
|
|
258
|
+
|
|
259
|
+
Example:
|
|
260
|
+
>>> export_graph_summary(graph, 'model_summary.txt')
|
|
261
|
+
"""
|
|
262
|
+
path = Path(path)
|
|
263
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
264
|
+
|
|
265
|
+
lines = []
|
|
266
|
+
lines.append("=" * 60)
|
|
267
|
+
lines.append("MODEL GRAPH SUMMARY")
|
|
268
|
+
lines.append("=" * 60)
|
|
269
|
+
lines.append("")
|
|
270
|
+
|
|
271
|
+
# Basic info
|
|
272
|
+
lines.append(f"Nodes: {len(graph.nodes)}")
|
|
273
|
+
lines.append(f"Edges: {len(graph.edges)}")
|
|
274
|
+
lines.append(f"Depth: {graph.get_depth()}")
|
|
275
|
+
lines.append(f"Width: {graph.get_max_width()}")
|
|
276
|
+
lines.append(f"Params: {graph.estimate_parameters():,}")
|
|
277
|
+
lines.append("")
|
|
278
|
+
|
|
279
|
+
# Nodes
|
|
280
|
+
lines.append("NODES:")
|
|
281
|
+
lines.append("-" * 60)
|
|
282
|
+
for node_id, node in graph.nodes.items():
|
|
283
|
+
lines.append(f" {node_id[:8]}... | {node.operation:15s} | {node.params}")
|
|
284
|
+
|
|
285
|
+
lines.append("")
|
|
286
|
+
|
|
287
|
+
# Edges
|
|
288
|
+
lines.append("EDGES:")
|
|
289
|
+
lines.append("-" * 60)
|
|
290
|
+
for _edge_id, edge in graph.edges.items():
|
|
291
|
+
src = edge.source.id[:8] if edge.source else "None"
|
|
292
|
+
tgt = edge.target.id[:8] if edge.target else "None"
|
|
293
|
+
lines.append(f" {src}... -> {tgt}...")
|
|
294
|
+
|
|
295
|
+
lines.append("")
|
|
296
|
+
lines.append("=" * 60)
|
|
297
|
+
|
|
298
|
+
with open(path, "w") as f:
|
|
299
|
+
f.write("\n".join(lines))
|
|
300
|
+
|
|
301
|
+
logger.info(f"Exported graph summary to {path}")
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def batch_save_graphs(
|
|
305
|
+
graphs: Dict[str, ModelGraph], output_dir: Union[str, Path], format: str = "json"
|
|
306
|
+
) -> None:
|
|
307
|
+
"""
|
|
308
|
+
Save multiple graphs to directory.
|
|
309
|
+
|
|
310
|
+
Args:
|
|
311
|
+
graphs: Dictionary mapping names to graphs
|
|
312
|
+
output_dir: Output directory
|
|
313
|
+
format: Save format
|
|
314
|
+
|
|
315
|
+
Example:
|
|
316
|
+
>>> graphs = {'model1': graph1, 'model2': graph2}
|
|
317
|
+
>>> batch_save_graphs(graphs, 'models/', format='json')
|
|
318
|
+
"""
|
|
319
|
+
output_dir = Path(output_dir)
|
|
320
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
321
|
+
|
|
322
|
+
for name, graph in graphs.items():
|
|
323
|
+
ext = {"json": ".json", "pickle": ".pkl", "yaml": ".yaml"}[format]
|
|
324
|
+
path = output_dir / f"{name}{ext}"
|
|
325
|
+
save_graph(graph, path, format=format)
|
|
326
|
+
|
|
327
|
+
logger.info(f"Saved {len(graphs)} graphs to {output_dir}")
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def batch_load_graphs(
|
|
331
|
+
input_dir: Union[str, Path], format: Optional[str] = None
|
|
332
|
+
) -> Dict[str, ModelGraph]:
|
|
333
|
+
"""
|
|
334
|
+
Load all graphs from directory.
|
|
335
|
+
|
|
336
|
+
Args:
|
|
337
|
+
input_dir: Input directory
|
|
338
|
+
format: Load format (None to infer from extensions)
|
|
339
|
+
|
|
340
|
+
Returns:
|
|
341
|
+
Dictionary mapping filenames to graphs
|
|
342
|
+
|
|
343
|
+
Example:
|
|
344
|
+
>>> graphs = batch_load_graphs('models/')
|
|
345
|
+
"""
|
|
346
|
+
input_dir = Path(input_dir)
|
|
347
|
+
|
|
348
|
+
if not input_dir.exists():
|
|
349
|
+
raise GraphError(f"Directory not found: {input_dir}")
|
|
350
|
+
|
|
351
|
+
graphs = {}
|
|
352
|
+
|
|
353
|
+
# Find all graph files
|
|
354
|
+
patterns = ["*.json", "*.pkl", "*.pickle", "*.yaml", "*.yml"]
|
|
355
|
+
for pattern in patterns:
|
|
356
|
+
for path in input_dir.glob(pattern):
|
|
357
|
+
name = path.stem
|
|
358
|
+
graphs[name] = load_graph(path, format=format)
|
|
359
|
+
|
|
360
|
+
logger.info(f"Loaded {len(graphs)} graphs from {input_dir}")
|
|
361
|
+
return graphs
|