OSCR

Spike-based alignment learning solves the weight transport problem.

Code ↔ Paper

10 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 10 matches
  1. [1] § Methods › Symmetrization in deep neural networks › SymmNet experiments ↔ scripts/symm_net/main_salnet.py, lines 161–216 · score 0.82 · cross entropy, RDDNet, SALNet, ConvNet, weight decay, FA
  2. [2] § Methods › Symmetrization in deep neural networks › SymmNet experiments ↔ symmnet/src/symmnet/conv_net.py, lines 27–149 · score 0.79 · ReLU, convolutional blocks, convolutional layer, ConvNet, FC, batch
  3. [3] § Results › Deep neural networks › Symmetrization in deep networks ↔ symmnet/src/symmnet/conv_net.py, lines 27–149 · score 0.75 · convolutional neural network, FC layers, convolutional layers, ConvNet, fully connected, alignment
  4. [4] § Methods › Neuron model ↔ spiking_sampling_network/src/neuralsampling/network.py, lines 51–80 · score 0.69 · instantaneous firing rate, refractory period, PSP kernel, matched, syn, neuron
  5. [5] § Methods › Symmetrization in deep neural networks › SymmNet experiments ↔ scripts/symm_net/main_salnet.py, lines 161–216 · score 0.62 · RDDNet, SALNet, ConvNet, layers, weights
  6. [6] § Methods › Boltzmann machines and sampling with spikes ↔ spiking_sampling_network/src/neuralsampling/network.py, lines 216–233 · score 0.54 · gradient descent, sleep phase, optimized, training, network, spikes
  7. [7] § Methods › Symmetrization in deep neural networks › SymmNet experiments ↔ symmnet/src/symmnet/rdd_net.py, lines 11–71 · score 0.53 · RDDNet, spiking network, external, SymmNet, layers, weights
  8. [8] § Methods › Spiking cortical microcircuits › Mathematical description of the model ↔ spiking_microcircuits/src/microcircuits/model.py, lines 357–378 · score 0.51 · membrane potential, basal, apical, compartments, pyramidal, voltages
  9. [9] § Results › Symmetrization in spiking sampling networks ↔ spiking_sampling_network/src/neuralsampling/network.py, lines 216–233 · score 0.51 · gradient descent, sleep phase, weight update, symmetric, network, trained
  10. [10] § Results › Symmetrization in spiking sampling networks ↔ spiking_sampling_network/src/neuralsampling/network.py, lines 133–213 · score 0.50 · binary state, weight matrix, vector, biases, PSPs, network

Paper

Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

