From a4776f9dea7977e28970bd63098b38214ced2602 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 12 Aug 2026 17:03:50 +0200 Subject: [PATCH] auto stimulus reset --- Runtime/Scripts/Core/Cluster.cs | 21 ++++++++------- Runtime/Scripts/Core/Neuron.cs | 46 ++++++++++++++++++++++++++------- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/Runtime/Scripts/Core/Cluster.cs b/Runtime/Scripts/Core/Cluster.cs index 3d154f7..35590fa 100644 --- a/Runtime/Scripts/Core/Cluster.cs +++ b/Runtime/Scripts/Core/Cluster.cs @@ -392,7 +392,7 @@ namespace NanoBrain { foreach (Synapse synapse in neuron.synapses) { if (synapse.trainable) { synapse.weight = (float)randomGenerator.NextDouble() * 2.0f - 1.0f; - Debug.Log($"{neuron.name}-{synapse.neuron.name} weight = {synapse.weight}"); + // Debug.Log($"{neuron.name}-{synapse.neuron.name} weight = {synapse.weight}"); } } } @@ -859,14 +859,15 @@ namespace NanoBrain { List computeOrder = this.computeOrders[startNucleus]; foreach (Nucleus nucleus in computeOrder) { - if (nucleus is not Cluster) { - nucleus.UpdateStateIsolated(); - if (nucleus is Neuron neuron) { - foreach (Nucleus receiver in neuron.receivers) { - if (receiver.parent != this) { - //Debug.Log($" External: {receiver.parent.name}.{receiver.name}"); - receiver.parent.UpdateFromNucleus(receiver); - } + if (nucleus is Cluster) + continue; + + nucleus.UpdateStateIsolated(); + if (nucleus is Neuron neuron) { + foreach (Nucleus receiver in neuron.receivers) { + if (receiver.parent != this) { + //Debug.Log($" External: {receiver.parent.name}.{receiver.name}"); + receiver.parent.UpdateFromNucleus(receiver); } } } @@ -940,7 +941,7 @@ namespace NanoBrain { if (synapse.neuron.parent.name != cluster.name) { ExternalClusterData clusterData = new(synapse.neuron.parent); if (GetCluster(clusterData.name) == null) { - //if (this.clusters.Find(data => data.name == clusterData.name) == null) { + //if (this.clusters.Find(data => data.name == clusterData.name) == null) { this.clusters.Add(clusterData); //Debug.Log("Add cluster"); } diff --git a/Runtime/Scripts/Core/Neuron.cs b/Runtime/Scripts/Core/Neuron.cs index 607b5cd..7f2f2c7 100644 --- a/Runtime/Scripts/Core/Neuron.cs +++ b/Runtime/Scripts/Core/Neuron.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; using UnityEngine; #if UNITY_MATHEMATICS using Unity.Mathematics; @@ -237,7 +239,7 @@ namespace NanoBrain { public Action WhenFiring; public Action WhenNotFiring; - + /// /// When true, the value will not be reset after timeToSleep. /// @@ -713,14 +715,14 @@ namespace NanoBrain { foreach (Synapse synapse in this.synapses) synapse.BackPropagation3D(this, derivative, learningRate); - // As the weight cannot change the direction of the derivative - // we can use the simpler, 1D backpropagation here - // But we still need to determine the sign of the derivative + // As the weight cannot change the direction of the derivative + // we can use the simpler, 1D backpropagation here + // But we still need to determine the sign of the derivative - // if (Synapse.AreOpposed(derivative, synapse.neuron.activation)) - // synapse.BackPropagation(this, -derivativeMagnitude, learningRate); - // else - // synapse.BackPropagation(this, derivativeMagnitude, learningRate); + // if (Synapse.AreOpposed(derivative, synapse.neuron.activation)) + // synapse.BackPropagation(this, -derivativeMagnitude, learningRate); + // else + // synapse.BackPropagation(this, derivativeMagnitude, learningRate); // Bias if (this.trainableBias) { @@ -739,14 +741,40 @@ namespace NanoBrain { #endregion Back propagation + private CancellationTokenSource _cts; + /// /// Process an external stimulus /// /// The value of the stimulus - public virtual void ProcessStimulus(Vector3 inputValue) { + public virtual void ProcessStimulus(Vector3 inputValue, float autoResetDelay = 0) { this.lastUpdate = Time.time; this.bias = inputValue; this.parent?.UpdateFromNucleus(this); + + if (autoResetDelay > 0) { + _cts?.Cancel(); + _cts?.Dispose(); + _cts = new CancellationTokenSource(); + _ = CallResetAfterDelayAsync(_cts.Token, autoResetDelay); + } + } + + private async Task CallResetAfterDelayAsync(CancellationToken token, float autoResetDelay) { + try { + await Task.Delay(TimeSpan.FromSeconds(autoResetDelay), token); + if (!token.IsCancellationRequested) + ResetStimulus(); + } + catch (TaskCanceledException) { + // Expected when Stimulus is called again; do nothing + } + } + + protected async void ResetStimulus() { + //Debug.Log("reset stimulus"); + this.bias = Vector3.zero; + this.parent?.UpdateFromNucleus(this); } }