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,422 @@
1
+ """Interactive Plotly dashboards for MorphML.
2
+
3
+ Create publication-quality interactive visualizations for NAS experiments.
4
+
5
+ Example:
6
+ >>> from morphml.visualization.plotly_dashboards import InteractiveDashboard
7
+ >>> dashboard = InteractiveDashboard()
8
+ >>> fig = dashboard.create_experiment_dashboard(history)
9
+ >>> fig.show()
10
+ """
11
+
12
+ from typing import Any, Dict, List
13
+
14
+ import numpy as np
15
+
16
+ try:
17
+ import plotly.express as px
18
+ import plotly.graph_objects as go
19
+ from plotly.subplots import make_subplots
20
+
21
+ PLOTLY_AVAILABLE = True
22
+ except ImportError:
23
+ PLOTLY_AVAILABLE = False
24
+ go = None
25
+ make_subplots = None
26
+ px = None
27
+
28
+ from morphml.logging_config import get_logger
29
+
30
+ logger = get_logger(__name__)
31
+
32
+
33
+ class InteractiveDashboard:
34
+ """
35
+ Create interactive Plotly dashboards for NAS experiments.
36
+
37
+ Provides comprehensive visualizations including:
38
+ - Convergence curves
39
+ - Pareto fronts (multi-objective)
40
+ - Architecture distributions
41
+ - Performance heatmaps
42
+
43
+ Example:
44
+ >>> dashboard = InteractiveDashboard()
45
+ >>> fig = dashboard.create_experiment_dashboard(history)
46
+ >>> fig.write_html("dashboard.html")
47
+ """
48
+
49
+ def __init__(self):
50
+ """Initialize dashboard generator."""
51
+ if not PLOTLY_AVAILABLE:
52
+ raise ImportError(
53
+ "Plotly is required for interactive dashboards. " "Install with: pip install plotly"
54
+ )
55
+ logger.info("Initialized InteractiveDashboard")
56
+
57
+ def create_experiment_dashboard(
58
+ self, history: Dict[str, Any], title: str = "Experiment Dashboard"
59
+ ) -> "go.Figure":
60
+ """
61
+ Create comprehensive experiment dashboard.
62
+
63
+ Args:
64
+ history: Optimization history with keys:
65
+ - best_fitness: List of best fitness per generation
66
+ - mean_fitness: List of mean fitness per generation
67
+ - diversity: List of diversity scores
68
+ - architectures: List of architecture dicts
69
+ title: Dashboard title
70
+
71
+ Returns:
72
+ Plotly Figure with subplots
73
+
74
+ Example:
75
+ >>> fig = dashboard.create_experiment_dashboard(optimizer.history)
76
+ >>> fig.show()
77
+ """
78
+ # Create subplots
79
+ fig = make_subplots(
80
+ rows=2,
81
+ cols=2,
82
+ subplot_titles=(
83
+ "Convergence Curve",
84
+ "Fitness Distribution",
85
+ "Diversity Over Time",
86
+ "Performance vs Complexity",
87
+ ),
88
+ specs=[
89
+ [{"type": "scatter"}, {"type": "histogram"}],
90
+ [{"type": "scatter"}, {"type": "scatter"}],
91
+ ],
92
+ )
93
+
94
+ # 1. Convergence curve
95
+ generations = list(range(len(history.get("best_fitness", []))))
96
+ best_fitness = history.get("best_fitness", [])
97
+ mean_fitness = history.get("mean_fitness", [])
98
+
99
+ fig.add_trace(
100
+ go.Scatter(
101
+ x=generations,
102
+ y=best_fitness,
103
+ mode="lines+markers",
104
+ name="Best Fitness",
105
+ line={"color": "#FF6B6B", "width": 2},
106
+ marker={"size": 6},
107
+ ),
108
+ row=1,
109
+ col=1,
110
+ )
111
+
112
+ fig.add_trace(
113
+ go.Scatter(
114
+ x=generations,
115
+ y=mean_fitness,
116
+ mode="lines",
117
+ name="Mean Fitness",
118
+ line={"color": "#4ECDC4", "width": 2, "dash": "dash"},
119
+ ),
120
+ row=1,
121
+ col=1,
122
+ )
123
+
124
+ # 2. Fitness distribution
125
+ all_fitness = []
126
+ for arch_list in history.get("population_fitness", []):
127
+ all_fitness.extend(arch_list)
128
+
129
+ if all_fitness:
130
+ fig.add_trace(
131
+ go.Histogram(
132
+ x=all_fitness,
133
+ nbinsx=30,
134
+ name="Fitness Distribution",
135
+ marker={"color": "#45B7D1"},
136
+ ),
137
+ row=1,
138
+ col=2,
139
+ )
140
+
141
+ # 3. Diversity over time
142
+ diversity = history.get("diversity", [])
143
+ if diversity:
144
+ fig.add_trace(
145
+ go.Scatter(
146
+ x=generations,
147
+ y=diversity,
148
+ mode="lines+markers",
149
+ name="Diversity",
150
+ line={"color": "#96CEB4", "width": 2},
151
+ marker={"size": 6},
152
+ ),
153
+ row=2,
154
+ col=1,
155
+ )
156
+
157
+ # 4. Performance vs Complexity
158
+ architectures = history.get("architectures", [])
159
+ if architectures:
160
+ params = [a.get("parameters", 0) for a in architectures]
161
+ fitness = [a.get("fitness", 0) for a in architectures]
162
+
163
+ fig.add_trace(
164
+ go.Scatter(
165
+ x=params,
166
+ y=fitness,
167
+ mode="markers",
168
+ name="Architectures",
169
+ marker={
170
+ "size": 8,
171
+ "color": fitness,
172
+ "colorscale": "Viridis",
173
+ "showscale": True,
174
+ "colorbar": {"title": "Fitness"},
175
+ },
176
+ text=[f"Params: {p:,}" for p in params],
177
+ hovertemplate="<b>Fitness:</b> %{y:.4f}<br><b>%{text}</b>",
178
+ ),
179
+ row=2,
180
+ col=2,
181
+ )
182
+
183
+ # Update layout
184
+ fig.update_xaxes(title_text="Generation", row=1, col=1)
185
+ fig.update_yaxes(title_text="Fitness", row=1, col=1)
186
+
187
+ fig.update_xaxes(title_text="Fitness", row=1, col=2)
188
+ fig.update_yaxes(title_text="Count", row=1, col=2)
189
+
190
+ fig.update_xaxes(title_text="Generation", row=2, col=1)
191
+ fig.update_yaxes(title_text="Diversity", row=2, col=1)
192
+
193
+ fig.update_xaxes(title_text="Parameters", row=2, col=2)
194
+ fig.update_yaxes(title_text="Fitness", row=2, col=2)
195
+
196
+ fig.update_layout(title=title, height=800, showlegend=True, template="plotly_white")
197
+
198
+ return fig
199
+
200
+ def create_pareto_front_3d(
201
+ self,
202
+ architectures: List[Dict[str, Any]],
203
+ objectives: List[str] = ["accuracy", "latency", "parameters"],
204
+ ) -> "go.Figure":
205
+ """
206
+ Create 3D Pareto front visualization.
207
+
208
+ Args:
209
+ architectures: List of architecture dicts with objective values
210
+ objectives: List of 3 objective names
211
+
212
+ Returns:
213
+ 3D scatter plot
214
+
215
+ Example:
216
+ >>> fig = dashboard.create_pareto_front_3d(architectures)
217
+ >>> fig.show()
218
+ """
219
+ if len(objectives) != 3:
220
+ raise ValueError("Exactly 3 objectives required for 3D plot")
221
+
222
+ # Extract objective values
223
+ x = [a.get(objectives[0], 0) for a in architectures]
224
+ y = [a.get(objectives[1], 0) for a in architectures]
225
+ z = [a.get(objectives[2], 0) for a in architectures]
226
+
227
+ # Create 3D scatter
228
+ fig = go.Figure(
229
+ data=[
230
+ go.Scatter3d(
231
+ x=x,
232
+ y=y,
233
+ z=z,
234
+ mode="markers",
235
+ marker={
236
+ "size": 6,
237
+ "color": x, # Color by first objective
238
+ "colorscale": "Viridis",
239
+ "showscale": True,
240
+ "colorbar": {"title": objectives[0]},
241
+ },
242
+ text=[f"ID: {a.get('id', 'N/A')}" for a in architectures],
243
+ hovertemplate=(
244
+ f"<b>{objectives[0]}:</b> %{{x:.4f}}<br>"
245
+ f"<b>{objectives[1]}:</b> %{{y:.4f}}<br>"
246
+ f"<b>{objectives[2]}:</b> %{{z:.4f}}<br>"
247
+ "<b>%{text}</b>"
248
+ ),
249
+ )
250
+ ]
251
+ )
252
+
253
+ fig.update_layout(
254
+ title="3D Pareto Front",
255
+ scene={
256
+ "xaxis_title": objectives[0],
257
+ "yaxis_title": objectives[1],
258
+ "zaxis_title": objectives[2],
259
+ },
260
+ height=700,
261
+ )
262
+
263
+ return fig
264
+
265
+ def create_operation_distribution(self, architectures: List[Dict[str, Any]]) -> "go.Figure":
266
+ """
267
+ Create operation distribution pie chart.
268
+
269
+ Args:
270
+ architectures: List of architecture dicts
271
+
272
+ Returns:
273
+ Pie chart figure
274
+ """
275
+ # Count operations
276
+ operation_counts = {}
277
+ for arch in architectures:
278
+ for node in arch.get("nodes", []):
279
+ op = node.get("operation", "unknown")
280
+ operation_counts[op] = operation_counts.get(op, 0) + 1
281
+
282
+ # Create pie chart
283
+ fig = go.Figure(
284
+ data=[
285
+ go.Pie(
286
+ labels=list(operation_counts.keys()),
287
+ values=list(operation_counts.values()),
288
+ hole=0.3,
289
+ marker={"colors": px.colors.qualitative.Set3},
290
+ )
291
+ ]
292
+ )
293
+
294
+ fig.update_layout(title="Operation Distribution", height=500)
295
+
296
+ return fig
297
+
298
+ def create_convergence_comparison(self, experiments: Dict[str, Dict[str, Any]]) -> "go.Figure":
299
+ """
300
+ Compare convergence across multiple experiments.
301
+
302
+ Args:
303
+ experiments: Dict mapping experiment names to history dicts
304
+
305
+ Returns:
306
+ Line plot comparing convergence
307
+
308
+ Example:
309
+ >>> experiments = {
310
+ ... 'GA': ga_history,
311
+ ... 'Random': random_history,
312
+ ... 'Bayesian': bayesian_history
313
+ ... }
314
+ >>> fig = dashboard.create_convergence_comparison(experiments)
315
+ """
316
+ fig = go.Figure()
317
+
318
+ colors = px.colors.qualitative.Set1
319
+
320
+ for i, (name, history) in enumerate(experiments.items()):
321
+ generations = list(range(len(history.get("best_fitness", []))))
322
+ best_fitness = history.get("best_fitness", [])
323
+
324
+ fig.add_trace(
325
+ go.Scatter(
326
+ x=generations,
327
+ y=best_fitness,
328
+ mode="lines+markers",
329
+ name=name,
330
+ line={"color": colors[i % len(colors)], "width": 2},
331
+ marker={"size": 6},
332
+ )
333
+ )
334
+
335
+ fig.update_layout(
336
+ title="Convergence Comparison",
337
+ xaxis_title="Generation",
338
+ yaxis_title="Best Fitness",
339
+ height=500,
340
+ template="plotly_white",
341
+ hovermode="x unified",
342
+ )
343
+
344
+ return fig
345
+
346
+ def create_performance_heatmap(
347
+ self,
348
+ architectures: List[Dict[str, Any]],
349
+ x_metric: str = "depth",
350
+ y_metric: str = "width",
351
+ z_metric: str = "fitness",
352
+ ) -> "go.Figure":
353
+ """
354
+ Create performance heatmap.
355
+
356
+ Args:
357
+ architectures: List of architecture dicts
358
+ x_metric: Metric for x-axis
359
+ y_metric: Metric for y-axis
360
+ z_metric: Metric for color (performance)
361
+
362
+ Returns:
363
+ Heatmap figure
364
+ """
365
+ # Extract metrics
366
+ x_values = [a.get(x_metric, 0) for a in architectures]
367
+ y_values = [a.get(y_metric, 0) for a in architectures]
368
+ z_values = [a.get(z_metric, 0) for a in architectures]
369
+
370
+ # Create bins
371
+ x_bins = np.linspace(min(x_values), max(x_values), 20)
372
+ y_bins = np.linspace(min(y_values), max(y_values), 20)
373
+
374
+ # Compute heatmap
375
+ heatmap, xedges, yedges = np.histogram2d(
376
+ x_values, y_values, bins=[x_bins, y_bins], weights=z_values
377
+ )
378
+
379
+ counts, _, _ = np.histogram2d(x_values, y_values, bins=[x_bins, y_bins])
380
+ heatmap = np.divide(heatmap, counts, where=counts != 0)
381
+
382
+ # Create heatmap
383
+ fig = go.Figure(
384
+ data=go.Heatmap(
385
+ z=heatmap.T,
386
+ x=xedges[:-1],
387
+ y=yedges[:-1],
388
+ colorscale="Viridis",
389
+ colorbar={"title": z_metric},
390
+ )
391
+ )
392
+
393
+ fig.update_layout(
394
+ title=f"{z_metric} Heatmap", xaxis_title=x_metric, yaxis_title=y_metric, height=500
395
+ )
396
+
397
+ return fig
398
+
399
+ def export_dashboard(self, fig: "go.Figure", output_path: str, format: str = "html"):
400
+ """
401
+ Export dashboard to file.
402
+
403
+ Args:
404
+ fig: Plotly figure
405
+ output_path: Output file path
406
+ format: Export format ('html', 'png', 'svg', 'pdf')
407
+
408
+ Example:
409
+ >>> dashboard.export_dashboard(fig, "dashboard.html")
410
+ """
411
+ if format == "html":
412
+ fig.write_html(output_path)
413
+ elif format == "png":
414
+ fig.write_image(output_path, format="png")
415
+ elif format == "svg":
416
+ fig.write_image(output_path, format="svg")
417
+ elif format == "pdf":
418
+ fig.write_image(output_path, format="pdf")
419
+ else:
420
+ raise ValueError(f"Unsupported format: {format}")
421
+
422
+ logger.info(f"Exported dashboard to {output_path}")