Building a forward backpropagation neural network with modern C++230829a

Use modern C++ to build a neural network, initialize the weight matrix weights, and examples of forward and backpropagation neural networks. Build a fully connected neural network (backpropagation Neural Network) with any number of layers and any number of nodes per layer. This example also includes basic gradient descent optimization, which requires the implementation of an XOR neural network and requires input data to have four groups of {1,0}, {0,1}, {1,1}, {0,0}, The training target data target also has four {1}, {1}, {0}, {0}... It is required to initialize the weight matrix before each train training. After the training, the weights weight matrix is ​​saved to a text file for next time. After adding other training data, use the weight matrix of the last training to continue training! It is required to add a menu, enter 4 to initialize the weight matrix; enter 5 to save the weight matrix to a text file name with a timestamp (the file name has a timestamp weights_yyMMdd .txt) Note that if the month in the time is less than October, add 0 in front, such as January and February!

ChatGPT

The following is sample code for using modern C++ to build a fully connected neural network with forward and back propagation. This example solves the exclusive OR (XOR) problem and includes basic gradient descent optimization. The code also contains a menu for initializing the weight matrix and saving the weight matrix to a timestamped file.

Note: This is just a simplified example to illustrate basic neural network operations and file operations.


//使用现代C++构建的前向、反向传播神经网络的例子。构建一个具有任意层数和每层任意结点数的全连接神经网络(backpropagation Neural Network)。这个例子也包括了基本的梯度下降优化,要求实现异或xor的神经网络,要求输入数据有四组{1,0}、{0,1}、{1,1}、{0,0},训练目标数据target也有四个{1}、{1}、{0}、{0}……要求每次train训练结束以后将weights权重矩阵保存到文本文件,以供下次添加其它训练数据后,使用上次训练的权重矩阵接着训练!要求增加1个菜单,输入4则初始化权重矩阵! modern异或c++ArbitraryLayerBackpropagationNN调整权重矩阵230830a.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <vector>
//#include <cmath>
#include <fstream>
#include <random>
#include <string> //std::to_string
#pragma warning(disable : 4996)

using namespace std;

class NeuralNetwork {
//private:
public:
    vector<vector<vector<double>>> weights;
    vector<vector<double>> layers;
    vector<vector<double>> deltas;

public:
    NeuralNetwork(vector<int> topology) {
        random_device rd;
        mt19937 gen(rd());
        normal_distribution<> d(0.0, 1.0);

        // Initialize weights
        for (int i = 1; i < topology.size(); ++i) {
            vector<vector<double>> layer_weights(topology[i], vector<double>(topology[i - 1]));
            for (auto& neuron_weights : layer_weights) {
                for (auto& weight : neuron_weights) {
                    weight = d(gen);
                }
            }
            weights.push_back(layer_weights);
        }

        // Initialize layers and deltas
        for (int neurons : topology) {
            layers.push_back(vector<double>(neurons, 0.0));
            deltas.push_back(vector<double>(neurons, 0.0));
        }
    }

    //-----------------------------------------------------------------

    // 初始化网络权重和偏置
    std::vector<std::vector<std::vector<double>>> initialize_weights(const std::vector<int>& layers) {
        std::vector<std::vector<std::vector<double>>> weights;
        std::random_device rd;
        std::mt19937 gen(rd());
        std::uniform_real_distribution<> dis(0.0, 1.0);

        for (size_t i = 1; i < layers.size(); ++i) {
            std::vector<std::vector<double>> layer_weights;

            for (int j = 0; j < layers[i]; ++j) {
                std::vector<double> neuron_weights;

                for (int k = 0; k < layers[i - 1]; ++k) {
                    neuron_weights.push_back(dis(gen));
                }

                layer_weights.push_back(neuron_weights);
            }

            weights.push_back(layer_weights);
        }

        return weights;
    }
//===========================================================



    void feedForward(vector<double> input) {
        layers[0] = input;
        for (int i = 1; i < layers.size(); ++i) {
            for (int j = 0; j < layers[i].size(); ++j) {
                layers[i][j] = 0;
                for (int k = 0; k < layers[i - 1].size(); ++k) {
                    layers[i][j] += layers[i - 1][k] * weights[i - 1][j][k];
                }
                layers[i][j] = 1 / (1 + exp(-layers[i][j]));
            }
        }
    }//void feedForward(

    void feedForwarOut(vector<double> input) {
        layers[0] = input;
        for (int i = 1; i < layers.size(); ++i) {
            for (int j = 0; j < layers[i].size(); ++j) {
                layers[i][j] = 0;
                for (int k = 0; k < layers[i - 1].size(); ++k) {
                    layers[i][j] += layers[i - 1][k] * weights[i - 1][j][k];
                }
                layers[i][j] = 1 / (1 + exp(-layers[i][j]));

                cout << layers[i][j];

                cout << "]," << endl;
            }

            cout << "}; " << endl;
            cout << endl;
        }
    }//void feedForwarOut(

