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.

Files changed (158) hide show
  1. morphml/__init__.py +14 -0
  2. morphml/api/__init__.py +26 -0
  3. morphml/api/app.py +326 -0
  4. morphml/api/auth.py +193 -0
  5. morphml/api/client.py +338 -0
  6. morphml/api/models.py +132 -0
  7. morphml/api/rate_limit.py +192 -0
  8. morphml/benchmarking/__init__.py +36 -0
  9. morphml/benchmarking/comparison.py +430 -0
  10. morphml/benchmarks/__init__.py +56 -0
  11. morphml/benchmarks/comparator.py +409 -0
  12. morphml/benchmarks/datasets.py +280 -0
  13. morphml/benchmarks/metrics.py +199 -0
  14. morphml/benchmarks/openml_suite.py +201 -0
  15. morphml/benchmarks/problems.py +289 -0
  16. morphml/benchmarks/suite.py +318 -0
  17. morphml/cli/__init__.py +5 -0
  18. morphml/cli/commands/experiment.py +329 -0
  19. morphml/cli/main.py +457 -0
  20. morphml/cli/quickstart.py +312 -0
  21. morphml/config.py +278 -0
  22. morphml/constraints/__init__.py +19 -0
  23. morphml/constraints/handler.py +205 -0
  24. morphml/constraints/predicates.py +285 -0
  25. morphml/core/__init__.py +3 -0
  26. morphml/core/crossover.py +449 -0
  27. morphml/core/dsl/README.md +359 -0
  28. morphml/core/dsl/__init__.py +72 -0
  29. morphml/core/dsl/ast_nodes.py +364 -0
  30. morphml/core/dsl/compiler.py +318 -0
  31. morphml/core/dsl/layers.py +368 -0
  32. morphml/core/dsl/lexer.py +336 -0
  33. morphml/core/dsl/parser.py +455 -0
  34. morphml/core/dsl/search_space.py +386 -0
  35. morphml/core/dsl/syntax.py +199 -0
  36. morphml/core/dsl/type_system.py +361 -0
  37. morphml/core/dsl/validator.py +386 -0
  38. morphml/core/graph/__init__.py +40 -0
  39. morphml/core/graph/edge.py +124 -0
  40. morphml/core/graph/graph.py +507 -0
  41. morphml/core/graph/mutations.py +409 -0
  42. morphml/core/graph/node.py +196 -0
  43. morphml/core/graph/serialization.py +361 -0
  44. morphml/core/graph/visualization.py +431 -0
  45. morphml/core/objectives/__init__.py +20 -0
  46. morphml/core/search/__init__.py +33 -0
  47. morphml/core/search/individual.py +252 -0
  48. morphml/core/search/parameters.py +453 -0
  49. morphml/core/search/population.py +375 -0
  50. morphml/core/search/search_engine.py +340 -0
  51. morphml/distributed/__init__.py +76 -0
  52. morphml/distributed/fault_tolerance.py +497 -0
  53. morphml/distributed/health_monitor.py +348 -0
  54. morphml/distributed/master.py +709 -0
  55. morphml/distributed/proto/README.md +224 -0
  56. morphml/distributed/proto/__init__.py +74 -0
  57. morphml/distributed/proto/worker.proto +170 -0
  58. morphml/distributed/proto/worker_pb2.py +79 -0
  59. morphml/distributed/proto/worker_pb2_grpc.py +423 -0
  60. morphml/distributed/resource_manager.py +416 -0
  61. morphml/distributed/scheduler.py +567 -0
  62. morphml/distributed/storage/__init__.py +33 -0
  63. morphml/distributed/storage/artifacts.py +381 -0
  64. morphml/distributed/storage/cache.py +366 -0
  65. morphml/distributed/storage/checkpointing.py +329 -0
  66. morphml/distributed/storage/database.py +459 -0
  67. morphml/distributed/worker.py +549 -0
  68. morphml/evaluation/__init__.py +5 -0
  69. morphml/evaluation/heuristic.py +237 -0
  70. morphml/exceptions.py +55 -0
  71. morphml/execution/__init__.py +5 -0
  72. morphml/execution/local_executor.py +350 -0
  73. morphml/integrations/__init__.py +28 -0
  74. morphml/integrations/jax_adapter.py +206 -0
  75. morphml/integrations/pytorch_adapter.py +530 -0
  76. morphml/integrations/sklearn_adapter.py +206 -0
  77. morphml/integrations/tensorflow_adapter.py +230 -0
  78. morphml/logging_config.py +93 -0
  79. morphml/meta_learning/__init__.py +66 -0
  80. morphml/meta_learning/architecture_similarity.py +277 -0
  81. morphml/meta_learning/experiment_database.py +240 -0
  82. morphml/meta_learning/knowledge_base/__init__.py +19 -0
  83. morphml/meta_learning/knowledge_base/embedder.py +179 -0
  84. morphml/meta_learning/knowledge_base/knowledge_base.py +313 -0
  85. morphml/meta_learning/knowledge_base/meta_features.py +265 -0
  86. morphml/meta_learning/knowledge_base/vector_store.py +271 -0
  87. morphml/meta_learning/predictors/__init__.py +27 -0
  88. morphml/meta_learning/predictors/ensemble.py +221 -0
  89. morphml/meta_learning/predictors/gnn_predictor.py +552 -0
  90. morphml/meta_learning/predictors/learning_curve.py +231 -0
  91. morphml/meta_learning/predictors/proxy_metrics.py +261 -0
  92. morphml/meta_learning/strategy_evolution/__init__.py +27 -0
  93. morphml/meta_learning/strategy_evolution/adaptive_optimizer.py +226 -0
  94. morphml/meta_learning/strategy_evolution/bandit.py +276 -0
  95. morphml/meta_learning/strategy_evolution/portfolio.py +230 -0
  96. morphml/meta_learning/transfer.py +581 -0
  97. morphml/meta_learning/warm_start.py +286 -0
  98. morphml/optimizers/__init__.py +74 -0
  99. morphml/optimizers/adaptive_operators.py +399 -0
  100. morphml/optimizers/bayesian/__init__.py +52 -0
  101. morphml/optimizers/bayesian/acquisition.py +387 -0
  102. morphml/optimizers/bayesian/base.py +319 -0
  103. morphml/optimizers/bayesian/gaussian_process.py +635 -0
  104. morphml/optimizers/bayesian/smac.py +534 -0
  105. morphml/optimizers/bayesian/tpe.py +411 -0
  106. morphml/optimizers/differential_evolution.py +220 -0
  107. morphml/optimizers/evolutionary/__init__.py +61 -0
  108. morphml/optimizers/evolutionary/cma_es.py +416 -0
  109. morphml/optimizers/evolutionary/differential_evolution.py +556 -0
  110. morphml/optimizers/evolutionary/encoding.py +426 -0
  111. morphml/optimizers/evolutionary/particle_swarm.py +449 -0
  112. morphml/optimizers/genetic_algorithm.py +486 -0
  113. morphml/optimizers/gradient_based/__init__.py +22 -0
  114. morphml/optimizers/gradient_based/darts.py +550 -0
  115. morphml/optimizers/gradient_based/enas.py +585 -0
  116. morphml/optimizers/gradient_based/operations.py +474 -0
  117. morphml/optimizers/gradient_based/utils.py +601 -0
  118. morphml/optimizers/hill_climbing.py +169 -0
  119. morphml/optimizers/multi_objective/__init__.py +56 -0
  120. morphml/optimizers/multi_objective/indicators.py +504 -0
  121. morphml/optimizers/multi_objective/nsga2.py +647 -0
  122. morphml/optimizers/multi_objective/visualization.py +427 -0
  123. morphml/optimizers/nsga2.py +308 -0
  124. morphml/optimizers/random_search.py +172 -0
  125. morphml/optimizers/simulated_annealing.py +181 -0
  126. morphml/plugins/__init__.py +35 -0
  127. morphml/plugins/custom_evaluator_example.py +81 -0
  128. morphml/plugins/custom_optimizer_example.py +63 -0
  129. morphml/plugins/plugin_system.py +454 -0
  130. morphml/reports/__init__.py +30 -0
  131. morphml/reports/generator.py +362 -0
  132. morphml/tracking/__init__.py +7 -0
  133. morphml/tracking/experiment.py +309 -0
  134. morphml/tracking/logger.py +301 -0
  135. morphml/tracking/reporter.py +357 -0
  136. morphml/utils/__init__.py +6 -0
  137. morphml/utils/checkpoint.py +189 -0
  138. morphml/utils/comparison.py +390 -0
  139. morphml/utils/export.py +407 -0
  140. morphml/utils/progress.py +392 -0
  141. morphml/utils/validation.py +392 -0
  142. morphml/version.py +7 -0
  143. morphml/visualization/__init__.py +50 -0
  144. morphml/visualization/analytics.py +423 -0
  145. morphml/visualization/architecture_diagrams.py +353 -0
  146. morphml/visualization/architecture_plot.py +223 -0
  147. morphml/visualization/convergence_plot.py +174 -0
  148. morphml/visualization/crossover_viz.py +386 -0
  149. morphml/visualization/graph_viz.py +338 -0
  150. morphml/visualization/pareto_plot.py +149 -0
  151. morphml/visualization/plotly_dashboards.py +422 -0
  152. morphml/visualization/population.py +309 -0
  153. morphml/visualization/progress.py +260 -0
  154. morphml-1.0.0.dist-info/METADATA +434 -0
  155. morphml-1.0.0.dist-info/RECORD +158 -0
  156. morphml-1.0.0.dist-info/WHEEL +4 -0
  157. morphml-1.0.0.dist-info/entry_points.txt +3 -0
  158. morphml-1.0.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,392 @@
