我正在关注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
包含Neurons
。 Paths
使用整数Neurons
标识nid
,Neuron
是相邻Layer
中struct 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循环中。我只是分配了新的权重,而我应该将添加到之前的权重中。
答案 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;
}
}