Python · 446 lines · 14 KB · MIT · 4 matches

  1. """Neural sampling implementation (Buesing et al. 2011)."""
  2. import time
  3. from datetime import datetime
  4. from typing import Any, Callable, TypeAlias
  5. import numba
  6. import numpy as np
  7. import numpy.typing as npt
  8. from .utils import (
  9. bm_to_probs,
  10. distr_from_states,
  11. get_states_from_spikes,
  12. list_of_states,
  13. ordered_spikes_to_list,
  14. )
  15. # declare my own types here:
  16. StdpFunc: TypeAlias = Callable[[npt.ArrayLike], npt.ArrayLike]
  17. SimParams: TypeAlias = dict[str, Any]
  18. @numba.njit(cache=False)
  19. def logistic(x: float, t_ref: float) -> float:
  20. """Logistic activation function shifted by log(t_ref)."""
  21. return 1.0 / (1.0 + np.exp(-(x - np.log(t_ref))))
  22. @numba.vectorize(cache=False)
  23. def heaviside(x: float) -> float:
  24. """Heaviside step function: 1 if x > 0, else 0."""
  25. if x > 0.0:
  26. return 1.0
  27. else:
  28. return 0.0
  29. @numba.njit(cache=False)
  30. def rect_kernel(x: float, tau_syn: float) -> float:
  31. """Rectangular PSP kernel: 1 within (0, tau_syn], else 0."""
  32. return heaviside(x) * heaviside(-x + tau_syn)
  33. @numba.njit(cache=False)
  34. def alpha_kernel(x: float, tau_ref: float, tau_syn: float) -> float:
  35. """Alpha-function PSP kernel."""
  36. return heaviside(tau_ref / tau_syn**2 * x * np.exp(-x / tau_syn))
  37. @numba.njit(cache=False)
  38. def calc_inst_rate(
  39. t: int,
  40. last_spikes: npt.NDArray,
  41. bias: npt.NDArray,
  42. weight_mat: npt.NDArray,
  43. t_ref: float,
  44. tau_syn: float,
  45. psp_kernel: Callable,
  46. ) -> npt.NDArray:
  47. """Compute instantaneous firing rates for all neurons at time t.
  48. Args:
  49. t: Current time step.
  50. last_spikes: (N, K) array of the K most recent spike times per neuron.
  51. bias: Neuron bias vector.
  52. weight_mat: Synaptic weight matrix.
  53. t_ref: Refractory period.
  54. tau_syn: Synaptic time constant.
  55. psp_kernel: PSP kernel function.
  56. Returns:
  57. Array of instantaneous firing rates, one per neuron.
  58. """
  59. psps = np.sum(psp_kernel(t - last_spikes, tau_syn), axis=1)
  60. mem_pot = bias + np.dot(weight_mat, psps)
  61. inst_rate = logistic(mem_pot, t_ref)
  62. # to match with buesing: substract log(t_ref) from mem_pot
  63. # (mind the unit of t_ref!)
  64. return inst_rate
  65. @numba.njit(cache=False)
  66. def sim_poisson_neurons(
  67. t_max: int,
  68. psp_kernel: Callable,
  69. bias: npt.NDArray,
  70. weights: npt.NDArray,
  71. t_ref: float,
  72. tau_syn: float,
  73. num_last_spikes: int = 10,
  74. ) -> npt.NDArray:
  75. """Simulate Poisson spiking neurons with PSP-based interactions.
  76. Args:
  77. t_max: Simulation duration in time steps.
  78. psp_kernel: PSP kernel function.
  79. bias: Neuron bias vector.
  80. weights: Synaptic weight matrix.
  81. t_ref: Refractory period.
  82. tau_syn: Synaptic time constant.
  83. num_last_spikes: Number of past spikes tracked per neuron.
  84. Returns:
  85. Ordered spike array of (time, neuron_id) tuples.
  86. """
  87. num_neurons = len(bias)
  88. ordered_spikes = []
  89. # how many past spikes do we take into account for the calculation of the
  90. # PSPs
  91. last_spikes = np.full((num_neurons, num_last_spikes), -100_000_000)
  92. for t in range(t_max):
  93. inst_rate = calc_inst_rate(
  94. t, last_spikes, bias, weights, t_ref, tau_syn, psp_kernel
  95. )
  96. # probability to spike in [t, t+dt]
  97. random_vals = np.random.random_sample(num_neurons)
  98. # check if the prob is smaller than the random value
  99. for i in np.nonzero(random_vals < inst_rate)[0]:
  100. # refractory machanism:
  101. if last_spikes[i, -1] < t - t_ref:
  102. # use nest/ssn convention
  103. ordered_spikes.append((t, i + 1.0))
  104. # push back the last_spikes-stack
  105. last_spikes[i, :-1] = last_spikes[i, 1:]
  106. last_spikes[i, -1] = t
  107. return np.array(ordered_spikes)
  108. class NeuralSampler:
  109. """Base neural sampler with wake and sleep phase simulation.
  110. Args:
  111. init_weight: Initial weight matrix (N, N).
  112. init_bias: Initial bias vector (N,).
  113. num_visible: Number of visible neurons.
  114. sim_params: Dict with keys psp_kernel, t_ref, tau_syn, num_last_spikes.
  115. rng_seed: Random seed.
  116. """
  117. def __init__(
  118. self,
  119. init_weight: npt.NDArray,
  120. init_bias: npt.NDArray,
  121. num_visible: int,
  122. sim_params: SimParams,
  123. rng_seed: int = 424242,
  124. ) -> None:
  125. np.random.seed(rng_seed)
  126. assert init_weight.shape[0] == init_weight.shape[1]
  127. assert init_weight.shape[0] == len(init_bias)
  128. self.num_nrns = len(init_bias)
  129. self.num_vis = num_visible
  130. self.num_hidden = self.num_nrns - self.num_vis
  131. assert self.num_hidden >= 0
  132. self.weight = init_weight
  133. self.bias = init_bias
  134. self.psp_kernel = sim_params["psp_kernel"]
  135. self.t_ref = sim_params["t_ref"]
  136. self.tau_syn = sim_params["tau_syn"]
  137. self.num_last_spikes = sim_params["num_last_spikes"]
  138. self.rng_seed = rng_seed
  139. def wake_phase(self, sim_dur: int, target: npt.NDArray) -> npt.NDArray:
  140. """Run a clamped simulation with target clamped to visible neurons."""
  141. bias = np.copy(self.bias)
  142. bias[: self.num_vis] = (target * 2.0 - 1.0) * 10.0
  143. spikes = sim_poisson_neurons(
  144. sim_dur, self.psp_kernel, bias, self.weight, self.t_ref, self.tau_syn
  145. )
  146. return spikes
  147. def sleep_phase(self, sim_dur: int) -> npt.NDArray:
  148. """Run a free simulation for `sim_dur` steps."""
  149. spikes = sim_poisson_neurons(
  150. sim_dur, self.psp_kernel, self.bias, self.weight, self.t_ref, self.tau_syn
  151. )
  152. return spikes
  153. def spikes_to_states(self, spikes: npt.NDArray, sim_dur: int) -> npt.NDArray:
  154. """Convert a spike array to a binary state matrix."""
  155. t_refs = np.full(self.num_nrns, self.t_ref)
  156. return get_states_from_spikes(
  157. self.num_nrns, spikes, t_refs, self.t_ref / 2.0, sim_dur
  158. )
  159. def restrict(self, arr: npt.NDArray) -> npt.NDArray:
  160. """Zero out visible-visible and hidden-hidden entries of arr."""
  161. arr[: self.num_vis, : self.num_vis] = 0.0
  162. arr[self.num_vis :, self.num_vis :] = 0.0
  163. return arr
  164. def restrict_weights(self) -> None:
  165. """Zero out visible-visible and hidden-hidden weights in-place."""
  166. self.weight[: self.num_vis, : self.num_vis] = 0.0
  167. self.weight[self.num_vis :, self.num_vis :] = 0.0
  168. def clip_weights(self, max_w: float) -> None:
  169. """Clip all weights to [-max_w, max_w] in-place."""
  170. self.weight[self.weight > max_w] = max_w
  171. self.weight[self.weight < -max_w] = -max_w
  172. def clip_bias(self, max_b: float) -> None:
  173. """Clip all biases to [-max_b, max_b] in-place."""
  174. self.bias[self.bias > max_b] = max_b
  175. self.bias[self.bias < -max_b] = -max_b
  176. class NeuralSamplerFullyConnected(NeuralSampler):
  177. """Fully connected neural sampler trained with STDP-based gradient descent.
  178. Args:
  179. init_weight: Initial weight matrix.
  180. init_bias: Initial bias vector.
  181. target_weight: Target BM weight matrix (used to compute target distribution).
  182. target_bias: Target BM bias vector.
  183. sim_params: Simulation parameters dict.
  184. dur_sleep: Sleep phase duration.
  185. optimizer_bias: Bias update optimizer.
  186. optimizer_weight: Weight update optimizer.
  187. optimizer_symm: Symmetrization optimizer (optional).
  188. max_w: Weight clip bound.
  189. max_b: Bias clip bound.
  190. rng_seed: Random seed.
  191. weight_decay: Per-step weight decay fraction.
  192. """
  193. def __init__(
  194. self,
  195. init_weight: npt.NDArray,
  196. init_bias: npt.NDArray,
  197. target_weight: npt.NDArray,
  198. target_bias: npt.NDArray,
  199. sim_params: SimParams,
  200. dur_sleep: int,
  201. optimizer_bias: Callable,
  202. optimizer_weight: Callable,
  203. optimizer_symm: Callable | None = None,
  204. max_w: float = 2.0,
  205. max_b: float = 2.0,
  206. rng_seed: int = 424242,
  207. weight_decay: float | npt.NDArray = 0.0,
  208. ):
  209. """Initialize sampler and compute target distribution analytically."""
  210. super().__init__(init_weight, init_bias, 0, sim_params, rng_seed=rng_seed)
  211. self.dur = dur_sleep
  212. self.optimizer_bias = optimizer_bias
  213. self.optimizer_weight = optimizer_weight
  214. self.optimizer_symm = optimizer_symm
  215. self.los = list_of_states(self.num_nrns)
  216. self.max_w = max_w
  217. self.max_b = max_b
  218. self.validation = False
  219. self.weight_decay = 1.0 - weight_decay
  220. self.target_distr, self.los, self.coact = bm_to_probs(
  221. target_weight, target_bias
  222. )
  223. self.marginals = np.diagonal(self.coact).copy()
  224. np.fill_diagonal(self.coact, 0.0)
  225. print("theoretical distribution", self.target_distr, flush=True)
  226. print("theoretical coactivation \n", self.coact, flush=True)
  227. print("theoretical marginals", self.marginals, flush=True)
  228. print(self.target_distr.shape)
  229. def spike_rates(self, spikes: npt.NDArray, dur: float | int) -> npt.NDArray:
  230. """Compute mean spike rates for all neurons.
  231. Args:
  232. spikes: Ordered spike array.
  233. dur: Simulation duration.
  234. Returns:
  235. Rate array, one per neuron.
  236. """
  237. rates = []
  238. list_of_spikes = ordered_spikes_to_list(
  239. spikes, list(range(1, self.num_nrns + 1))
  240. )
  241. for spks in list_of_spikes:
  242. rates.append(len(spks) / dur * self.t_ref)
  243. return np.array(rates)
  244. def sleep_phase(
  245. self, stdp_rule: StdpFunc, sal_rule: StdpFunc | None = None
  246. ) -> tuple[npt.NDArray, npt.NDArray, npt.NDArray, npt.NDArray | None]:
  247. """Run a sleep phase and return STDP, rates, sampled distribution, and SAL.
  248. Args:
  249. stdp_rule: STDP rule callable.
  250. sal_rule: SAL rule callable (optional).
  251. Returns:
  252. Tuple of (stdp, rates, sampled_distr, stdp_sal).
  253. """
  254. spikes = super().sleep_phase(self.dur)
  255. states = self.spikes_to_states(spikes, self.dur)
  256. sampled_distr = distr_from_states(states, self.los)
  257. rates = self.spike_rates(spikes, self.dur)
  258. stdp = stdp_rule(spikes) / self.dur * self.t_ref
  259. if sal_rule is not None:
  260. stdp_sal = sal_rule(spikes) / self.dur * self.t_ref
  261. else:
  262. stdp_sal = None
  263. return stdp, rates, sampled_distr, stdp_sal
  264. def training_iteration(
  265. self,
  266. stdp_rule: StdpFunc,
  267. sal_rule: StdpFunc | None = None,
  268. ) -> dict:
  269. """Run one training step: sleep phase → gradient → weight/bias update.
  270. Args:
  271. stdp_rule: STDP rule callable.
  272. sal_rule: SAL rule callable (optional).
  273. Returns:
  274. Dict with sampled_distr, weights, biases, sleep_stdp, sal_stdp, target_distr.
  275. """
  276. sleep_stdp, sleep_rates, sampled_distr, stdp_sal = self.sleep_phase(
  277. stdp_rule=stdp_rule,
  278. sal_rule=sal_rule,
  279. )
  280. corrected_coact = (
  281. self.coact * stdp_rule.noised_correlation_factors() / self.t_ref
  282. )
  283. grad_weight = corrected_coact - sleep_stdp
  284. grad_bias = self.marginals - sleep_rates
  285. delta_weight = self.optimizer_weight.update(grad_weight)
  286. delta_bias = self.optimizer_bias.update(grad_bias)
  287. # update params:
  288. self.bias = self.bias + delta_bias
  289. self.weight = self.weight + delta_weight
  290. # weight decay
  291. self.weight = self.weight * self.weight_decay
  292. # optional: symmetrization with sal
  293. if sal_rule is not None:
  294. delta_sal = self.optimizer_symm(stdp_sal)
  295. self.weight = self.weight + delta_sal
  296. # impose RBM restrictions:
  297. self.clip_weights(self.max_w)
  298. self.clip_bias(self.max_b)
  299. np.fill_diagonal(self.weight, 0.0)
  300. res = {
  301. "sampled_distr": sampled_distr,
  302. "weights": np.copy(self.weight),
  303. "biases": np.copy(self.bias),
  304. "sleep_stdp": sleep_stdp,
  305. "sal_stdp": stdp_sal,
  306. "target_distr": self.target_distr,
  307. }
  308. return res
  309. def train(
  310. self,
  311. num_iter: int,
  312. stdp_rule: StdpFunc,
  313. stdp_rule_symm: StdpFunc | None = None,
  314. callback: Callable | None = None,
  315. validation_step: int = 1,
  316. validation_factor: int = 10,
  317. ) -> None:
  318. """Train for `num_iter` iterations, calling `callback` after each step.
  319. Args:
  320. num_iter: Number of training iterations.
  321. stdp_rule: STDP rule callable.
  322. stdp_rule_symm: SAL rule callable (optional).
  323. callback: Called with (result_dict, step); return True to stop early.
  324. validation_step: Run a longer validation every this many steps.
  325. validation_factor: Multiply sleep duration during validation.
  326. """
  327. for step in range(num_iter):
  328. # every validation_step-th iteration change the sleep duration,
  329. # but not if validation_step == 1
  330. if step % validation_step == 0 and (validation_step - 1):
  331. tick = time.time()
  332. self.dur *= validation_factor
  333. print(
  334. f"TRAINING ITERATION NO. {step} -- {datetime.now().ctime()}",
  335. flush=True,
  336. )
  337. print("validation phase!")
  338. self.validation = True
  339. res = self.training_iteration(
  340. stdp_rule,
  341. sal_rule=stdp_rule_symm,
  342. )
  343. quit = False
  344. if callback is not None:
  345. quit = callback(res, step)
  346. if step % validation_step == 0 and (validation_step - 1):
  347. tock = time.time()
  348. self.dur /= validation_factor
  349. self.validation = False
  350. print(f"Time for iteration: {tock - tick}", flush=True)
  351. if quit:
  352. print(
  353. "Recieved signal to stop training from callback function!",
  354. flush=True,
  355. )
  356. break
  357. class GradDescent(object):
  358. """Gradient descent optimizer: update = lr * grad."""
  359. def __init__(self, lr: float) -> None:
  360. """Set learning rate."""
  361. self.lr = lr
  362. def update(self, grad: npt.NDArray) -> npt.NDArray:
  363. """Return lr * grad."""
  364. return self.lr * grad
  365. def __call__(self, grad: npt.NDArray) -> npt.NDArray:
  366. """Alias for `update`."""
  367. return self.update(grad)

