From b8854e43d96cdbacd4177a92028ab54ff3e2bbcd Mon Sep 17 00:00:00 2001 From: AHMETHAKANBEZIR1 Date: Fri, 23 Oct 2026 05:05:17 +0300 Subject: [PATCH] fix: forward mean-field learning rule options by name Co-authored-by: OpenAI Codex --- CHANGELOG.md | 2 + bindsnet/network/topology.py | 2 +- test/network/test_meanfield_update_options.py | 44 +++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 test/network/test_meanfield_update_options.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 5179fe8c..e0710276 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ see the [GitHub releases / tags](https://github.com/BindsNET/bindsnet/releases). ## [Unreleased] ### Fixed +- Forward mean-field `weight_decay` to the learning rule instead of treating it as + the update reduction; explicit `reduction` arguments are now accepted as well. - `--seed` now makes GPU runs repeatable in `eth_mnist.py`, `batch_eth_mnist.py`, `supervised_mnist.py`, `conv_mnist.py`, `conv1d_MNIST.py`, `conv3d_MNIST.py`, `SOM_LM-SNNs.py` and `breakout/random_network_baseline.py`: they call diff --git a/bindsnet/network/topology.py b/bindsnet/network/topology.py index aa43c5cc..2ffb15aa 100644 --- a/bindsnet/network/topology.py +++ b/bindsnet/network/topology.py @@ -2089,7 +2089,7 @@ def __init__( tensor of same size as w :param float norm: Total weight per target neuron normalization constant. """ - super().__init__(source, target, nu, weight_decay, **kwargs) + super().__init__(source, target, nu=nu, weight_decay=weight_decay, **kwargs) w = kwargs.get("w", None) if w is None: diff --git a/test/network/test_meanfield_update_options.py b/test/network/test_meanfield_update_options.py new file mode 100644 index 00000000..7a0dfdbf --- /dev/null +++ b/test/network/test_meanfield_update_options.py @@ -0,0 +1,44 @@ +import pytest +import torch + +from bindsnet.network import Network +from bindsnet.network.nodes import Input, LIFNodes +from bindsnet.network.topology import MeanFieldConnection + + +@pytest.mark.parametrize("weight_decay", [0.0, 0.1, 1.0]) +@pytest.mark.parametrize("shared", [False, True]) +def test_meanfield_weight_decay_during_network_run(weight_decay, shared): + network = Network() + source, target = Input(n=2), LIFNodes(n=3) + network.add_layer(source, "X") + network.add_layer(target, "Y") + initial = torch.tensor(0.5) if shared else torch.tensor([0.25, 0.5, 0.75]) + connection = MeanFieldConnection( + source, target, w=initial.clone(), weight_decay=weight_decay + ) + network.add_connection(connection, "X", "Y") + parameter = connection.w + # No STDP rule or normalization: the common learning-rule decay acts alone. + for step in range(1, 4): + network.run({"X": torch.zeros(1, 1, 2)}, time=1) + expected = initial * (1 - weight_decay) ** step + torch.testing.assert_close(connection.w, expected) + assert connection.w is parameter + + +@pytest.mark.parametrize( + "reduction,expected", + [(torch.sum, [5.0, 7.0, 9.0]), (torch.mean, [2.5, 3.5, 4.5])], +) +def test_meanfield_accepts_update_reduction(reduction, expected): + connection = MeanFieldConnection( + Input(n=2), + LIFNodes(n=3), + w=torch.tensor(0.5), + weight_decay=0.1, + reduction=reduction, + ) + updates = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) + actual = connection.update_rule.reduction(updates, dim=0) + torch.testing.assert_close(actual, torch.tensor(expected))