反向传播算法实现

时间:2013-12-21 19:13:38

标签: c++ neural-network backpropagation

我正在关注this article。我正在使用这篇文章来理解逻辑,但我使用structs以不同的方式实现了它。

问题

问题在于它永远不会收敛到所需的输出。我没有得到我想要的输出。这意味着权重未正确更新。如果我训练网络足够多次,输出会停止更改,这意味着权重不会更新,因此网络认为它已经获得了正确的权重,但输出显示其他情况。

每个神经元都有一个Paths数组。权重是Path的一个属性,而Neurons可以将值'向下发送到'Path,它会转到另一方的Neuron

以下是代码......

const double e =2.7182818284;

神经元:

struct Neuron{

double value;   //Local input
double bias;
double gradient;
double out; //Output value
Path *p;    //path array 
int nc; //number of paths/connections belonging to *this



};

路径:

struct Path{
    double weight;
    double prevDelta;
    double delta;
    int nid;    //neuron id in *n
};

Layers包含NeuronsPaths使用整数Neurons标识nidNeuron是相邻Layerstruct Layer{ int nneurons; //number of neurons in cluster/layer Neuron *n; //Local Neuron array to reference Layer *neighbor; void Transfer(int nid) //compute target Neuron's input and assign it to it { double valueOut=0; Neuron *temp; temp=&n[nid]; //for each connection, send w*v to paired neuron for(int i=0; i<n[nid].nc; i++) { valueOut=temp->p[i].weight * temp->out; //neuron nid(as referenced by p[]), which is in the other layer, receives the value neighbor->n[temp->p[i].nid].value+=valueOut; } } void Initialize(int size) { nneurons=size; n=new Neuron[nneurons]; for(int i=0; i<nneurons; i++) { n[i].value=0.0; n[i].bias=1.0; n[i].out=0.0; } } void FormConnections(Layer& nl)//with neighboring layer { neighbor=&nl; int nCon=neighbor->nneurons; for(int i=0; i<nneurons; i++) { n[i].nc=nCon; n[i].p=new Path[nCon]; //neuron 'i' will link its paths to neurons in the other layer for(int ii=0; ii<n[i].nc; ii++) { n[i].p[ii].weight=1.0; n[i].p[ii].prevDelta=0.0; n[i].p[ii].nid=ii; } } } }; 数组的索引。

层:

 class Brain{
   public:

double eta;
double alpha;
Layer   input,
        hidden,
        output;

double *target;

void GetInput(double* in){
    for(int i=0; i<input.nneurons; i++)
        input.n[i].value=in[i];

}

void GetDesiredOutput(double* t)
{
    target=t;
}

void Initialize(int inputsize, int hiddensize, int outputsize)
{
    input.Initialize(inputsize);
    hidden.Initialize(hiddensize);
    output.Initialize(outputsize);

    input.FormConnections(hidden);
    hidden.FormConnections(output);

}

void BP()
{

    //Calculate gradients for output
    for(int i=0; i<output.nneurons; i++)
    {output.n[i].gradient=(target[i] - output.n[i].out) * (1 - output.n[i].out) * (1 + output.n[i].out);}

    Neuron* temp;
    for(int i=0; i<hidden.nneurons; i++)
        {
            temp=&hidden.n[i];
            temp->gradient=0;
            //for each connection...
            for(int ii=0; ii<hidden.n[i].nc; ii++)
            {
                //temp's gradient gets values in the form w1*g2 + w2*g2 + ... + wn*gn,
                //where w is the weight of p that leads to output.n[i] from temp(hidden), and g
                //is the gradient of that output at p[CurrentConnection].nid

                temp->gradient+= temp->p[ii].weight * output.n[temp->p[ii].nid].gradient;
            }

            //Multiply the resultant sums with d/dx S(x)
            temp->gradient*= (temp->out)*(1-temp->out);


        }
    /

/---------------------------------------------------------------------------
        //Calculate delta

        for(int i=0; i<input.nneurons; i++)
        {
            temp=&input.n[i];

            //temp->bias=eta*temp->gradient;

            for(int ii=0; ii<input.n[i].nc; ii++)
            {   
                temp->p[ii].delta=eta* hidden.n[temp->p[ii].nid].gradient* temp->value;
                temp->p[ii].weight=temp->p[ii].prevDelta*alpha+temp->p[ii].delta;
                temp->p[ii].prevDelta=temp->p[ii].delta;
            }
        }

        for(int i=0; i<hidden.nneurons; i++)
        {
            temp=&hidden.n[i];

            temp->bias=eta*temp->gradient;

            for(int ii=0; ii<hidden.n[i].nc; ii++)
            {   temp->p[ii].delta=eta* output.n[temp->p[ii].nid].gradient* temp->value;
                temp->p[ii].weight=temp->p[ii].prevDelta*alpha+temp->p[ii].delta;
                temp->p[ii].prevDelta=temp->p[ii].delta;
            }

        }

        for(int i=0; i<output.nneurons; i++)
        {
            temp=&output.n[i];

            temp->bias=eta*temp->gradient;
        }
    Zero(hidden);
    Zero(output);
    }

    void Process()
    {
        for(int i=0; i<input.nneurons; i++)
        {   input.n[i].out=input.n[i].value;
            input.Transfer(i);//transfer each neuron data in input to hidden
        }
        for(int i=0; i<hidden.nneurons; i++)
        {

            hidden.n[i].out=Sigmoid(hidden.n[i].value + hidden.n[i].bias);

            hidden.Transfer(i);
        }

        for(int i=0; i<output.nneurons; i++)
        {

            output.n[i].out=HyperTan(output.n[i].value + output.n[i].bias);
            cout<<"Output "<<i<<": "<<output.n[i].out<<endl;
        }


    }

    void Zero(Layer &l){ for(int i=0; i<l.nneurons; i++) l.n[i].value=0.0;}
    void Randomize(Layer &l)
    {
        for(int i=0; i<l.nneurons; i++)
        {
            for(int ii=0; ii<l.n[i].nc; ii++)
            {
                l.n[i].p[ii].weight=rand()%100/10;

            }
        }
    }
    Brain(){eta=0.9; alpha=0.4;}

     double Sigmoid(double x)
  {
    if (x < -45.0) return 0.0;
    else if (x > 45.0) return 1.0;
    else return (1.0 / (1.0 + pow(e, -x)));
  }
  double HyperTan(double x)
  {
    if (x < -10.0) return -1.0;
    else if (x > 10.0) return 1.0;
    else return tanh(x);
  }
};

大脑(神经网络):

Brain b;

double data[]={1.0,2.0, 3.0};
double ddata[]={-0.25,0.14};



b.Initialize(3,4,2);

b.GetDesiredOutput(ddata);
b.GetInput(data);


b.Process();
b.BP();

典型的计划是:

{{1}}

实施例: eta = 0.9,alpha = 0.4  输入1.0,2.0,3.0

我明白了:

  

-0.117471和0.0661122

预期输出为:

  

-0.25,0.14

UPDATE(25/12/2013): 问题在于计算隐藏到输出权重的增量值,并且在使用这些新增量更新权重时存在额外的错误,这些增量都发生在相同的for循环中。我只是分配了新的权重,而我应该添加到之前的权重中。

1 个答案:

答案 0 :(得分:0)

问题在于计算权重的增量值,并且在使用这些新增量更新权重时会出现额外的错误,这些增量都发生在相同的for循环中。我只是分配了新的权重,而我应该将它们添加到之前的权重中。纠正增量计算和权重分配:

for(int i=0; i<input.nneurons; i++)
    {
        temp=&input.n[i];



        for(int ii=0; ii<input.n[i].nc; ii++)
        {   
            temp->p[ii].delta=eta* hidden.n[temp->p[ii].nid].gradient* temp->out;
            temp->p[ii].weight+=temp->p[ii].prevDelta*alpha +temp->p[ii].delta;
            temp->p[ii].prevDelta=temp->p[ii].delta;



        }

    }

隐藏输出:

for(int i=0; i<hidden.nneurons; i++)
    {
        temp=&hidden.n[i];
        temp->bd=eta*temp->gradient;

        temp->bias+=temp->bd+ alpha*temp->pbd;
        temp->pbd=temp->bd;

        for(int ii=0; ii<hidden.n[i].nc; ii++)
        {   
            temp->p[ii].delta=eta* output.n[temp->p[ii].nid].gradient* temp->out;
            temp->p[ii].weight+=temp->p[ii].prevDelta*alpha+ temp->p[ii].delta;
            temp->p[ii].prevDelta=temp->p[ii].delta;


        }

    }