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,386 @@
|
|
|
1
|
+
"""Search space definition using the MorphML DSL.
|
|
2
|
+
|
|
3
|
+
This module provides the SearchSpace class for defining neural architecture
|
|
4
|
+
search spaces in a Pythonic way.
|
|
5
|
+
|
|
6
|
+
Example:
|
|
7
|
+
>>> from morphml.core.dsl import SearchSpace, Layer
|
|
8
|
+
>>>
|
|
9
|
+
>>> # Define search space
|
|
10
|
+
>>> space = SearchSpace(name="cifar10_cnn")
|
|
11
|
+
>>>
|
|
12
|
+
>>> # Add layers
|
|
13
|
+
>>> space.add_layer(Layer.input(shape=(3, 32, 32)))
|
|
14
|
+
>>> space.add_layer(Layer.conv2d(filters=[32, 64], kernel_size=[3, 5]))
|
|
15
|
+
>>> space.add_layer(Layer.relu())
|
|
16
|
+
>>> space.add_layer(Layer.maxpool(pool_size=2))
|
|
17
|
+
>>> space.add_layer(Layer.dense(units=[128, 256, 512]))
|
|
18
|
+
>>> space.add_layer(Layer.output(units=10))
|
|
19
|
+
>>>
|
|
20
|
+
>>> # Sample architectures
|
|
21
|
+
>>> arch1 = space.sample()
|
|
22
|
+
>>> arch2 = space.sample()
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
26
|
+
|
|
27
|
+
from morphml.core.dsl.layers import LayerSpec
|
|
28
|
+
from morphml.core.graph import GraphEdge, ModelGraph
|
|
29
|
+
from morphml.exceptions import SearchSpaceError
|
|
30
|
+
from morphml.logging_config import get_logger
|
|
31
|
+
|
|
32
|
+
logger = get_logger(__name__)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class SearchSpace:
|
|
36
|
+
"""
|
|
37
|
+
Defines a search space for neural architecture search.
|
|
38
|
+
|
|
39
|
+
A SearchSpace consists of:
|
|
40
|
+
- A sequence of layer specifications
|
|
41
|
+
- Constraints on valid architectures
|
|
42
|
+
- Metadata about the space
|
|
43
|
+
|
|
44
|
+
Architectures are sampled by:
|
|
45
|
+
1. Sampling parameters for each layer
|
|
46
|
+
2. Connecting layers sequentially
|
|
47
|
+
3. Validating the resulting graph
|
|
48
|
+
|
|
49
|
+
Attributes:
|
|
50
|
+
name: Search space name
|
|
51
|
+
layers: List of layer specifications
|
|
52
|
+
constraints: List of constraint functions
|
|
53
|
+
metadata: Additional metadata
|
|
54
|
+
|
|
55
|
+
Example:
|
|
56
|
+
>>> space = SearchSpace("my_space")
|
|
57
|
+
>>> space.add_layer(Layer.conv2d(filters=[32, 64]))
|
|
58
|
+
>>> space.add_layer(Layer.dense(units=10))
|
|
59
|
+
>>> architecture = space.sample()
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __init__(
|
|
63
|
+
self,
|
|
64
|
+
name: str = "search_space",
|
|
65
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
66
|
+
):
|
|
67
|
+
"""
|
|
68
|
+
Initialize search space.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
name: Search space name
|
|
72
|
+
metadata: Optional metadata
|
|
73
|
+
"""
|
|
74
|
+
self.name = name
|
|
75
|
+
self.layers: List[LayerSpec] = []
|
|
76
|
+
self.constraints: List[Callable[[ModelGraph], bool]] = []
|
|
77
|
+
self.metadata = metadata or {}
|
|
78
|
+
|
|
79
|
+
logger.debug(f"Created SearchSpace: {name}")
|
|
80
|
+
|
|
81
|
+
def add_layer(self, layer_spec: LayerSpec) -> "SearchSpace":
|
|
82
|
+
"""
|
|
83
|
+
Add a layer specification to the search space.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
layer_spec: Layer specification to add
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
Self (for method chaining)
|
|
90
|
+
|
|
91
|
+
Example:
|
|
92
|
+
>>> space.add_layer(Layer.conv2d(filters=64))
|
|
93
|
+
>>> space.add_layer(Layer.relu())
|
|
94
|
+
"""
|
|
95
|
+
self.layers.append(layer_spec)
|
|
96
|
+
logger.debug(f"Added layer: {layer_spec.operation}")
|
|
97
|
+
return self
|
|
98
|
+
|
|
99
|
+
def add_layers(self, *layer_specs: LayerSpec) -> "SearchSpace":
|
|
100
|
+
"""
|
|
101
|
+
Add multiple layer specifications.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
*layer_specs: Layer specifications to add
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
Self (for method chaining)
|
|
108
|
+
|
|
109
|
+
Example:
|
|
110
|
+
>>> space.add_layers(
|
|
111
|
+
... Layer.conv2d(filters=64),
|
|
112
|
+
... Layer.relu(),
|
|
113
|
+
... Layer.maxpool()
|
|
114
|
+
... )
|
|
115
|
+
"""
|
|
116
|
+
for layer_spec in layer_specs:
|
|
117
|
+
self.add_layer(layer_spec)
|
|
118
|
+
return self
|
|
119
|
+
|
|
120
|
+
def add_constraint(self, constraint_fn: Callable[[ModelGraph], bool]) -> "SearchSpace":
|
|
121
|
+
"""
|
|
122
|
+
Add a constraint function.
|
|
123
|
+
|
|
124
|
+
Constraint functions should take a ModelGraph and return bool.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
constraint_fn: Function that validates a graph
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
Self (for method chaining)
|
|
131
|
+
|
|
132
|
+
Example:
|
|
133
|
+
>>> def max_depth(graph):
|
|
134
|
+
... return graph.get_depth() <= 20
|
|
135
|
+
>>> space.add_constraint(max_depth)
|
|
136
|
+
"""
|
|
137
|
+
self.constraints.append(constraint_fn)
|
|
138
|
+
return self
|
|
139
|
+
|
|
140
|
+
def sample(self, max_attempts: int = 100) -> ModelGraph:
|
|
141
|
+
"""
|
|
142
|
+
Sample a random architecture from this search space.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
max_attempts: Maximum sampling attempts before giving up
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
Sampled ModelGraph
|
|
149
|
+
|
|
150
|
+
Raises:
|
|
151
|
+
SearchSpaceError: If unable to sample valid architecture
|
|
152
|
+
|
|
153
|
+
Example:
|
|
154
|
+
>>> arch = space.sample()
|
|
155
|
+
>>> print(arch)
|
|
156
|
+
"""
|
|
157
|
+
for attempt in range(max_attempts):
|
|
158
|
+
try:
|
|
159
|
+
# Create graph
|
|
160
|
+
graph = ModelGraph(metadata={"search_space": self.name})
|
|
161
|
+
|
|
162
|
+
# Sample nodes from each layer spec
|
|
163
|
+
nodes = []
|
|
164
|
+
for layer_spec in self.layers:
|
|
165
|
+
node = layer_spec.sample()
|
|
166
|
+
graph.add_node(node)
|
|
167
|
+
nodes.append(node)
|
|
168
|
+
|
|
169
|
+
# Connect sequentially
|
|
170
|
+
for i in range(len(nodes) - 1):
|
|
171
|
+
edge = GraphEdge(nodes[i], nodes[i + 1])
|
|
172
|
+
graph.add_edge(edge)
|
|
173
|
+
|
|
174
|
+
# Validate
|
|
175
|
+
if not graph.is_valid():
|
|
176
|
+
logger.debug(f"Attempt {attempt + 1}: Invalid graph")
|
|
177
|
+
continue
|
|
178
|
+
|
|
179
|
+
# Check constraints
|
|
180
|
+
if not self._check_constraints(graph):
|
|
181
|
+
logger.debug(f"Attempt {attempt + 1}: Constraint violation")
|
|
182
|
+
continue
|
|
183
|
+
|
|
184
|
+
logger.debug(f"Successfully sampled architecture (attempt {attempt + 1})")
|
|
185
|
+
return graph
|
|
186
|
+
|
|
187
|
+
except Exception as e:
|
|
188
|
+
logger.debug(f"Attempt {attempt + 1} failed: {e}")
|
|
189
|
+
continue
|
|
190
|
+
|
|
191
|
+
raise SearchSpaceError(f"Failed to sample valid architecture after {max_attempts} attempts")
|
|
192
|
+
|
|
193
|
+
def sample_batch(self, batch_size: int, max_attempts: int = 100) -> List[ModelGraph]:
|
|
194
|
+
"""
|
|
195
|
+
Sample multiple architectures.
|
|
196
|
+
|
|
197
|
+
Args:
|
|
198
|
+
batch_size: Number of architectures to sample
|
|
199
|
+
max_attempts: Max attempts per architecture
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
List of sampled architectures
|
|
203
|
+
|
|
204
|
+
Example:
|
|
205
|
+
>>> architectures = space.sample_batch(10)
|
|
206
|
+
"""
|
|
207
|
+
return [self.sample(max_attempts) for _ in range(batch_size)]
|
|
208
|
+
|
|
209
|
+
def _check_constraints(self, graph: ModelGraph) -> bool:
|
|
210
|
+
"""
|
|
211
|
+
Check if graph satisfies all constraints.
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
graph: Graph to validate
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
True if all constraints satisfied
|
|
218
|
+
"""
|
|
219
|
+
for constraint_fn in self.constraints:
|
|
220
|
+
try:
|
|
221
|
+
if not constraint_fn(graph):
|
|
222
|
+
return False
|
|
223
|
+
except Exception as e:
|
|
224
|
+
logger.warning(f"Constraint check failed: {e}")
|
|
225
|
+
return False
|
|
226
|
+
|
|
227
|
+
return True
|
|
228
|
+
|
|
229
|
+
def get_complexity(self) -> Dict[str, Any]:
|
|
230
|
+
"""
|
|
231
|
+
Estimate search space complexity.
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
Dictionary with complexity metrics
|
|
235
|
+
"""
|
|
236
|
+
total_combinations = 1
|
|
237
|
+
param_counts: Dict[str, int] = {}
|
|
238
|
+
|
|
239
|
+
for layer_spec in self.layers:
|
|
240
|
+
layer_combinations = 1
|
|
241
|
+
for param_name, values in layer_spec.param_ranges.items():
|
|
242
|
+
if isinstance(values, list):
|
|
243
|
+
layer_combinations *= len(values)
|
|
244
|
+
param_counts[param_name] = param_counts.get(param_name, 0) + len(values)
|
|
245
|
+
|
|
246
|
+
total_combinations *= layer_combinations
|
|
247
|
+
|
|
248
|
+
return {
|
|
249
|
+
"total_combinations": total_combinations,
|
|
250
|
+
"num_layers": len(self.layers),
|
|
251
|
+
"param_counts": param_counts,
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
255
|
+
"""Serialize search space to dictionary."""
|
|
256
|
+
return {
|
|
257
|
+
"name": self.name,
|
|
258
|
+
"layers": [layer.to_dict() for layer in self.layers],
|
|
259
|
+
"metadata": self.metadata,
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
@classmethod
|
|
263
|
+
def from_dict(cls, data: Dict[str, Any]) -> "SearchSpace":
|
|
264
|
+
"""
|
|
265
|
+
Deserialize search space from dictionary.
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
data: Dictionary representation
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
SearchSpace instance
|
|
272
|
+
"""
|
|
273
|
+
space = cls(name=data["name"], metadata=data.get("metadata", {}))
|
|
274
|
+
|
|
275
|
+
for layer_data in data["layers"]:
|
|
276
|
+
layer_spec = LayerSpec.from_dict(layer_data)
|
|
277
|
+
space.add_layer(layer_spec)
|
|
278
|
+
|
|
279
|
+
return space
|
|
280
|
+
|
|
281
|
+
def __repr__(self) -> str:
|
|
282
|
+
"""String representation."""
|
|
283
|
+
complexity = self.get_complexity()
|
|
284
|
+
return (
|
|
285
|
+
f"SearchSpace(name={self.name}, "
|
|
286
|
+
f"layers={len(self.layers)}, "
|
|
287
|
+
f"combinations={complexity['total_combinations']})"
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
def __len__(self) -> int:
|
|
291
|
+
"""Return number of layers."""
|
|
292
|
+
return len(self.layers)
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
# Convenience functions
|
|
296
|
+
def create_cnn_space(
|
|
297
|
+
num_classes: int = 10,
|
|
298
|
+
input_shape: tuple = (3, 32, 32),
|
|
299
|
+
conv_filters: Optional[List[List[int]]] = None,
|
|
300
|
+
dense_units: Optional[List[List[int]]] = None,
|
|
301
|
+
) -> SearchSpace:
|
|
302
|
+
"""
|
|
303
|
+
Create a standard CNN search space.
|
|
304
|
+
|
|
305
|
+
Args:
|
|
306
|
+
num_classes: Number of output classes
|
|
307
|
+
input_shape: Input shape (C, H, W)
|
|
308
|
+
conv_filters: List of filter options for each conv layer
|
|
309
|
+
dense_units: List of unit options for each dense layer
|
|
310
|
+
|
|
311
|
+
Returns:
|
|
312
|
+
Configured SearchSpace
|
|
313
|
+
|
|
314
|
+
Example:
|
|
315
|
+
>>> space = create_cnn_space(
|
|
316
|
+
... num_classes=10,
|
|
317
|
+
... conv_filters=[[32, 64], [64, 128]],
|
|
318
|
+
... dense_units=[[128, 256]]
|
|
319
|
+
... )
|
|
320
|
+
"""
|
|
321
|
+
from morphml.core.dsl.layers import Layer
|
|
322
|
+
|
|
323
|
+
conv_filters = conv_filters or [[32, 64, 128], [64, 128, 256]]
|
|
324
|
+
dense_units = dense_units or [[128, 256, 512]]
|
|
325
|
+
|
|
326
|
+
space = SearchSpace(name="cnn_space")
|
|
327
|
+
|
|
328
|
+
# Input
|
|
329
|
+
space.add_layer(Layer.input(shape=input_shape))
|
|
330
|
+
|
|
331
|
+
# Conv blocks
|
|
332
|
+
for filters in conv_filters:
|
|
333
|
+
space.add_layer(Layer.conv2d(filters=filters, kernel_size=[3, 5]))
|
|
334
|
+
space.add_layer(Layer.relu())
|
|
335
|
+
space.add_layer(Layer.maxpool(pool_size=2))
|
|
336
|
+
|
|
337
|
+
# Dense layers
|
|
338
|
+
for units in dense_units:
|
|
339
|
+
space.add_layer(Layer.dense(units=units))
|
|
340
|
+
space.add_layer(Layer.relu())
|
|
341
|
+
space.add_layer(Layer.dropout(rate=[0.3, 0.5]))
|
|
342
|
+
|
|
343
|
+
# Output
|
|
344
|
+
space.add_layer(Layer.output(units=num_classes))
|
|
345
|
+
|
|
346
|
+
return space
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def create_mlp_space(
|
|
350
|
+
num_classes: int = 10,
|
|
351
|
+
input_shape: tuple = (784,),
|
|
352
|
+
hidden_layers: int = 3,
|
|
353
|
+
units_range: Optional[List[int]] = None,
|
|
354
|
+
) -> SearchSpace:
|
|
355
|
+
"""
|
|
356
|
+
Create a multi-layer perceptron search space.
|
|
357
|
+
|
|
358
|
+
Args:
|
|
359
|
+
num_classes: Number of output classes
|
|
360
|
+
input_shape: Input shape
|
|
361
|
+
hidden_layers: Number of hidden layers
|
|
362
|
+
units_range: Range of units per layer
|
|
363
|
+
|
|
364
|
+
Returns:
|
|
365
|
+
Configured SearchSpace
|
|
366
|
+
"""
|
|
367
|
+
from morphml.core.dsl.layers import Layer
|
|
368
|
+
|
|
369
|
+
if units_range is None:
|
|
370
|
+
units_range = [128, 256, 512]
|
|
371
|
+
|
|
372
|
+
space = SearchSpace(name="mlp_space")
|
|
373
|
+
|
|
374
|
+
# Input
|
|
375
|
+
space.add_layer(Layer.input(shape=input_shape))
|
|
376
|
+
|
|
377
|
+
# Hidden layers
|
|
378
|
+
for _ in range(hidden_layers):
|
|
379
|
+
space.add_layer(Layer.dense(units=units_range))
|
|
380
|
+
space.add_layer(Layer.relu())
|
|
381
|
+
space.add_layer(Layer.dropout(rate=[0.3, 0.5]))
|
|
382
|
+
|
|
383
|
+
# Output
|
|
384
|
+
space.add_layer(Layer.output(units=num_classes))
|
|
385
|
+
|
|
386
|
+
return space
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""Token definitions and grammar for MorphML DSL.
|
|
2
|
+
|
|
3
|
+
This module defines all tokens, keywords, and grammar rules for the
|
|
4
|
+
text-based DSL that allows users to define search spaces using a
|
|
5
|
+
declarative syntax.
|
|
6
|
+
|
|
7
|
+
Grammar (EBNF):
|
|
8
|
+
experiment := search_space_def evolution_def
|
|
9
|
+
search_space_def := "SearchSpace" "(" param_list ")"
|
|
10
|
+
layer_def := "Layer" "." layer_type "(" param_list ")"
|
|
11
|
+
param_list := param ("," param)*
|
|
12
|
+
param := IDENTIFIER "=" value_list
|
|
13
|
+
value_list := "[" value ("," value)* "]" | value
|
|
14
|
+
value := NUMBER | STRING | BOOLEAN | IDENTIFIER
|
|
15
|
+
|
|
16
|
+
Author: Eshan Roy <eshanized@proton.me>
|
|
17
|
+
Organization: TONMOY INFRASTRUCTURE & VISION
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from enum import Enum, auto
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class TokenType(Enum):
|
|
24
|
+
"""All token types in the MorphML DSL."""
|
|
25
|
+
|
|
26
|
+
# Literals
|
|
27
|
+
NUMBER = auto()
|
|
28
|
+
STRING = auto()
|
|
29
|
+
BOOLEAN = auto()
|
|
30
|
+
|
|
31
|
+
# Identifiers and keywords
|
|
32
|
+
IDENTIFIER = auto()
|
|
33
|
+
SEARCHSPACE = auto()
|
|
34
|
+
LAYER = auto()
|
|
35
|
+
EVOLUTION = auto()
|
|
36
|
+
EXPERIMENT = auto()
|
|
37
|
+
CONSTRAINT = auto()
|
|
38
|
+
|
|
39
|
+
# Operators and delimiters
|
|
40
|
+
ASSIGN = auto()
|
|
41
|
+
COMMA = auto()
|
|
42
|
+
DOT = auto()
|
|
43
|
+
COLON = auto()
|
|
44
|
+
LPAREN = auto()
|
|
45
|
+
RPAREN = auto()
|
|
46
|
+
LBRACKET = auto()
|
|
47
|
+
RBRACKET = auto()
|
|
48
|
+
LBRACE = auto()
|
|
49
|
+
RBRACE = auto()
|
|
50
|
+
|
|
51
|
+
# Special
|
|
52
|
+
EOF = auto()
|
|
53
|
+
NEWLINE = auto()
|
|
54
|
+
COMMENT = auto()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# Keywords that are recognized as special tokens
|
|
58
|
+
KEYWORDS = {
|
|
59
|
+
"SearchSpace": TokenType.SEARCHSPACE,
|
|
60
|
+
"Layer": TokenType.LAYER,
|
|
61
|
+
"Evolution": TokenType.EVOLUTION,
|
|
62
|
+
"Experiment": TokenType.EXPERIMENT,
|
|
63
|
+
"Constraint": TokenType.CONSTRAINT,
|
|
64
|
+
"True": TokenType.BOOLEAN,
|
|
65
|
+
"False": TokenType.BOOLEAN,
|
|
66
|
+
"true": TokenType.BOOLEAN,
|
|
67
|
+
"false": TokenType.BOOLEAN,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# Supported layer types in the DSL
|
|
71
|
+
LAYER_TYPES = [
|
|
72
|
+
"conv2d",
|
|
73
|
+
"conv3d",
|
|
74
|
+
"dense",
|
|
75
|
+
"linear",
|
|
76
|
+
"batch_norm",
|
|
77
|
+
"layer_norm",
|
|
78
|
+
"dropout",
|
|
79
|
+
"max_pool",
|
|
80
|
+
"avg_pool",
|
|
81
|
+
"global_avg_pool",
|
|
82
|
+
"activation",
|
|
83
|
+
"flatten",
|
|
84
|
+
"relu",
|
|
85
|
+
"elu",
|
|
86
|
+
"gelu",
|
|
87
|
+
"tanh",
|
|
88
|
+
"sigmoid",
|
|
89
|
+
"leaky_relu",
|
|
90
|
+
"softmax",
|
|
91
|
+
"input",
|
|
92
|
+
"output",
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
# Optimizer types
|
|
96
|
+
OPTIMIZER_TYPES = [
|
|
97
|
+
"adam",
|
|
98
|
+
"sgd",
|
|
99
|
+
"rmsprop",
|
|
100
|
+
"adamw",
|
|
101
|
+
"adagrad",
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
# Activation functions
|
|
105
|
+
ACTIVATION_TYPES = [
|
|
106
|
+
"relu",
|
|
107
|
+
"elu",
|
|
108
|
+
"gelu",
|
|
109
|
+
"tanh",
|
|
110
|
+
"sigmoid",
|
|
111
|
+
"leaky_relu",
|
|
112
|
+
"softmax",
|
|
113
|
+
"selu",
|
|
114
|
+
"swish",
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
# Evolution strategies
|
|
118
|
+
EVOLUTION_STRATEGIES = [
|
|
119
|
+
"genetic",
|
|
120
|
+
"random_search",
|
|
121
|
+
"hill_climbing",
|
|
122
|
+
"differential_evolution",
|
|
123
|
+
"cma_es",
|
|
124
|
+
"bayesian",
|
|
125
|
+
"nsga2",
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
# Operator symbols
|
|
129
|
+
OPERATORS = {
|
|
130
|
+
"=": TokenType.ASSIGN,
|
|
131
|
+
",": TokenType.COMMA,
|
|
132
|
+
".": TokenType.DOT,
|
|
133
|
+
":": TokenType.COLON,
|
|
134
|
+
"(": TokenType.LPAREN,
|
|
135
|
+
")": TokenType.RPAREN,
|
|
136
|
+
"[": TokenType.LBRACKET,
|
|
137
|
+
"]": TokenType.RBRACKET,
|
|
138
|
+
"{": TokenType.LBRACE,
|
|
139
|
+
"}": TokenType.RBRACE,
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def is_layer_type(name: str) -> bool:
|
|
144
|
+
"""Check if name is a valid layer type."""
|
|
145
|
+
return name in LAYER_TYPES
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def is_optimizer_type(name: str) -> bool:
|
|
149
|
+
"""Check if name is a valid optimizer type."""
|
|
150
|
+
return name in OPTIMIZER_TYPES
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def is_activation_type(name: str) -> bool:
|
|
154
|
+
"""Check if name is a valid activation function."""
|
|
155
|
+
return name in ACTIVATION_TYPES
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def is_evolution_strategy(name: str) -> bool:
|
|
159
|
+
"""Check if name is a valid evolution strategy."""
|
|
160
|
+
return name in EVOLUTION_STRATEGIES
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
# Grammar documentation
|
|
164
|
+
GRAMMAR_DOCS = """
|
|
165
|
+
MorphML DSL Grammar (Extended Backus-Naur Form)
|
|
166
|
+
|
|
167
|
+
experiment := search_space_def [evolution_def] [constraint_list]
|
|
168
|
+
search_space_def := "SearchSpace" "(" [space_params] ")"
|
|
169
|
+
space_params := "layers" "=" layer_list ["," param_list]
|
|
170
|
+
layer_list := "[" layer_def ("," layer_def)* "]"
|
|
171
|
+
layer_def := "Layer" "." layer_type "(" [param_list] ")"
|
|
172
|
+
evolution_def := "Evolution" "(" param_list ")"
|
|
173
|
+
constraint_list := "Constraint" "(" constraint_expr ("," constraint_expr)* ")"
|
|
174
|
+
|
|
175
|
+
param_list := param ("," param)*
|
|
176
|
+
param := IDENTIFIER "=" value_expr
|
|
177
|
+
value_expr := value | value_list
|
|
178
|
+
value_list := "[" value ("," value)* "]"
|
|
179
|
+
value := NUMBER | STRING | BOOLEAN | IDENTIFIER
|
|
180
|
+
|
|
181
|
+
layer_type := IDENTIFIER # Must be in LAYER_TYPES
|
|
182
|
+
constraint_expr := STRING | function_call
|
|
183
|
+
|
|
184
|
+
Examples:
|
|
185
|
+
SearchSpace(
|
|
186
|
+
layers=[
|
|
187
|
+
Layer.conv2d(filters=[32, 64, 128], kernel_size=3),
|
|
188
|
+
Layer.relu(),
|
|
189
|
+
Layer.maxpool(pool_size=2),
|
|
190
|
+
Layer.dense(units=[128, 256])
|
|
191
|
+
]
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
Evolution(
|
|
195
|
+
strategy="genetic",
|
|
196
|
+
population_size=50,
|
|
197
|
+
num_generations=100
|
|
198
|
+
)
|
|
199
|
+
"""
|