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,277 @@
|
|
|
1
|
+
"""Architecture similarity metrics for transfer learning.
|
|
2
|
+
|
|
3
|
+
Measures distance between neural architectures for warm-starting.
|
|
4
|
+
|
|
5
|
+
Author: Eshan Roy <eshanized@proton.me>
|
|
6
|
+
Organization: TONMOY INFRASTRUCTURE & VISION
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from collections import Counter
|
|
10
|
+
from typing import TYPE_CHECKING, List
|
|
11
|
+
|
|
12
|
+
import numpy as np
|
|
13
|
+
|
|
14
|
+
from morphml.core.graph import ModelGraph
|
|
15
|
+
from morphml.logging_config import get_logger
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from morphml.meta_learning.experiment_database import TaskMetadata
|
|
19
|
+
|
|
20
|
+
logger = get_logger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ArchitectureSimilarity:
|
|
24
|
+
"""
|
|
25
|
+
Compute similarity between neural architectures.
|
|
26
|
+
|
|
27
|
+
Provides multiple similarity metrics:
|
|
28
|
+
1. **Operation Distribution** - Fast, compares layer type distributions
|
|
29
|
+
2. **Graph Edit Distance** - Precise, expensive for large graphs
|
|
30
|
+
3. **Path Encoding** - Medium complexity, encodes computational paths
|
|
31
|
+
|
|
32
|
+
Example:
|
|
33
|
+
>>> sim = ArchitectureSimilarity()
|
|
34
|
+
>>> similarity = sim.compute(graph1, graph2, method='operation_distribution')
|
|
35
|
+
>>> print(f"Similarity: {similarity:.3f}")
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
def compute(
|
|
40
|
+
graph1: ModelGraph, graph2: ModelGraph, method: str = "operation_distribution"
|
|
41
|
+
) -> float:
|
|
42
|
+
"""
|
|
43
|
+
Compute similarity between two architectures.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
graph1: First architecture
|
|
47
|
+
graph2: Second architecture
|
|
48
|
+
method: Similarity method
|
|
49
|
+
- 'operation_distribution': Fast, based on layer types
|
|
50
|
+
- 'graph_structure': Medium, considers connections
|
|
51
|
+
- 'combined': Weighted combination
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
Similarity score (0-1, 1=identical)
|
|
55
|
+
"""
|
|
56
|
+
if method == "operation_distribution":
|
|
57
|
+
return ArchitectureSimilarity.operation_distribution_similarity(graph1, graph2)
|
|
58
|
+
elif method == "graph_structure":
|
|
59
|
+
return ArchitectureSimilarity.graph_structure_similarity(graph1, graph2)
|
|
60
|
+
elif method == "combined":
|
|
61
|
+
op_sim = ArchitectureSimilarity.operation_distribution_similarity(graph1, graph2)
|
|
62
|
+
struct_sim = ArchitectureSimilarity.graph_structure_similarity(graph1, graph2)
|
|
63
|
+
return 0.6 * op_sim + 0.4 * struct_sim
|
|
64
|
+
else:
|
|
65
|
+
raise ValueError(f"Unknown similarity method: {method}")
|
|
66
|
+
|
|
67
|
+
@staticmethod
|
|
68
|
+
def operation_distribution_similarity(graph1: ModelGraph, graph2: ModelGraph) -> float:
|
|
69
|
+
"""
|
|
70
|
+
Compare operation type distributions (fast method).
|
|
71
|
+
|
|
72
|
+
Computes cosine similarity between operation count vectors.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
graph1: First architecture
|
|
76
|
+
graph2: Second architecture
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Similarity score (0-1)
|
|
80
|
+
"""
|
|
81
|
+
# Extract operations
|
|
82
|
+
ops1 = [layer.layer_type for layer in graph1.layers]
|
|
83
|
+
ops2 = [layer.layer_type for layer in graph2.layers]
|
|
84
|
+
|
|
85
|
+
if not ops1 or not ops2:
|
|
86
|
+
return 0.0
|
|
87
|
+
|
|
88
|
+
# Count operation types
|
|
89
|
+
count1 = Counter(ops1)
|
|
90
|
+
count2 = Counter(ops2)
|
|
91
|
+
|
|
92
|
+
# All operation types
|
|
93
|
+
all_ops = sorted(set(count1.keys()) | set(count2.keys()))
|
|
94
|
+
|
|
95
|
+
if not all_ops:
|
|
96
|
+
return 1.0
|
|
97
|
+
|
|
98
|
+
# Create normalized vectors
|
|
99
|
+
vec1 = np.array([count1.get(op, 0) for op in all_ops], dtype=float)
|
|
100
|
+
vec2 = np.array([count2.get(op, 0) for op in all_ops], dtype=float)
|
|
101
|
+
|
|
102
|
+
# Normalize
|
|
103
|
+
vec1 = vec1 / (vec1.sum() + 1e-8)
|
|
104
|
+
vec2 = vec2 / (vec2.sum() + 1e-8)
|
|
105
|
+
|
|
106
|
+
# Cosine similarity
|
|
107
|
+
similarity = np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2) + 1e-8)
|
|
108
|
+
|
|
109
|
+
return max(0.0, min(1.0, similarity))
|
|
110
|
+
|
|
111
|
+
@staticmethod
|
|
112
|
+
def graph_structure_similarity(graph1: ModelGraph, graph2: ModelGraph) -> float:
|
|
113
|
+
"""
|
|
114
|
+
Compare graph structures (medium complexity).
|
|
115
|
+
|
|
116
|
+
Considers both nodes and edges.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
graph1: First architecture
|
|
120
|
+
graph2: Second architecture
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Similarity score (0-1)
|
|
124
|
+
"""
|
|
125
|
+
# Number of layers
|
|
126
|
+
n1 = len(graph1.layers)
|
|
127
|
+
n2 = len(graph2.layers)
|
|
128
|
+
|
|
129
|
+
if n1 == 0 and n2 == 0:
|
|
130
|
+
return 1.0
|
|
131
|
+
|
|
132
|
+
# Normalized layer count difference
|
|
133
|
+
size_similarity = 1.0 - abs(n1 - n2) / max(n1, n2, 1)
|
|
134
|
+
|
|
135
|
+
# Operation similarity
|
|
136
|
+
op_similarity = ArchitectureSimilarity.operation_distribution_similarity(graph1, graph2)
|
|
137
|
+
|
|
138
|
+
# Combine
|
|
139
|
+
similarity = 0.5 * size_similarity + 0.5 * op_similarity
|
|
140
|
+
|
|
141
|
+
return similarity
|
|
142
|
+
|
|
143
|
+
@staticmethod
|
|
144
|
+
def parameter_count_similarity(graph1: ModelGraph, graph2: ModelGraph) -> float:
|
|
145
|
+
"""
|
|
146
|
+
Compare models by parameter count.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
graph1: First architecture
|
|
150
|
+
graph2: Second architecture
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
Similarity score (0-1)
|
|
154
|
+
"""
|
|
155
|
+
params1 = graph1.count_parameters()
|
|
156
|
+
params2 = graph2.count_parameters()
|
|
157
|
+
|
|
158
|
+
if params1 == 0 and params2 == 0:
|
|
159
|
+
return 1.0
|
|
160
|
+
|
|
161
|
+
# Normalized difference
|
|
162
|
+
max_params = max(params1, params2, 1)
|
|
163
|
+
similarity = 1.0 - abs(params1 - params2) / max_params
|
|
164
|
+
|
|
165
|
+
return similarity
|
|
166
|
+
|
|
167
|
+
@staticmethod
|
|
168
|
+
def depth_similarity(graph1: ModelGraph, graph2: ModelGraph) -> float:
|
|
169
|
+
"""
|
|
170
|
+
Compare network depth.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
graph1: First architecture
|
|
174
|
+
graph2: Second architecture
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
Similarity score (0-1)
|
|
178
|
+
"""
|
|
179
|
+
depth1 = len(graph1.layers)
|
|
180
|
+
depth2 = len(graph2.layers)
|
|
181
|
+
|
|
182
|
+
if depth1 == 0 and depth2 == 0:
|
|
183
|
+
return 1.0
|
|
184
|
+
|
|
185
|
+
max_depth = max(depth1, depth2, 1)
|
|
186
|
+
similarity = 1.0 - abs(depth1 - depth2) / max_depth
|
|
187
|
+
|
|
188
|
+
return similarity
|
|
189
|
+
|
|
190
|
+
@staticmethod
|
|
191
|
+
def batch_similarity(
|
|
192
|
+
query_graph: ModelGraph,
|
|
193
|
+
candidate_graphs: List[ModelGraph],
|
|
194
|
+
method: str = "operation_distribution",
|
|
195
|
+
) -> np.ndarray:
|
|
196
|
+
"""
|
|
197
|
+
Compute similarity between one graph and multiple candidates.
|
|
198
|
+
|
|
199
|
+
Efficient batch computation.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
query_graph: Query architecture
|
|
203
|
+
candidate_graphs: List of candidate architectures
|
|
204
|
+
method: Similarity method
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
Array of similarity scores
|
|
208
|
+
"""
|
|
209
|
+
similarities = []
|
|
210
|
+
|
|
211
|
+
for candidate in candidate_graphs:
|
|
212
|
+
sim = ArchitectureSimilarity.compute(query_graph, candidate, method=method)
|
|
213
|
+
similarities.append(sim)
|
|
214
|
+
|
|
215
|
+
return np.array(similarities)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def compute_task_similarity(
|
|
219
|
+
task1: "TaskMetadata", task2: "TaskMetadata", method: str = "meta_features"
|
|
220
|
+
) -> float:
|
|
221
|
+
"""
|
|
222
|
+
Compute similarity between tasks.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
task1: First task
|
|
226
|
+
task2: Second task
|
|
227
|
+
method: Similarity method
|
|
228
|
+
- 'meta_features': Based on dataset characteristics
|
|
229
|
+
- 'dataset_name': Simple name matching
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
Similarity score (0-1)
|
|
233
|
+
"""
|
|
234
|
+
if method == "dataset_name":
|
|
235
|
+
# Simple string similarity
|
|
236
|
+
if task1.dataset_name == task2.dataset_name:
|
|
237
|
+
return 1.0
|
|
238
|
+
elif task1.dataset_name in task2.dataset_name or task2.dataset_name in task1.dataset_name:
|
|
239
|
+
return 0.7
|
|
240
|
+
else:
|
|
241
|
+
return 0.0
|
|
242
|
+
|
|
243
|
+
elif method == "meta_features":
|
|
244
|
+
# Meta-feature based similarity
|
|
245
|
+
features1 = np.array(
|
|
246
|
+
[
|
|
247
|
+
task1.num_samples / 100000.0,
|
|
248
|
+
task1.num_classes / 100.0,
|
|
249
|
+
task1.input_size[0] / 3.0, # Channels
|
|
250
|
+
task1.input_size[1] / 224.0, # Height
|
|
251
|
+
task1.input_size[2] / 224.0, # Width
|
|
252
|
+
]
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
features2 = np.array(
|
|
256
|
+
[
|
|
257
|
+
task2.num_samples / 100000.0,
|
|
258
|
+
task2.num_classes / 100.0,
|
|
259
|
+
task2.input_size[0] / 3.0,
|
|
260
|
+
task2.input_size[1] / 224.0,
|
|
261
|
+
task2.input_size[2] / 224.0,
|
|
262
|
+
]
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
# Cosine similarity
|
|
266
|
+
similarity = np.dot(features1, features2) / (
|
|
267
|
+
np.linalg.norm(features1) * np.linalg.norm(features2) + 1e-8
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
# Problem type bonus
|
|
271
|
+
if task1.problem_type == task2.problem_type:
|
|
272
|
+
similarity *= 1.2 # Boost for same problem type
|
|
273
|
+
|
|
274
|
+
return max(0.0, min(1.0, similarity))
|
|
275
|
+
|
|
276
|
+
else:
|
|
277
|
+
raise ValueError(f"Unknown method: {method}")
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"""Experiment database for meta-learning knowledge base.
|
|
2
|
+
|
|
3
|
+
Stores and retrieves past experiments for transfer learning.
|
|
4
|
+
|
|
5
|
+
Author: Eshan Roy <eshanized@proton.me>
|
|
6
|
+
Organization: TONMOY INFRASTRUCTURE & VISION
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
12
|
+
|
|
13
|
+
from morphml.core.graph import ModelGraph
|
|
14
|
+
from morphml.logging_config import get_logger
|
|
15
|
+
|
|
16
|
+
logger = get_logger(__name__)
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
DB_AVAILABLE = True
|
|
20
|
+
except ImportError:
|
|
21
|
+
DB_AVAILABLE = False
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class TaskMetadata:
|
|
26
|
+
"""
|
|
27
|
+
Metadata describing a machine learning task.
|
|
28
|
+
|
|
29
|
+
Used for task similarity computation and warm-starting.
|
|
30
|
+
|
|
31
|
+
Attributes:
|
|
32
|
+
task_id: Unique task identifier
|
|
33
|
+
dataset_name: Name of dataset (e.g., 'CIFAR-10')
|
|
34
|
+
num_samples: Number of training samples
|
|
35
|
+
num_classes: Number of output classes
|
|
36
|
+
input_size: Input tensor shape (C, H, W)
|
|
37
|
+
problem_type: Type of problem ('classification', 'detection', 'segmentation')
|
|
38
|
+
metadata: Additional task-specific metadata
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
task_id: str
|
|
42
|
+
dataset_name: str
|
|
43
|
+
num_samples: int
|
|
44
|
+
num_classes: int
|
|
45
|
+
input_size: Tuple[int, int, int] # (C, H, W)
|
|
46
|
+
problem_type: str = "classification"
|
|
47
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
48
|
+
|
|
49
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
50
|
+
"""Convert to dictionary."""
|
|
51
|
+
return {
|
|
52
|
+
"task_id": self.task_id,
|
|
53
|
+
"dataset_name": self.dataset_name,
|
|
54
|
+
"num_samples": self.num_samples,
|
|
55
|
+
"num_classes": self.num_classes,
|
|
56
|
+
"input_size": list(self.input_size),
|
|
57
|
+
"problem_type": self.problem_type,
|
|
58
|
+
"metadata": self.metadata,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@classmethod
|
|
62
|
+
def from_dict(cls, data: Dict[str, Any]) -> "TaskMetadata":
|
|
63
|
+
"""Create from dictionary."""
|
|
64
|
+
return cls(
|
|
65
|
+
task_id=data["task_id"],
|
|
66
|
+
dataset_name=data["dataset_name"],
|
|
67
|
+
num_samples=data["num_samples"],
|
|
68
|
+
num_classes=data["num_classes"],
|
|
69
|
+
input_size=tuple(data["input_size"]),
|
|
70
|
+
problem_type=data.get("problem_type", "classification"),
|
|
71
|
+
metadata=data.get("metadata", {}),
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class ExperimentDatabase:
|
|
76
|
+
"""
|
|
77
|
+
Database interface for past experiments.
|
|
78
|
+
|
|
79
|
+
Provides access to experiment history for meta-learning:
|
|
80
|
+
- Query tasks by similarity
|
|
81
|
+
- Retrieve top architectures
|
|
82
|
+
- Get search trajectories
|
|
83
|
+
- Store new experiments
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
db_manager: DatabaseManager instance (if using SQL backend)
|
|
87
|
+
storage_path: Path to local storage (if using file backend)
|
|
88
|
+
|
|
89
|
+
Example:
|
|
90
|
+
>>> db = ExperimentDatabase(db_manager)
|
|
91
|
+
>>> tasks = db.get_all_tasks()
|
|
92
|
+
>>> archs = db.get_top_architectures('exp1', top_k=10)
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
def __init__(self, db_manager: Optional[Any] = None, storage_path: Optional[str] = None):
|
|
96
|
+
"""Initialize experiment database."""
|
|
97
|
+
self.db_manager = db_manager
|
|
98
|
+
self.storage_path = storage_path
|
|
99
|
+
|
|
100
|
+
# In-memory cache
|
|
101
|
+
self._task_cache: Dict[str, TaskMetadata] = {}
|
|
102
|
+
self._arch_cache: Dict[str, List[ModelGraph]] = {}
|
|
103
|
+
|
|
104
|
+
logger.info("Initialized ExperimentDatabase")
|
|
105
|
+
|
|
106
|
+
def add_task(self, task: TaskMetadata) -> None:
|
|
107
|
+
"""
|
|
108
|
+
Add task metadata to database.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
task: Task metadata
|
|
112
|
+
"""
|
|
113
|
+
self._task_cache[task.task_id] = task
|
|
114
|
+
logger.debug(f"Added task {task.task_id} to database")
|
|
115
|
+
|
|
116
|
+
def get_all_tasks(self) -> List[TaskMetadata]:
|
|
117
|
+
"""
|
|
118
|
+
Get all past tasks.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
List of task metadata
|
|
122
|
+
"""
|
|
123
|
+
if self.db_manager and DB_AVAILABLE:
|
|
124
|
+
# Query from SQL database
|
|
125
|
+
try:
|
|
126
|
+
experiments = self.db_manager.list_experiments()
|
|
127
|
+
tasks = [self._experiment_to_task_metadata(exp) for exp in experiments]
|
|
128
|
+
return tasks
|
|
129
|
+
except Exception as e:
|
|
130
|
+
logger.warning(f"Failed to query database: {e}")
|
|
131
|
+
|
|
132
|
+
# Return from cache
|
|
133
|
+
return list(self._task_cache.values())
|
|
134
|
+
|
|
135
|
+
def get_task(self, task_id: str) -> Optional[TaskMetadata]:
|
|
136
|
+
"""
|
|
137
|
+
Get specific task metadata.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
task_id: Task identifier
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
Task metadata or None
|
|
144
|
+
"""
|
|
145
|
+
return self._task_cache.get(task_id)
|
|
146
|
+
|
|
147
|
+
def get_top_architectures(self, task_id: str, top_k: int = 10) -> List[ModelGraph]:
|
|
148
|
+
"""
|
|
149
|
+
Get top-k architectures for a task.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
task_id: Task identifier
|
|
153
|
+
top_k: Number of architectures to return
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
List of best architectures
|
|
157
|
+
"""
|
|
158
|
+
# Check cache first
|
|
159
|
+
if task_id in self._arch_cache:
|
|
160
|
+
cached = self._arch_cache[task_id]
|
|
161
|
+
return cached[:top_k]
|
|
162
|
+
|
|
163
|
+
if self.db_manager and DB_AVAILABLE:
|
|
164
|
+
# Query from SQL database
|
|
165
|
+
try:
|
|
166
|
+
best = self.db_manager.get_best_architectures(task_id, top_k=top_k)
|
|
167
|
+
graphs = []
|
|
168
|
+
|
|
169
|
+
for arch in best:
|
|
170
|
+
try:
|
|
171
|
+
graph_dict = json.loads(arch.architecture_json)
|
|
172
|
+
graph = ModelGraph.from_dict(graph_dict)
|
|
173
|
+
graphs.append(graph)
|
|
174
|
+
except Exception as e:
|
|
175
|
+
logger.warning(f"Failed to deserialize architecture: {e}")
|
|
176
|
+
|
|
177
|
+
# Cache results
|
|
178
|
+
self._arch_cache[task_id] = graphs
|
|
179
|
+
|
|
180
|
+
return graphs
|
|
181
|
+
except Exception as e:
|
|
182
|
+
logger.warning(f"Failed to query architectures: {e}")
|
|
183
|
+
|
|
184
|
+
return []
|
|
185
|
+
|
|
186
|
+
def add_architecture(self, task_id: str, graph: ModelGraph, fitness: float) -> None:
|
|
187
|
+
"""
|
|
188
|
+
Add architecture to database.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
task_id: Task identifier
|
|
192
|
+
graph: Architecture graph
|
|
193
|
+
fitness: Performance score
|
|
194
|
+
"""
|
|
195
|
+
if task_id not in self._arch_cache:
|
|
196
|
+
self._arch_cache[task_id] = []
|
|
197
|
+
|
|
198
|
+
self._arch_cache[task_id].append(graph)
|
|
199
|
+
|
|
200
|
+
# Sort by fitness (need to store fitness too)
|
|
201
|
+
# For now just append
|
|
202
|
+
logger.debug(f"Added architecture to task {task_id}")
|
|
203
|
+
|
|
204
|
+
def _experiment_to_task_metadata(self, experiment: Any) -> TaskMetadata:
|
|
205
|
+
"""Convert database Experiment to TaskMetadata."""
|
|
206
|
+
try:
|
|
207
|
+
config = json.loads(experiment.config) if hasattr(experiment, "config") else {}
|
|
208
|
+
(json.loads(experiment.search_space) if hasattr(experiment, "search_space") else {})
|
|
209
|
+
|
|
210
|
+
# Extract metadata
|
|
211
|
+
return TaskMetadata(
|
|
212
|
+
task_id=str(experiment.id),
|
|
213
|
+
dataset_name=experiment.name,
|
|
214
|
+
num_samples=config.get("num_samples", 50000),
|
|
215
|
+
num_classes=config.get("num_classes", 10),
|
|
216
|
+
input_size=tuple(config.get("input_size", [3, 32, 32])),
|
|
217
|
+
problem_type=config.get("problem_type", "classification"),
|
|
218
|
+
metadata={
|
|
219
|
+
"optimizer": experiment.optimizer,
|
|
220
|
+
"status": experiment.status,
|
|
221
|
+
"num_evaluations": experiment.num_evaluations,
|
|
222
|
+
},
|
|
223
|
+
)
|
|
224
|
+
except Exception as e:
|
|
225
|
+
logger.warning(f"Failed to convert experiment: {e}")
|
|
226
|
+
# Return default
|
|
227
|
+
return TaskMetadata(
|
|
228
|
+
task_id=str(experiment.id),
|
|
229
|
+
dataset_name=experiment.name,
|
|
230
|
+
num_samples=50000,
|
|
231
|
+
num_classes=10,
|
|
232
|
+
input_size=(3, 32, 32),
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
def get_statistics(self) -> Dict[str, Any]:
|
|
236
|
+
"""Get database statistics."""
|
|
237
|
+
return {
|
|
238
|
+
"num_tasks": len(self._task_cache),
|
|
239
|
+
"num_cached_architectures": sum(len(archs) for archs in self._arch_cache.values()),
|
|
240
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Knowledge base for experiment history and retrieval.
|
|
2
|
+
|
|
3
|
+
Vector-based storage and similarity search for architectures.
|
|
4
|
+
|
|
5
|
+
Author: Eshan Roy <eshanized@proton.me>
|
|
6
|
+
Organization: TONMOY INFRASTRUCTURE & VISION
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from morphml.meta_learning.knowledge_base.embedder import ArchitectureEmbedder
|
|
10
|
+
from morphml.meta_learning.knowledge_base.knowledge_base import KnowledgeBase
|
|
11
|
+
from morphml.meta_learning.knowledge_base.meta_features import MetaFeatureExtractor
|
|
12
|
+
from morphml.meta_learning.knowledge_base.vector_store import VectorStore
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"ArchitectureEmbedder",
|
|
16
|
+
"VectorStore",
|
|
17
|
+
"KnowledgeBase",
|
|
18
|
+
"MetaFeatureExtractor",
|
|
19
|
+
]
|