    //----------------------------------------------------------------------

    void backPropagate(vector<double> target) {
        for (int i = 0; i < layers.back().size(); ++i) {
            double output = layers.back()[i];
            deltas.back()[i] = output * (1 - output) * (target[i] - output);
        }

        for (int i = layers.size() - 2; i > 0; --i) {
            for (int j = 0; j < layers[i].size(); ++j) {
                double sum = 0;
                for (int k = 0; k < layers[i + 1].size(); ++k) {
                    sum += deltas[i + 1][k] * weights[i][k][j];
                }
                deltas[i][j] = layers[i][j] * (1 - layers[i][j]) * sum;
            }
        }

        for (int i = 0; i < weights.size(); ++i) {
            for (int j = 0; j < weights[i].size(); ++j) {
                for (int k = 0; k < weights[i][j].size(); ++k) {
                    weights[i][j][k] += 0.5 * deltas[i + 1][j] * layers[i][k];
                }
            }
        }
    }

    void train(vector<vector<double>> inputs, vector<vector<double>> targets, int epochs) {
        for (int i = 0; i < epochs; ++i) {
            for (int j = 0; j < inputs.size(); ++j) {
                feedForward(inputs[j]);
                backPropagate(targets[j]);
            }
        }
    }

    void saveWeights(const string& filename) {
        ofstream file(filename);
        if (file.is_open()) {
            for (const auto& layer : weights) {
                for (const auto& neuron : layer) {
                    for (const auto& weight : neuron) {
                        file << weight << " ";
                    }
                    file << endl;
                }
            }
            file.close();
        }
    }

    void loadWeights(const string& filename) {
        ifstream file(filename);
        if (file.is_open()) {
            for (auto& layer : weights) {
                for (auto& neuron : layer) {
                    for (auto& weight : neuron) {
                        file >> weight;
                    }
                }
            }
            file.close();
        }
    }
};


std::string getCurrentTimeStamp() {
    std::time_t t = std::time(nullptr); // 获取当前时间
    std::tm tm = *std::localtime(&t);  // 将 time_t 转换为 tm 结构体

    char buffer[20];
    // 格式化时间字符串为 "yyMMddHHmmss" 格式
    std::strftime(buffer, sizeof(buffer), "%y%m%d%H%M%S", &tm);

    return std::string(buffer);
}

int main() {
    vector<vector<double>> inputs = { {1, 1}, {0, 0}, {1, 0}, {0, 1} };
    vector<vector<double>> targets = { {0}, {0}, {1}, {1} };

    NeuralNetwork nn({ 2, 3, 1 });
    string weightFile = "\/weights220101.txt";

    int choice;

    for (int ii = 0; true; ++ii) {//for110ii
        cout << "Menu: \n";
        cout << "1: (调用上次weights)并继续训练,并保存weights!Load and continue training, then save weights\n";
        cout << "2:(调用上次weights)继续训练,且不保存weights!\n";
        cout << "3:不训练,只保存weights!\n";
        cout << "4: 初始化weights矩阵!Initialize new weights and train, then save weights\n";
        cout << "5:保存weights到 特定文件(带时间戳的)!\n";
        cout << "Enter your choice: ";
        cin >> choice;

        if (choice == 1) {
            nn.loadWeights(weightFile);
        }

        cout << "Training..." << endl;
        nn.train(inputs, targets, 500000);// 10000);

        if (choice == 1 || choice == 4) {
            nn.saveWeights(weightFile);
            cout << "Weights saved to " << weightFile << endl;
        }

        if (4 == choice) {
            
            nn.weights = nn.initialize_weights({ 2, 3, 1 });

        }//
        //-----------------------------------------------------
//        inputs[0] = { 1,1 };
        cout << "[1,1:_ ";
        nn.feedForwarOut(inputs[0]);

//        inputs[1] = { 0,0 };
        cout << "[0,0:_ ";
        nn.feedForwarOut(inputs[1]);
//        inputs[2] = { 1,0 };
        cout << "[1,0:_ ";
        nn.feedForwarOut(inputs[2]);
//        inputs[3] = { 0,1 };
        cout << "[0,1:_ ";
        nn.feedForwarOut(inputs[3]);
        cout << endl;


        if (5 == choice) {
            time_t now = time(0);
            tm* ltm = localtime(&now);
            std::string filename02 = "\/weights_" + getCurrentTimeStamp() + std::to_string(ltm->tm_mday) + ".txt";
            nn.saveWeights( filename02);
        }//if(5==choice
        //======================================================
    }//for110i

    return 0;
}//main(

Guess you like

Origin blog.csdn.net/aw344/article/details/132580018