异或神经网络(FF)收敛到0.5
XOR Neural Network(FF) converges to 0.5
我创建了一个程序,允许我创建任何 size/length 的灵活神经网络,但是我正在使用 XOR 设置的简单结构(前馈、S 形激活、反向传播)对其进行测试,没有批处理)。
编辑:以下是针对我的原始问题的全新方法,它没有提供足够的信息
编辑 2:我在 -2.5 和 2.5 之间开始我的体重,并解决了我的代码中我忘记了一些底片的问题。现在它要么对所有情况收敛到 0,要么对所有情况收敛到 1,而不是 0.5
一切都按照我认为它应该的方式工作,但是它正在向 0.5 收敛,而不是在 0 和 1 的输出之间振荡。我已经完全完成并手工计算了喂养 forward/calculating delta errors/back prop./ 等的整个设置,它与我从程序中得到的相匹配。我还尝试通过改变学习率/动量来优化它,以及增加网络的复杂性(更多 neurons/layers)。
因此,我假设我的方程式中有一个是错误的,或者我对我的神经网络有其他误解。以下是我为每个步骤遵循的方程式逻辑:
我有一个包含两个输入和一个偏置的输入层,一个包含 2 个神经元和一个偏置的隐藏层,以及一个包含 1 个神经元的输出层。
- 分别取两个输入神经元和偏置神经元的输入,分别乘以各自的权重,然后相加作为隐藏层两个神经元的输入。
- 获取每个隐藏神经元的输入,通过 Sigmoid 激活函数(参考 1)并将其用作神经元的输入输出。
- 获取隐藏层中每个神经元的输出(偏置为 1),将它们乘以各自的权重,并将这些值添加到输出神经元的输入。
- 通过 Sigmoid 激活函数传递输出神经元的输入,并将其用作整个网络的输出。
- 计算Delta Error(参考2)输出神经元
- 为 2 个 隐藏 神经元中的每一个计算 Delta Error(参考 3)
- 计算每个权重的梯度(参考4)
- 计算每个权重的 Delta 权重(参考 5),并将其添加到其值中。
- 通过更改输入和预期输出(参考6)
重新开始该过程
以下是对 equations/processes 的具体引用(这可能是我的问题所在!):
- x是神经元的输入:
(1/(1 + Math.pow(Math.E, (-1 * x))))
-1*(actualOutput - expectedOutput)*(Sigmoid(x) * (1 - Sigmoid(x))//Same sigmoid used in reference 1
SigmoidDerivative(Neuron.input)*(The sum of(Neuron.Weights * the deltaError of the neuron they connect to))
ParentNeuron.output * NeuronItConnectsTo.deltaError
learningRate*(weight.gradient) + momentum*(Previous Delta Weight)
- 我有一个 arrayList,其中的值
0,1,1,0
按此顺序排列。它接受第一对(0,1)
,然后期望1
。第二次通过时,它采用第二对 (1,1)
并期望 0
。它只是不断迭代每个新集合的列表。也许以这种系统的方式训练它会导致问题?
就像我之前说的,他们认为我不认为这是代码问题是因为它与我用纸和铅笔计算的结果完全匹配(如果有编码错误就不会发生这种情况)。
另外,当我第一次初始化权重时,我给它们一个介于 0 和 1 之间的随机双精度值。这篇文章表明这可能会导致问题:Neural Network with backpropogation not converging
可能是这样吗? 我使用了 n^(-1/2) 规则,但没有解决问题。
如果我能说得更具体一点或者你想要其他代码请告诉我,谢谢!
这是错误的
SigmoidDerivative(Neuron.input)*((Neuron.Weights * 它们连接的神经元的deltaError之和))
首先是 sigmoid 激活 (g)
第二个是 sigmoid 激活的导数
private double g(double z) {
return 1 / (1 + Math.pow(2.71828, -z));
}
private double gD(double gZ) {
return gZ * (1 - gZ);
}
不相关的说明:你的 (-1*x) 符号真的很奇怪,只需使用 -x
从您如何表述 ANN 的步骤来看,您的实施似乎很差。尝试着重于实现 Forward/BackPropogation,然后是 UpdateWeights 方法。
创建矩阵 class
这是我的Java实现,非常简单,也有些粗糙。我使用 Matrix class 使其背后的数学在代码中显得非常简单。
如果您可以使用 C++ 编写代码,则可以重载运算符,这将使编写更容易理解的代码成为可能。
这是算法 (C++)
所有这些代码都可以在我的 github 上找到(神经网络很简单而且很实用)
每一层都包含偏置节点,这就是为什么有偏移量
void NeuralNet::forwardPropagation(std::vector<double> data) {
setBiasPropogation(); //sets all the bias nodes activation to 1
a(0).set(1, Matrix(data)); //1 to offset for bias unit (A = X)
for (int i = 1; i < layers; ++i) {
// (set(1 -- offsets the bias unit
z(i).set(1, w(i - 1) * a(i - 1));
a(i) = g(z(i)); // g(z ) if the sigmoid function
}
}
void NeuralNet::setBiasPropogation() {
for (int i = 0; i < activation.size(); ++i) {
a(i).set(0, 0, 1);
}
}
outLayer D = A - Y(y为输出数据)
隐藏层 d^l = (w^l(T) * d^l+1) *: gD(a^l)
d = 导数向量
W = 权重矩阵(长度 = 连接,宽度 = 特征)
a = 激活矩阵
gD = 微分函数
^l = IS NOT POWER OF(这仅表示在第 l 层)
- = 点积
*:= multiply (将每个元素相乘"through")
cpy(n) returns 偏移 n 的矩阵副本(忽略 n 行)
void NeuralNet::backwardPropagation(std::vector<double> output) {
d(layers - 1) = a(layers - 1) - Matrix(output);
for (int i = layers - 2; i > -1; --i) {
d(i) = (w(i).T() * d(i + 1).cpy(1)).x(gD(a(i)));
}
}
如果没有图片,解释这段代码可能会令人困惑,所以我发送这个 link,我认为这是一个很好的来源,它还包含对反向传播的解释,这可能比我自己的解释更好。
http://galaxy.agh.edu.pl/~vlsi/AI/backp_t_en/backprop.html
void NeuralNet::updateWeights() {
// the operator () (int l, int w) returns a double reference at that position in the matrix
// thet operator [] (int n) returns the nth double (reference) in the matrix (useful for vectors)
for (int l = 0; l < layers - 1; ++l) {
for (int i = 1; i < d(l + 1).length(); ++i) {
for (int j = 0; j < a(l).length(); ++j) {
w(l)(i - 1, j) -= (d(l + 1)[i] * a(l)[j]) * learningRate + m(l)(i - 1, j);
m(l)(i - 1, j) = (d(l + 1)[i] * a(l)[j]) * learningRate * momentumRate;
}
}
}
}
我创建了一个程序,允许我创建任何 size/length 的灵活神经网络,但是我正在使用 XOR 设置的简单结构(前馈、S 形激活、反向传播)对其进行测试,没有批处理)。
编辑:以下是针对我的原始问题的全新方法,它没有提供足够的信息
编辑 2:我在 -2.5 和 2.5 之间开始我的体重,并解决了我的代码中我忘记了一些底片的问题。现在它要么对所有情况收敛到 0,要么对所有情况收敛到 1,而不是 0.5
一切都按照我认为它应该的方式工作,但是它正在向 0.5 收敛,而不是在 0 和 1 的输出之间振荡。我已经完全完成并手工计算了喂养 forward/calculating delta errors/back prop./ 等的整个设置,它与我从程序中得到的相匹配。我还尝试通过改变学习率/动量来优化它,以及增加网络的复杂性(更多 neurons/layers)。
因此,我假设我的方程式中有一个是错误的,或者我对我的神经网络有其他误解。以下是我为每个步骤遵循的方程式逻辑:
我有一个包含两个输入和一个偏置的输入层,一个包含 2 个神经元和一个偏置的隐藏层,以及一个包含 1 个神经元的输出层。
- 分别取两个输入神经元和偏置神经元的输入,分别乘以各自的权重,然后相加作为隐藏层两个神经元的输入。
- 获取每个隐藏神经元的输入,通过 Sigmoid 激活函数(参考 1)并将其用作神经元的输入输出。
- 获取隐藏层中每个神经元的输出(偏置为 1),将它们乘以各自的权重,并将这些值添加到输出神经元的输入。
- 通过 Sigmoid 激活函数传递输出神经元的输入,并将其用作整个网络的输出。
- 计算Delta Error(参考2)输出神经元
- 为 2 个 隐藏 神经元中的每一个计算 Delta Error(参考 3)
- 计算每个权重的梯度(参考4)
- 计算每个权重的 Delta 权重(参考 5),并将其添加到其值中。
- 通过更改输入和预期输出(参考6) 重新开始该过程
以下是对 equations/processes 的具体引用(这可能是我的问题所在!):
- x是神经元的输入:
(1/(1 + Math.pow(Math.E, (-1 * x))))
-1*(actualOutput - expectedOutput)*(Sigmoid(x) * (1 - Sigmoid(x))//Same sigmoid used in reference 1
SigmoidDerivative(Neuron.input)*(The sum of(Neuron.Weights * the deltaError of the neuron they connect to))
ParentNeuron.output * NeuronItConnectsTo.deltaError
learningRate*(weight.gradient) + momentum*(Previous Delta Weight)
- 我有一个 arrayList,其中的值
0,1,1,0
按此顺序排列。它接受第一对(0,1)
,然后期望1
。第二次通过时,它采用第二对(1,1)
并期望0
。它只是不断迭代每个新集合的列表。也许以这种系统的方式训练它会导致问题?
就像我之前说的,他们认为我不认为这是代码问题是因为它与我用纸和铅笔计算的结果完全匹配(如果有编码错误就不会发生这种情况)。
另外,当我第一次初始化权重时,我给它们一个介于 0 和 1 之间的随机双精度值。这篇文章表明这可能会导致问题:Neural Network with backpropogation not converging
可能是这样吗? 我使用了 n^(-1/2) 规则,但没有解决问题。
如果我能说得更具体一点或者你想要其他代码请告诉我,谢谢!
这是错误的
SigmoidDerivative(Neuron.input)*((Neuron.Weights * 它们连接的神经元的deltaError之和)) 首先是 sigmoid 激活 (g) 第二个是 sigmoid 激活的导数
private double g(double z) {
return 1 / (1 + Math.pow(2.71828, -z));
}
private double gD(double gZ) {
return gZ * (1 - gZ);
}
不相关的说明:你的 (-1*x) 符号真的很奇怪,只需使用 -x
从您如何表述 ANN 的步骤来看,您的实施似乎很差。尝试着重于实现 Forward/BackPropogation,然后是 UpdateWeights 方法。 创建矩阵 class
这是我的Java实现,非常简单,也有些粗糙。我使用 Matrix class 使其背后的数学在代码中显得非常简单。
如果您可以使用 C++ 编写代码,则可以重载运算符,这将使编写更容易理解的代码成为可能。
这是算法 (C++)
所有这些代码都可以在我的 github 上找到(神经网络很简单而且很实用) 每一层都包含偏置节点,这就是为什么有偏移量
void NeuralNet::forwardPropagation(std::vector<double> data) {
setBiasPropogation(); //sets all the bias nodes activation to 1
a(0).set(1, Matrix(data)); //1 to offset for bias unit (A = X)
for (int i = 1; i < layers; ++i) {
// (set(1 -- offsets the bias unit
z(i).set(1, w(i - 1) * a(i - 1));
a(i) = g(z(i)); // g(z ) if the sigmoid function
}
}
void NeuralNet::setBiasPropogation() {
for (int i = 0; i < activation.size(); ++i) {
a(i).set(0, 0, 1);
}
}
outLayer D = A - Y(y为输出数据) 隐藏层 d^l = (w^l(T) * d^l+1) *: gD(a^l)
d = 导数向量
W = 权重矩阵(长度 = 连接,宽度 = 特征)
a = 激活矩阵
gD = 微分函数
^l = IS NOT POWER OF(这仅表示在第 l 层)
- = 点积
*:= multiply (将每个元素相乘"through")
cpy(n) returns 偏移 n 的矩阵副本(忽略 n 行)
void NeuralNet::backwardPropagation(std::vector<double> output) {
d(layers - 1) = a(layers - 1) - Matrix(output);
for (int i = layers - 2; i > -1; --i) {
d(i) = (w(i).T() * d(i + 1).cpy(1)).x(gD(a(i)));
}
}
如果没有图片,解释这段代码可能会令人困惑,所以我发送这个 link,我认为这是一个很好的来源,它还包含对反向传播的解释,这可能比我自己的解释更好。 http://galaxy.agh.edu.pl/~vlsi/AI/backp_t_en/backprop.html
void NeuralNet::updateWeights() {
// the operator () (int l, int w) returns a double reference at that position in the matrix
// thet operator [] (int n) returns the nth double (reference) in the matrix (useful for vectors)
for (int l = 0; l < layers - 1; ++l) {
for (int i = 1; i < d(l + 1).length(); ++i) {
for (int j = 0; j < a(l).length(); ++j) {
w(l)(i - 1, j) -= (d(l + 1)[i] * a(l)[j]) * learningRate + m(l)(i - 1, j);
m(l)(i - 1, j) = (d(l + 1)[i] * a(l)[j]) * learningRate * momentumRate;
}
}
}
}