老妪能训,老妪能编--用现代C++构建的前向、反向传播神经网络的例子。构建一个具有任意层数和每层任意结点数的全连接神经网络(backpropagation Neural Network

为了做到老妪能训练,老妪能编程……

使用现代C++构建的前向、反向传播神经网络的例子。构建一个具有任意层数和每层任意结点数的全连接神经网络(backpropagation Neural Network)。这个例子也包括了基本的梯度下降优化,要求实现异或xor的神经网络,要求输入数据有四组{1,0}、{0,1}、{1,1}、{0,0},训练目标数据target也有四个{1}、{1}、{0}、{0}……要求每次train训练结束以后将weights权重矩阵保存到文本文件,以供下次添加其它训练数据后,使用上次训练的权重矩阵接着训练!

// modern异或c++ArbitraryLayerBackpropagationNN调整权重矩阵230830a.cpp :

//使用现代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 
#include 
//#include 
#include 
#include 
#include  //std::to_string
#pragma warning(disable : 4996)

using namespace std;

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

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

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

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

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

    // 初始化网络权重和偏置
    std::vector>> initialize_weights(const std::vector& layers) {
        std::vector>> 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> layer_weights;

            for (int j = 0; j < layers[i]; ++j) {
                std::vector 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 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 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 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];
                    weights[i][j][k] += 0.05 * deltas[i + 1][j] * layers[i][k];     //学习率 LearningRate
                }
            }
        }
    }

    void train(vector> inputs, vector> 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> inputs = { {1, 1}, {0, 0}, {1, 0}, {0, 1} };
    vector> targets = { {0}, {0}, {1}, {1} };

    vector>inputs22= { {1, 1}, {0, 1}, {1, 0}, {0, 0} };

    NeuralNetwork nn({ 2, 6,6,4, 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, 5000);// 10000);

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

        if (4 == choice) {
            
            nn.weights = nn.initialize_weights({ 2, 6,6,4, 1 }); 网络结构

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

        inputs22[1] = { 0,0 };
        cout << "[0,0:_ ";
        nn.feedForwarOut(inputs22[1]);
        inputs22[2] = { 1,0 };
        cout << "[1,0:_ ";
        nn.feedForwarOut(inputs22[2]);
//        inputs22[3] = { 0,1 };
        cout << "[1,1:_ ";
        nn.feedForwarOut(inputs22[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(

你可能感兴趣的:(c++,算法,开发语言)