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,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
+ ]