我一直在网上关注jeff heaton指南,我来到这一点,我正在尝试创建一个简单的NN,它有三个输入神经元和一个输出神经元没有隐藏层三个权重与这三个输入神经元相关联。
神经网络从总共6个二进制组合中识别出3个比特的两个二进制组合。
以下是代码:
class neural{
double weight1=1.0,weight2=1.0,weight3=1.0;
double learningRate = 0.000001;
public double getOutput(double i1,double i2,double i3,double ideals){
double u = weight1*i1 + weight2*i2 + weight3*i3;
double error = 0.0;
error = ideals -u;
weight1 += error * learningRate * i1;
weight2 += error * learningRate * i2 ;
weight3 += error * learningRate * i3 ;
return u;
}
}
public class pattern{
public static void main(String argz[]){
neural a = new neural();
for(int i = 0; i < 2000; i++){
a.getOutput(0.0, 0.0, 0.0,0.0);
a.getOutput(0.0, 0.0, 1.0,1.0);
a.getOutput(0.0, 1.0, 0.0,1.0);
a.getOutput(0.0, 1.0, 1.0,0.0);
a.getOutput(1.0, 1.0, 0.0,0.0);
a.getOutput(1.0, 1.0, 1.0,1.0);
}
}
}
正如@Widdershins所指出的那样,我尝试了低至0.000001的学习率
任何高于0.5的值都是1,低于此值的任何值都是0.因此输出为000101而不是011001
答案 0 :(得分:2)
所以,让我们在脑海中解决这个问题。
u
是输入和给定权重的结果。
ideals
是您希望实现的输出。
error
则u
出错了;它应该是从 u
到ideals
的距离。也就是说,它应该是ideals - u
。这似乎是正确的。
你的学习价值似乎相当高。设置这些值太高可以引起振荡而不是收敛,尤其是对于高度常规的输入。您是否在学习循环结束后的连续运行中检查了您的体重值是什么样的?你试过降低学习率吗?
免责声明:我不是神经网络专家,您应该考虑我做出的任何断言,但这是我的理解。
编辑:我尝试使用更小的学习值(介于0.25和0.01之间)运行代码,只需200次,并获得所需的输出。你不应该为网络提供几乎两万个循环这么简单,并且记得保持你的学习率足够低以避免奇怪的结果:有大约200个学习循环,网络将开始输出学习率达到约0.7的临界值时,000101而不是001010不正确。学习率越低,即使是非常低的学习率,也会产生更好的结果。
现在我们正在研究sigmoid函数:
import java.util.Random;
import java.util.Arrays;
public class NeuralNet {
static final Random rand = new Random();
static final double[][] teach = new double[][]
{ {0d, 0d, 0d, 0d},
{0d, 0d, 1d, 0d},
{0d, 1d, 0d, 1d},
{0d, 1d, 1d, 0d},
{1d, 1d, 0d, 1d},
{1d, 1d, 1d, 0d} };
public static void main(String[] args) {
Neural a = new Neural();
for(int i = 0; i < 2000; i++){
int t = rand.nextInt(teach.length);
a.learn(teach[t][0], teach[t][1], teach[t][2], teach[t][3]);
}
System.out.println(a);
for (int t = 0; t < teach.length; t++) {
System.out.println(a.react(teach[t][0], teach[t][1], teach[t][2]));
}
}
public static double sigmoid(double u) {
return 1 / (1 + Math.exp(-u));
}
static class Neural {
static final double INIT_WEIGHT_RANGE = 1 / Math.sqrt(3);
final double LEARNING_RATE = 0.1;
double offset = (rand.nextDouble() * 2 - 1) * INIT_WEIGHT_RANGE,
weight1 = (rand.nextDouble() * 2 - 1) * INIT_WEIGHT_RANGE,
weight2 = (rand.nextDouble() * 2 - 1) * INIT_WEIGHT_RANGE,
weight3 = (rand.nextDouble() * 2 - 1) * INIT_WEIGHT_RANGE;
public double learn(double i1, double i2, double i3, double ideals) {
double u =
offset +
weight1 * i1 +
weight2 * i2 +
weight3 * i3;
u = sigmoid(u);
double correction = (ideals - u) * LEARNING_RATE;
offset += correction;
weight1 += correction * i1;
weight2 += correction * i2;
weight3 += correction * i3;
return u;
}
public double react(double i1, double i2, double i3) {
double u =
offset +
weight1 * i1 +
weight2 * i2 +
weight3 * i3;
return sigmoid(u);
}
public String toString() {
// how lazy!
return Arrays.toString(new double[] {offset, weight1, weight2, weight3});
}
}
}
我现在已经对我们应该具备什么样的反向传播功能进行了相当多的阅读,但只是将它保持为线性似乎工作得非常好。 For all I can tell这可能是正确的。有了足够的纪元,这几乎可以学习从0到1的任何值。
答案 1 :(得分:1)
理想输出0和理想输出1的训练模式不是线性可分的,这意味着没有隐藏层的网络无法学习您想要获得的预期输出。特别要注意的是,当i1 = 0时你要求的输出等同于众所周知的xor问题。请参阅此here的解释。