Hi everyone, I’ve been working on an Artificial Life simulator of late as a sort of pet project. I’ve been working on building neural networks for the creatures brains, networks that can take in inputs such as raycasts or colliders and output values to “jets” or other force applicators. The neural network seems to work well enough, but my biggest problem is in optimizing them. Put simply, it takes too long, and even as few as five creatures lags my machine so much its unplayable. Even neural networks with as few as three neurons do this.
In an attempt to speed up the processing time, I’ve been working on a solution that involves multithreading; the code is below. I used [this][1] answer to build the thread code, but I am seeing no improvements in performance or the number of creatures I can have on the screen. I’m looking for any tips on optimization and threading. I’m mostly self-taught so if my documentation is bad please let me know and I’ll clean it up. Thanks!
Thread class:
public class ThreadedJob {
private bool m_IsDone = false;
private object m_Handle = new object();
private System.Threading.Thread m_Thread = null;
public bool IsDone
{
get
{
bool tmp;
lock (m_Handle)
{
tmp = m_IsDone;
}
return tmp;
}
set
{
lock (m_Handle)
{
m_IsDone = value;
}
}
}
public virtual void Start()
{
m_Thread = new System.Threading.Thread(Run);
m_Thread.Start();
}
public virtual void Abort()
{
m_Thread.Abort();
}
protected virtual void ThreadFunction() { }
protected virtual void OnFinished() { }
public virtual bool Update()
{
if (IsDone)
{
OnFinished();
return true;
}
return false;
}
IEnumerator WaitFor()
{
while (!Update())
{
yield return null;
}
}
private void Run()
{
ThreadFunction();
IsDone = true;
}
}
Neural net handler class (to interact with Unity API):
public class BrainInterface : MonoBehaviour
{
EyeControl[] eyes;
JetControl[] jets;
Brain brain;
public float[] inputValues;
public float[] outputValues;
public float[] weights;
int inputNum, layerNum, neuronPerLayer, outputNum;
void Start()
{
Birth birth = gameObject.GetComponent<Birth>();
eyes = GetComponentsInChildren<EyeControl>();
jets = GetComponentsInChildren<JetControl>();
inputNum = eyes.Length;
layerNum = 1;
neuronPerLayer = 1;
outputNum = jets.Length;
// Debug.Log("output number is " + outputNum);
inputValues = new float[inputNum];
for(int i = 0; i < inputNum; i++)
{
inputValues *= 0;*
}
outputValues = new float[outputNum];
for (int i = 0; i < outputNum; i++)
{
outputValues = 0;
}
weights = birth.arWeights;
brain = new Brain(inputNum, layerNum, neuronPerLayer, outputNum, weights);
brain.inputVal = inputValues;
foreach(float f in inputValues)
{
Debug.Log(f);
}
brain.Start();
}
void Update()
{
// Debug.Log(“reached”);
if(brain != null)
{
// Debug.Log(“brain is thinking”);
if (brain.Update())
{
// Debug.Log(“completed one think sesh”);
brain.inputVal = inputValues;
outputValues = brain.output;
brain.Start();
}
}
for(int j = 0; j < jets.Length; j++)
{
jets[j].setSpeed(outputValues[j]);
}
}
Brain class (too big to put the whole thing so this is just the function that “thinks”)
protected override void ThreadFunction()
{
think();
}
public void think()
{
// Debug.Log(“in the think function”);
// Debug.Log(inputVal.Length);
for(int i = 0; i < inputVal.Length; i++)
{
// Debug.Log("inputting value of " + inputVal*);*
}
//get the new inputs and calculate the first layer
for(int neu = 0; neu < neuronsPerLayer; neu++)
{
// Debug.Log(“now calculaing inputs for " + neu + " neuron”);
for (int i = 0; i < inputVal.Length; i++)
{
midLayer[0, neu].sumInput(inputVal*, i);*
// yield return null;
}
midLayer[0, neu].calOutput();
midLayer[0, neu].clearInput();
// Debug.Log("neuron " + neu + " has an output of " + midLayer[0, neu].getOutput());
// yield return null;
}
//calculate all the middle layers (might be none)
for(int lay = 1; lay < layerNum; lay++)
{
// Debug.Log(“now on " + lay + " layer”);
for (int neu = 0; neu < neuronsPerLayer; neu++)
{
// Debug.Log("working on neuron " + neu);
for(int oP = 0; oP < neuronsPerLayer; oP++)
{
midLayer[lay, neu].sumInput(midLayer[lay - 1, oP].getOutput(), oP);
// yield return null;
}
midLayer[lay, neu].calOutput();
midLayer[lay, neu].clearInput();
// Debug.Log("neuron " + neu + " has an output of " + midLayer[lay, neu].getOutput());
// yield return null;
}
}
//calculate the outputs
// Debug.Log(“now calculating the outputs”);
for(int neu = 0; neu < outputNum; neu++)
{
for(int oP = 0; oP< neuronsPerLayer; oP++)
{
outLayer[neu].sumInput(midLayer[layerNum - 1, oP].getOutput(), oP);
// yield return null;
}
outLayer[neu].calOutput();
outLayer[neu].clearInput();
Debug.Log("neuron " + neu + " has an output of " + outLayer[neu].getOutput());
output[neu] = outLayer[neu].getOutput();
}
// Debug.Log(“at the end of the thought”);
}
Thanks in advance for your time!
_*[1]: http://answers.unity3d.com/questions/357033/unity3d-and-c-coroutines-vs-threading.html*_

