Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <vector>
- #include <iostream>
- #include <cstdlib>
- #include <cassert>
- #include <cmath>
- #include <fstream>
- #include <sstream>
- using namespace std;
- /* --- --- --- Training --- --- --- */
- class TrainingData
- {
- public:
- TrainingData(vector<unsigned> topology);
- void getTopology(vector<unsigned> &topology);
- unsigned getNextInputs(vector<double> &inputVals);
- unsigned getTargetOutputs(vector<double> &targetOutputVals);
- private:
- vector<double> _inputVals;
- vector<double> _outputVals;
- vector<unsigned> _topology;
- };
- TrainingData::TrainingData(vector<unsigned> topology)
- {
- _topology = topology;
- }
- void TrainingData::getTopology(vector<unsigned> &topology)
- {
- for (unsigned i = 0; i < _topology.size(); i++)
- {
- topology.push_back(_topology[i]);
- }
- }
- unsigned TrainingData::getNextInputs(vector<double> &inputVals)
- {
- _inputVals.clear();
- _outputVals.clear();
- inputVals.clear();
- int n1 = (int)(2.0 * rand() / double(RAND_MAX));
- int n2 = (int)(2.0 * rand() / double(RAND_MAX));
- int t = n1 ^ n2; //should be 1 or 0
- _inputVals.push_back(n1);
- _inputVals.push_back(n2);
- _outputVals.push_back(t);
- inputVals.push_back(n1);
- inputVals.push_back(n2);
- return inputVals.size();
- }
- unsigned TrainingData::getTargetOutputs(vector<double> &targetOutputVals)
- {
- targetOutputVals.clear();
- for (unsigned i = 0; i < _outputVals.size(); i++)
- {
- targetOutputVals.push_back(_outputVals[i]);
- }
- return targetOutputVals.size();
- }
- struct Connection
- {
- double weight;
- double deltaWeight;
- };
- class Neuron;
- typedef vector<Neuron> Layer;
- /* --- --- --- Neuron --- --- --- */
- class Neuron
- {
- public:
- Neuron(unsigned numOutputs, unsigned myIndex);
- void setOutputVal(double val) { _outputVal = val; }
- double getOutputVal(void) const { return _outputVal; }
- void feedForward(const Layer &prevLayer);
- void calOutputGradients(double targetVal);
- void calcOutputHiddenGradients(const Layer &nextLayer);
- void updateInputWeights(Layer &prevLayer);
- private:
- static double _eta;
- static double _alpha;
- static double _transferFunction(double x);
- static double _transferFunctionDerivative(double x);
- static double _randomWeight(void) { return rand() / double(RAND_MAX); }
- double _sumDow(const Layer &nextLayer) const;
- double _outputVal;
- vector<Connection> _outputWeights;
- unsigned _myIndex;
- double _gradient;
- };
- /*-- Neuron::public --*/
- double Neuron::_eta = 0.15; //overall learning rate
- double Neuron::_alpha = 0.5;
- Neuron::Neuron(unsigned numOutputs, unsigned myIndex)
- {
- for (unsigned c = 0; c < numOutputs; c++)
- {
- _outputWeights.push_back(Connection());
- _outputWeights.back().weight = _randomWeight();
- }
- _myIndex = myIndex;
- }
- void Neuron::feedForward(const Layer &prevLayer)
- {
- double sum = 0.0;
- for (unsigned n = 0; n < prevLayer.size(); n++)
- {
- sum += prevLayer[n].getOutputVal() *
- prevLayer[n]._outputWeights[_myIndex].weight;
- }
- _outputVal = Neuron::_transferFunction(sum);
- }
- void Neuron::calOutputGradients(double targetVal)
- {
- double delta = targetVal - _outputVal;
- _gradient = delta * Neuron::_transferFunctionDerivative(_outputVal);
- }
- void Neuron::calcOutputHiddenGradients(const Layer &nextLayer)
- {
- double dow = _sumDow(nextLayer);
- _gradient = dow * Neuron::_transferFunctionDerivative(_outputVal);
- }
- void Neuron::updateInputWeights(Layer &prevLayer)
- {
- for (unsigned n = 0; n < prevLayer.size(); ++n)
- {
- Neuron &neuron = prevLayer[n];
- double oldDeltaWeight = neuron._outputWeights[_myIndex].deltaWeight;
- double newDeltaWeight =
- _eta *
- neuron.getOutputVal() *
- _gradient +
- _alpha *
- oldDeltaWeight;
- neuron._outputWeights[_myIndex].deltaWeight = newDeltaWeight;
- neuron._outputWeights[_myIndex].weight += newDeltaWeight;
- }
- }
- /*-- Neuron::private --*/
- double Neuron::_transferFunction(double x)
- {
- return tanh(x);
- }
- double Neuron::_transferFunctionDerivative(double x)
- {
- return 1.0 - x*x;
- }
- double Neuron::_sumDow(const Layer &nextLayer) const
- {
- double sum = 0.0;
- for (unsigned n = 0; n < nextLayer.size() - 1; n++)
- {
- sum += _outputWeights[n].weight * nextLayer[n]._gradient;
- }
- return sum;
- }
- /* --- --- --- Net --- --- --- */
- class Net
- {
- public:
- Net(const vector<unsigned> &topology);
- void feedForward(const vector<double> &inputVals);
- void backProp(const vector<double> &targetVals);
- void getResults(vector<double> &resultVals) const;
- double gerRecentAverageError(void) const { return _recentAverageError; }
- private:
- vector<Layer> _layers;
- double _error;
- double _recentAverageError;
- double _recentAverageSmoothingFactor;
- };
- /*-- Net::public --*/
- Net::Net(const vector<unsigned> &topology)
- {
- unsigned numLayers = topology.size();
- for (unsigned layerNum = 0; layerNum < numLayers; layerNum++)
- {
- _layers.push_back(Layer());
- unsigned numOutputs = layerNum == topology.size() - 1 ? 0 : topology[layerNum + 1];
- for (unsigned neuronNum = 0; neuronNum <= topology[layerNum]; neuronNum++)
- {
- _layers.back().push_back(Neuron(numOutputs, neuronNum));
- cout << "Made a neuron! Layer: " << layerNum << "\n";
- }
- }
- }
- void Net::feedForward(const vector<double> &inputVals)
- {
- assert(inputVals.size() == _layers.size() - 1);
- for (unsigned i = 0; i < inputVals.size(); i++)
- {
- _layers[0][i].setOutputVal(inputVals[i]);
- }
- //Forward propagate
- for (unsigned layerNum = 1; layerNum < _layers.size() - 1; layerNum++)
- {
- Layer &prevLayer = _layers[layerNum - 1];
- for (unsigned n = 0; n < _layers[layerNum].size() - 1; n++)
- {
- _layers[layerNum][n].feedForward(prevLayer); //Neuron::feedForward()
- }
- }
- }
- void Net::backProp(const vector<double> &targetVals)
- {
- //RMSE [sqrt(MSE)]
- Layer &outputLayer = _layers.back();
- _error = 0.0;
- for (unsigned n = 0; n < outputLayer.size() - 1; n++)
- {
- double delta = targetVals[n] - outputLayer[n].getOutputVal();
- _error += delta * delta;
- }
- _error /= outputLayer.size() - 1;
- _error = sqrt(_error);
- //running average of an error
- _recentAverageError =
- (_recentAverageError * _recentAverageSmoothingFactor + _error)
- / (_recentAverageSmoothingFactor + 1.0);
- //calc output layer gradient
- for (unsigned n = 0; n < outputLayer.size() - 1; n++)
- {
- outputLayer[n].calOutputGradients(targetVals[n]);
- }
- //calc gradient on hidden layers
- for (unsigned layerNum = _layers.size() - 2; layerNum > 0; --layerNum)
- {
- Layer &hiddenLayer = _layers[layerNum];
- Layer &nextLayer = _layers[layerNum + 1];
- for (unsigned n = 0; n < hiddenLayer.size(); n++)
- {
- hiddenLayer[n].calcOutputHiddenGradients(nextLayer);
- }
- }
- for (unsigned layerNum = _layers.size() - 1; layerNum > 0; --layerNum)
- {
- Layer &layer = _layers[layerNum];
- Layer &prevLayer = _layers[layerNum - 1];
- for (unsigned n = 0; n < layer.size() - 1; ++n)
- {
- layer[n].updateInputWeights(prevLayer);
- }
- }
- }
- void Net::getResults(vector<double> &resultVals) const
- {
- resultVals.clear();
- for (unsigned n = 0; n < _layers.back().size() - 1; ++n)
- {
- resultVals.push_back(_layers.back()[n].getOutputVal());
- }
- }
- /*-- Net::private --*/
- /* -=NULL=- */
- void showVectorVals(string label, vector<double> &v)
- {
- cout << label << " ";
- for (unsigned i = 0; i < v.size(); i++)
- {
- cout << v[i] << " ";
- }
- cout << "\n";
- }
- int main()
- {
- vector<unsigned> topology;
- topology.push_back(2);
- topology.push_back(4);
- topology.push_back(1);
- TrainingData trainData(topology);
- Net myNet(topology);
- vector<double> inputVals, targetVals, resultVals;
- int trainingPass = 0;
- bool end = false;
- for (; 2 < 3;)
- {
- ++trainingPass;
- cout << "\n" << "Pass: " << trainingPass;
- if (trainData.getNextInputs(inputVals) != topology[0])
- {
- break;
- }
- showVectorVals(": Inputs:", inputVals);
- myNet.feedForward(inputVals);
- //collect net's actual results
- myNet.getResults(resultVals);
- showVectorVals("Outputs:", resultVals);
- //train the net
- trainData.getTargetOutputs(targetVals);
- showVectorVals("Targets:", targetVals);
- assert(targetVals.size() == topology.back());
- myNet.backProp(targetVals);
- cout << "Ten recent avg error: " << myNet.gerRecentAverageError() << "\n";
- system("PAUSE");
- }
- system("PAUSE");
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement