几天前,我试图将今年在人工智能讲座上学到的关于神经网络的知识付诸实践。我试着做一个简单的,只有2个神经元,可以复制它的输入信号。这是一张网络的小图,以及我的计算:https://i.stack.imgur.com/aKinR.jpg(很抱歉用法语发表评论,它们并不重要)
奇怪的是,它确实收敛了,但对于一个简单的二进制输入信号,当信号为0时,网络有效地发送~0,但当信号为1时,它发送~0.5,我不明白为什么。此外,我必须将学习率设置得很高(约100)才能使其发挥作用,我也不知道为什么。
以下是我用来测试网络的java代码:
public class Main
{
final static double R = 100;
public static void main(String[] args)
{
double w1 = Math.random(), w2 = Math.random();
for (int iter = 1; iter <= 100; iter++)
{
int x;
if (Math.random() >= 0.5)
{
x = 1;
}
else
{
x = 0;
}
double p1 = x * w1;
double y = 1 / (1 + Math.exp(-p1));
double p2 = y * w2;
double z = 1 / (1 + Math.exp(-p2));
double P = -0.5 * Math.pow(x - z, 2);
double dP1 = (x - z) * z * (1 - z) * w2 * y * (1 - y) * x;
double dP2 = (x - z) * z * (1 - z) * y;
w1 += R * dP1;
w2 += R * dP2;
System.out.println("x = " + x + ", z = " + z + ", P = " + P);
}
}
}
你知道问题可能来自哪里吗?
谢谢。
LeChocdesGitans
编辑:
我终于设法让它工作起来了(我听从了你关于网络配置的建议)。我想还有一个实现错误,因为在我改变网络布局后,它没有直接工作,但我重新开始了,现在我可以做一些非常有趣的事情,比如字符识别,与我的应用程序的基础相比,它工作得很好。
再次感谢你的建议!
正如rpd所说,您的主要问题是要连续训练两层。从数学上讲,这意味着应用于节点1的所有校正都必须通过节点2进行滤波。是的,您可以应用链式规则、贝叶斯定理或其他等效的过滤,但这总是存在实现错误的风险。
从您描述的效果来看,您几乎可以肯定在实现中存在错误。最大的线索是,你必须将学习率提高到任何合理的值以上,才能获得哪怕是勉强可以接受的结果。记住,这是识别迈出小步的比例因子。值为100意味着你正在对正确的调整进行最佳的当前估计,然后再进行100倍的调整。如果你的算法的其余部分是正确的,那么超过1.0的学习率就是有意在不收敛的情况下剧烈振荡。
如果您已经跟踪了您的中间值,请发布更新序列;如果没有,则应该使用该调试步骤。
然而,你应该先把你隐藏的神经元并联起来,而不是串联起来。首先,函数的卷积只是浪费步骤。另一方面,权重应该通过相同的过程(并行)进行更新。结果应该收敛于易于归一化为1.0的不同权重(例如,通过SoftMax操作)。一层反向传播是一种低阶计算:在尝试使用您设置的三次(甚至更差)误差函数更快地收敛之前,使用简单的线性过程(欧拉方法)调试该过程。
我对你的笔记和算法做了一些处理,得到了一些观察结果。
-
你在笔记的第一行中去掉了一个负号:如果p(x,z)=-1/2(x-z)^2,则导数为-(x-z)或z-x。在算法中进行这种改变在一定程度上有助于收敛。
-
神经元串联的卷积通常是有缺陷的;这简单地简化为具有单个隐藏神经元的模型。