1
+ """Search space validation utilities.
2
+
3
+ Validate search spaces before running expensive NAS operations.
4
+
5
+ Example:
6
+ >>> from morphml.utils.validation import validate_search_space
7
+ >>>
8
+ >>> issues = validate_search_space(space)
9
+ >>> if issues:
10
+ ... for issue in issues:
11
+ ... print(f"Warning: {issue}")
12
+ """
13
+
14
+ from typing import List, Optional
15
+
16
+ from morphml.core.dsl import SearchSpace
17
+ from morphml.logging_config import get_logger
18
+
19
+ logger = get_logger(__name__)
20
+
21
+
22
+ class ValidationIssue:
23
+ """Represents a validation issue."""
24
+
25
+ def __init__(self, severity: str, message: str, suggestion: Optional[str] = None):
26
+ """
27
+ Initialize validation issue.
28
+
29
+ Args:
30
+ severity: "error", "warning", or "info"
31
+ message: Issue description
32
+ suggestion: Optional fix suggestion
33
+ """
34
+ self.severity = severity
35
+ self.message = message
36
+ self.suggestion = suggestion
37
+
38
+ def __str__(self) -> str:
39
+ result = f"[{self.severity.upper()}] {self.message}"
40
+ if self.suggestion:
41
+ result += f"\n Suggestion: {self.suggestion}"
42
+ return result
43
+
44
+ def __repr__(self) -> str:
45
+ return f"ValidationIssue(severity='{self.severity}', message='{self.message}')"
46
+
47
+
48
+ class SearchSpaceValidator:
49
+ """
50
+ Validate search spaces for common issues.
51
+
52
+ Example:
53
+ >>> validator = SearchSpaceValidator(space)
54
+ >>> validator.validate()
55
+ >>> validator.print_report()
56
+ """
57
+
58
+ def __init__(self, search_space: SearchSpace):
59
+ """
60
+ Initialize validator.
61
+
62
+ Args:
63
+ search_space: Search space to validate
64
+ """
65
+ self.search_space = search_space
66
+ self.issues: List[ValidationIssue] = []
67
+
68
+ def validate(self) -> List[ValidationIssue]:
69
+ """
70
+ Run all validation checks.
71
+
72
+ Returns:
73
+ List of validation issues
74
+ """
75
+ self.issues.clear()
76
+
77
+ self._check_layer_count()
78
+ self._check_layer_types()
79
+ self._check_search_space_size()
80
+ self._check_flatten_usage()
81
+ self._check_parameter_ranges()
82
+ self._check_connectivity()
83
+
84
+ return self.issues
85
+
86
+ def _check_layer_count(self):
87
+ """Check if layer count is reasonable."""
88
+ num_layers = len(self.search_space.layers)
89
+
90
+ if num_layers == 0:
91
+ self.issues.append(
92
+ ValidationIssue(
93
+ "error", "Search space has no layers", "Add layers using space.add_layers()"
94
+ )
95
+ )
96
+ elif num_layers < 3:
97
+ self.issues.append(
98
+ ValidationIssue(
99
+ "warning",
100
+ f"Search space has only {num_layers} layers",
101
+ "Consider adding more layers for meaningful search",
102
+ )
103
+ )
104
+ elif num_layers > 50:
105
+ self.issues.append(
106
+ ValidationIssue(
107
+ "warning",
108
+ f"Search space has {num_layers} layers (very deep)",
109
+ "Deep spaces may be slow to search",
110
+ )
111
+ )
112
+
113
+ def _check_layer_types(self):
114
+ """Check layer type distribution."""
115
+ layer_types = {}
116
+ has_input = False
117
+ has_output = False
118
+
119
+ for layer_spec in self.search_space.layers:
120
+ op = layer_spec.operation
121
+ layer_types[op] = layer_types.get(op, 0) + 1
122
+
123
+ if op == "input":
124
+ has_input = True
125
+ if op in ["output", "softmax"]:
126
+ has_output = True
127
+
128
+ # Check for input layer
129
+ if not has_input:
130
+ self.issues.append(
131
+ ValidationIssue(
132
+ "warning",
133
+ "No explicit input layer",
134
+ "Add Layer.input(shape=...) at the beginning",
135
+ )
136
+ )
137
+
138
+ # Check for output activation
139
+ if not has_output:
140
+ self.issues.append(
141
+ ValidationIssue(
142
+ "info",
143
+ "No explicit output activation",
144
+ "Consider adding Layer.softmax() or Layer.sigmoid() at the end",
145
+ )
146
+ )
147
+
148
+ # Check for activation functions
149
+ activations = sum(layer_types.get(act, 0) for act in ["relu", "sigmoid", "tanh", "softmax"])
150
+ if activations == 0:
151
+ self.issues.append(
152
+ ValidationIssue(
153
+ "warning",
154
+ "No activation functions found",
155
+ "Add activation layers like Layer.relu()",
156
+ )
157
+ )
158
+
159
+ def _check_search_space_size(self):
160
+ """Estimate search space size."""
161
+ try:
162
+ size = 1
163
+ for layer_spec in self.search_space.layers:
164
+ # Count choices for each parameter
165
+ layer_choices = 1
166
+ for param_values in layer_spec.param_ranges.values():
167
+ if isinstance(param_values, list) and len(param_values) > 1:
168
+ layer_choices *= len(param_values)
169
+ size *= max(layer_choices, 1)
170
+
171
+ if size > 1e12:
172
+ self.issues.append(
173
+ ValidationIssue(
174
+ "warning",
175
+ f"Extremely large search space (~{size:.2e} combinations)",
176
+ "Consider reducing parameter choices",
177
+ )
178
+ )
179
+ elif size > 1e9:
180
+ self.issues.append(
181
+ ValidationIssue(
182
+ "info",
183
+ f"Large search space (~{size:.2e} combinations)",
184
+ "May require many generations to explore",
185
+ )
186
+ )
187
+ elif size < 100:
188
+ self.issues.append(
189
+ ValidationIssue(
190
+ "info",
191
+ f"Small search space (~{size} combinations)",
192
+ "Consider adding more parameter choices for richer search",
193
+ )
194
+ )
195
+
196
+ except Exception as e:
197
+ logger.debug(f"Could not estimate search space size: {e}")
198
+
199
+ def _check_flatten_usage(self):
200
+ """Check flatten layer usage."""
201
+ has_conv = False
202
+ has_dense = False
203
+ has_flatten = False
204
+
205
+ for layer_spec in self.search_space.layers:
206
+ if layer_spec.operation in ["conv2d", "maxpool", "avgpool"]:
207
+ has_conv = True
208
+ elif layer_spec.operation == "dense":
209
+ has_dense = True
210
+ elif layer_spec.operation == "flatten":
211
+ has_flatten = True
212
+
213
+ # If has both conv and dense, should have flatten
214
+ if has_conv and has_dense and not has_flatten:
215
+ self.issues.append(
216
+ ValidationIssue(
217
+ "warning",
218
+ "Conv layers followed by Dense without Flatten",
219
+ "Add Layer.flatten() between conv and dense layers",
220
+ )
221
+ )
222
+
223
+ def _check_parameter_ranges(self):
224
+ """Check parameter value ranges."""
225
+ for layer_spec in self.search_space.layers:
226
+ op = layer_spec.operation
227
+
228
+ # Check conv2d filters
229
+ if op == "conv2d":
230
+ filters = layer_spec.param_ranges.get("filters", [])
231
+ if isinstance(filters, list):
232
+ if any(f < 1 for f in filters):
233
+ self.issues.append(
234
+ ValidationIssue(
235
+ "error",
236
+ f"Conv2d has invalid filter count: {filters}",
237
+ "Filters must be positive integers",
238
+ )
239
+ )
240
+ if any(f > 1024 for f in filters):
241
+ self.issues.append(
242
+ ValidationIssue(
243
+ "warning",
244
+ f"Conv2d has very large filter count: {max(filters)}",
245
+ "Large filter counts increase parameters significantly",
246
+ )
247
+ )
248
+
249
+ # Check dense units
250
+ if op == "dense":
251
+ units = layer_spec.param_ranges.get("units", [])
252
+ if isinstance(units, list):
253
+ if any(u < 1 for u in units):
254
+ self.issues.append(
255
+ ValidationIssue(
256
+ "error",
257
+ f"Dense has invalid unit count: {units}",
258
+ "Units must be positive integers",
259
+ )
260
+ )
261
+
262
+ # Check dropout rate
263
+ if op == "dropout":
264
+ rates = layer_spec.param_ranges.get("rate", [])
265
+ if isinstance(rates, list):
266
+ if any(r < 0 or r >= 1 for r in rates):
267
+ self.issues.append(
268
+ ValidationIssue(
269
+ "error",
270
+ f"Dropout has invalid rate: {rates}",
271
+ "Dropout rate must be in [0, 1)",
272
+ )
273
+ )
274
+
275
+ def _check_connectivity(self):
276
+ """Check if sampled architectures will be connected."""
277
+ try:
278
+ # Sample a few architectures to check
279
+ for _ in range(3):
280
+ graph = self.search_space.sample()
281
+
282
+ if not graph.is_valid():
283
+ self.issues.append(
284
+ ValidationIssue(
285
+ "error",
286
+ "Sampled architecture is not a valid DAG",
287
+ "Check search space definition",
288
+ )
289
+ )
290
+ break
291
+
292
+ except Exception as e:
293
+ self.issues.append(
294
+ ValidationIssue(
295
+ "error",
296
+ f"Failed to sample from search space: {e}",
297
+ "Check layer definitions and parameters",
298
+ )
299
+ )
300
+
301
+ def print_report(self):
302
+ """Print validation report."""
303
+ if not self.issues:
304
+ print("✓ Search space validation passed!")
305
+ return
306
+
307
+ print("\nSearch Space Validation Report")
308
+ print("=" * 70)
309
+
310
+ errors = [i for i in self.issues if i.severity == "error"]
311
+ warnings = [i for i in self.issues if i.severity == "warning"]
312
+ infos = [i for i in self.issues if i.severity == "info"]
313
+
314
+ if errors:
315
+ print(f"\n❌ Errors ({len(errors)}):")
316
+ for issue in errors:
317
+ print(f" {issue}")
318
+
319
+ if warnings:
320
+ print(f"\n⚠️ Warnings ({len(warnings)}):")
321
+ for issue in warnings:
322
+ print(f" {issue}")
323
+
324
+ if infos:
325
+ print(f"\nℹ️ Info ({len(infos)}):")
326
+ for issue in infos:
327
+ print(f" {issue}")
328
+
329
+ print("=" * 70)
330
+
331
+ if errors:
332
+ print("\n❌ Validation failed! Fix errors before running NAS.")
333
+ elif warnings:
334
+ print("\n⚠️ Validation passed with warnings. Review before running NAS.")
335
+ else:
336
+ print("\n✓ Validation passed!")
337
+
338
+ def has_errors(self) -> bool:
339
+ """Check if there are any errors."""
340
+ return any(i.severity == "error" for i in self.issues)
341
+
342
+ def has_warnings(self) -> bool:
343
+ """Check if there are any warnings."""
344
+ return any(i.severity == "warning" for i in self.issues)
345
+
346
+
347
+ def validate_search_space(
348
+ search_space: SearchSpace,
349
+ print_report: bool = True,
350
+ ) -> List[ValidationIssue]:
351
+ """
352
+ Validate search space and optionally print report.
353
+
354
+ Args:
355
+ search_space: Search space to validate
356
+ print_report: Whether to print validation report
357
+
358
+ Returns:
359
+ List of validation issues
360
+
361
+ Example:
362
+ >>> issues = validate_search_space(space)
363
+ >>> if any(i.severity == "error" for i in issues):
364
+ ... print("Fix errors before running NAS!")
365
+ """
366
+ validator = SearchSpaceValidator(search_space)
367
+ issues = validator.validate()
368
+
369
+ if print_report:
370
+ validator.print_report()
371
+
372
+ return issues
373
+
374
+
375
+ def quick_validate(search_space: SearchSpace) -> bool:
376
+ """
377
+ Quick validation returning True if no errors.
378
+
379
+ Args:
380
+ search_space: Search space to validate
381
+
382
+ Returns:
383
+ True if validation passed (no errors)
384
+
385
+ Example:
386
+ >>> if quick_validate(space):
387
+ ... # Run NAS
388
+ ... pass
389
+ """
390
+ validator = SearchSpaceValidator(search_space)
391
+ validator.validate()
392
+ return not validator.has_errors()
morphml/version.py ADDED
@@ -0,0 +1,7 @@
1
+ """Version information for MorphML."""
2
+
3
+ __version__ = "1.0.0"
4
+ __author__ = "Vedanth & Eshan Roy"
5
+ __email__ = "vedanth@vedanthq.com, eshanized@proton.me"
6
+ __organization__ = "TONMOY INFRASTRUCTURE & VISION"
7
+ __repository__ = "https://github.com/TIVerse/MorphML"
@@ -0,0 +1,50 @@
1
+ """Visualization tools for architectures and optimization."""
2
+
3
+ from morphml.visualization.analytics import PerformanceAnalytics
4
+ from morphml.visualization.architecture_diagrams import ArchitectureDiagramGenerator
5
+ from morphml.visualization.architecture_plot import (
6
+ plot_architecture,
7
+ plot_architecture_hierarchy,
8
+ plot_architecture_stats,
9
+ )
10
+ from morphml.visualization.convergence_plot import (
11
+ plot_convergence,
12
+ plot_convergence_comparison,
13
+ plot_fitness_distribution,
14
+ )
15
+ from morphml.visualization.graph_viz import GraphVisualizer
16
+
17
+ # Phase 2: Advanced visualization
18
+ from morphml.visualization.pareto_plot import (
19
+ plot_parallel_coordinates,
20
+ plot_pareto_front_2d,
21
+ plot_pareto_front_3d,
22
+ )
23
+
24
+ # Phase 5: Interactive dashboards and professional diagrams
25
+ from morphml.visualization.plotly_dashboards import InteractiveDashboard
26
+ from morphml.visualization.population import PopulationVisualizer
27
+ from morphml.visualization.progress import ProgressPlotter
28
+
29
+ __all__ = [
30
+ # Phase 1
31
+ "GraphVisualizer",
32
+ "ProgressPlotter",
33
+ "PopulationVisualizer",
34
+ # Phase 2: Pareto
35
+ "plot_pareto_front_2d",
36
+ "plot_pareto_front_3d",
37
+ "plot_parallel_coordinates",
38
+ # Phase 2: Convergence
39
+ "plot_convergence",
40
+ "plot_convergence_comparison",
41
+ "plot_fitness_distribution",
42
+ # Phase 2: Architecture
43
+ "plot_architecture",
44
+ "plot_architecture_hierarchy",
45
+ "plot_architecture_stats",
46
+ # Phase 5: Interactive & Professional
47
+ "InteractiveDashboard",
48
+ "ArchitectureDiagramGenerator",
49
+ "PerformanceAnalytics",
50
+ ]