Skip to content

Basic SNN functionality in hls4ml (mapped from snntorch)#1470

Open
bmdillon wants to merge 32 commits into
fastmachinelearning:mainfrom
bmdillon:hls4ml-pr
Open

Basic SNN functionality in hls4ml (mapped from snntorch)#1470
bmdillon wants to merge 32 commits into
fastmachinelearning:mainfrom
bmdillon:hls4ml-pr

Conversation

@bmdillon
Copy link
Copy Markdown

@bmdillon bmdillon commented May 5, 2026

Description

This PR adds initial PyTorch/SNN support to hls4ml.

It includes conversion support for IF/LIF neuron layers, SNN readout handling, Vivado templates, documentation, tests, and a small example notebook.

Dependencies:

  • snntorch
  • torch

Type of change

  • New feature (non-breaking change which adds functionality)
  • Documentation update

Tests

Added pytest coverage for PyTorch SNN parsing, IF/LIF layer handling, scalar/vector beta and threshold values, SNN readout options, and custom PyTorch SNN extension parsing.

@vloncar vloncar self-assigned this May 6, 2026
@bmdillon
Copy link
Copy Markdown
Author

bmdillon commented May 8, 2026

pre-commit.ci autofix

Copy link
Copy Markdown
Contributor

@vloncar vloncar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good, needs minor changes to keep it in line with the rest of the codebase

Comment thread docs/advanced/snn.rst
Comment thread docs/advanced/snn.rst
Comment thread docs/advanced/snn.rst Outdated
Comment thread hls4ml/converters/pytorch/snn.py
Comment thread hls4ml/converters/pytorch/snn.py Outdated
return;
}

if (CONFIG_T::decision_rule == snn_decision_rule::binary_logit) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could the decision_rule be implemented as a function pointer? That way you avoid the excessive if statements (and the valid combination has already been checked in the earlier stages of conversion)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain a bit more, where should the functions be? For now I’ve refactored the code in nnet_snnreadout.h to include helper functions, if we need more I can edit further

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking if there's a way to have something like CONFIG_T::decision_rule() that would be a function pointer to the helper functions that you would set in the config templates. We used a similar approach for matrix-vector multiplication functions in the past. It's not essential for this PR though, it's purely cosmetics

Comment thread hls4ml/templates/vivado/build_prj.tcl Outdated
Comment thread hls4ml/contrib/snntorch.py
Comment thread test/pytest/test_extensions_pytorch_snn.py Outdated
Comment thread hls4ml-snn-example.ipynb Outdated
@bmdillon bmdillon requested a review from vloncar May 17, 2026 17:33
@bmdillon
Copy link
Copy Markdown
Author

pre-commit.ci autofix

@JanFSchulte JanFSchulte added please test Trigger testing by creating local PR branch feature New hls4ml feature labels May 18, 2026
@JanFSchulte
Copy link
Copy Markdown
Contributor

The PR tests show several failures for this new feature. Can you have a look and make sure things work correctly?

image

@bmdillon
Copy link
Copy Markdown
Author

bmdillon commented May 19, 2026

The PR tests show several failures for this new feature. Can you have a look and make sure things work correctly?

image

These should be fixed now, all run locally. Just a note, I updated utils/config.py, it was setting some layer attributes to default values if they weren't TypeAttribute or RF. If this is the intended behaviour, I can find an alternative fix.

@JanFSchulte JanFSchulte added please test Trigger testing by creating local PR branch and removed please test Trigger testing by creating local PR branch labels May 19, 2026
@vloncar vloncar added please test Trigger testing by creating local PR branch and removed please test Trigger testing by creating local PR branch labels May 23, 2026
for node in model.graph.values():
if isinstance(node, (IFNeuron, LIFNeuron)) and node.get_attr('window_size') != window_size:
node.set_attr('window_size', window_size)
changed = True
Copy link
Copy Markdown
Contributor

@vloncar vloncar May 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is needed. It is required when changes are made to the execution graph (nodes added/removed/replaced), or if change in an attribute of one node affects some other. But the latter case should be avoided. I don't think that we need to return True in this pass. Can you check if it works without it?

Comment thread hls4ml/utils/config.py
else:
if attr.default is not None:
if attr.name in layer:
layer_config[attr.config_name] = layer[attr.name]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the idea here is that there may be attributes of the layer that the user configured during model definition, which would then be part of the model when parsed, but that the user can still override during conversion and deployment? Up to this point we considered the semantics of configurable attributes as something purely in hls4ml that controls the behavior of the model in a way that cannot be specified during model definition (in e.g., pytorch, snntorch or kersas), such as the reuse factor or type definitions for non-quantized models. One can argue this breaks the concept of what it means for something to be configurable, but I don't have strong opinions on enforcing it. We kept it hidden (not part of the dict this method produces, but still doable if you really know what you're doing). Thoughts @JanFSchulte @jmitrevs @calad0i @bo3z ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me. Maybe apply the same change to the other frontends also for consistency.

I would argue that the qkeras autoconfig generator is already doing similar things with the quantizers, i.e., quantizer params defined through config and overridable by the user, though not the same Attribute knobs, I would argue they are similar.

If the user overrides anything inside the default config, they shall know what they are doing. Also, adding the
"default" config here don't change the actual downstream behavior (if this doesn't exist, one can still insert it manually), so also no new footgun.

@vloncar
Copy link
Copy Markdown
Contributor

vloncar commented May 23, 2026

To me this looks ready, assuming tests pass. Let's see if other main devs have issue with the slight change in semantics of configurable attributes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New hls4ml feature please test Trigger testing by creating local PR branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants