Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 22 additions & 18 deletions Assets/scripts/ForrestCTRL.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@

[RequireComponent(typeof(Rigidbody))]
public class ForrestCTRL : MonoBehaviour {
ctrl C;
Rigidbody rb;
Collider col;
public NN nn = new NN(5,4);
protected ctrl C;
protected Rigidbody rb;
protected Collider col;
protected float[] ini;
protected bool menu;

public NN nn;
public string myName;
public float movement;
public float fitness;
float[] ini;
public bool ended, stLap;
public Vector2 lap;
public float[] inp;
public string brain;

bool menu;

// Use this for initialization
void Start() {
virtual protected void Start() {
menu = SceneManager.GetActiveScene().name == "menu";

if (!menu)
Expand Down Expand Up @@ -56,9 +56,12 @@ void Start() {
}

// Update is called once per frame
void Update()
virtual protected void FixedUpdate()
{
if(nn.inputs < 1) { Debug.Log("Forrest doesn't have a brain"); return; }

brain = nn.ReadBrain();
float[] nnOutputs;

// Rotate the charater based on Horizonal Input & later NN Output
transform.rotation = Quaternion.Euler(transform.eulerAngles + Vector3.up * movement * 2.5f);
Expand Down Expand Up @@ -113,14 +116,15 @@ void Update()
// Add to our fitness every frame
fitness += (ended) ? 0 : inp2fit(inp);

nnOutputs = nn.CalculateNN(inp);
// This sets the output text display to be the output of our NN
if (!menu)
{
movement = ended ? 0 : ((C.intelli == ctrl.IntelMode.Human) ? Input.GetAxis("Horizontal") : nn.CalculateNN(inp));
movement = ended ? 0 : ((C.intelli == ctrl.IntelMode.Human) ? Input.GetAxis("Horizontal") : nnOutputs[0]);
}
else
{
movement = ended ? 0 : (nn.CalculateNN(inp));
movement = ended ? 0 : nnOutputs[0];
}

//
Expand Down Expand Up @@ -173,7 +177,7 @@ void OnTriggerEnter(Collider col)
}
}

public void Reset()
virtual public void Reset()
{
fitness = 0;
lap.x = 1;
Expand All @@ -189,7 +193,7 @@ public void Reset()
}
}

void CheckIfLast()
protected void CheckIfLast()
{
// Grab a ref to every Active Forrest
GameObject[] f = GameObject.FindGameObjectsWithTag("Active");
Expand Down Expand Up @@ -219,7 +223,7 @@ public void Freeze()
r.material = Resources.Load<Material>("forrest_full 1");
}

nn.SetFitness(fitness);
nn.SetFitness(fitness);

// Remove self from All Forrest Attempts Controller Listings
C.allFatt.Remove(this);
Expand All @@ -230,8 +234,9 @@ public void Freeze()
/// Set the Genetic Code for the attempt
/// </summary>
/// <param name="i"></param>
public void SetBrain(float[] i)
public void SetBrain(int[] brainConfig, float[] i)
{
nn = new NN(brainConfig[0],brainConfig[1],brainConfig[2]);
ini = i;
nn.IniWeights(ini);
}
Expand All @@ -240,10 +245,9 @@ public void SetBrain(float[] i)
/// Set the Genetic Code for the attempt with name
/// </summary>
/// <param name="i"></param>
public void SetBrain(float[] i, string n)
public void SetBrain(int[] brainConfig, float[] i, string n)
{
ini = i;
nn.IniWeights(ini);
SetBrain(brainConfig, i);
nn.SetName(n);
myName = nn.name;
gameObject.name = myName;
Expand Down
118 changes: 63 additions & 55 deletions Assets/scripts/NN.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,19 @@ public class NN
int _inputs;
public int inputs { get { return _inputs; } }
float[][] _hLw;
public int weightCount { get { return TotalWeightCount(); } }
float[] _hLb;
float[] Ow;
float Ob;
int _outputs;
public int outputs { get { return _outputs; } }
float[][] Ow;
float[] Ob;
float _fitness;
public double fitness { get { return _fitness; } }
public int geneSize { get { return (_inputs * _hL.Length) + (_hL.Length) + (_hL.Length * _outputs) + Ob.Length; } }

public static int GetGeneSize(int inputs, int hiddenLayers, int outputs)
{
return (inputs * hiddenLayers) + hiddenLayers + (hiddenLayers * outputs) + outputs;
}

/// <summary>
/// Sometimes you just want access to variables like fitness & don't need to pass in node counts
Expand All @@ -33,11 +40,14 @@ public NN()
/// </summary>
/// <param name="inpsNumb"></param>
/// <param name="_hLNodes"></param>
public NN(int inpsNumb, int _hLNodes)
public NN(int inpsNumb, int _hLNodes, int outputs = 1)
{
_hL = new float[_hLNodes];
IniWeights(inpsNumb);
_inputs = inpsNumb;
_outputs = outputs;
Ow = new float[outputs][];
Ob = new float[outputs];
IniWeights(inpsNumb);
}

/// <summary>
Expand All @@ -58,8 +68,12 @@ void IniWeights(int inps)
//
_inputs = inps;

//
Ow = new float[_hL.Length];
//
Ow = new float[_outputs][];
for(int i = 0; i < _outputs; i++) {
Ow[i] = new float[_hL.Length];
}
Ob = new float[Ow.Length];

// Set a double nested array, [hidden layer length][input length]
_hLw = new float[_hL.Length][];
Expand All @@ -72,14 +86,22 @@ void IniWeights(int inps)
{
_hLw[i] = new float[inps];
_hLb[i] = 0;// r.Next(-cap, cap);
Ow[i] = 0;// r.Next(-cap, cap);

//
for (int j = 0; j < _hLw[i].Length; j++)
{
_hLw[i][j] = 0;// r.Next(-cap, cap);
}
}

for(int i = 0; i < _outputs; i++)
{
for(int j = 0; j < _hL.Length; j++)
{
Ow[i][j] = 0;
}
Ob[i] = 0;
}
}

/// <summary>
Expand All @@ -88,6 +110,9 @@ void IniWeights(int inps)
/// <param name="w"></param>
public void IniWeights(float[] w)
{
int outputWeightOffset = (inputs*_hL.Length)+_hLb.Length;
int outputBiasOffset = w.Length - Ob.Length;

// Okay don't freak out from this code let's walk through it step by step.

// first were going to run a for loop the length of the number of nodes in our Hidden Layer
Expand All @@ -99,17 +124,22 @@ public void IniWeights(float[] w)
for (int j = 0; j < _hLw[i].Length; j++)
{
// this is exactly what I described above but in math form
_hLw[i][j] = w[j + (i * 6)];
_hLw[i][j] = w[j + (i * (inputs+1))];
}

// then we're going to map all the biases for ALL nodes in the Hidden Layer, as described above but in math form
_hLb[i] = w[5 + (i * 6)];

_hLb[i] = w[inputs + (i * (inputs+1))];
}
for(int i = 0; i < _outputs; i++) {
// Then we're going to map all of the Output weights, as described above but in math form
Ow[i] = w[i + 24];
for(int j = 0; j < _hL.Length; j++) {
Ow[i][j] = w[j + (i * _hL.Length) + outputWeightOffset];
}
}

for(int i = 0; i < Ob.Length; i++) {
// & lastly the Output bias is the last on the input w sequence & we're done!
Ob = w[w.Length - 1];
Ob[i] = w[w.Length - outputBiasOffset + i];
}
}