network.py at commit f379585, under MIT · at the source

Overview

Authors: Timo Gierlich1,2, Andreas Baumbach2, Akos F. Kungl2, Kevin Max1,3, Mihai A. Petrovici1
ORCID iDs: Kevin Max
  1. Department of Physiology, Bern University,Bern, Switzerland
  2. Kirchhoff-Institut für Physik, Ruprecht-Karls-Universität Heidelberg,Heidelberg, Germany
  3. Neural Computation Unit, Okinawa Institute of Science and Technology,Okinawa, Japan
Journal: Nature communications, volume 17, issue 1, article 8699
Dates: received 28 February 2025; accepted 8 June 2026; published online 7 July 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1038/s41467-026-74460-8 · PMID 42414269 · PMCID PMC13490435 · OpenAlex W4415335376
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: computational modeling (no new data) (modality), human (organism)
Methods: Preprocessing, Machine learning, fMRI & imaging, Single-unit activity, calcium imaging, Smoothing, state filtering, decompositions
Keywords: Electronic and spintronic devices, Learning algorithms, Computational science, Network models
MeSH: Action Potentials*, Learning*, Models, Neurological*, Neurons*, Algorithms, Animals, Bayes Theorem, Computer Simulation, Humans, Neural Networks, Computer, Synapses (* major topic)
Topic: Neural dynamics and brain function (Cognitive Neuroscience, Neuroscience), according to OpenAlex
Funding: #101147319 (ERC: EBRAINS 2.0 Project)
Citations: not cited yet (Europe PMC); 118 references in the paper

