Hardware-Aware SNN NAS¶
NSGA-II evolutionary search over SNN architectures under FPGA resource budgets.
Searches {neuron model, layer width, bitstream length, delay range} jointly — the first NAS that optimizes hardware parameters alongside topology.
The public surface exposes derived architecture helpers for layer count, compiler-facing layer dimensions, and dense connection counts. Search and equivalence result objects also provide compact textual summaries for logs, reports, and CI artifacts.
Search Space¶
sc_neurocore.nas.search_space
¶
Define the architecture search space for hardware-aware SNN NAS.
Search dimensions
- n_layers: number of hidden layers
- widths: neurons per layer
- neuron_type: per-layer neuron model
- bitstream_length: per-layer SC precision (L)
- delay_range: maximum synaptic delay per layer
Each architecture encodes one point in this joint space. FPGA constraints (LUT, BRAM budgets) prune infeasible points.
Architecture
dataclass
¶
One point in the NAS search space.
Source code in src/sc_neurocore/nas/search_space.py
| Python | |
|---|---|
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | |
SearchSpace
dataclass
¶
Configurable NAS search space.
Parameters¶
n_inputs : int Input dimension. n_outputs : int Output dimension (width of final layer). min_layers, max_layers : int Range of hidden layer count. width_choices : list of int Candidate widths per layer. neuron_choices : list of str Candidate neuron models. L_choices : list of int Candidate bitstream lengths. delay_choices : list of int Candidate max-delay values.
Source code in src/sc_neurocore/nas/search_space.py
| Python | |
|---|---|
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | |
space_size
property
¶
Approximate total architectures in the search space.
random_architecture(rng)
¶
Sample a random architecture from the space.
Source code in src/sc_neurocore/nas/search_space.py
| Python | |
|---|---|
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | |
mutate(arch, rng)
¶
Mutate one random gene in the architecture.
Source code in src/sc_neurocore/nas/search_space.py
| Python | |
|---|---|
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | |
crossover(a, b, rng)
¶
Uniform crossover between two architectures of equal layer count.
Source code in src/sc_neurocore/nas/search_space.py
| Python | |
|---|---|
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | |
Search Engine¶
sc_neurocore.nas.search
¶
NSGA-II evolutionary search over SNN architectures under FPGA constraints.
Searches {neuron model, layer width, bitstream length, delay range} jointly, evaluating each candidate for accuracy (simulated) and hardware cost (via the energy estimator). Returns a Pareto front of non-dominated architectures.
No equivalent exists: SpikeNAS searches only software architectures. This is the first NAS that searches hardware parameters (L, delays, LUTs) alongside network topology.
NASResult
dataclass
¶
Result of a NAS run.
Source code in src/sc_neurocore/nas/search.py
| Python | |
|---|---|
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | |
best_accuracy()
¶
Architecture with highest accuracy on the Pareto front.
Source code in src/sc_neurocore/nas/search.py
| Python | |
|---|---|
43 44 45 46 47 | |
best_efficiency()
¶
Architecture with lowest energy on the Pareto front.
Source code in src/sc_neurocore/nas/search.py
| Python | |
|---|---|
49 50 51 52 53 | |
summary()
¶
Return a line-oriented summary of the Pareto front.
Source code in src/sc_neurocore/nas/search.py
| Python | |
|---|---|
55 56 57 58 59 60 61 62 63 64 65 66 67 | |
nas(space, target='ice40', population_size=50, generations=20, max_luts=None, accuracy_fn=None, seed=42)
¶
Run hardware-aware NAS using NSGA-II.
Parameters¶
space : SearchSpace Architecture search space definition. target : str FPGA target for hardware cost evaluation. population_size : int Number of architectures per generation. generations : int Number of evolutionary generations. max_luts : int, optional Hard LUT budget. Architectures exceeding this are penalized. If None, uses the target's total LUT count. accuracy_fn : callable, optional Function(Architecture) -> float accuracy in [0, 1]. If None, uses a proxy based on network capacity. seed : int Random seed.
Returns¶
NASResult Pareto front + all evaluated architectures.
Source code in src/sc_neurocore/nas/search.py
| Python | |
|---|---|
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | |
Hardware-Aware SC-NAS Engine¶
sc_neurocore.nas.sc_nas_engine provides the evolutionary SC-NAS surface used
for bitstream-length, decorrelator, neuron-family, and FPGA-resource search.
It evaluates candidate resource estimates, extracts a Pareto front, emits
SystemVerilog parameter shells for selected candidates, and can route
tournament selection through the optional Rust extension when that extension is
available at import time.
sc_neurocore.nas.sc_nas_engine
¶
Evolutionary neural architecture search for SC bitstream hardware.
Jointly optimises topology, neuron types, per-layer bitstream lengths,
and decorrelation strategies against an FPGA resource budget. Produces
Pareto-optimal SC networks with auto-generated SystemVerilog via the
model zoo VerilogGenerator.
No external dependencies beyond NumPy — the evaluator uses pure-Python
SC simulation (bitstream variance model), so torch is NOT required.
DecorrelationStrategy
¶
Bases: Enum
Supported bitstream decorrelation generators for SC-NAS candidates.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
40 41 42 43 44 45 46 | |
NeuronType
¶
Bases: Enum
Neuron model families available to the hardware-aware NAS search.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
49 50 51 52 53 54 55 | |
FPGAResourceBudget
dataclass
¶
Hardware resource constraints for the target FPGA.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | |
utilisation(luts, ffs, bram, dsp)
¶
Return per-resource utilisation ratios for a candidate design.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
83 84 85 86 87 88 89 90 | |
NASObjective
dataclass
¶
Search objectives and constraints.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
93 94 95 96 97 98 99 100 101 102 103 | |
LayerConfig
dataclass
¶
Configuration for a single network layer.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | |
lut_cost
property
¶
Return estimated LUT cost for this layer.
ff_cost
property
¶
Return estimated flip-flop cost for this layer.
dsp_cost
property
¶
Return estimated DSP block cost for this layer.
bram_cost_kb
property
¶
Return estimated BRAM storage cost in kibibytes.
power_cost
property
¶
Return estimated dynamic power cost in milliwatts.
SCCandidate
dataclass
¶
A candidate SC network architecture.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | |
fingerprint
property
¶
Return a deterministic non-cryptographic architecture fingerprint.
evaluate_resources()
¶
Update aggregate resource estimates from the candidate layers.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
162 163 164 165 166 167 168 | |
meets_budget(budget)
¶
Return whether this candidate fits within an FPGA resource budget.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
170 171 172 173 174 175 176 177 178 179 | |
SCFitnessEvaluator
¶
Pure-Python SC simulation fitness evaluator.
Uses the SC variance model: for a bitstream of length N encoding probability p, the variance is p*(1-p)/N. Accuracy is estimated as 1 − mean_variance across all layers.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | |
evaluate(candidate, target_p=0.5)
¶
Evaluate candidate accuracy via SC variance model.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | |
EvolutionaryNAS
¶
µ+λ evolutionary search with tournament selection.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 | |
search()
¶
Run the evolutionary search. Returns the final Pareto front.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 | |
NASReport
dataclass
¶
Summary report from an SC-NAS search.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 | |
best_accuracy
property
¶
Return the best accuracy in the Pareto front, or zero when empty.
most_efficient
property
¶
Return the lowest-LUT candidate in the Pareto front, if present.
summary()
¶
Return a deterministic human-readable search summary.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
482 483 484 485 486 487 488 489 490 491 492 493 | |
NASVerilogEmitter
¶
Emits SystemVerilog for Pareto-optimal SC-NAS candidates.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 | |
emit(candidate, module_name='sc_nas_network')
staticmethod
¶
Generate SystemVerilog for a searched architecture.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 | |
emit_pareto(front)
staticmethod
¶
Emit Verilog for all Pareto-optimal candidates.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
600 601 602 603 604 605 606 607 | |
pareto_front(candidates, objectives=('accuracy', 'total_luts'))
¶
Extract the Pareto-optimal front (NSGA-II non-dominated sorting).
Maximises accuracy, minimises resource usage.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | |
run_nas(objective=None, budget=None, population_size=50, num_generations=100, seed=42, convergence_patience=0, surrogate_optimizer=None)
¶
Run an SC-NAS search and return its report.
Source code in src/sc_neurocore/nas/sc_nas_engine.py
| Python | |
|---|---|
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 | |
Differentiable SC-NAS¶
sc_neurocore.nas.darts_sc_nas provides the DARTS relaxation used to train
bitstream-length choices through Gumbel-Softmax architecture weights. Its public
surface documents candidate variance injection, mixed-operation resource costs,
optimal bitstream extraction, and network-level hardware penalties.
sc_neurocore.nas.darts_sc_nas
¶
DARTS-based differentiable NAS for SC bitstream optimization.
BitstreamCandidate
¶
Bases: Module
SC bitstream candidate that injects variance for one stream length.
Source code in src/sc_neurocore/nas/darts_sc_nas.py
| Python | |
|---|---|
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | |
forward(x)
¶
Return the candidate output with training-time SC variance noise.
Source code in src/sc_neurocore/nas/darts_sc_nas.py
| Python | |
|---|---|
29 30 31 32 33 34 35 36 37 38 39 40 | |
SCMixedOp
¶
Bases: Module
Continuous relaxation over discrete SC bitstream configurations.
Source code in src/sc_neurocore/nas/darts_sc_nas.py
| Python | |
|---|---|
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | |
forward(x)
¶
Return the mixed convolution output under DARTS bitstream weights.
Source code in src/sc_neurocore/nas/darts_sc_nas.py
| Python | |
|---|---|
67 68 69 70 71 72 73 74 75 | |
expected_resource_cost()
¶
Return expected LUT and power costs from architecture weights.
Source code in src/sc_neurocore/nas/darts_sc_nas.py
| Python | |
|---|---|
77 78 79 80 81 82 83 | |
extract_optimal_config()
¶
Return the bitstream length with the largest architecture logit.
Source code in src/sc_neurocore/nas/darts_sc_nas.py
| Python | |
|---|---|
85 86 87 88 | |
SCNASNetwork
¶
Bases: Module
Small differentiable hardware-aware search network for SC-NAS.
Source code in src/sc_neurocore/nas/darts_sc_nas.py
| Python | |
|---|---|
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | |
forward(x)
¶
Return class logits from the differentiable SC-NAS network.
Source code in src/sc_neurocore/nas/darts_sc_nas.py
| Python | |
|---|---|
102 103 104 105 106 107 108 109 110 | |
hardware_penalty()
¶
Return expected LUT and power penalties across search layers.
Source code in src/sc_neurocore/nas/darts_sc_nas.py
| Python | |
|---|---|
112 113 114 115 116 117 | |
Formal Equivalence¶
sc_neurocore.nas.equiv
¶
Generate and run formal equivalence proofs between Python and Verilog models.
Uses SymbiYosys (sby) for bounded model checking. The miter circuit drives both the DUT and a reference Verilog model with symbolic inputs. If outputs match for ALL input sequences up to depth N, equivalence is proved.
Pre-built proofs live in hdl/equiv/. This module generates new proofs for arbitrary neuron configurations and optionally runs them.
EquivResult
dataclass
¶
Result of a formal equivalence check.
Source code in src/sc_neurocore/nas/equiv.py
| Python | |
|---|---|
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | |
summary()
¶
Return a one-line verdict for the equivalence proof result.
Source code in src/sc_neurocore/nas/equiv.py
| Python | |
|---|---|
39 40 41 42 43 44 | |
check_equivalence(dut_verilog='sc_lif_neuron', ref_verilog='sc_lif_reference', depth=30, run=False)
¶
Check formal equivalence between DUT and reference.
Parameters¶
dut_verilog : str DUT module name (must exist in hdl/). ref_verilog : str Reference module name (must exist in hdl/equiv/). depth : int BMC depth (number of clock cycles to check). run : bool If True, actually run SymbiYosys. Requires sby + z3 installed. If False, generate proof files and return without running.
Returns¶
EquivResult
Source code in src/sc_neurocore/nas/equiv.py
| Python | |
|---|---|
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | |
generate_miter(dut_module, ref_module, top_name, data_width=16, fraction=8)
¶
Generate a Verilog miter circuit for two modules.
Both modules must have identical port signatures: clk, rst_n, leak_k, gain_k, I_t, noise_in -> spike_out, v_out
Source code in src/sc_neurocore/nas/equiv.py
| Python | |
|---|---|
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | |
generate_sby(top_name, verilog_files, depth=30, engine='smtbmc z3')
¶
Generate a SymbiYosys .sby proof script.
Source code in src/sc_neurocore/nas/equiv.py
| Python | |
|---|---|
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | |