反向传播算法的实现
Backpropagation Algorithm Implementation
我正在关注这篇文章。我使用这篇文章来理解逻辑,但我使用structs
以不同的方式实现了它。
问题
问题是它永远不会收敛到期望的输出。我没有得到我想要的输出。这意味着权重没有正确更新。如果我对网络进行足够多次的训练,输出就会停止变化,这意味着权重不会更新,因此网络认为它得到了正确的权重,但输出却显示出相反的情况。
每个神经元都有一个CCD_ 2的数组。权重是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
};
CCD_ 7包含CCD_。Paths
用整数nid
标识Neurons
,该整数是相邻Layer
中的Neuron
阵列的索引。
层:
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();
示例:η=0.9,alpha=0.4对于输入1.0、2.0、3.0
我得到:
-0.1117471和0.0661122
预期输出为:
-0.25,0.14
更新(2013年12月25日):问题是计算隐藏到输出权重的增量值,使用这些新的增量更新权重时出现了额外的错误,这些都发生在同一个for循环中。我只是简单地分配了新的权重,而我应该将它们添加到以前的权重中。
问题在于计算权重的delta值,使用这些新的delta更新权重时出现了额外的错误,这些都发生在同一个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;
}
}
相关文章:
- std::unordered_map 搜索算法是如何实现的?
- 如何实现高效的算法来计算大型数据集的多个不同值?
- 了解算法的性能差异(如果以不同的编程语言实现)
- 它是否定义了哪些算法可以接受可变 lambda 的实现?
- 为什么在此排序算法实现中,向量明显比数组慢?
- 快速实现 PRIM 算法
- 如何知道用于实现标准代码段的确切数据结构和算法,例如在C++STL中?
- 在 Eigen3 中实现 Bartels-Stewart 算法 -- 仅实矩阵?
- 在 c++ 或 python 中生成一个体面的视差图以在 Raspberry Pi 上实现的最佳方法(算法或函数)是什么
- 字母C++实现中的 Prim 算法
- 尝试实现二叉搜索算法,似乎无法使其工作
- C++17 并行算法已经实现了吗?
- AES_XCBC算法的实现
- C++ GDAL 算法 GDALFillNodata() 的实现
- 如何检查 CNG Windows API 是否返回符合 FIPS 的算法实现
- OpenMP:共享同一算法的单线程和多线程实现
- 使用L1CPUCache实现c++算法的Python
- 实现算法(气泡排序)来组织阵列
- 实现O(n)算法来确定字符串是否所有字符都是唯一的
- 我应该如何去实现算法与黑白和彩色图像使用