#include <iostream>
#include <vector>
#include <cmath>
#include <cstdlib>
#include <ctime>
class NeuralNetwork {
private:
std::vector<std::vector<double>> weights1; // Weights between input and hidden layer
std::vector<std::vector<double>> weights2; // Weights between hidden and output layer
std::vector<double> hiddenLayer; // Neurons in the hidden layer
std::vector<double> outputLayer; // Neurons in the output layer
double learningRate;
// Activation function (sigmoid)
double sigmoid(double x) {
return 1.0 / (1.0 + exp(-x));
}
// Derivative of the sigmoid function
double sigmoidDerivative(double x) {
return x * (1.0 - x);
}
public:
NeuralNetwork(int inputSize, int hiddenSize, int outputSize, double lr) : learningRate(lr) {
srand(static_cast<unsigned>(time(0)));
// Initialize weights with random values
weights1.resize(inputSize, std::vector<double>(hiddenSize));
for (auto &row : weights1) {
for (auto &weight : row) {
weight = ((double)rand() / RAND_MAX);
}
}
weights2.resize(hiddenSize, std::vector<double>(outputSize));
for (auto &row : weights2) {
for (auto &weight : row) {
weight = ((double)rand() / RAND_MAX);
}
}
hiddenLayer.resize(hiddenSize);
outputLayer.resize(outputSize);
}
// Feedforward process
std::vector<double> feedForward(const std::vector<double> &input) {
for (size_t i = 0; i < hiddenLayer.size(); ++i) {
double sum = 0.0;
for (size_t j = 0; j < input.size(); ++j) {
sum += input[j] * weights1[j][i];
}
hiddenLayer[i] = sigmoid(sum);
}
for (size_t i = 0; i < outputLayer.size(); ++i) {
double sum = 0.0;
for (size_t j = 0; j < hiddenLayer.size(); ++j) {
sum += hiddenLayer[j] * weights2[j][i];
}
outputLayer[i] = sigmoid(sum);
}
return outputLayer;
}
// Backpropagation process
void backpropagate(const std::vector<double> &input, const std::vector<double> &target) {
std::vector<double> outputError(outputLayer.size());
std::vector<double> hiddenError(hiddenLayer.size());
// Calculate error at output layer
for (size_t i = 0; i < outputLayer.size(); ++i) {
outputError[i] = (target[i] - outputLayer[i]) * sigmoidDerivative(outputLayer[i]);
}
// Calculate error at hidden layer
for (size_t i = 0; i < hiddenLayer.size(); ++i) {
double sum = 0.0;
for (size_t j = 0; j < outputError.size(); ++j) {
sum += outputError[j] * weights2[i][j];
}
hiddenError[i] = sum * sigmoidDerivative(hiddenLayer[i]);
}
// Update weights between hidden and output layer
for (size_t i = 0; i < hiddenLayer.size(); ++i) {
for (size_t j = 0; j < outputLayer.size(); ++j) {
weights2[i][j] += learningRate * outputError[j] * hiddenLayer[i];
}
}
// Update weights between input and hidden layer
for (size_t i = 0; i < input.size(); ++i) {
for (size_t j = 0; j < hiddenLayer.size(); ++j) {
weights1[i][j] += learningRate * hiddenError[j] * input[i];
}
}
}
// Train the neural network
void train(const std::vector<std::vector<double>> &trainingInputs, const std::vector<std::vector<double>> &trainingOutputs, int epochs) {
for (int i = 0; i < epochs; ++i) {
for (size_t j = 0; j < trainingInputs.size(); ++j) {
feedForward(trainingInputs[j]);
backpropagate(trainingInputs[j], trainingOutputs[j]);
}
}
}
// Test the neural network
void test(const std::vector<double> &input) {
std::vector<double> output = feedForward(input);
std::cout << "Output: ";
for (const auto &o : output) {
std::cout << o << " ";
}
std::cout << "\n";
}
};
int main() {
// Simple dataset for XOR problem
std::vector<std::vector<double>> inputs = {{0, 0}, {0, 1}, {1, 0}, {1, 1}};
std::vector<std::vector<double>> outputs = {{0}, {1}, {1}, {0}};
NeuralNetwork nn(2, 2, 1, 0.5);
// Train the network
nn.train(inputs, outputs, 10000);
// Test the network
std::cout << "Testing the trained network on XOR problem:\n";
for (const auto &input : inputs) {
std::cout << "Input: " << input[0] << " " << input[1] << " => ";
nn.test(input);
}
return 0;
}