Add memory cell
This commit is contained in:
parent
f4559efe40
commit
8d1a4c3b72
@ -76,6 +76,7 @@
|
|||||||
<Compile Include="Assets/NanoBrain/ClusterInstance.cs" />
|
<Compile Include="Assets/NanoBrain/ClusterInstance.cs" />
|
||||||
<Compile Include="Assets/NanoBrain/LinearAlgebra/src/Spherical.cs" />
|
<Compile Include="Assets/NanoBrain/LinearAlgebra/src/Spherical.cs" />
|
||||||
<Compile Include="Assets/NanoBrain/LinearAlgebra/test/Vector3FloatTest.cs" />
|
<Compile Include="Assets/NanoBrain/LinearAlgebra/test/Vector3FloatTest.cs" />
|
||||||
|
<Compile Include="Assets/NanoBrain/MemoryCell.cs" />
|
||||||
<Compile Include="Assets/NanoBrain/LinearAlgebra/test/QuaternionTest.cs" />
|
<Compile Include="Assets/NanoBrain/LinearAlgebra/test/QuaternionTest.cs" />
|
||||||
<Compile Include="Assets/Scenes/Boids/Scripts/Boid.cs" />
|
<Compile Include="Assets/Scenes/Boids/Scripts/Boid.cs" />
|
||||||
<Compile Include="Assets/NanoBrain/LinearAlgebra/src/SwingTwist.cs" />
|
<Compile Include="Assets/NanoBrain/LinearAlgebra/src/SwingTwist.cs" />
|
||||||
|
|||||||
65
Assets/NanoBrain/MemoryCell.cs
Normal file
65
Assets/NanoBrain/MemoryCell.cs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
using static Unity.Mathematics.math;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class MemoryCell : Neuron {
|
||||||
|
|
||||||
|
public MemoryCell(Cluster cluster, string name) : base(cluster, name) {}
|
||||||
|
|
||||||
|
#region Parameters
|
||||||
|
|
||||||
|
// Returns the memorized value weighted by time
|
||||||
|
// return lastValue * (current time - last time)
|
||||||
|
[SerializeField]
|
||||||
|
public bool deltaValue = false;
|
||||||
|
|
||||||
|
#endregion Parameters
|
||||||
|
|
||||||
|
#region State
|
||||||
|
|
||||||
|
private float3 _memorizedValue;
|
||||||
|
private float _memorizedTime;
|
||||||
|
|
||||||
|
public override void UpdateState() {
|
||||||
|
// A memorycell does not have an activation function
|
||||||
|
float3 result = new(0, 0, 0);
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
//Applying the weight factgors
|
||||||
|
foreach (Synapse synapse in this.synapses) {
|
||||||
|
if (synapse.nucleus == this) {
|
||||||
|
float deltaTime = Time.time - this.lastTime;
|
||||||
|
synapse.weight = deltaTime;
|
||||||
|
}
|
||||||
|
result += synapse.weight * synapse.nucleus.outputValue;
|
||||||
|
if (lengthsq(synapse.nucleus.outputValue) != 0)
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.average)
|
||||||
|
result /= n;
|
||||||
|
|
||||||
|
UpdateResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateResult(Vector3 result) {
|
||||||
|
// output value is the previous value
|
||||||
|
if (this.deltaValue) {
|
||||||
|
float deltaTime = Time.time - this._memorizedTime;
|
||||||
|
this._outputValue = this._memorizedValue * deltaTime;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
this._outputValue = this._memorizedValue;
|
||||||
|
|
||||||
|
// Store the result for the next time
|
||||||
|
this._memorizedValue = result;
|
||||||
|
this._memorizedTime = Time.time;
|
||||||
|
|
||||||
|
foreach (INucleus receiver in this.receivers)
|
||||||
|
receiver.UpdateState();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion State
|
||||||
|
}
|
||||||
2
Assets/NanoBrain/MemoryCell.cs.meta
Normal file
2
Assets/NanoBrain/MemoryCell.cs.meta
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 29633aa3fe5cd9dcc8d886051f45d4d8
|
||||||
@ -54,8 +54,13 @@ public class Neuron : INucleus {
|
|||||||
}
|
}
|
||||||
public AnimationCurve curve;
|
public AnimationCurve curve;
|
||||||
public float curveMax = 1.0f;
|
public float curveMax = 1.0f;
|
||||||
|
|
||||||
|
#region Parameters
|
||||||
|
|
||||||
public bool average = false;
|
public bool average = false;
|
||||||
|
|
||||||
|
#endregion Parameters
|
||||||
|
|
||||||
public AnimationCurve GenerateCurve() {
|
public AnimationCurve GenerateCurve() {
|
||||||
switch (this.curvePreset) {
|
switch (this.curvePreset) {
|
||||||
case CurvePresets.Linear:
|
case CurvePresets.Linear:
|
||||||
@ -132,8 +137,8 @@ public class Neuron : INucleus {
|
|||||||
|
|
||||||
#endregion Activation
|
#endregion Activation
|
||||||
|
|
||||||
private float3 _outputValue;
|
protected float3 _outputValue;
|
||||||
public float3 outputValue {
|
public virtual float3 outputValue {
|
||||||
get { return _outputValue; }
|
get { return _outputValue; }
|
||||||
set {
|
set {
|
||||||
this.stale = 0;
|
this.stale = 0;
|
||||||
@ -147,6 +152,7 @@ public class Neuron : INucleus {
|
|||||||
|
|
||||||
private bool _isSleeping = false;
|
private bool _isSleeping = false;
|
||||||
public bool isSleeping => _isSleeping;
|
public bool isSleeping => _isSleeping;
|
||||||
|
public float lastTime { get; private set; }
|
||||||
|
|
||||||
public void UpdateNuclei() {
|
public void UpdateNuclei() {
|
||||||
this.stale++;
|
this.stale++;
|
||||||
@ -238,11 +244,16 @@ public class Neuron : INucleus {
|
|||||||
|
|
||||||
//Applying the weight factgors
|
//Applying the weight factgors
|
||||||
foreach (Synapse synapse in this.synapses) {
|
foreach (Synapse synapse in this.synapses) {
|
||||||
|
if (synapse.nucleus == this) {
|
||||||
|
float deltaTime = Time.time - this.lastTime;
|
||||||
|
synapse.weight = deltaTime;
|
||||||
|
}
|
||||||
sum += synapse.weight * synapse.nucleus.outputValue;
|
sum += synapse.weight * synapse.nucleus.outputValue;
|
||||||
|
// Perhaps synapses should be removed when the output value goes to 0....
|
||||||
if (lengthsq(synapse.nucleus.outputValue) != 0)
|
if (lengthsq(synapse.nucleus.outputValue) != 0)
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
if (average)
|
if (this.average)
|
||||||
sum /= n;
|
sum /= n;
|
||||||
|
|
||||||
// Activation function
|
// Activation function
|
||||||
@ -267,7 +278,8 @@ public class Neuron : INucleus {
|
|||||||
}
|
}
|
||||||
UpdateResult(result);
|
UpdateResult(result);
|
||||||
}
|
}
|
||||||
public void UpdateResult(Vector3 result) {
|
|
||||||
|
public virtual void UpdateResult(Vector3 result) {
|
||||||
// float d = Vector3.Distance(result, this.outputValue);
|
// float d = Vector3.Distance(result, this.outputValue);
|
||||||
// if (d < 0.5f) {
|
// if (d < 0.5f) {
|
||||||
// //Debug.Log($"insignificant update: {d}");
|
// //Debug.Log($"insignificant update: {d}");
|
||||||
@ -275,6 +287,7 @@ public class Neuron : INucleus {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
this.outputValue = result;
|
this.outputValue = result;
|
||||||
|
this.lastTime = Time.time;
|
||||||
foreach (INucleus receiver in this.receivers)
|
foreach (INucleus receiver in this.receivers)
|
||||||
receiver.UpdateState();
|
receiver.UpdateState();
|
||||||
|
|
||||||
|
|||||||
61
Assets/NanoBrain/Velocity.asset
Normal file
61
Assets/NanoBrain/Velocity.asset
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3}
|
||||||
|
m_Name: Velocity
|
||||||
|
m_EditorClassIdentifier: Assembly-CSharp::Cluster
|
||||||
|
asset: {fileID: 0}
|
||||||
|
nuclei:
|
||||||
|
- rid: 2243601362379866169
|
||||||
|
references:
|
||||||
|
version: 2
|
||||||
|
RefIds:
|
||||||
|
- rid: 2243601362379866169
|
||||||
|
type: {class: Neuron, ns: , asm: Assembly-CSharp}
|
||||||
|
data:
|
||||||
|
_name: Output
|
||||||
|
_synapses: []
|
||||||
|
_receivers: []
|
||||||
|
_array:
|
||||||
|
rid: 2243601362379866170
|
||||||
|
_curvePreset: 0
|
||||||
|
curve:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Curve:
|
||||||
|
- serializedVersion: 3
|
||||||
|
time: 0
|
||||||
|
value: 0
|
||||||
|
inSlope: 0
|
||||||
|
outSlope: 1
|
||||||
|
tangentMode: 0
|
||||||
|
weightedMode: 0
|
||||||
|
inWeight: 0
|
||||||
|
outWeight: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
time: 1000
|
||||||
|
value: 1000
|
||||||
|
inSlope: 1
|
||||||
|
outSlope: 0
|
||||||
|
tangentMode: 0
|
||||||
|
weightedMode: 0
|
||||||
|
inWeight: 0
|
||||||
|
outWeight: 0
|
||||||
|
m_PreInfinity: 2
|
||||||
|
m_PostInfinity: 2
|
||||||
|
m_RotationOrder: 4
|
||||||
|
curveMax: 1
|
||||||
|
average: 0
|
||||||
|
- rid: 2243601362379866170
|
||||||
|
type: {class: NucleusArray, ns: , asm: Assembly-CSharp}
|
||||||
|
data:
|
||||||
|
_nuclei:
|
||||||
|
- rid: 2243601362379866169
|
||||||
|
name: Output
|
||||||
8
Assets/NanoBrain/Velocity.asset.meta
Normal file
8
Assets/NanoBrain/Velocity.asset.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: dd622ac7ed09e70ea8edac595047ac82
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -488,14 +488,20 @@ public class ClusterInspector : Editor {
|
|||||||
|
|
||||||
this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name);
|
this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name);
|
||||||
if (this.currentNucleus is Neuron neuroid) {
|
if (this.currentNucleus is Neuron neuroid) {
|
||||||
EditorGUILayout.BeginHorizontal();
|
if (this.currentNucleus is MemoryCell memory) {
|
||||||
EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150));
|
// should use serializedProperty
|
||||||
if (neuroid.curveMax > 0)
|
memory.deltaValue = EditorGUILayout.Toggle("DeltaValue", memory.deltaValue);
|
||||||
EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax));
|
}
|
||||||
else
|
else {
|
||||||
EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax));
|
EditorGUILayout.BeginHorizontal();
|
||||||
neuroid.curvePreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100));
|
EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150));
|
||||||
EditorGUILayout.EndHorizontal();
|
if (neuroid.curveMax > 0)
|
||||||
|
EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax));
|
||||||
|
else
|
||||||
|
EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax));
|
||||||
|
neuroid.curvePreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100));
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
}
|
||||||
|
|
||||||
if (neuroid.array == null || neuroid.array.nuclei == null || neuroid.array.nuclei.Count() == 0)
|
if (neuroid.array == null || neuroid.array.nuclei == null || neuroid.array.nuclei.Count() == 0)
|
||||||
neuroid.array = new NucleusArray(neuroid);
|
neuroid.array = new NucleusArray(neuroid);
|
||||||
@ -544,6 +550,8 @@ public class ClusterInspector : Editor {
|
|||||||
ConnectNucleus(this.cluster, this.currentNucleus);
|
ConnectNucleus(this.cluster, this.currentNucleus);
|
||||||
if (GUILayout.Button("Add Input Neuron"))
|
if (GUILayout.Button("Add Input Neuron"))
|
||||||
AddInputNeuron(this.currentNucleus);
|
AddInputNeuron(this.currentNucleus);
|
||||||
|
if (GUILayout.Button("Add Input MemoryCell"))
|
||||||
|
AddInputMemoryCell(this.currentNucleus);
|
||||||
if (GUILayout.Button("Add Input Cluster"))
|
if (GUILayout.Button("Add Input Cluster"))
|
||||||
AddCluster(this.currentNucleus);
|
AddCluster(this.currentNucleus);
|
||||||
|
|
||||||
@ -598,6 +606,13 @@ public class ClusterInspector : Editor {
|
|||||||
BuildLayers();
|
BuildLayers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void AddInputMemoryCell(INucleus nucleus) {
|
||||||
|
MemoryCell newMemory = new(this.cluster.cluster, "New memory cell");
|
||||||
|
newMemory.AddReceiver(nucleus);
|
||||||
|
this.currentNucleus = newMemory;
|
||||||
|
BuildLayers();
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual void AddCluster(INucleus nucleus) {
|
protected virtual void AddCluster(INucleus nucleus) {
|
||||||
BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster");
|
BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster");
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user