Abstract

Learning algorithms are often subject to symmetry constraints that are difficult to reconcile with local computation in physical neuronal networks. For example, contrastive Hebbian learning typically assumes symmetric connectivity, while error backpropagation requires knowledge of the forward weights in the backward pass. To solve this weight transport problem, we introduce spike-based alignment learning (SAL), a synapse-local learning rule that harnesses noise for weight alignment. This rule can operate simultaneously with other functional learning rules to maintain the necessary symmetry throughout learning and thereby ensure the correct local representation of gradients. SAL implicitly alleviates any discrepancy arising from the neuron and synapse variability that is ubiquitous in analog substrates, whether biological or artificial. We demonstrate the efficacy of our mechanism using different network models for spiking Bayesian inference and bio-plausible error backpropagation, and benchmark it in a deep learning computer vision task.

Reproduced under the paper's license (CC BY), from the paper cited above.

Repositories

Its files are read in the Code ↔ Paper reader above, with 10 matches between paragraphs and lines of code.

zalandoresearch/fashion-mnist

License: MIT
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: b2617bb6d3ffa2e429640350f613e3291e10b141, 21 March 2022
Languages: Python (11), JavaScript (1)
Size: 51 files, 12 scripts
Software Heritage: archived
Found in: “Data availability”
Holds: README, license file, environment (Dockerfile, requirements.txt), documentation
Not found: CITATION.cff, tests, continuous integration
Tools: NumPy (5 files), scikit-learn (2 files), TensorFlow (2 files), Matplotlib (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
14 files

unibe-cns/sal-code

License: MIT
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: f37958586af3f8918da47c9dce2d10c756f1c024, 10 September 2026
Languages: Python (47), Jupyter (12), Shell (11)
Size: 114 files, 70 scripts
Software Heritage: not archived
Found in: “Code availability”
Holds: README, license file, environment (pyproject.toml, requirements.txt, spiking_microcircuits/pyproject.toml, spiking_sampling_network/pyproject.toml, stdd_calculator/pyproject.toml, symmnet/pyproject.toml), tests, continuous integration, 12 notebooks
Not found: CITATION.cff, documentation
Tools: NumPy (30 files), Matplotlib (18 files), PyTorch (9 files), SciPy (6 files), Numba (4 files), pandas (4 files), seaborn (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
72 files

Code availability

The simulations were performed by custom code written in Python (v3.11), numpy (v2.0) and numba (v0.60). The SymmNet simulations were done using PyTorch (v2.7). All code is made available under https://github.com/unibe-cns/sal-code.

Reproduced under the paper's license (CC BY), from the paper cited above.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 2 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 82 scripts, each with its path and the digest of its content;
  • 10 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

No dataset and no data link were found in the paper.

Data availability

The datasets used in this study are publicly available. CIFAR-10 is available at https://www.cs.toronto.edu/k̃riz/cifar.html79, Fashion-MNIST at https://github.com/zalandoresearch/fashion-mnist80, and SVHN at http://ufldl.stanford.edu/housenumbers/81. No new datasets were generated for the current study.

Reproduced under the paper's license (CC BY), from the paper cited above.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 1, 27 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 5 authors, 4 keywords, 11 MeSH terms, 1 funder, 91 references.

Cite

This paper

Gierlich, T., Baumbach, A., Kungl, A. F., Max, K., & Petrovici, M. A. (2026). Spike-based alignment learning solves the weight transport problem. Nature communications, 17(1), 8699. https://doi.org/10.1038/s41467-026-74460-8

BibTeX

@article{gierlich2026spike,
author = {Gierlich, Timo and Baumbach, Andreas and Kungl, Akos F. and Max, Kevin and Petrovici, Mihai A.},
title = {{Spike-based alignment learning solves the weight transport problem}},
journal = {Nature communications},
year = {2026},
month = jul,
volume = {17},
number = {1},
pages = {8699},
publisher = {Nature Publishing Group},
issn = {2041-1723},
doi = {10.1038/s41467-026-74460-8},
url = {https://doi.org/10.1038/s41467-026-74460-8},
pmid = {42414269},
pmcid = {PMC13490435}
}

RIS

TY - JOUR
AU - Gierlich, Timo
AU - Baumbach, Andreas
AU - Kungl, Akos F.
AU - Max, Kevin
AU - Petrovici, Mihai A.
TI - Spike-based alignment learning solves the weight transport problem
T2 - Nature communications
J2 - Nat Commun
PY - 2026
DA - 2026/07/07
VL - 17
IS - 1
SP - 8699
SN - 2041-1723
PB - Nature Publishing Group
DO - 10.1038/s41467-026-74460-8
UR - https://doi.org/10.1038/s41467-026-74460-8
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s41467-026-74460-8",
"type": "article-journal",
"title": "Spike-based alignment learning solves the weight transport problem",
"container-title": "Nature communications",
"author": [
{
"family": "Gierlich",
"given": "Timo"
},
{
"family": "Baumbach",
"given": "Andreas"
},
{
"family": "Kungl",
"given": "Akos F."
},
{
"family": "Max",
"given": "Kevin"
},
{
"family": "Petrovici",
"given": "Mihai A."
}
],
"container-title-short": "Nat Commun",
"volume": "17",
"issue": "1",
"page": "8699",
"DOI": "10.1038/s41467-026-74460-8",
"PMID": "42414269",
"PMCID": "PMC13490435",
"ISSN": "2041-1723",
"publisher": "Nature Publishing Group",
"URL": "https://doi.org/10.1038/s41467-026-74460-8",
"language": "en",
"issued": {
"date-parts": [
[
2026,
7,
7
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.1371/journal.pcbi.1014164 [code]
'Backpropagation and the brain' realized in cortical error neuron microcircuits.
Journal: PLoS computational biology
In common: PyTorch, SciPy, Matplotlib, 1 other tool, computational modeling (no new data), 17 references, author Kevin Max
[2] doi:10.7554/elife.105968 [code]
Modeling the hallucinatory effects of classical psychedelics in terms of replay-dependent plasticity mechanisms.
Journal: eLife
In common: PyTorch, scikit-learn, Matplotlib, 1 other tool, 8 references
[3] doi:10.7554/elife.111876 [code]
Distinct sensorimotor encoding in tuft dendrites and somata associated with action, correction, and learning.
Journal: eLife
In common: PyTorch, seaborn, scikit-learn, 4 other tools, 5 references
[4] doi:10.7554/elife.105953 [code]
Top-down feedback in deep neural networks leads to functional differences during audiovisual integration.
Journal: eLife
In common: PyTorch, seaborn, scikit-learn, 4 other tools, 4 references
[5] doi:10.1371/journal.pcbi.1014730 [code]
A unified model of short- and long-term plasticity: Effects on network connectivity and information capacity.
Journal: PLoS computational biology
In common: seaborn, scikit-learn, pandas, 3 other tools, computational modeling (no new data), 4 references
[6] doi:10.1038/s41467-026-74816-0 [code]
Hierarchical optimization predicts plasticity in the macaque inferior temporal cortex following object training.
Journal: Nature communications
In common: PyTorch, seaborn, scikit-learn, 4 other tools, 4 references
[7] doi:10.1038/s41467-026-70354-x [code]
Global error signal guides local optimization in mismatch calculation.
Journal: Nature communications
In common: Numba, seaborn, scikit-learn, 3 other tools, computational modeling (no new data), 3 references
[8] doi:10.1038/s41467-026-74358-5 [code]
Brain-inspired spatial intelligence for embodied agents.
Journal: Nature communications
In common: Numba, TensorFlow, PyTorch, 6 other tools, 1 reference
[9] doi: [code]
Going deeper with morphologically detailed neural networks by simulation-based gradient propagation
Journal: Frontiers in computational neuroscience
In common: TensorFlow, SciPy, Matplotlib, 1 other tool, computational modeling (no new data), 4 references
[10] doi:10.1523/jneurosci.0987-25.2026 [code]
Cell-Type-Specific Synaptic Scaling Mechanisms Differentially Contribute to Associative Learning.
Journal: The Journal of neuroscience : the official journal of the Society for Neuroscience
In common: Numba, seaborn, pandas, 3 other tools, 3 references

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.

Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.