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,81 @@
|
|
|
1
|
+
"""Example custom evaluator plugin.
|
|
2
|
+
|
|
3
|
+
Demonstrates how to create a custom evaluator plugin for MorphML.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
>>> from morphml.plugins import PluginManager
|
|
7
|
+
>>> manager = PluginManager()
|
|
8
|
+
>>> plugin = manager.load_plugin_from_file(
|
|
9
|
+
... 'morphml/plugins/custom_evaluator_example.py',
|
|
10
|
+
... config={'latency_weight': 0.5}
|
|
11
|
+
... )
|
|
12
|
+
>>> fitness = plugin.evaluate(architecture)
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from morphml.core.graph import ModelGraph
|
|
16
|
+
from morphml.plugins import EvaluatorPlugin
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Plugin(EvaluatorPlugin):
|
|
20
|
+
"""
|
|
21
|
+
Example plugin: Multi-objective evaluator combining accuracy and latency.
|
|
22
|
+
|
|
23
|
+
This plugin demonstrates how to:
|
|
24
|
+
1. Inherit from EvaluatorPlugin
|
|
25
|
+
2. Implement custom evaluation logic
|
|
26
|
+
3. Combine multiple objectives
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def initialize(self, config):
|
|
30
|
+
"""
|
|
31
|
+
Initialize plugin with configuration.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
config: Configuration dictionary with keys:
|
|
35
|
+
- latency_weight: Weight for latency objective (default: 0.3)
|
|
36
|
+
- accuracy_weight: Weight for accuracy objective (default: 0.7)
|
|
37
|
+
"""
|
|
38
|
+
self.latency_weight = config.get("latency_weight", 0.3)
|
|
39
|
+
self.accuracy_weight = config.get("accuracy_weight", 0.7)
|
|
40
|
+
|
|
41
|
+
# Normalize weights
|
|
42
|
+
total = self.latency_weight + self.accuracy_weight
|
|
43
|
+
self.latency_weight /= total
|
|
44
|
+
self.accuracy_weight /= total
|
|
45
|
+
|
|
46
|
+
print("Initialized Multi-Objective Evaluator plugin:")
|
|
47
|
+
print(f" Accuracy weight: {self.accuracy_weight:.2f}")
|
|
48
|
+
print(f" Latency weight: {self.latency_weight:.2f}")
|
|
49
|
+
|
|
50
|
+
def evaluate(self, architecture: ModelGraph) -> float:
|
|
51
|
+
"""
|
|
52
|
+
Evaluate architecture with multi-objective fitness.
|
|
53
|
+
|
|
54
|
+
Combines estimated accuracy and latency into single fitness score.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
architecture: ModelGraph to evaluate
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Combined fitness score (0-1, higher is better)
|
|
61
|
+
"""
|
|
62
|
+
# Estimate accuracy (simplified)
|
|
63
|
+
depth = architecture.estimate_depth()
|
|
64
|
+
width = architecture.estimate_width()
|
|
65
|
+
params = architecture.estimate_parameters()
|
|
66
|
+
|
|
67
|
+
# Heuristic accuracy estimate
|
|
68
|
+
accuracy_score = min(1.0, (depth * width) / 1000.0)
|
|
69
|
+
|
|
70
|
+
# Estimate latency (inverse of parameters, normalized)
|
|
71
|
+
# Lower parameters = lower latency = higher score
|
|
72
|
+
latency_score = 1.0 / (1.0 + params / 1000000.0)
|
|
73
|
+
|
|
74
|
+
# Combine objectives
|
|
75
|
+
fitness = self.accuracy_weight * accuracy_score + self.latency_weight * latency_score
|
|
76
|
+
|
|
77
|
+
return fitness
|
|
78
|
+
|
|
79
|
+
def cleanup(self):
|
|
80
|
+
"""Cleanup when plugin is unloaded."""
|
|
81
|
+
print("Multi-Objective Evaluator plugin unloaded")
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Example custom optimizer plugin.
|
|
2
|
+
|
|
3
|
+
Demonstrates how to create a custom optimizer plugin for MorphML.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
>>> from morphml.plugins import PluginManager
|
|
7
|
+
>>> manager = PluginManager()
|
|
8
|
+
>>> plugin = manager.load_plugin_from_file(
|
|
9
|
+
... 'morphml/plugins/custom_optimizer_example.py',
|
|
10
|
+
... config={'temperature': 100.0, 'cooling_rate': 0.95}
|
|
11
|
+
... )
|
|
12
|
+
>>> optimizer = plugin.get_optimizer()
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from morphml.optimizers.simulated_annealing import SimulatedAnnealing
|
|
16
|
+
from morphml.plugins import OptimizerPlugin
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Plugin(OptimizerPlugin):
|
|
20
|
+
"""
|
|
21
|
+
Example plugin: Simulated Annealing optimizer with custom configuration.
|
|
22
|
+
|
|
23
|
+
This plugin demonstrates how to:
|
|
24
|
+
1. Inherit from OptimizerPlugin
|
|
25
|
+
2. Initialize with custom configuration
|
|
26
|
+
3. Return a configured optimizer instance
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def initialize(self, config):
|
|
30
|
+
"""
|
|
31
|
+
Initialize plugin with configuration.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
config: Configuration dictionary with keys:
|
|
35
|
+
- temperature: Initial temperature (default: 100.0)
|
|
36
|
+
- cooling_rate: Cooling rate (default: 0.95)
|
|
37
|
+
- max_iterations: Maximum iterations (default: 1000)
|
|
38
|
+
"""
|
|
39
|
+
self.temperature = config.get("temperature", 100.0)
|
|
40
|
+
self.cooling_rate = config.get("cooling_rate", 0.95)
|
|
41
|
+
self.max_iterations = config.get("max_iterations", 1000)
|
|
42
|
+
|
|
43
|
+
print("Initialized SimulatedAnnealing plugin:")
|
|
44
|
+
print(f" Temperature: {self.temperature}")
|
|
45
|
+
print(f" Cooling rate: {self.cooling_rate}")
|
|
46
|
+
print(f" Max iterations: {self.max_iterations}")
|
|
47
|
+
|
|
48
|
+
def get_optimizer(self):
|
|
49
|
+
"""
|
|
50
|
+
Return configured SimulatedAnnealing optimizer.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
SimulatedAnnealing instance
|
|
54
|
+
"""
|
|
55
|
+
return SimulatedAnnealing(
|
|
56
|
+
temperature=self.temperature,
|
|
57
|
+
cooling_rate=self.cooling_rate,
|
|
58
|
+
max_iterations=self.max_iterations,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
def cleanup(self):
|
|
62
|
+
"""Cleanup when plugin is unloaded."""
|
|
63
|
+
print("SimulatedAnnealing plugin unloaded")
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
"""Plugin system implementation for MorphML.
|
|
2
|
+
|
|
3
|
+
Provides base classes and plugin manager for extending MorphML functionality.
|
|
4
|
+
|
|
5
|
+
Example:
|
|
6
|
+
>>> from morphml.plugins import PluginManager, OptimizerPlugin
|
|
7
|
+
>>>
|
|
8
|
+
>>> class MyPlugin(OptimizerPlugin):
|
|
9
|
+
... def initialize(self, config):
|
|
10
|
+
... self.config = config
|
|
11
|
+
...
|
|
12
|
+
... def get_optimizer(self):
|
|
13
|
+
... return MyCustomOptimizer(self.config)
|
|
14
|
+
>>>
|
|
15
|
+
>>> manager = PluginManager()
|
|
16
|
+
>>> manager.register_plugin('my_optimizer', MyPlugin)
|
|
17
|
+
>>> plugin = manager.load_plugin('my_optimizer', config={})
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import importlib
|
|
21
|
+
import importlib.util
|
|
22
|
+
from abc import ABC, abstractmethod
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
from typing import Any, Dict, List, Optional, Type
|
|
25
|
+
|
|
26
|
+
from morphml.logging_config import get_logger
|
|
27
|
+
|
|
28
|
+
logger = get_logger(__name__)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class Plugin(ABC):
|
|
32
|
+
"""
|
|
33
|
+
Base class for all MorphML plugins.
|
|
34
|
+
|
|
35
|
+
All plugins must inherit from this class and implement
|
|
36
|
+
the required methods.
|
|
37
|
+
|
|
38
|
+
Example:
|
|
39
|
+
>>> class MyPlugin(Plugin):
|
|
40
|
+
... def initialize(self, config):
|
|
41
|
+
... self.config = config
|
|
42
|
+
...
|
|
43
|
+
... def execute(self, context):
|
|
44
|
+
... return self.config['value'] * 2
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
@abstractmethod
|
|
48
|
+
def initialize(self, config: Dict[str, Any]):
|
|
49
|
+
"""
|
|
50
|
+
Initialize plugin with configuration.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
config: Plugin configuration dictionary
|
|
54
|
+
"""
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
@abstractmethod
|
|
58
|
+
def execute(self, context: Dict[str, Any]) -> Any:
|
|
59
|
+
"""
|
|
60
|
+
Execute plugin logic.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
context: Execution context with relevant data
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Plugin execution result
|
|
67
|
+
"""
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
def cleanup(self):
|
|
71
|
+
"""Optional cleanup method called when plugin is unloaded."""
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class OptimizerPlugin(Plugin):
|
|
76
|
+
"""
|
|
77
|
+
Plugin for custom optimizers.
|
|
78
|
+
|
|
79
|
+
Allows users to add custom optimization algorithms.
|
|
80
|
+
|
|
81
|
+
Example:
|
|
82
|
+
>>> class SimulatedAnnealingPlugin(OptimizerPlugin):
|
|
83
|
+
... def initialize(self, config):
|
|
84
|
+
... self.temperature = config.get('temperature', 100.0)
|
|
85
|
+
...
|
|
86
|
+
... def get_optimizer(self):
|
|
87
|
+
... return SimulatedAnnealing(temperature=self.temperature)
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
@abstractmethod
|
|
91
|
+
def get_optimizer(self):
|
|
92
|
+
"""
|
|
93
|
+
Return optimizer instance.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
Optimizer instance (subclass of BaseOptimizer)
|
|
97
|
+
"""
|
|
98
|
+
pass
|
|
99
|
+
|
|
100
|
+
def execute(self, context: Dict[str, Any]):
|
|
101
|
+
"""Execute returns the optimizer."""
|
|
102
|
+
return self.get_optimizer()
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class EvaluatorPlugin(Plugin):
|
|
106
|
+
"""
|
|
107
|
+
Plugin for custom evaluation metrics.
|
|
108
|
+
|
|
109
|
+
Allows users to define custom architecture evaluation functions.
|
|
110
|
+
|
|
111
|
+
Example:
|
|
112
|
+
>>> class LatencyEvaluatorPlugin(EvaluatorPlugin):
|
|
113
|
+
... def evaluate(self, architecture):
|
|
114
|
+
... return estimate_latency(architecture)
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
@abstractmethod
|
|
118
|
+
def evaluate(self, architecture) -> float:
|
|
119
|
+
"""
|
|
120
|
+
Evaluate architecture.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
architecture: ModelGraph to evaluate
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
Fitness score
|
|
127
|
+
"""
|
|
128
|
+
pass
|
|
129
|
+
|
|
130
|
+
def execute(self, context: Dict[str, Any]) -> float:
|
|
131
|
+
"""Execute evaluation."""
|
|
132
|
+
return self.evaluate(context.get("architecture"))
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class MutationPlugin(Plugin):
|
|
136
|
+
"""
|
|
137
|
+
Plugin for custom mutation operators.
|
|
138
|
+
|
|
139
|
+
Allows users to define custom mutation strategies.
|
|
140
|
+
|
|
141
|
+
Example:
|
|
142
|
+
>>> class LayerSwapMutationPlugin(MutationPlugin):
|
|
143
|
+
... def mutate(self, architecture):
|
|
144
|
+
... # Swap two random layers
|
|
145
|
+
... return mutated_architecture
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
@abstractmethod
|
|
149
|
+
def mutate(self, architecture):
|
|
150
|
+
"""
|
|
151
|
+
Mutate architecture.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
architecture: ModelGraph to mutate
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
Mutated ModelGraph
|
|
158
|
+
"""
|
|
159
|
+
pass
|
|
160
|
+
|
|
161
|
+
def execute(self, context: Dict[str, Any]):
|
|
162
|
+
"""Execute mutation."""
|
|
163
|
+
return self.mutate(context.get("architecture"))
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class ObjectivePlugin(Plugin):
|
|
167
|
+
"""
|
|
168
|
+
Plugin for custom objectives in multi-objective optimization.
|
|
169
|
+
|
|
170
|
+
Example:
|
|
171
|
+
>>> class EnergyObjectivePlugin(ObjectivePlugin):
|
|
172
|
+
... def compute(self, architecture):
|
|
173
|
+
... return estimate_energy_consumption(architecture)
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
@abstractmethod
|
|
177
|
+
def compute(self, architecture) -> float:
|
|
178
|
+
"""
|
|
179
|
+
Compute objective value.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
architecture: ModelGraph
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
Objective value
|
|
186
|
+
"""
|
|
187
|
+
pass
|
|
188
|
+
|
|
189
|
+
def execute(self, context: Dict[str, Any]) -> float:
|
|
190
|
+
"""Execute objective computation."""
|
|
191
|
+
return self.compute(context.get("architecture"))
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class VisualizationPlugin(Plugin):
|
|
195
|
+
"""
|
|
196
|
+
Plugin for custom visualizations.
|
|
197
|
+
|
|
198
|
+
Example:
|
|
199
|
+
>>> class CustomPlotPlugin(VisualizationPlugin):
|
|
200
|
+
... def visualize(self, data):
|
|
201
|
+
... # Create custom plot
|
|
202
|
+
... return figure
|
|
203
|
+
"""
|
|
204
|
+
|
|
205
|
+
@abstractmethod
|
|
206
|
+
def visualize(self, data: Any):
|
|
207
|
+
"""
|
|
208
|
+
Create visualization.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
data: Data to visualize
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
Visualization object (e.g., matplotlib Figure)
|
|
215
|
+
"""
|
|
216
|
+
pass
|
|
217
|
+
|
|
218
|
+
def execute(self, context: Dict[str, Any]):
|
|
219
|
+
"""Execute visualization."""
|
|
220
|
+
return self.visualize(context.get("data"))
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
class PluginManager:
|
|
224
|
+
"""
|
|
225
|
+
Manage and load plugins.
|
|
226
|
+
|
|
227
|
+
Supports loading plugins from:
|
|
228
|
+
- Built-in morphml.plugins module
|
|
229
|
+
- External Python files
|
|
230
|
+
- Installed packages with entry points
|
|
231
|
+
|
|
232
|
+
Example:
|
|
233
|
+
>>> manager = PluginManager()
|
|
234
|
+
>>> manager.register_plugin('my_optimizer', MyOptimizerPlugin)
|
|
235
|
+
>>> plugin = manager.load_plugin('my_optimizer', config={'lr': 0.01})
|
|
236
|
+
>>> optimizer = plugin.get_optimizer()
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
def __init__(self):
|
|
240
|
+
"""Initialize plugin manager."""
|
|
241
|
+
self.plugins: Dict[str, Plugin] = {}
|
|
242
|
+
self.plugin_classes: Dict[str, Type[Plugin]] = {}
|
|
243
|
+
logger.info("Initialized PluginManager")
|
|
244
|
+
|
|
245
|
+
def register_plugin(self, name: str, plugin_class: Type[Plugin]):
|
|
246
|
+
"""
|
|
247
|
+
Register a plugin class.
|
|
248
|
+
|
|
249
|
+
Args:
|
|
250
|
+
name: Plugin name
|
|
251
|
+
plugin_class: Plugin class (subclass of Plugin)
|
|
252
|
+
|
|
253
|
+
Example:
|
|
254
|
+
>>> manager.register_plugin('my_plugin', MyPlugin)
|
|
255
|
+
"""
|
|
256
|
+
if not issubclass(plugin_class, Plugin):
|
|
257
|
+
raise TypeError(f"{plugin_class} must be a subclass of Plugin")
|
|
258
|
+
|
|
259
|
+
self.plugin_classes[name] = plugin_class
|
|
260
|
+
logger.info(f"Registered plugin class: {name}")
|
|
261
|
+
|
|
262
|
+
def load_plugin(self, name: str, config: Optional[Dict[str, Any]] = None) -> Plugin:
|
|
263
|
+
"""
|
|
264
|
+
Load and initialize a plugin.
|
|
265
|
+
|
|
266
|
+
Args:
|
|
267
|
+
name: Plugin name
|
|
268
|
+
config: Plugin configuration
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
Initialized plugin instance
|
|
272
|
+
|
|
273
|
+
Example:
|
|
274
|
+
>>> plugin = manager.load_plugin('my_plugin', {'param': 'value'})
|
|
275
|
+
"""
|
|
276
|
+
if name in self.plugins:
|
|
277
|
+
logger.warning(f"Plugin {name} already loaded, returning existing instance")
|
|
278
|
+
return self.plugins[name]
|
|
279
|
+
|
|
280
|
+
# Try registered plugins first
|
|
281
|
+
if name in self.plugin_classes:
|
|
282
|
+
plugin_class = self.plugin_classes[name]
|
|
283
|
+
else:
|
|
284
|
+
# Try loading from morphml.plugins module
|
|
285
|
+
plugin_class = self._load_plugin_from_module(name)
|
|
286
|
+
|
|
287
|
+
if plugin_class is None:
|
|
288
|
+
raise ValueError(f"Plugin {name} not found")
|
|
289
|
+
|
|
290
|
+
# Initialize plugin
|
|
291
|
+
plugin = plugin_class()
|
|
292
|
+
plugin.initialize(config or {})
|
|
293
|
+
|
|
294
|
+
self.plugins[name] = plugin
|
|
295
|
+
logger.info(f"Loaded plugin: {name}")
|
|
296
|
+
|
|
297
|
+
return plugin
|
|
298
|
+
|
|
299
|
+
def _load_plugin_from_module(self, name: str) -> Optional[Type[Plugin]]:
|
|
300
|
+
"""
|
|
301
|
+
Load plugin from morphml.plugins module.
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
name: Plugin name
|
|
305
|
+
|
|
306
|
+
Returns:
|
|
307
|
+
Plugin class or None
|
|
308
|
+
"""
|
|
309
|
+
try:
|
|
310
|
+
module = importlib.import_module(f"morphml.plugins.{name}")
|
|
311
|
+
|
|
312
|
+
# Look for Plugin class
|
|
313
|
+
if hasattr(module, "Plugin"):
|
|
314
|
+
return module.Plugin
|
|
315
|
+
|
|
316
|
+
# Look for class with matching name
|
|
317
|
+
class_name = "".join(word.capitalize() for word in name.split("_"))
|
|
318
|
+
if hasattr(module, class_name):
|
|
319
|
+
return getattr(module, class_name)
|
|
320
|
+
|
|
321
|
+
logger.warning(f"No Plugin class found in morphml.plugins.{name}")
|
|
322
|
+
return None
|
|
323
|
+
|
|
324
|
+
except ImportError as e:
|
|
325
|
+
logger.debug(f"Could not import morphml.plugins.{name}: {e}")
|
|
326
|
+
return None
|
|
327
|
+
|
|
328
|
+
def load_plugin_from_file(
|
|
329
|
+
self, filepath: str, name: Optional[str] = None, config: Optional[Dict[str, Any]] = None
|
|
330
|
+
) -> Plugin:
|
|
331
|
+
"""
|
|
332
|
+
Load plugin from Python file.
|
|
333
|
+
|
|
334
|
+
Args:
|
|
335
|
+
filepath: Path to Python file
|
|
336
|
+
name: Optional plugin name (defaults to filename)
|
|
337
|
+
config: Plugin configuration
|
|
338
|
+
|
|
339
|
+
Returns:
|
|
340
|
+
Initialized plugin instance
|
|
341
|
+
|
|
342
|
+
Example:
|
|
343
|
+
>>> plugin = manager.load_plugin_from_file(
|
|
344
|
+
... 'my_plugin.py',
|
|
345
|
+
... name='my_plugin',
|
|
346
|
+
... config={'param': 'value'}
|
|
347
|
+
... )
|
|
348
|
+
"""
|
|
349
|
+
path = Path(filepath)
|
|
350
|
+
|
|
351
|
+
if not path.exists():
|
|
352
|
+
raise FileNotFoundError(f"Plugin file not found: {filepath}")
|
|
353
|
+
|
|
354
|
+
# Use filename as plugin name if not provided
|
|
355
|
+
if name is None:
|
|
356
|
+
name = path.stem
|
|
357
|
+
|
|
358
|
+
# Load module from file
|
|
359
|
+
spec = importlib.util.spec_from_file_location(name, filepath)
|
|
360
|
+
if spec is None or spec.loader is None:
|
|
361
|
+
raise ImportError(f"Could not load module from {filepath}")
|
|
362
|
+
|
|
363
|
+
module = importlib.util.module_from_spec(spec)
|
|
364
|
+
spec.loader.exec_module(module)
|
|
365
|
+
|
|
366
|
+
# Find Plugin class
|
|
367
|
+
if hasattr(module, "Plugin"):
|
|
368
|
+
plugin_class = module.Plugin
|
|
369
|
+
else:
|
|
370
|
+
raise AttributeError(f"No Plugin class found in {filepath}")
|
|
371
|
+
|
|
372
|
+
# Initialize and register
|
|
373
|
+
plugin = plugin_class()
|
|
374
|
+
plugin.initialize(config or {})
|
|
375
|
+
|
|
376
|
+
self.plugins[name] = plugin
|
|
377
|
+
logger.info(f"Loaded plugin from file: {filepath}")
|
|
378
|
+
|
|
379
|
+
return plugin
|
|
380
|
+
|
|
381
|
+
def get_plugin(self, name: str) -> Optional[Plugin]:
|
|
382
|
+
"""
|
|
383
|
+
Get loaded plugin by name.
|
|
384
|
+
|
|
385
|
+
Args:
|
|
386
|
+
name: Plugin name
|
|
387
|
+
|
|
388
|
+
Returns:
|
|
389
|
+
Plugin instance or None
|
|
390
|
+
|
|
391
|
+
Example:
|
|
392
|
+
>>> plugin = manager.get_plugin('my_plugin')
|
|
393
|
+
"""
|
|
394
|
+
return self.plugins.get(name)
|
|
395
|
+
|
|
396
|
+
def unload_plugin(self, name: str):
|
|
397
|
+
"""
|
|
398
|
+
Unload a plugin.
|
|
399
|
+
|
|
400
|
+
Args:
|
|
401
|
+
name: Plugin name
|
|
402
|
+
|
|
403
|
+
Example:
|
|
404
|
+
>>> manager.unload_plugin('my_plugin')
|
|
405
|
+
"""
|
|
406
|
+
if name in self.plugins:
|
|
407
|
+
plugin = self.plugins[name]
|
|
408
|
+
plugin.cleanup()
|
|
409
|
+
del self.plugins[name]
|
|
410
|
+
logger.info(f"Unloaded plugin: {name}")
|
|
411
|
+
|
|
412
|
+
def list_plugins(self) -> List[str]:
|
|
413
|
+
"""
|
|
414
|
+
List all loaded plugins.
|
|
415
|
+
|
|
416
|
+
Returns:
|
|
417
|
+
List of plugin names
|
|
418
|
+
|
|
419
|
+
Example:
|
|
420
|
+
>>> plugins = manager.list_plugins()
|
|
421
|
+
>>> print(plugins)
|
|
422
|
+
['optimizer_plugin', 'evaluator_plugin']
|
|
423
|
+
"""
|
|
424
|
+
return list(self.plugins.keys())
|
|
425
|
+
|
|
426
|
+
def list_registered_classes(self) -> List[str]:
|
|
427
|
+
"""
|
|
428
|
+
List all registered plugin classes.
|
|
429
|
+
|
|
430
|
+
Returns:
|
|
431
|
+
List of registered class names
|
|
432
|
+
"""
|
|
433
|
+
return list(self.plugin_classes.keys())
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
# Global plugin manager instance
|
|
437
|
+
_global_manager = None
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def get_plugin_manager() -> PluginManager:
|
|
441
|
+
"""
|
|
442
|
+
Get global plugin manager instance.
|
|
443
|
+
|
|
444
|
+
Returns:
|
|
445
|
+
Global PluginManager instance
|
|
446
|
+
|
|
447
|
+
Example:
|
|
448
|
+
>>> manager = get_plugin_manager()
|
|
449
|
+
>>> manager.load_plugin('my_plugin')
|
|
450
|
+
"""
|
|
451
|
+
global _global_manager
|
|
452
|
+
if _global_manager is None:
|
|
453
|
+
_global_manager = PluginManager()
|
|
454
|
+
return _global_manager
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Report generation tools.
|
|
2
|
+
|
|
3
|
+
This module provides tools to generate comprehensive HTML reports
|
|
4
|
+
for neural architecture search experiments.
|
|
5
|
+
|
|
6
|
+
Example:
|
|
7
|
+
>>> from morphml.reports import ReportGenerator, create_comparison_report
|
|
8
|
+
>>>
|
|
9
|
+
>>> # Quick report
|
|
10
|
+
>>> create_comparison_report(
|
|
11
|
+
... "My Experiment",
|
|
12
|
+
... comparison_results,
|
|
13
|
+
... "report.html"
|
|
14
|
+
... )
|
|
15
|
+
|
|
16
|
+
>>> # Custom report
|
|
17
|
+
>>> generator = ReportGenerator("Custom Report")
|
|
18
|
+
>>> generator.add_section("Results", content)
|
|
19
|
+
>>> generator.generate("custom_report.html")
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from morphml.reports.generator import (
|
|
23
|
+
ReportGenerator,
|
|
24
|
+
create_comparison_report,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"ReportGenerator",
|
|
29
|
+
"create_comparison_report",
|
|
30
|
+
]
|