summaryrefslogtreecommitdiffstats
path: root/ai/Layer.cpp
diff options
context:
space:
mode:
authorBen Boeckel <MathStuf@gmail.com>2007-09-21 15:36:22 +0000
committerBen Boeckel <MathStuf@gmail.com>2007-09-21 15:36:22 +0000
commit5b55d13ead7e352ee1feaae72009e8abf5bd071a (patch)
tree6c2838312dd7f42769280e24e8abc16b53c165cb /ai/Layer.cpp
parente94d9893b8753e72adb92b2c5eb203830ddf641c (diff)
downloadsigen-5b55d13ead7e352ee1feaae72009e8abf5bd071a.tar.gz
sigen-5b55d13ead7e352ee1feaae72009e8abf5bd071a.tar.xz
sigen-5b55d13ead7e352ee1feaae72009e8abf5bd071a.zip
[FIX] Neural Network methods complete
[FIX] Wrapped Node up into the layer [FIX] Wrapped NatureEffect into Nature [FIX] Getting around to fixing up the design of the PokéMod stuff [FIX] Creating new subclasses now returns pointer to new subclass [FIX] Simplified interfaces [FIX] Minor style issues [FIX] Renamed CoinItem to CoinListObject [FIX] Renamed MapTrainerTeam to MapTrainerPokemon [FIX] Renamed MapWildPokemon to MapWildListPokemon [FIX] Moved global enums to relevant classes [FIX] Removed general logging features [DEL] pokemod/Debug.{h, cpp} [DEL] pokemod/Path.{h, cpp} [FIX] Using QFile rather than custom Path class for checking for files [FIX] Set* methods now return a bool to let the caller know if anything actually changed (if it can fail, otherwise it is void) [ADD] Compliation without errors is required for pokemod from now on before commits git-svn-id: https://pokegen.svn.sourceforge.net/svnroot/pokegen/trunk@24 6ecfd1a5-f3ed-3746-8530-beee90d26b22
Diffstat (limited to 'ai/Layer.cpp')
-rw-r--r--ai/Layer.cpp542
1 files changed, 333 insertions, 209 deletions
diff --git a/ai/Layer.cpp b/ai/Layer.cpp
index 67d18d13..5afee91a 100644
--- a/ai/Layer.cpp
+++ b/ai/Layer.cpp
@@ -1,209 +1,333 @@
-/////////////////////////////////////////////////////////////////////////////
-// Name: ai/Layer.cpp
-// Purpose: A layer of a NeuralNet
-// Author: Ben Boeckel
-// Modified by: Ben Boeckel
-// Created: Thu May 5 15:55:21 2007
-// Copyright: ©2007 Nerdy Productions
-// Licence:
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License along
-// with this program. If not, see <http://www.gnu.org/licenses/>.
-/////////////////////////////////////////////////////////////////////////////
-
-#include "Layer.h"
-
-PokeGen::NeuralNetwork::Layer::Layer(const Layer *par, const Layer *cld, const unsigned num) :
- parent(par),
- child(cld)
-{
- for (unsigned i = 0; i < num; ++i)
- nodes.append(Node(this, i));
- if (parent)
- parent->RandomizeWeights();
-}
-
-void PokeGen::NeuralNetwork::Layer::SaveData(QFile &fout) const
-{
- fout << "-Layer\n";
- for (unsigned i = 0; i < GetNumNodes(); ++i)
- nodes[i].SaveData(fout);
-}
-
-void PokeGen::NeuralNetwork::Layer::LoadData(const QFile &fin)
-{
- QChar next;
- nodes.clear();
- fin >> next;
- while (next == '+')
- {
- AddNode();
- nodes[GetNumNodes() - 1].LoadData(fin.readLine());
- fin >> next;
- }
-}
-
-void PokeGen::NeuralNetwork::Layer::AddNode()
-{
- nodes.append(Node(this, GetNumNodes()));
- parent->UpdateBias();
-}
-
-void PokeGen::NeuralNetwork::Layer::DeleteNode(const unsigned n)
-{
- if (n < GetNumNodes())
- {
- nodes.erase(nodes.begin() + n);
- parent->UpdateBias(n);
- }
-}
-
-void PokeGen::NeuralNetwork::Layer::UpdateBias(const unsigned n)
-{
- if (n == UINT_MAX)
- bias.append((abs(std::rand()) % 201) / 100.0);
- else if (n < GetNumNodes())
- bias.erase(bias.begin() + n);
- else
- return;
- for (unsigned i = 0; i < GetNumNodes(); ++i)
- nodes[i].UpdateWeights(n);
-}
-
-unsigned PokeGen::NeuralNetwork::Layer::GetNumNodes() const
-{
- return nodes.size();
-}
-
-void PokeGen::NeuralNetwork::Layer::RandomizeWeights()
-{
- bias.clear();
- for (unsigned i = 0; i < child->GetNumNodes(); ++i)
- bias.append((abs(std::rand()) % 201) / 100.0);
- for (unsigned i = 0; i < GetNumNodes(); ++i)
- nodes[i].RandomizeWeights();
-}
-
-void PokeGen::NeuralNetwork::Layer::CalculateErrors()
-{
- for (unsigned i = 0; i < GetNumNodes(); ++i)
- nodes[i].CalculateError();
-}
-
-void PokeGen::NeuralNetwork::Layer::AdjustWeights()
-{
- for (unsigned i = 0; i < GetNumNodes(); ++i)
- nodes[i].AdjustWeights();
-}
-
-void PokeGen::NeuralNetwork::Layer::CalculateValues()
-{
- for (unsigned i = 0; i < GetNumNodes(); ++i)
- nodes[i].CalculateValue();
-}
-
-void PokeGen::NeuralNetwork::Layer::SetInput(const unsigned n, const double i)
-{
- if (n < GetNumNodes())
- nodes[n].SetInput(i);
-}
-
-void PokeGen::NeuralNetwork::Layer::SetDesired(const unsigned n, const double o)
-{
- if (n < GetNumNodes())
- nodes[n].SetDesired(o);
-}
-
-void PokeGen::NeuralNetwork::Layer::SetMomentum(const unsigned n, const double m)
-{
- if (n < GetNumNodes())
- nodes[n].SetMomentum(m);
-}
-
-void PokeGen::NeuralNetwork::Layer::SetMomentumFactor(const unsigned n, const double m)
-{
- if (n < GetNumNodes())
- nodes[n].SetMomentumFactor(m);
-}
-
-void PokeGen::NeuralNetwork::Layer::SetLearnRate(const unsigned n, const double l)
-{
- if (n < GetNumNodes())
- nodes[n].SetLearnRate(l);
-}
-
-void PokeGen::NeuralNetwork::Layer::SetFunction(const unsigned n, const unsigned f)
-{
- if (n < GetNumNodes())
- nodes[n].SetFunction(f);
-}
-
-double PokeGen::NeuralNetwork::Layer::GetOutput(const unsigned n) const
-{
- if (n < GetNumNodes())
- return nodes[n].GetOutput();
- return 0;
-}
-
-double PokeGen::NeuralNetwork::Layer::GetError(const unsigned n) const
-{
- if (n < GetNumNodes())
- return nodes[n].GetError();
- return 0;
-}
-
-double PokeGen::NeuralNetwork::Layer::GetMomentum(const unsigned n) const
-{
- if (n < GetNumNodes())
- return nodes[n].GetMomentum();
- return 0;
-}
-
-double PokeGen::NeuralNetwork::Layer::GetMomentumFactor(const unsigned n) const
-{
- if (n < GetNumNodes())
- return nodes[n].GetMomentumFactor();
- return 0;
-}
-
-double PokeGen::NeuralNetwork::Layer::GetLearnRate(const unsigned n) const
-{
- if (n < GetNumNodes())
- return nodes[n].GetLearnRate();
- return 0;
-}
-
-unsigned PokeGen::NeuralNetwork::Layer::GetFunction(const unsigned n) const
-{
- if (n < GetNumNodes())
- return nodes[n].GetFunction();
- return UINT_MAX;
-}
-
-double PokeGen::NeuralNetwork::Layer::GetWeight(const unsigned n, const unsigned i) const
-{
- if (n < GetNumNodes())
- return nodes[n].GetWeight(i);
- return 0;
-}
-
-void PokeGen::NeuralNetwork::Layer::ChangeBias(const unsigned n, const double d)
-{
- bias[n] += d * GetError(n) * parent->GetBias(n);
-}
-
-double PokeGen::NeuralNetwork::Layer::GetBias(const unsigned n) const
-{
- if (n < GetNumNodes())
- return bias[n];
- return 0;
-}
+/////////////////////////////////////////////////////////////////////////////
+// Name: ai/Layer.cpp
+// Purpose: A layer of a NeuralNet
+// Author: Ben Boeckel
+// Modified by: Ben Boeckel
+// Created: Thu May 5 15:55:21 2007
+// Copyright: ©2007 Nerdy Productions
+// Licence:
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program. If not, see <http://www.gnu.org/licenses/>.
+/////////////////////////////////////////////////////////////////////////////
+
+#include "Layer.h"
+
+PokeGen::NeuralNetwork::Layer::Layer(const unsigned num) :
+ parent(NULL),
+ child(NULL)
+{
+ for (unsigned i = 0; i < num; ++i)
+ AddNode();
+}
+
+void PokeGen::NeuralNetwork::Layer::SaveData(Ini& nnData, const unsigned i) const
+{
+ nnData.AddField("numBias", bias.size());
+ for (int j = 0; j < bias.size(); ++j)
+ nnData.AddField(QString("layer%1-bias%2").arg(i).arg(j), bias[i]);
+ nnData.AddField("numNodes", GetNumNodes());
+ for (unsigned j = 0; j < GetNumNodes(); ++j)
+ {
+ nnData.AddField(QString("layer%1-node%2-input").arg(i).arg(j), nodes[j].input);
+ nnData.AddField(QString("layer%1-node%2-output").arg(i).arg(j), nodes[j].output);
+ nnData.AddField(QString("layer%1-node%2-momentum").arg(i).arg(j), nodes[j].momentum);
+ nnData.AddField(QString("layer%1-node%2-momentumFactor").arg(i).arg(j), nodes[j].momentumFactor);
+ nnData.AddField(QString("layer%1-node%2-learnRate").arg(i).arg(j), nodes[j].learnRate);
+ nnData.AddField(QString("layer%1-node%2-function").arg(i).arg(j), nodes[j].function);
+ for (int k = 0; k < nodes[j].weights.size(); ++k)
+ {
+ nnData.AddField(QString("layer%1-node%2-weight%3").arg(i).arg(j).arg(k), nodes[j].weights[k]);
+ nnData.AddField(QString("layer%1-node%2-weightChange%3").arg(i).arg(j).arg(k), nodes[j].weightChanges[k]);
+ }
+ }
+}
+
+void PokeGen::NeuralNetwork::Layer::SetParent(Layer* par)
+{
+ parent = par;
+}
+
+void PokeGen::NeuralNetwork::Layer::SetChild(Layer* cld)
+{
+ child = cld;
+ if (child)
+ RandomizeWeights();
+}
+
+void PokeGen::NeuralNetwork::Layer::AddNode()
+{
+ nodes.append(Node(child ? child->GetNumNodes() : 0));
+ if (parent)
+ parent->RandomizeWeights();
+}
+
+bool PokeGen::NeuralNetwork::Layer::DeleteNode(const unsigned n)
+{
+ if (n < GetNumNodes())
+ {
+ nodes.removeAt(n);
+ if (parent)
+ parent->RandomizeWeights();
+ return true;
+ }
+ return false;
+}
+
+unsigned PokeGen::NeuralNetwork::Layer::GetNumNodes() const
+{
+ return nodes.size();
+}
+
+bool PokeGen::NeuralNetwork::Layer::RandomizeWeights()
+{
+ if (child)
+ {
+ bias.clear();
+ for (unsigned i = 0; i < child->GetNumNodes(); ++i)
+ bias.append((abs(std::rand()) % 201) / 100.0);
+ for (unsigned i = 0; i < GetNumNodes(); ++i)
+ {
+ nodes[i].weights.clear();
+ nodes[i].weightChanges.clear();
+ for (unsigned j = 0; j < child->GetNumNodes(); ++j)
+ {
+ nodes[i].weights.append((abs(std::rand()) % 201) / 100.0);
+ nodes[i].weightChanges.append(0);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool PokeGen::NeuralNetwork::Layer::CalculateErrors()
+{
+ if (parent)
+ {
+ for (unsigned i = 0; i < GetNumNodes(); ++i)
+ {
+ if (child)
+ {
+ nodes[i].error = 0;
+ for (unsigned j = 0; j < child->GetNumNodes(); ++j)
+ nodes[i].error += child->GetError(j) * nodes[i].weights[j];
+ }
+ else
+ nodes[i].error = nodes[i].desired - nodes[i].output;
+ switch (nodes[i].function)
+ {
+ case Step:
+ nodes[i].error *= .01;
+ break;
+ case SymmetricSigmoid:
+ nodes[i].error *= 2;
+ case Sigmoid:
+ nodes[i].error *= nodes[i].output * (1 - nodes[i].output);
+ break;
+ case InverseTangent:
+ nodes[i].error *= 1 / (1 + (nodes[i].output * nodes[i].output));
+ break;
+ case HyperbolicTangent:
+ nodes[i].error *= 1 - tanh(nodes[i].output) * tanh(nodes[i].output);
+ break;
+ case Radial:
+ nodes[i].error *= 2 * nodes[i].output * exp(nodes[i].output * nodes[i].output);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool PokeGen::NeuralNetwork::Layer::AdjustWeights()
+{
+ if (child)
+ {
+ double delta;
+ for (unsigned i = 0; i < GetNumNodes(); ++i)
+ {
+ for (unsigned j = 0; j < child->GetNumNodes(); ++j)
+ {
+ delta = nodes[i].learnRate * child->GetError(j) * nodes[i].output;
+ nodes[i].weights[j] += delta + nodes[i].momentum * nodes[i].weightChanges[j] + nodes[i].momentumFactor * nodes[i].weightChanges[j];
+ nodes[i].weightChanges[j] = delta;
+ }
+ }
+ for (unsigned i = 0; i < child->GetNumNodes(); ++i)
+ bias[i] += child->GetLearnRate(i) * child->GetError(i) * bias[i];
+ return true;
+ }
+ return false;
+}
+
+bool PokeGen::NeuralNetwork::Layer::CalculateValues()
+{
+ if (parent)
+ {
+ for (unsigned i = 0; i < GetNumNodes(); ++i)
+ {
+ double val = 0;
+ for (unsigned j = 0; j < parent->GetNumNodes(); ++j)
+ val += parent->GetOutput(j) * parent->GetWeight(j, i);
+ val += parent->GetBias(i);
+ switch (nodes[i].function)
+ {
+ case Identity:
+ nodes[i].output = val;
+ break;
+ case Step:
+ nodes[i].output = (val <= 0) ? 0 : 1;
+ break;
+ case Sigmoid:
+ nodes[i].output = 1.0 / (1 + exp(val));
+ break;
+ case SymmetricSigmoid:
+ nodes[i].output = 2.0 / (1 + exp(val)) - 1;
+ break;
+ case InverseTangent:
+ nodes[i].output = atan(val);
+ break;
+ case HyperbolicTangent:
+ nodes[i].output = tanh(val);
+ break;
+ case Radial:
+ nodes[i].output = exp(val * val);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool PokeGen::NeuralNetwork::Layer::SetInput(const unsigned n, const double i)
+{
+ if (n < GetNumNodes())
+ {
+ nodes[n].input = i;
+ return true;
+ }
+ return false;
+}
+
+bool PokeGen::NeuralNetwork::Layer::SetDesired(const unsigned n, const double o)
+{
+ if (n < GetNumNodes())
+ {
+ nodes[n].desired = o;
+ return true;
+ }
+ return false;
+}
+
+bool PokeGen::NeuralNetwork::Layer::SetMomentum(const unsigned n, const double m)
+{
+ if (n < GetNumNodes())
+ {
+ nodes[n].momentum = m;
+ return true;
+ }
+ return false;
+}
+
+bool PokeGen::NeuralNetwork::Layer::SetMomentumFactor(const unsigned n, const double m)
+{
+ if (n < GetNumNodes())
+ {
+ nodes[n].momentumFactor = m;
+ return true;
+ }
+ return false;
+}
+
+bool PokeGen::NeuralNetwork::Layer::SetLearnRate(const unsigned n, const double l)
+{
+ if (n < GetNumNodes())
+ {
+ nodes[n].learnRate = l;
+ return true;
+ }
+ return false;
+}
+
+bool PokeGen::NeuralNetwork::Layer::SetFunction(const unsigned n, const unsigned f)
+{
+ if ((n < GetNumNodes()) && (f < FunctionEnd))
+ {
+ nodes[n].function = f;
+ return true;
+ }
+ return false;
+}
+
+double PokeGen::NeuralNetwork::Layer::GetOutput(const unsigned n) const
+{
+ if (n < GetNumNodes())
+ return nodes[n].output;
+ return 0;
+}
+
+double PokeGen::NeuralNetwork::Layer::GetDesired(const unsigned n) const
+{
+ if (n < GetNumNodes())
+ return nodes[n].desired;
+ return 0;
+}
+
+double PokeGen::NeuralNetwork::Layer::GetError(const unsigned n) const
+{
+ if (n < GetNumNodes())
+ return nodes[n].error;
+ return 0;
+}
+
+double PokeGen::NeuralNetwork::Layer::GetMomentum(const unsigned n) const
+{
+ if (n < GetNumNodes())
+ return nodes[n].momentum;
+ return 0;
+}
+
+double PokeGen::NeuralNetwork::Layer::GetMomentumFactor(const unsigned n) const
+{
+ if (n < GetNumNodes())
+ return nodes[n].momentumFactor;
+ return 0;
+}
+
+double PokeGen::NeuralNetwork::Layer::GetLearnRate(const unsigned n) const
+{
+ if (n < GetNumNodes())
+ return nodes[n].learnRate;
+ return 0;
+}
+
+unsigned PokeGen::NeuralNetwork::Layer::GetFunction(const unsigned n) const
+{
+ if (n < GetNumNodes())
+ return nodes[n].function;
+ return FunctionEnd;
+}
+
+double PokeGen::NeuralNetwork::Layer::GetWeight(const unsigned n, const unsigned i) const
+{
+ if (n < GetNumNodes())
+ return nodes[n].weights[i];
+ return 0;
+}
+
+double PokeGen::NeuralNetwork::Layer::GetBias(const unsigned n) const
+{
+ if (n < child->GetNumNodes())
+ return bias[n];
+ return 0;
+}