using System;
using UnityEngine;
using Unity.Mathematics;
namespace NanoBrain {
///
/// A Synapse connects the ouput of a Neuron to another Neuron
///
[Serializable]
public class Synapse {
///
/// The neuron from which input is received
///
[SerializeReference]
[HideInInspector]
public Neuron neuron;
///
/// The weight value to apply to the Neuron input
///
public float weight;
///
/// Indicator whether the weight can be trained
///
public bool trainable = false;
///
/// Create a new Synapse
///
/// The neuron from which input is received
/// The weight value to apply to the Neuron input
public Synapse(Neuron nucleus, float weight = 1.0f) {
this.neuron = nucleus;
this.weight = weight;
}
public virtual void BackPropagation(Neuron receiver, float error, float learningRate) {
float derivative = error;
switch (receiver.activator) {
case Neuron.ActivationType.Linear:
derivative *= 1;
break;
case Neuron.ActivationType.Power:
// untested
derivative *= 2 * math.length(this.neuron.combination);
break;
case Neuron.ActivationType.Reciprocal:
// untested
derivative *= -1 / Mathf.Pow(math.length(this.neuron.combination), 2);
break;
default:
Debug.Log("other activator");
break;
}
this.neuron.BackPropagation1D(derivative * this.weight, learningRate);
derivative *= math.length(this.neuron.activation);
if (this.trainable) {
float deltaWeight = learningRate * derivative;
this.weight += deltaWeight;
}
}
public virtual void BackPropagation(Neuron receiver, Vector3 derivative, float learningRate) {
//Vector3 derivative = error;
switch (receiver.activator) {
case Neuron.ActivationType.Linear:
derivative *= 1;
break;
case Neuron.ActivationType.Power:
// untested
derivative *= 2 * math.length(this.neuron.combination);
break;
case Neuron.ActivationType.Reciprocal:
// untested
derivative *= -1 / Mathf.Pow(math.length(this.neuron.combination), 2);
break;
default:
Debug.Log("other activator");
break;
}
this.neuron.BackPropagation3D(derivative * this.weight, learningRate);
derivative = Vector3.Scale(derivative, this.neuron.activation);
if (this.trainable) {
// Compared to the 1D solution, this does not decrease the weight.
// direction and sign are different....
// Perhaps the sign is determine by the direction of the derivative and the neuron activation?
// When they are oppositie, the sign is negative? (or the other way round...)
this.weight += learningRate * derivative.magnitude;
}
}
}
}