首页 文章

神经网络的输出每次都保持相同的值

提问于
浏览
2

我正在研究一个非常简单的前馈神经网络来练习我的编程技巧 . 有3个类:

  • Neural :: Net;构建网络,提供输入值(目前没有反向传播)

  • Neural :: Neuron;具有神经元的特征(指数,输出,重量等)

  • Neural :: Connection;类似结构的类,随机化权重并保持输出,增量权重等 .

该程序非常基础:我使用2个隐藏层和随机权重构建网络,然后要求它提供相同的输入值 .

我的问题是:预计程序在每次运行后都会以不同的输出值结束,但输出总是相同的 . 我尝试在任何地方放置标记,以了解为什么它一遍又一遍地计算相同的东西,但我不能把我的手指放在错误上 .

这是代码:

#include <iostream>
#include <cassert>
#include <cstdlib>
#include <vector>
#include "ConsoleColor.hpp"

using namespace std;

namespace Neural {
    class Neuron;
    typedef vector<Neuron> Layer;

    // ******************** Class: Connection ******************** //
    class Connection {
    public:
        Connection();
        void setOutput(const double& outputVal) { myOutputVal = outputVal; }
        void setWeight(const double& weight) { myDeltaWeight = myWeight - weight; myWeight = weight; }
        double getOutput(void) const { return myOutputVal; }
        double getWeight(void) const { return myWeight; }
    private:
        static double randomizeWeight(void) { return rand() / double(RAND_MAX); }
        double myOutputVal;
        double myWeight;
        double myDeltaWeight;
    };

    Connection::Connection() { 
        myOutputVal = 0;
        myWeight = Connection::randomizeWeight();
        myDeltaWeight = myWeight;
        cout << "Weight: " << myWeight << endl;
    }

    // ******************** Class: Neuron ************************ //
    class Neuron {
    public:
        Neuron();
        void setIndex(const unsigned int& index) { myIndex = index; }
        void setOutput(const double& output) { myConnection.setOutput(output); }
        unsigned int getIndex(void) const { return myIndex; }
        double getOutput(void) const { return myConnection.getOutput(); }
        void feedForward(const Layer& prevLayer);
        void printOutput(void) const;

    private:
        inline static double transfer(const double& weightedSum);
        Connection myConnection;
        unsigned int myIndex;
    };

    Neuron::Neuron() : myIndex(0), myConnection() { } 
    double Neuron::transfer(const double& weightedSum) { return 1 / double((1 + exp(-weightedSum))); }
    void Neuron::printOutput(void) const { cout << "Neuron " << myIndex << ':' << myConnection.getOutput() << endl; }
    void Neuron::feedForward(const Layer& prevLayer) {
        // Weight sum of the previous layer's output values
        double weightedSum = 0;
        for (unsigned int i = 0; i < prevLayer.size(); ++i) {
            weightedSum += prevLayer[i].getOutput()*myConnection.getWeight();
            cout << "Neuron " << i << " from prevLayer has output: " << prevLayer[i].getOutput() << endl;
            cout << "Weighted sum: " << weightedSum << endl;
        }
        // Transfer function
        myConnection.setOutput(Neuron::transfer(weightedSum));
        cout << "Transfer: " << myConnection.getOutput() << endl;
    }

    // ******************** Class: Net *************************** //
    class Net {
    public:
        Net(const vector<unsigned int>& topology);
        void setTarget(const vector<double>& targetVals);
        void feedForward(const vector<double>& inputVals);
        void backPropagate(void);
        void printOutput(void) const;
    private:
        vector<Layer> myLayers;
        vector<double> myTargetVals;

    };
    Net::Net(const vector<unsigned int>& topology) : myTargetVals() {
        assert(topology.size() > 0);
        for (unsigned int i = 0; i < topology.size(); ++i) { // Creating the layers
            myLayers.push_back(Layer(((i + 1) == topology.size()) ? topology[i] : topology[i] + 1)); // +1 is for bias neuron
            // Setting each neurons index inside layer
            for (unsigned int j = 0; j < myLayers[i].size(); ++j) {
                myLayers[i][j].setIndex(j); 
            }
            // Console log
            cout << red;
            if (i == 0) {
                cout << "Input layer (" << myLayers[i].size() << " neurons including bias neuron) created." << endl;
                myLayers[i].back().setOutput(1);
            }
            else if (i < topology.size() - 1) { 
                cout << "Hidden layer " << i << " (" << myLayers[i].size() << " neurons including bias neuron) created." << endl; 
                myLayers[i].back().setOutput(1);
            }
            else { cout << "Output layer (" << myLayers[i].size() << " neurons) created." << endl; }
            cout << white;
        }
    }
    void Net::setTarget(const vector<double>& targetVals) { assert(targetVals.size() == myLayers.back().size()); myTargetVals = targetVals; }
    void Net::feedForward(const vector<double>& inputVals) {
        assert(myLayers[0].size() - 1 == inputVals.size());
        for (unsigned int i = 0; i < inputVals.size(); ++i) { // Setting input vals to input layer
            cout << yellow << "Setting input vals...";
            myLayers[0][i].setOutput(inputVals[i]); // myLayers[0] is the input layer
            cout << "myLayer[0][" << i << "].getOutput()==" << myLayers[0][i].getOutput() << white << endl;
        }
        for (unsigned int i = 1; i < myLayers.size() - 1; ++i) { // Updating hidden layers
            for (unsigned int j = 0; j < myLayers[i].size() - 1; ++j) { // - 1 because bias neurons do not have input
                cout << "myLayers[" << i << "].size()==" << myLayers[i].size() << endl;
                cout << green << "Updating neuron " << j << " inside layer " << i << white << endl;
                myLayers[i][j].feedForward(myLayers[i - 1]); // Updating the neurons output based on the neurons of the previous layer
            }
        }
        for (unsigned int i = 0; i < myLayers.back().size(); ++i) { // Updating output layer
            cout << green << "Updating output neuron " << i << ": " << white << endl;
            const Layer& prevLayer = myLayers[myLayers.size() - 2];
            myLayers.back()[i].feedForward(prevLayer); // Updating the neurons output based on the neurons of the previous layer
        }
    }
    void Net::printOutput(void) const {
        for (unsigned int i = 0; i < myLayers.back().size(); ++i) {
            cout << blue;  myLayers.back()[i].printOutput(); cout << white;
        }
    }
    void Net::backPropagate(void) {

    }
}

int main(int argc, char* argv[]) {
    vector<unsigned int> myTopology;
    myTopology.push_back(3);
    myTopology.push_back(4);
    myTopology.push_back(2);
    myTopology.push_back(2);

    cout << myTopology.size() << endl << endl; // myTopology == {3, 4, 2 ,1}

    vector<double> myTargetVals= {0.5,1};
    vector<double> myInputVals= {1, 0.5, 1};

    Neural::Net myNet(myTopology);
    myNet.feedForward(myInputVals);
    myNet.printOutput();

    return 0;
}

编辑:我认为输入层中的偏置神经元被正确设置为输出1而隐藏层中的偏置神经元被设置为0并且我修复了它 . 但每次运行的输出仍然相同 . 我在一张纸上做了数学计算,然后就可以了 . 这是输出(为清晰起见,颜色编码):

Console log

我已经预期这些值就像权重一样是随机的 . 不应该是这样吗?我很迷惑 .

1 回答

  • 0

    我发现了自己的错误 . 我以为rand()会自动初始化它的种子 . 我知道这是一件蠢事 . 我在程序开头添加了 srand(time(NULL)); ,现在它可以正常工作 .

相关问题