Expand All @@ -119,55 +149,37 @@ public void IniWeights(float[] w)
/// <param name="w"></param>
public void IniWeights(string inp)
{
float[] w = new float[weightCount];

float[] w = new float[geneSize];
string[] splitWeights = inp.Split(',');
for (int i = 0; i < w.Length; i++)
{
w[i] = float.Parse(inp.Split(',')[i]);
}

// Okay don't freak out from this code let's walk through it step by step.

// first were going to run a for loop the length of the number of nodes in our Hidden Layer
for (int i = 0; i < _hLw.Length; i++)
{
// then we're going to map all of the hidden layer weights from our float vector input w
// & because I encode the input vector w as all _hL[0] weights then _hL[0] bias, then _hL[1] weight -> _hL[1] bias
// all the way to it's length, then do all Output weights, then Output bias, I am going to map my Neural Net accordingly
for (int j = 0; j < _hLw[i].Length; j++)
{
// this is exactly what I described above but in math form
_hLw[i][j] = w[j + (i * 6)];
}

// then we're going to map all the biases for ALL nodes in the Hidden Layer, as described above but in math form
_hLb[i] = w[5 + (i * 6)];

// Then we're going to map all of the Output weights, as described above but in math form
Ow[i] = w[i + 24];

// & lastly the Output bias is the last on the input w sequence & we're done!
Ob = w[w.Length - 1];
w[i] = float.Parse(splitWeights[i]);
}
IniWeights(w);
}

/// <summary>
/// This will return the output aka guess for the joystick movement
/// </summary>
/// <param name="inps"></param>
/// <returns></returns>
public float CalculateNN(float[] inps)
public float[] CalculateNN(float[] inps)
{
float[] Outputs = new float[_outputs];
// Set the value of all hidden layer outputs
for (int i = 0; i < _hL.Length; i++)
{
_hL[i] = ReLU(Sum(inps, _hLw[i]) + _hLb[i]);
}

float O = SoftSign(Sum(Ow, _hL) + Ob);
for(int i = 0; i < _outputs; i++) {
Outputs[i] = SoftSign(Sum(Ow[i], _hL) + Ob[i]);
}
//float O = SoftSign(Sum(Ow, _hL) + Ob);
//float O = ACTIVATION(Sum(Ow, _hL) + Ob);

return O;
//return O;
return Outputs;
}

/// <summary>
Expand Down Expand Up @@ -223,12 +235,17 @@ public string ReadBrain()

for (int i = 0; i < Ow.Length; i++)
{
dna += Ow[i] + ",";
for (int j = 0; j < _hL.Length; j++) {
dna += Ow[i][j] + ",";
}
}

dna += Ob;
for (int i = 0; i < Ob.Length; i++)
{
dna += Ob[i] + ",";
}

return dna;
return dna.TrimEnd(',');
}

/// <summary>
Expand All @@ -249,15 +266,6 @@ public float[] GetBrain()
return ret;
}

/// <summary>
/// Returns the total weight count
/// </summary>
/// <returns></returns>
int TotalWeightCount()
{
return (_hLw[0].Length * _inputs) + Ow.Length;
}

/// <summary>
/// Sets the name of the NN
/// </summary>
Expand Down
Loading