1 #ifndef NEURAL_NETWORK_HPP
2 #define NEURAL_NETWORK_HPP
35 Neuron(
unsigned numOutputs,
unsigned index);
53 void feedForward(
const std::vector<Neuron>& prevLayer);
78 static double randomWeight();
85 static double activationFunction(
double x);
92 static double activationFunctionDerivative(
double x);
99 double sumDOW(
const std::vector<Neuron>& nextLayer)
const;
102 std::vector<Connection> m_outputWeights;
112 double Neuron::eta = 0.15;
113 double Neuron::alpha = 0.5;
118 for (
unsigned c = 0; c < numOutputs; ++c) {
120 conn.
weight = randomWeight();
122 m_outputWeights.push_back(conn);
139 for (
size_t n = 0; n < prevLayer.size(); ++n) {
140 sum += prevLayer[n].getOutputVal() * prevLayer[n].m_outputWeights[m_myIndex].weight;
143 m_outputVal = Neuron::activationFunction(sum);
147 double delta = targetVal - m_outputVal;
148 m_gradient = delta * Neuron::activationFunctionDerivative(m_outputVal);
152 double dow = sumDOW(nextLayer);
153 m_gradient = dow * Neuron::activationFunctionDerivative(m_outputVal);
158 for (
size_t n = 0; n < prevLayer.size(); ++n) {
159 Neuron& neuron = prevLayer[n];
160 double oldDeltaWeight = neuron.m_outputWeights[m_myIndex].deltaWeight;
162 double newDeltaWeight =
166 + alpha * oldDeltaWeight;
168 neuron.m_outputWeights[m_myIndex].deltaWeight = newDeltaWeight;
169 neuron.m_outputWeights[m_myIndex].weight += newDeltaWeight;
173 double Neuron::randomWeight() {
174 return rand() / double(RAND_MAX);
177 double Neuron::activationFunction(
double x) {
182 double Neuron::activationFunctionDerivative(
double x) {
187 double Neuron::sumDOW(
const std::vector<Neuron>& nextLayer)
const {
191 for (
size_t n = 0; n < nextLayer.size() - 1; ++n) {
192 sum += m_outputWeights[n].weight * nextLayer[n].m_gradient;
214 void feedForward(
const std::vector<double>& inputVals);
220 void backProp(
const std::vector<double>& targetVals);
226 void getResults(std::vector<double>& resultVals)
const;
235 std::vector<std::vector<Neuron>> m_layers;
237 double m_recentAverageError;
238 static double m_recentAverageSmoothingFactor;
242 double NeuralNetwork::m_recentAverageSmoothingFactor = 100.0;
245 size_t numLayers = topology.size();
246 for (
size_t layerNum = 0; layerNum < numLayers; ++layerNum) {
247 m_layers.push_back(std::vector<Neuron>());
248 unsigned numOutputs = (layerNum == topology.size() - 1) ? 0 : topology[layerNum + 1];
251 for (
unsigned neuronNum = 0; neuronNum <= topology[layerNum]; ++neuronNum) {
252 m_layers.back().push_back(
Neuron(numOutputs, neuronNum));
257 m_layers.back().back().setOutputVal(1.0);
262 assert(inputVals.size() == m_layers[0].size() - 1);
265 for (
size_t i = 0; i < inputVals.size(); ++i) {
266 m_layers[0][i].setOutputVal(inputVals[i]);
270 for (
size_t layerNum = 1; layerNum < m_layers.size(); ++layerNum) {
271 std::vector<Neuron>& prevLayer = m_layers[layerNum - 1];
272 for (
size_t n = 0; n < m_layers[layerNum].size() - 1; ++n) {
273 m_layers[layerNum][n].feedForward(prevLayer);
280 std::vector<Neuron>& outputLayer = m_layers.back();
283 for (
size_t n = 0; n < outputLayer.size() - 1; ++n) {
284 double delta = targetVals[n] - outputLayer[n].getOutputVal();
285 m_error += delta * delta;
287 m_error /= outputLayer.size() - 1;
288 m_error = sqrt(m_error);
291 m_recentAverageError =
292 (m_recentAverageError * m_recentAverageSmoothingFactor + m_error)
293 / (m_recentAverageSmoothingFactor + 1.0);
296 for (
size_t n = 0; n < outputLayer.size() - 1; ++n) {
297 outputLayer[n].calcOutputGradients(targetVals[n]);
301 for (
size_t layerNum = m_layers.size() - 2; layerNum > 0; --layerNum) {
302 std::vector<Neuron>& hiddenLayer = m_layers[layerNum];
303 std::vector<Neuron>& nextLayer = m_layers[layerNum + 1];
305 for (
size_t n = 0; n < hiddenLayer.size(); ++n) {
306 hiddenLayer[n].calcHiddenGradients(nextLayer);
311 for (
size_t layerNum = m_layers.size() - 1; layerNum > 0; --layerNum) {
312 std::vector<Neuron>& layer = m_layers[layerNum];
313 std::vector<Neuron>& prevLayer = m_layers[layerNum - 1];
315 for (
size_t n = 0; n < layer.size() - 1; ++n) {
316 layer[n].updateInputWeights(prevLayer);
323 const std::vector<Neuron>& outputLayer = m_layers.back();
324 for (
size_t n = 0; n < outputLayer.size() - 1; ++n) {
325 resultVals.push_back(outputLayer[n].getOutputVal());
330 return m_recentAverageError;
Represents the neural network consisting of layers of neurons.
Definition: NeuralNetwork.hpp:202
void backProp(const std::vector< double > &targetVals)
Performs backpropagation to adjust weights.
Definition: NeuralNetwork.hpp:278
NeuralNetwork(const std::vector< unsigned > &topology)
Constructs a NeuralNetwork with the given topology.
Definition: NeuralNetwork.hpp:244
void feedForward(const std::vector< double > &inputVals)
Feeds the input values forward through the network.
Definition: NeuralNetwork.hpp:261
void getResults(std::vector< double > &resultVals) const
Gets the results from the output layer.
Definition: NeuralNetwork.hpp:321
double getRecentAverageError() const
Gets the recent average error of the network.
Definition: NeuralNetwork.hpp:329
Represents a single neuron in the neural network.
Definition: NeuralNetwork.hpp:28
void setOutputVal(double val)
Sets the output value of the neuron.
Definition: NeuralNetwork.hpp:126
void feedForward(const std::vector< Neuron > &prevLayer)
Feeds forward the input values to the next layer.
Definition: NeuralNetwork.hpp:134
Neuron(unsigned numOutputs, unsigned index)
Constructs a Neuron.
Definition: NeuralNetwork.hpp:115
void updateInputWeights(std::vector< Neuron > &prevLayer)
Updates the input weights for the neuron.
Definition: NeuralNetwork.hpp:156
void calcHiddenGradients(const std::vector< Neuron > &nextLayer)
Calculates the hidden gradients for hidden layers.
Definition: NeuralNetwork.hpp:151
double getOutputVal() const
Gets the output value of the neuron.
Definition: NeuralNetwork.hpp:130
void calcOutputGradients(double targetVal)
Calculates the output gradients for the output layer.
Definition: NeuralNetwork.hpp:146
Represents a connection between neurons with a weight and a change in weight.
Definition: NeuralNetwork.hpp:19
double deltaWeight
The change in weight (for momentum).
Definition: NeuralNetwork.hpp:21
double weight
The weight of the connection.
Definition: NeuralNetwork.hpp:20