神经网络反向传播实施问题

Dav*_*s72 5 c++ algorithm machine-learning neural-network

我一直在阅读有关神经网络的很多内容,并使用backprogpagation进行训练,主要是这个Coursera课程,还有来自这里这里的额外阅读.我认为我对核心算法有一个非常好的掌握,但我尝试构建一个反向传播训练的神经网络还没有完全解决,我不知道为什么.

代码是用C++编写的,目前还没有矢量化.

我想构建一个简单的2输入神经元,1个隐藏神经元,1个输出神经元,网络来模拟AND功能.只是为了理解这些概念在进入更复杂的例子之前是如何工作的当我在权重和偏差的值中手工编码时,我的前向传播代码就起作用了.

float NeuralNetwork::ForwardPropagte(const float *dataInput)
{
        int number = 0; // Write the input data into the input layer
        for ( auto & node : m_Network[0])
        {
            node->input = dataInput[number++];
        }

        // For each layer in the network
        for ( auto & layer : m_Network)
        {
            // For each neuron in the layer
            for (auto & neuron : layer)
            {
                float activation;
                if (layerIndex != 0)
                {
                   neuron->input += neuron->bias;
                   activation = Sigmoid( neuron->input);
                } else {
                    activation = neuron->input;
                }

                for (auto & pair : neuron->outputNeuron)
                {
                    pair.first->input += static_cast<float>(pair.second)*activation;
                }
            }
        }

        return Sigmoid(m_Network[m_Network.size()-1][0]->input);
}
Run Code Online (Sandbox Code Playgroud)

其中一些变量命名相当差,但基本上,neuron-> outputNeuron是一对矢量.第一个是指向下一个神经元的指针,第二个是重量值.neuron-> input是神经网络方程中的"z"值,是所有wieghts*激活+ bais的总和.Sigmoid由下式给出:

float NeuralNetwork::Sigmoid(float value) const
{
    return 1.0f/(1.0f + exp(-value));
}
Run Code Online (Sandbox Code Playgroud)

这两个似乎按预期工作.在通过网络之后,所有'z'或'神经元 - >输入'值被重置为零(或者在反向传播之后).

然后我按照下面的psudo代码训练网络.培训代码多次运行.

for trainingExample=0 to m // m = number of training examples
   perform forward propagation to calculate hyp(x)
   calculate cost delta of last layer
         delta = y - hyp(x)
   use the delta of the output to calculate delta for all layers
   move over the network adjusting the weights based on this value
   reset network
Run Code Online (Sandbox Code Playgroud)

实际代码在这里:

void NeuralNetwork::TrainNetwork(const std::vector<std::pair<std::pair<float,float>,float>> & trainingData)
{
    for (int i = 0; i < 100; ++i)
    {
        for (auto & trainingSet : trainingData)
        {
            float x[2] = {trainingSet.first.first,trainingSet.first.second};
            float y      = trainingSet.second;
            float estimatedY = ForwardPropagte(x);

            m_Network[m_Network.size()-1][0]->error = estimatedY - y;
            CalculateError();
            RunBackpropagation();
            ResetActivations();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用反向传播函数给出:

void NeuralNetwork::RunBackpropagation()
{
    for (int index = m_Network.size()-1; index >= 0; --index)
    {
        for(auto &node : m_Network[index])
        {
            // Again where the "outputNeuron" is a list of the next layer of neurons and associated weights
            for (auto &weight : node->outputNeuron)
            {
                weight.second += weight.first->error*Sigmoid(node->input);
            }
            node->bias = node->error; // I'm not sure how to adjust the bias, some of the formulas seemed to point to this. Is it correct?
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

和计算的成本:

void NeuralNetwork::CalculateError()
{
    for (int index = m_Network.size()-2; index > 0; --index)
    {
        for(auto &node : m_Network[index])
        {
            node->error = 0.0f;

            float sigmoidPrime = Sigmoid(node->input)*(1 - Sigmoid(node->input));

            for (auto &weight : node->outputNeuron)
            {
                node->error += (weight.first->error*weight.second)*sigmoidPrime;
            }
        }
    }   
}
Run Code Online (Sandbox Code Playgroud)

我将权重随机化并在数据集上运行:

    x = {0.0f,0.0f} y =0.0f
    x = {1.0f,0.0f} y =0.0f
    x = {0.0f,1.0f} y =0.0f
    x = {1.0f,1.0f} y =1.0f 
Run Code Online (Sandbox Code Playgroud)

当然,我不应该使用相同的数据集进行训练和测试,但我只是想让基本的反向传播算法运行起来.当我运行此代码时,我看到权重/偏差如下:

Layer 0
    Bias 0.111129
    NeuronWeight 0.058659
    Bias -0.037814
    NeuronWeight -0.018420
Layer 1
    Bias 0.016230
    NeuronWeight -0.104935
Layer 2
    Bias 0.080982
Run Code Online (Sandbox Code Playgroud)

运行训练集并且delta [outputLayer]的均方误差看起来像:

Error: 0.156954
Error: 0.152529
Error: 0.213887
Error: 0.305257
Error: 0.359612
Error: 0.373494
Error: 0.374910
Error: 0.374995
Error: 0.375000

... remains at this value for ever...
Run Code Online (Sandbox Code Playgroud)

并且最终的权重看起来像:(它们总是以这个值结束)

Layer 0
    Bias 0.000000
    NeuronWeight 15.385233
    Bias 0.000000
    NeuronWeight 16.492933
Layer 1
    Bias 0.000000
    NeuronWeight 293.518585
Layer 2
    Bias 0.000000
Run Code Online (Sandbox Code Playgroud)

我接受这似乎是学习神经网络的一种迂回方式,而且(目前)实施非常不理想.但是,任何人都可以发现我做出无效假设的任何一点,或者执行或公式是错误的吗?

编辑

感谢偏差值的反馈,我停止将它们应用于输入层并停止通过sigmoid函数传递输入层.另外我的Sigmoid主要功能无效.但网络仍然无法正常工作.我已经更新了上面的错误和输出,现在发生了什么.

Dav*_*s72 1

我解决了我的问题(超出了上面最初的偏见/签名的主要问题)。我开始减去而不是增加权重。在我查看的来源中,他们在增量值计算中有一个负号,我没有,但我保留了将负值添加到权重的格式。此外,我对如何处理重量感到困惑,并误读了一个据说将其分配给错误的来源。我现在发现直觉将其视为正常权重,但乘以偏置常数 1 而不是 z。添加这些更改后,迭代训练集约 1000 次就可以对 OR 和 AND 等简单的按位表达式进行建模。