#include #include // #include // #include // #include #include struct Perceptron { std::vector _weights; double _bias; // random weight between -1 and 1 but not 0 Perceptron(size_t n) : _weights(n) { for (size_t i = 0; i < n; ++i) { _weights[i] = (rand() % 2000 - 1000) / 1000.0; } _bias = (rand() % 2000 - 1000) / 1000.0; } float evaluate(const std::vector& inputs, float (*const activation)(float)) { float sum = 0.0; for (size_t i = 0; i < inputs.size(); ++i) { sum += inputs[i] * _weights[i]; } return activation(sum + _bias); } }; struct Layer { std::vector _perceptrons; float (*const _activation)(float); float (*const _actDeriv)(float); Layer(size_t n, size_t i, float (*const activation)(float), float (*const actDeriv)(float)) : _perceptrons(n, Perceptron(i)), _activation(activation), _actDeriv(actDeriv) { } std::vector evaluate(const std::vector& inputs) { std::vector outputs; for (size_t i = 0; i < _perceptrons.size(); ++i) { outputs.push_back(_perceptrons[i].evaluate(inputs, _activation)); } // std::transform(std::execution::par_unseq, _perceptrons.begin(), _perceptrons.end(), outputs.begin(), [&](Perceptron& perceptron) { // return perceptron.evaluate(inputs, _activation); // }); return outputs; } }; struct NeuralNetwork { private: std::vector _layers; public: NeuralNetwork() { } void addLayer(size_t n, size_t i, float (*const activation)(float), float (*const actDeriv)(float)) { _layers.emplace_back(n, i, activation, actDeriv); } std::vector eval(const std::vector& inputs) { std::vector outputs = inputs; for (int i = 0; i < _layers.size(); ++i) { outputs = _layers[i].evaluate(outputs); } return outputs; } void train(const std::vector>& inputs, const std::vector>& outputs, float learningRate, int epochs) { for (int i = 0; i < epochs; ++i) { float avgError = 0.0; for (int sample = 0; sample < inputs.size(); ++sample) { std::vector> layerOutputs; std::vector> layerInputs; layerInputs.push_back(inputs[sample]); for (int j = 0; j < _layers.size(); ++j) { layerOutputs.push_back(_layers[j].evaluate(layerInputs[j])); layerInputs.push_back(layerOutputs[j]); } std::vector error(outputs[sample].size()); for (int j = 0; j < outputs[sample].size(); ++j) { error[j] = outputs[sample][j] - layerOutputs.back()[j]; } for (int j = _layers.size() - 1; j >= 0; --j) { std::vector newError(_layers[j]._perceptrons.size()); for (int k = 0; k < _layers[j]._perceptrons.size(); ++k) { if (j == _layers.size() - 1) { newError[k] = error[k] * _layers[j]._actDeriv(layerOutputs[j][k]); } else { newError[k] = 0.0; for (int l = 0; l < _layers[j + 1]._perceptrons.size(); ++l) { newError[k] += _layers[j + 1]._perceptrons[l]._weights[k] * error[l]; } newError[k] *= _layers[j]._actDeriv(layerOutputs[j][k]); } } for (int k = 0; k < _layers[j]._perceptrons.size(); ++k) { for (int l = 0; l < layerInputs[j].size(); ++l) { _layers[j]._perceptrons[k]._weights[l] += learningRate * newError[k] * layerInputs[j][l]; } _layers[j]._perceptrons[k]._bias += learningRate * newError[k]; } error = newError; } for (int j = 0; j < error.size(); ++j) { avgError += std::abs(error[j]); } } avgError /= outputs[0].size() * outputs.size(); if (i % 1000 == 0) std::cout << "epoch: " << i << " error: " << avgError << "\n"; } } }; float sigmoid(float x) { return 1.0 / (1.0 + std::expf(-x)); } float sigmoidDerivative(float x) { return x * (1 - x); } int main() { NeuralNetwork nn; nn.addLayer(2, 2, sigmoid, sigmoidDerivative); nn.addLayer(1, 2, sigmoid, sigmoidDerivative); std::vector> ref = { {0, 0}, {0, 1}, {1, 0}, {1, 1} }; std::vector> out = { {0}, {1}, {1}, {0} }; nn.train(ref, out, 0.1, 100000); std::cout << "0, 0: " << nn.eval({0, 0})[0] << "\n"; std::cout << "0, 1: " << nn.eval({0, 1})[0] << "\n"; std::cout << "1, 0: " << nn.eval({1, 0})[0] << "\n"; std::cout << "1, 1: " << nn.eval({1, 1})[0] << "\n"; return 0; }