/Neural-Network-From-Scratch-in-Cpp-using-Pipes

Developed a Neural Network from scratch in C++ and use processes according to the number of layers and used threads for the neurons in the layers. Named Pipes are used to store the values of a layer and then pass it to the other layer.

Primary LanguageC++

Neural Network Code

The provided code is an implementation of a neural network. It consists of multiple processes and threads working together to perform the calculations. Below is a step-by-step guide explaining the code functionality:

Processing of the Neural Networks

Neural1 Neural2 Neural3 ## Also the BackTracking Neural4
  1. Include the necessary libraries:
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <iostream>
#include <sstream>
using namespace std;
  1. Define constants and variables:
const int num_processes = 7;
const int max_num_threads = 8;
double input[] = {0.1, 0.2};
// Neural network weights
double input_weight_1[][8] = { ... };
double hidden_layer_1_weights[][8] = { ... };
double hidden_layer_2_weights[][8] = { ... };
double hidden_layer_3_weights[][8] = { ... };
double hidden_layer_4_weights[][8] = { ... };
double hidden_layer_5_weights[][8] = { ... };
double output_layer[] = { ... };
double output_1[8] = { ... };
double result[8] = { ... };
double final = 0.0;
double next_input[2] = { ... };

sem_t sem[max_num_threads];
sem_t sem_all_threads_done;
pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
sem_t process_sem[num_processes];
sem_t sem_all_process_done;

struct thread_arg {
    int thread_id;
    int process_id;
};
  1. Define a helper function to perform the neural network calculations:
void *thread_process(void *arg) {
    struct thread_arg *ta = (struct thread_arg *)arg;

    sem_wait(&sem[ta->thread_id - 1]);

    // Perform calculations based on the process and thread ID
    // Update the result array with the calculated values

    sem_post(&sem[ta->thread_id % max_num_threads]);
    sem_post(&sem_all_threads_done);

    return nullptr;
}
  1. Define a function to process a specific layer of the neural network:
void process(int id, int num_threads) {
    pthread_t threads[max_num_threads];
    struct thread_arg args[max_num_threads];

    // Launch the threads
    for (int i = 0; i < num_threads; ++i) {
        args[i].thread_id = i + 1;
        args[i].process_id = id;
        pthread_create(&threads[i], nullptr, thread_process, (void *)&args[i]);
    }

    // Wait for all the threads to finish without using pthread_join()
    for (int i = 0; i < num_threads; ++i) {
        sem_wait(&sem_all_threads_done);
    }

    // Print the process ID and the calculated result
    std::cout << "Process " << id << " calculated result: " << result[0] << std::endl;
}
  1. Define a helper function to calculate the values for the next input:
void final_next(double x) {
    // Perform calculations to get the values for the next input
    next_input[0] = value_1;
    next_input[1] = value_2;
    cout << endl;
    cout << "Values for next input are  " << next_input[0] << " and  " << next_input[1] << endl;
}
  1. Implement the main function
int main() {
    // Initialize the semaphores
    for (int i = 0; i < max_num_threads; ++i) {
        sem_init(&sem[i], 0, 0);
    }
    sem_init(&sem_all_threads_done, 0, 0);

    for (int i = 0; i < num_processes; ++i) {
        sem_init(&process_sem[i], 0, 0);
    }
    sem_init(&sem_all_process_done, 0, 0);

    // Create child processes
    pid_t pid;
    for (int i = 0; i < num_processes; ++i) {
        pid = fork();
        if (pid < 0) {
            cout << "Fork error!" << endl;
            return 1;
        } else if (pid == 0) {
            // Child process
            process(i);
            sem_post(&sem_all_process_done);
            return 0;
        }
    }

    // Parent process
    // Wait for all child processes to finish
    for (int i = 0; i < num_processes; ++i) {
        sem_wait(&sem_all_process_done);
    }

    // Calculate values for the next input
    final_next(final);

    // Close the semaphores
    sem_destroy(&sem_all_threads_done);
    for (int i = 0; i < max_num_threads; ++i) {
        sem_destroy(&sem[i]);
    }
    for (int i = 0; i < num_processes; ++i) {
        sem_destroy(&process_sem[i]);
    }
    sem_destroy(&sem_all_process_done);

    return 0;
}
  1. Use helper function to calculate the values for the next input:
void final_next(double x) {
    // Perform calculations to get the values for the next input
    next_input[0] = value_1;
    next_input[1] = value_2;
    cout << endl;
    cout << "Values for next input are  " << next_input[0] << " and  " << next_input[1] << endl;
}
  1. Pass the updated values of the output to the next cpp file whose comiplationed file is named ./q2 using:

You can change the ./q2 to whatever you like to just named it exactly the compiled file you make

For Example

 g++ -pthread forward_backward_propagation_1.cpp -o q1
  g++ -pthread forward_propagation_2.cpp -o q2
  
  # in the End you need to run the q1 

./q1

# this will also exexcute your q2 file.

For Sending Values to the next file forward_propagation_2.cpp

 execlp("./q2", "./q2", oss.str().c_str(), (char *)NULL);
  1. Recieve the data in the argumentd of the main of the next file and put it into another array
int main(int argc, char *argv[])
{
   std::istringstream iss(argv[1]);

   // Parse the string back into double values
   iss >> input[0] >> input[1];

   std::cout << "Values: " << input[0] << ", " << input[1] << '\n';

CopyRight,

This is Code is totally done by Muhammad Ali Ahson. If you like this code then please star this repo and folow me.