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,230 @@
|
|
|
1
|
+
"""Portfolio optimization - run multiple strategies in parallel.
|
|
2
|
+
|
|
3
|
+
Author: Eshan Roy <eshanized@proton.me>
|
|
4
|
+
Organization: TONMOY INFRASTRUCTURE & VISION
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
8
|
+
from typing import Any, Callable, Dict, List
|
|
9
|
+
|
|
10
|
+
from morphml.core.dsl import SearchSpace
|
|
11
|
+
from morphml.core.graph import ModelGraph
|
|
12
|
+
from morphml.logging_config import get_logger
|
|
13
|
+
|
|
14
|
+
logger = get_logger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class PortfolioOptimizer:
|
|
18
|
+
"""
|
|
19
|
+
Run multiple optimization strategies in parallel.
|
|
20
|
+
|
|
21
|
+
Allocates computational budget across different strategies
|
|
22
|
+
and combines their results.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
search_space: Search space definition
|
|
26
|
+
evaluator: Architecture evaluation function
|
|
27
|
+
strategies: Dict mapping strategy name to configuration
|
|
28
|
+
budget_allocation: Budget allocation strategy
|
|
29
|
+
- 'equal': Equal budget to each
|
|
30
|
+
- 'performance': Allocate based on past performance
|
|
31
|
+
|
|
32
|
+
Example:
|
|
33
|
+
>>> strategies = {
|
|
34
|
+
... 'random': {'num_samples': 100},
|
|
35
|
+
... 'ga': {'population_size': 50, 'num_generations': 10},
|
|
36
|
+
... 'hc': {'num_iterations': 200}
|
|
37
|
+
... }
|
|
38
|
+
>>>
|
|
39
|
+
>>> portfolio = PortfolioOptimizer(
|
|
40
|
+
... search_space=space,
|
|
41
|
+
... evaluator=evaluator,
|
|
42
|
+
... strategies=strategies
|
|
43
|
+
... )
|
|
44
|
+
>>>
|
|
45
|
+
>>> best_archs = portfolio.optimize(total_budget=500)
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
def __init__(
|
|
49
|
+
self,
|
|
50
|
+
search_space: SearchSpace,
|
|
51
|
+
evaluator: Callable[[ModelGraph], float],
|
|
52
|
+
strategies: Dict[str, Dict[str, Any]],
|
|
53
|
+
budget_allocation: str = "equal",
|
|
54
|
+
parallel: bool = False,
|
|
55
|
+
):
|
|
56
|
+
"""Initialize portfolio optimizer."""
|
|
57
|
+
self.search_space = search_space
|
|
58
|
+
self.evaluator = evaluator
|
|
59
|
+
self.strategies = strategies
|
|
60
|
+
self.budget_allocation = budget_allocation
|
|
61
|
+
self.parallel = parallel
|
|
62
|
+
|
|
63
|
+
self.results = {}
|
|
64
|
+
|
|
65
|
+
logger.info(
|
|
66
|
+
f"Initialized PortfolioOptimizer with {len(strategies)} strategies: "
|
|
67
|
+
f"{list(strategies.keys())}"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
def optimize(self, total_budget: int = 500, top_k: int = 10) -> List[ModelGraph]:
|
|
71
|
+
"""
|
|
72
|
+
Run portfolio optimization.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
total_budget: Total evaluation budget
|
|
76
|
+
top_k: Number of best architectures to return
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
List of best architectures across all strategies
|
|
80
|
+
"""
|
|
81
|
+
logger.info(f"Starting portfolio optimization with budget={total_budget}")
|
|
82
|
+
|
|
83
|
+
# Allocate budget
|
|
84
|
+
budgets = self._allocate_budget(total_budget)
|
|
85
|
+
|
|
86
|
+
logger.info(f"Budget allocation: {budgets}")
|
|
87
|
+
|
|
88
|
+
# Run strategies
|
|
89
|
+
if self.parallel:
|
|
90
|
+
all_results = self._run_parallel(budgets)
|
|
91
|
+
else:
|
|
92
|
+
all_results = self._run_sequential(budgets)
|
|
93
|
+
|
|
94
|
+
# Combine and sort
|
|
95
|
+
combined = []
|
|
96
|
+
for _strategy, results in all_results.items():
|
|
97
|
+
combined.extend(results)
|
|
98
|
+
|
|
99
|
+
# Sort by fitness
|
|
100
|
+
combined.sort(key=lambda x: x[1], reverse=True)
|
|
101
|
+
|
|
102
|
+
# Extract top-k architectures
|
|
103
|
+
best_architectures = [arch for arch, _ in combined[:top_k]]
|
|
104
|
+
|
|
105
|
+
logger.info(f"Portfolio optimization complete! " f"Best fitness: {combined[0][1]:.4f}")
|
|
106
|
+
|
|
107
|
+
return best_architectures
|
|
108
|
+
|
|
109
|
+
def _allocate_budget(self, total_budget: int) -> Dict[str, int]:
|
|
110
|
+
"""
|
|
111
|
+
Allocate budget across strategies.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
total_budget: Total budget
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
Dict mapping strategy to allocated budget
|
|
118
|
+
"""
|
|
119
|
+
budgets = {}
|
|
120
|
+
|
|
121
|
+
if self.budget_allocation == "equal":
|
|
122
|
+
# Equal allocation
|
|
123
|
+
budget_per_strategy = total_budget // len(self.strategies)
|
|
124
|
+
for strategy in self.strategies:
|
|
125
|
+
budgets[strategy] = budget_per_strategy
|
|
126
|
+
|
|
127
|
+
elif self.budget_allocation == "performance":
|
|
128
|
+
# Allocate based on past performance
|
|
129
|
+
# (simplified - would use historical data in practice)
|
|
130
|
+
budget_per_strategy = total_budget // len(self.strategies)
|
|
131
|
+
for strategy in self.strategies:
|
|
132
|
+
budgets[strategy] = budget_per_strategy
|
|
133
|
+
|
|
134
|
+
else:
|
|
135
|
+
raise ValueError(f"Unknown allocation: {self.budget_allocation}")
|
|
136
|
+
|
|
137
|
+
return budgets
|
|
138
|
+
|
|
139
|
+
def _run_sequential(self, budgets: Dict[str, int]) -> Dict[str, List[tuple]]:
|
|
140
|
+
"""Run strategies sequentially."""
|
|
141
|
+
all_results = {}
|
|
142
|
+
|
|
143
|
+
for strategy, budget in budgets.items():
|
|
144
|
+
logger.info(f"Running {strategy} with budget {budget}")
|
|
145
|
+
|
|
146
|
+
results = self._run_strategy(strategy, budget)
|
|
147
|
+
all_results[strategy] = results
|
|
148
|
+
|
|
149
|
+
best_fitness = max(f for _, f in results) if results else 0.0
|
|
150
|
+
logger.info(
|
|
151
|
+
f"{strategy} complete: {len(results)} evaluations, " f"best={best_fitness:.4f}"
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
return all_results
|
|
155
|
+
|
|
156
|
+
def _run_parallel(self, budgets: Dict[str, int]) -> Dict[str, List[tuple]]:
|
|
157
|
+
"""Run strategies in parallel."""
|
|
158
|
+
all_results = {}
|
|
159
|
+
|
|
160
|
+
with ThreadPoolExecutor(max_workers=len(self.strategies)) as executor:
|
|
161
|
+
# Submit all strategies
|
|
162
|
+
futures = {
|
|
163
|
+
executor.submit(self._run_strategy, strategy, budget): strategy
|
|
164
|
+
for strategy, budget in budgets.items()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
# Collect results
|
|
168
|
+
for future in as_completed(futures):
|
|
169
|
+
strategy = futures[future]
|
|
170
|
+
try:
|
|
171
|
+
results = future.result()
|
|
172
|
+
all_results[strategy] = results
|
|
173
|
+
|
|
174
|
+
best_fitness = max(f for _, f in results) if results else 0.0
|
|
175
|
+
logger.info(
|
|
176
|
+
f"{strategy} complete: {len(results)} evaluations, "
|
|
177
|
+
f"best={best_fitness:.4f}"
|
|
178
|
+
)
|
|
179
|
+
except Exception as e:
|
|
180
|
+
logger.error(f"{strategy} failed: {e}")
|
|
181
|
+
all_results[strategy] = []
|
|
182
|
+
|
|
183
|
+
return all_results
|
|
184
|
+
|
|
185
|
+
def _run_strategy(self, strategy: str, budget: int) -> List[tuple]:
|
|
186
|
+
"""
|
|
187
|
+
Run a single strategy.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
strategy: Strategy name
|
|
191
|
+
budget: Evaluation budget
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
List of (architecture, fitness) tuples
|
|
195
|
+
"""
|
|
196
|
+
results = []
|
|
197
|
+
config = self.strategies[strategy]
|
|
198
|
+
|
|
199
|
+
if strategy == "random":
|
|
200
|
+
# Random search
|
|
201
|
+
for _ in range(budget):
|
|
202
|
+
arch = self.search_space.sample()
|
|
203
|
+
fitness = self.evaluator(arch)
|
|
204
|
+
results.append((arch, fitness))
|
|
205
|
+
|
|
206
|
+
elif strategy in ["ga", "genetic"]:
|
|
207
|
+
# Genetic algorithm
|
|
208
|
+
from morphml.optimizers import GeneticAlgorithm
|
|
209
|
+
|
|
210
|
+
pop_size = config.get("population_size", 20)
|
|
211
|
+
num_gen = budget // pop_size
|
|
212
|
+
|
|
213
|
+
ga = GeneticAlgorithm(
|
|
214
|
+
search_space=self.search_space,
|
|
215
|
+
evaluator=self.evaluator,
|
|
216
|
+
population_size=pop_size,
|
|
217
|
+
num_generations=num_gen,
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
ga.search()
|
|
221
|
+
results = [(ind.architecture, ind.fitness) for ind in ga.history]
|
|
222
|
+
|
|
223
|
+
else:
|
|
224
|
+
# Fallback to random
|
|
225
|
+
for _ in range(budget):
|
|
226
|
+
arch = self.search_space.sample()
|
|
227
|
+
fitness = self.evaluator(arch)
|
|
228
|
+
results.append((arch, fitness))
|
|
229
|
+
|
|
230
|
+
return results
|